color changes, client, realization time
This commit is contained in:
@ -0,0 +1,36 @@
|
|||||||
|
# Generated by Django 5.1.4 on 2024-12-21 13:34
|
||||||
|
|
||||||
|
import app.models
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('app', '0002_meal'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterModelOptions(
|
||||||
|
name='meal',
|
||||||
|
options={'verbose_name': 'Danie', 'verbose_name_plural': 'Dania'},
|
||||||
|
),
|
||||||
|
migrations.AlterModelOptions(
|
||||||
|
name='order',
|
||||||
|
options={'verbose_name': 'Zamówienie', 'verbose_name_plural': 'Zamówienia'},
|
||||||
|
),
|
||||||
|
migrations.AlterModelOptions(
|
||||||
|
name='waiter',
|
||||||
|
options={'verbose_name': 'Kelner', 'verbose_name_plural': 'Kelnerzy'},
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='order',
|
||||||
|
name='client',
|
||||||
|
field=models.CharField(blank=True, max_length=250, null=True, verbose_name='Klient'),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='order',
|
||||||
|
name='realization_time',
|
||||||
|
field=models.DateTimeField(default=app.models.default_realization_time, verbose_name='Godzina realizacji'),
|
||||||
|
),
|
||||||
|
]
|
@ -0,0 +1,23 @@
|
|||||||
|
# Generated by Django 5.1.4 on 2024-12-21 14:25
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('app', '0003_alter_meal_options_alter_order_options_and_more'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='order',
|
||||||
|
name='realization_time',
|
||||||
|
field=models.CharField(blank=True, max_length=250, null=True, verbose_name='Godzina realizacji'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='order',
|
||||||
|
name='status',
|
||||||
|
field=models.PositiveSmallIntegerField(choices=[(1, 'Zamówienie złożone'), (2, 'Zamówienie w trakcie przygotowywania'), (3, 'Zamówienie gotowe'), (4, 'Zamówienie zrealizowane')], default=1, verbose_name='Status zamówienia'),
|
||||||
|
),
|
||||||
|
]
|
@ -1,9 +1,14 @@
|
|||||||
from django.db import models
|
from django.db import models
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
from django.utils import timezone
|
||||||
|
|
||||||
# Create your models here.
|
# Create your models here.
|
||||||
|
|
||||||
|
|
||||||
|
def default_realization_time():
|
||||||
|
return timezone.now() # + datetime.timedelta(hours=1)
|
||||||
|
|
||||||
|
|
||||||
class Waiter(models.Model):
|
class Waiter(models.Model):
|
||||||
name = models.CharField(_('Imię i nazwisko'), max_length=120)
|
name = models.CharField(_('Imię i nazwisko'), max_length=120)
|
||||||
|
|
||||||
@ -11,8 +16,8 @@ class Waiter(models.Model):
|
|||||||
return self.name
|
return self.name
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
verbose_name = _("Kelner")
|
verbose_name = _('Kelner')
|
||||||
verbose_name_plural = _("Kelnerzy")
|
verbose_name_plural = _('Kelnerzy')
|
||||||
|
|
||||||
|
|
||||||
class Meal(models.Model):
|
class Meal(models.Model):
|
||||||
@ -22,23 +27,31 @@ class Meal(models.Model):
|
|||||||
return self.name
|
return self.name
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
verbose_name = _("Danie")
|
verbose_name = _('Danie')
|
||||||
verbose_name_plural = _("Dania")
|
verbose_name_plural = _('Dania')
|
||||||
|
|
||||||
|
|
||||||
class Order(models.Model):
|
class Order(models.Model):
|
||||||
created_on = models.DateTimeField(_('Utworzono'), auto_now_add=True)
|
created_on = models.DateTimeField(_('Utworzono'), auto_now_add=True)
|
||||||
updated_on = models.DateTimeField(_('Zaktualizowano'), auto_now=True)
|
updated_on = models.DateTimeField(_('Zaktualizowano'), auto_now=True)
|
||||||
waiter = models.ForeignKey(
|
realization_time = models.CharField(
|
||||||
Waiter, models.SET_NULL, related_name='orders', verbose_name=_('Kelner'), null=True
|
_('Godzina realizacji'), max_length=250, null=True, blank=True
|
||||||
)
|
)
|
||||||
|
waiter = models.ForeignKey(
|
||||||
|
Waiter,
|
||||||
|
models.SET_NULL,
|
||||||
|
related_name='orders',
|
||||||
|
verbose_name=_('Kelner'),
|
||||||
|
null=True,
|
||||||
|
)
|
||||||
|
client = models.CharField(_('Klient'), max_length=250, null=True, blank=True)
|
||||||
data = models.JSONField(_('Dane zamówienia'), default=dict)
|
data = models.JSONField(_('Dane zamówienia'), default=dict)
|
||||||
|
|
||||||
class StatusChoices(models.IntegerChoices):
|
class StatusChoices(models.IntegerChoices):
|
||||||
ORDERED = (1, _('Zamówienie złożone'))
|
ORDERED = (1, _('Zamówienie złożone'))
|
||||||
IN_PROGRESS = (2, ('Zamówienie w trakcie przygotowywania'))
|
IN_PROGRESS = (2, ('Zamówienie w trakcie przygotowywania'))
|
||||||
READY = (3, _('Zamówienie gotowe'))
|
READY = (3, _('Zamówienie gotowe'))
|
||||||
FINALIZED = (4, _('Zamówienie skończone'))
|
FINALIZED = (4, _('Zamówienie zrealizowane'))
|
||||||
|
|
||||||
status = models.PositiveSmallIntegerField(
|
status = models.PositiveSmallIntegerField(
|
||||||
_('Status zamówienia'),
|
_('Status zamówienia'),
|
||||||
@ -47,8 +60,8 @@ class Order(models.Model):
|
|||||||
)
|
)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.id
|
return str(self.id)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
verbose_name = _("Zamówienie")
|
verbose_name = _('Zamówienie')
|
||||||
verbose_name_plural = _("Zamówienia")
|
verbose_name_plural = _('Zamówienia')
|
||||||
|
@ -67,6 +67,8 @@ class OrderSerializer(serializers.ModelSerializer):
|
|||||||
'id',
|
'id',
|
||||||
'created_on',
|
'created_on',
|
||||||
'updated_on',
|
'updated_on',
|
||||||
|
'realization_time',
|
||||||
|
'client',
|
||||||
'waiter',
|
'waiter',
|
||||||
'waiter_name',
|
'waiter_name',
|
||||||
'data',
|
'data',
|
||||||
|
@ -4,7 +4,7 @@ FROM node:alpine AS base
|
|||||||
FROM base AS deps
|
FROM base AS deps
|
||||||
# Check https://github.com/nodejs/docker-node/tree/b4117f9333da4138b03a546ec926ef50a31506c3#nodealpine to understand why libc6-compat might be needed.
|
# Check https://github.com/nodejs/docker-node/tree/b4117f9333da4138b03a546ec926ef50a31506c3#nodealpine to understand why libc6-compat might be needed.
|
||||||
RUN apk add --no-cache libc6-compat
|
RUN apk add --no-cache libc6-compat
|
||||||
WORKDIR /app
|
WORKDIR /src
|
||||||
|
|
||||||
# Install dependencies based on the preferred package manager
|
# Install dependencies based on the preferred package manager
|
||||||
COPY package.json yarn.lock* package-lock.json* pnpm-lock.yaml* ./
|
COPY package.json yarn.lock* package-lock.json* pnpm-lock.yaml* ./
|
||||||
@ -18,14 +18,15 @@ RUN \
|
|||||||
|
|
||||||
# Rebuild the source code only when needed
|
# Rebuild the source code only when needed
|
||||||
FROM base AS builder
|
FROM base AS builder
|
||||||
WORKDIR /app
|
WORKDIR /src
|
||||||
COPY --from=deps /app/node_modules ./node_modules
|
COPY --from=deps /src/node_modules ./node_modules
|
||||||
COPY . .
|
COPY . .
|
||||||
|
|
||||||
# Next.js collects completely anonymous telemetry data about general usage.
|
# Next.js collects completely anonymous telemetry data about general usage.
|
||||||
# Learn more here: https://nextjs.org/telemetry
|
# Learn more here: https://nextjs.org/telemetry
|
||||||
# Uncomment the following line in case you want to disable telemetry during the build.
|
# Uncomment the following line in case you want to disable telemetry during the build.
|
||||||
# ENV NEXT_TELEMETRY_DISABLED 1
|
ENV NEXT_TELEMETRY_DISABLED=1
|
||||||
|
ENV NEXT_PRIVATE_STANDALONE=true
|
||||||
|
|
||||||
RUN yarn build
|
RUN yarn build
|
||||||
|
|
||||||
@ -34,16 +35,16 @@ RUN yarn build
|
|||||||
|
|
||||||
# Production image, copy all the files and run next
|
# Production image, copy all the files and run next
|
||||||
FROM base AS runner
|
FROM base AS runner
|
||||||
WORKDIR /app
|
WORKDIR /src
|
||||||
|
|
||||||
ENV NODE_ENV production
|
ENV NODE_ENV=production
|
||||||
# Uncomment the following line in case you want to disable telemetry during runtime.
|
# Uncomment the following line in case you want to disable telemetry during runtime.
|
||||||
ENV NEXT_TELEMETRY_DISABLED 1
|
ENV NEXT_TELEMETRY_DISABLED=1
|
||||||
|
|
||||||
RUN addgroup --system --gid 1001 nodejs
|
RUN addgroup --system --gid 1001 nodejs
|
||||||
RUN adduser --system --uid 1001 nextjs
|
RUN adduser --system --uid 1001 nextjs
|
||||||
|
|
||||||
COPY --from=builder /app/public ./public
|
COPY --from=builder /src/public ./public
|
||||||
|
|
||||||
# Set the correct permission for prerender cache
|
# Set the correct permission for prerender cache
|
||||||
RUN mkdir .next
|
RUN mkdir .next
|
||||||
@ -51,15 +52,13 @@ RUN chown nextjs:nodejs .next
|
|||||||
|
|
||||||
# Automatically leverage output traces to reduce image size
|
# Automatically leverage output traces to reduce image size
|
||||||
# https://nextjs.org/docs/advanced-features/output-file-tracing
|
# https://nextjs.org/docs/advanced-features/output-file-tracing
|
||||||
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
|
COPY --from=builder --chown=nextjs:nodejs /src/.next/standalone ./
|
||||||
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
|
COPY --from=builder --chown=nextjs:nodejs /src/.next/static ./.next/static
|
||||||
|
|
||||||
USER nextjs
|
USER nextjs
|
||||||
|
|
||||||
EXPOSE 3000
|
EXPOSE 3000
|
||||||
|
|
||||||
ENV PORT 3000
|
ENV PORT=3000
|
||||||
# set hostname to localhost
|
# set hostname to localhost
|
||||||
ENV HOSTNAME "0.0.0.0"
|
CMD HOSTNAME="0.0.0.0" node server.js
|
||||||
|
|
||||||
CMD ["node", "server.js"]
|
|
||||||
|
@ -2,7 +2,8 @@
|
|||||||
|
|
||||||
import useSWR from 'swr'
|
import useSWR from 'swr'
|
||||||
|
|
||||||
export const fetcher = (...args) => fetch(...args).then(res => res.json()) // @ts-ignore
|
// @ts-expect-error ignore ...args type
|
||||||
|
export const fetcher = (...args) => fetch(...args).then(res => res.json())
|
||||||
|
|
||||||
|
|
||||||
export function useUser (id: number) {
|
export function useUser (id: number) {
|
||||||
|
15
frontend/app/components.tsx
Normal file
15
frontend/app/components.tsx
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
import { Order } from './tools';
|
||||||
|
|
||||||
|
export function OrderID({ order }: { order: Order }) {
|
||||||
|
return (
|
||||||
|
<h1 className="text-xl">
|
||||||
|
<span className="font-mono">
|
||||||
|
{'['}
|
||||||
|
{String(order.id % 1000).padStart(3, '0')}
|
||||||
|
{']'}
|
||||||
|
</span>{' '}
|
||||||
|
- Godzina realizacji -{' '}
|
||||||
|
<span className="font-mono">{order.realization_time}</span>
|
||||||
|
</h1>
|
||||||
|
);
|
||||||
|
}
|
@ -3,7 +3,7 @@
|
|||||||
@tailwind utilities;
|
@tailwind utilities;
|
||||||
|
|
||||||
|
|
||||||
form#form p {
|
form#form p, form#form div {
|
||||||
@apply flex flex-col;
|
@apply flex flex-col;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,19 +2,9 @@
|
|||||||
|
|
||||||
import { fetcher } from '@/app/api/tools';
|
import { fetcher } from '@/app/api/tools';
|
||||||
import useSWR from 'swr';
|
import useSWR from 'swr';
|
||||||
import Link from 'next/link';
|
|
||||||
import { useEffect, useRef, useState } from 'react';
|
import { useEffect, useRef, useState } from 'react';
|
||||||
|
import { getDishBg, getOrderBg, Order } from '../tools';
|
||||||
type Order = {
|
import { OrderID } from '../components';
|
||||||
id: number;
|
|
||||||
created_on: string;
|
|
||||||
updated_on: string;
|
|
||||||
waiter: number;
|
|
||||||
waiter_name: string;
|
|
||||||
data: [{ item: string; additional_info: string; finished: boolean }];
|
|
||||||
status: number;
|
|
||||||
status_name: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
export default function Home() {
|
export default function Home() {
|
||||||
const audioRef = useRef({} as HTMLAudioElement);
|
const audioRef = useRef({} as HTMLAudioElement);
|
||||||
@ -25,11 +15,7 @@ export default function Home() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const play = () => {
|
const play = () => {
|
||||||
if (audioRef.current) {
|
if (audioRef.current) audioRef.current.play();
|
||||||
audioRef.current.play();
|
|
||||||
} else {
|
|
||||||
// Throw error
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -48,12 +34,11 @@ export default function Home() {
|
|||||||
play();
|
play();
|
||||||
setPlayedIDs(playedIDs.concat(justPlayed));
|
setPlayedIDs(playedIDs.concat(justPlayed));
|
||||||
}
|
}
|
||||||
}, [data]);
|
}, [playedIDs, data]);
|
||||||
|
|
||||||
const update_finished = (o: number, i: number, v: boolean) => {
|
const update_finished = (o: number, i: number, v: boolean) => {
|
||||||
let d = data;
|
const d = data;
|
||||||
d[o].data[i].finished = v;
|
d[o].data[i].finished = v;
|
||||||
console.log(v);
|
|
||||||
fetch(`/api/orders?id=${d[o].id}`, {
|
fetch(`/api/orders?id=${d[o].id}`, {
|
||||||
method: 'PUT',
|
method: 'PUT',
|
||||||
body: JSON.stringify(d[o]),
|
body: JSON.stringify(d[o]),
|
||||||
@ -64,9 +49,8 @@ export default function Home() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const update_status = (o: number, v: number) => {
|
const update_status = (o: number, v: number) => {
|
||||||
let d = data;
|
const d = data;
|
||||||
d[o].status = v;
|
d[o].status = v;
|
||||||
console.log(v);
|
|
||||||
fetch(`/api/orders?id=${d[o].id}`, {
|
fetch(`/api/orders?id=${d[o].id}`, {
|
||||||
method: 'PUT',
|
method: 'PUT',
|
||||||
body: JSON.stringify(d[o]),
|
body: JSON.stringify(d[o]),
|
||||||
@ -87,36 +71,23 @@ export default function Home() {
|
|||||||
{data?.map((order: Order, oi: number) => (
|
{data?.map((order: Order, oi: number) => (
|
||||||
<li
|
<li
|
||||||
key={order.id}
|
key={order.id}
|
||||||
className={`m-2 p-2 rounded-md border-2 ${
|
className={`m-2 p-2 rounded-md border-2 ${getOrderBg(order)}`}
|
||||||
{
|
|
||||||
1: 'bg-red-200 border-red-400',
|
|
||||||
2: 'bg-purple-200 border-purple-400',
|
|
||||||
3: 'bg-green-200 border-green-400',
|
|
||||||
4: 'bg-gray-100 border-gray-400',
|
|
||||||
}[order.status]
|
|
||||||
}`}
|
|
||||||
>
|
>
|
||||||
<h1 className="text-xl">
|
<OrderID order={order} />
|
||||||
<span className="font-mono">
|
|
||||||
{'['}
|
|
||||||
{String(order.id % 1000).padStart(3, '0')}
|
|
||||||
{']'}
|
|
||||||
</span>{' '}
|
|
||||||
- {new Date(order.updated_on).toLocaleTimeString('pl-PL')}
|
|
||||||
</h1>
|
|
||||||
<h2 className="text-xl">{order.waiter_name}</h2>
|
<h2 className="text-xl">{order.waiter_name}</h2>
|
||||||
|
{ (order.client) ? <h2 className="text-xl">Klient: {order.client}</h2> : <></>}
|
||||||
<h3>
|
<h3>
|
||||||
<select
|
<select
|
||||||
value={order.status}
|
value={order.status}
|
||||||
onChange={(e) =>
|
onChange={(e) =>
|
||||||
update_status(oi, e.target.value as unknown as number)
|
update_status(oi, e.target.value as unknown as number)
|
||||||
}
|
}
|
||||||
className="form border-2 border-gray-500"
|
className="form border-2 my-2 border-gray-500"
|
||||||
>
|
>
|
||||||
<option value="1">Zamówienie złożone</option>
|
<option value="1">Zamówienie złożone</option>
|
||||||
<option value="2">Zamówienie w trakcie przygotowywania</option>
|
<option value="2">Zamówienie w trakcie przygotowywania</option>
|
||||||
<option value="3">Zamówienie gotowe</option>
|
<option value="3">Zamówienie gotowe</option>
|
||||||
<option value="4">Zamówienie skończone</option>
|
<option value="4">Zamówienie zrealizowane</option>
|
||||||
</select>
|
</select>
|
||||||
</h3>
|
</h3>
|
||||||
<div className="">
|
<div className="">
|
||||||
@ -124,7 +95,7 @@ export default function Home() {
|
|||||||
{order.data.map((dish, i) => (
|
{order.data.map((dish, i) => (
|
||||||
<li
|
<li
|
||||||
key={dish.item}
|
key={dish.item}
|
||||||
className={`p-2 m-2 flex gap-4 border-2 bg-white border-gray-400`}
|
className={`p-2 m-2 flex gap-4 border-2 ${getDishBg(dish)}`}
|
||||||
>
|
>
|
||||||
<input
|
<input
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
@ -132,7 +103,7 @@ export default function Home() {
|
|||||||
onChange={(e) => update_finished(oi, i, e.target.checked)}
|
onChange={(e) => update_finished(oi, i, e.target.checked)}
|
||||||
/>
|
/>
|
||||||
<div>
|
<div>
|
||||||
<p className="text-lg">{dish.item}</p>
|
<p className="text-lg">{dish.item} - {dish.takeout ? 'Na wynos' : 'Na miejscu'}</p>
|
||||||
<div>{dish.additional_info}</div>
|
<div>{dish.additional_info}</div>
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
|
@ -1,9 +1,8 @@
|
|||||||
import type { Metadata } from "next";
|
import type { Metadata } from 'next';
|
||||||
import "./globals.css";
|
import './globals.css';
|
||||||
|
|
||||||
export const metadata: Metadata = {
|
export const metadata: Metadata = {
|
||||||
title: "Create Next App",
|
title: 'Bistro',
|
||||||
description: "Generated by create next app",
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function RootLayout({
|
export default function RootLayout({
|
||||||
@ -13,9 +12,7 @@ export default function RootLayout({
|
|||||||
}>) {
|
}>) {
|
||||||
return (
|
return (
|
||||||
<html lang="pl">
|
<html lang="pl">
|
||||||
<body
|
<body className="antialiased p-4 flex flex-col gap-2 items-center">
|
||||||
className={`antialiased p-4 flex flex-col gap-2 items-center`}
|
|
||||||
>
|
|
||||||
{children}
|
{children}
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
import Image from 'next/image';
|
|
||||||
import Link from 'next/link';
|
import Link from 'next/link';
|
||||||
|
|
||||||
export default function Home() {
|
export default function Home() {
|
||||||
|
35
frontend/app/tools.ts
Normal file
35
frontend/app/tools.ts
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
export type Dish = {
|
||||||
|
item: string;
|
||||||
|
additional_info: string;
|
||||||
|
finished: boolean;
|
||||||
|
takeout: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type Order = {
|
||||||
|
id: number;
|
||||||
|
created_on: string;
|
||||||
|
updated_on: string;
|
||||||
|
realization_time: string;
|
||||||
|
client: string;
|
||||||
|
waiter: number;
|
||||||
|
waiter_name: string;
|
||||||
|
data: Dish[];
|
||||||
|
status: number;
|
||||||
|
status_name: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export function getOrderBg(order: Order): string {
|
||||||
|
const nonTakeouts = order.data.filter((dish) => !dish.takeout);
|
||||||
|
|
||||||
|
if (order.status == 4) return 'bg-red-200 border-red-400';
|
||||||
|
|
||||||
|
return nonTakeouts.length > 0
|
||||||
|
? 'bg-green-200 border-green-400'
|
||||||
|
: 'bg-blue-200 border-blue-400';
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getDishBg(dish: Dish): string {
|
||||||
|
return dish.takeout
|
||||||
|
? 'bg-blue-300 border-blue-500'
|
||||||
|
: 'bg-green-300 border-green-500';
|
||||||
|
}
|
@ -3,16 +3,15 @@
|
|||||||
import Link from 'next/link';
|
import Link from 'next/link';
|
||||||
import { useParams, useRouter } from 'next/navigation';
|
import { useParams, useRouter } from 'next/navigation';
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import { useForm, useFieldArray, useWatch, Control } from 'react-hook-form';
|
import { useForm, useFieldArray } from 'react-hook-form';
|
||||||
import { fetcher } from '@/app/api/tools';
|
import { fetcher } from '@/app/api/tools';
|
||||||
import useSWR from 'swr';
|
import useSWR from 'swr';
|
||||||
|
import { Dish } from '@/app/tools';
|
||||||
|
|
||||||
type FormValues = {
|
type FormValues = {
|
||||||
data: {
|
client: string;
|
||||||
item: string;
|
realization_time: string;
|
||||||
additional_info: string;
|
data: Dish[];
|
||||||
finished: boolean;
|
|
||||||
}[];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function App() {
|
export default function App() {
|
||||||
@ -27,9 +26,13 @@ export default function App() {
|
|||||||
formState: { errors },
|
formState: { errors },
|
||||||
} = useForm<FormValues>({
|
} = useForm<FormValues>({
|
||||||
defaultValues: {
|
defaultValues: {
|
||||||
data: [{ item: '', additional_info: '', finished: false }],
|
client: '',
|
||||||
|
realization_time: new Date().toLocaleTimeString('pl-PL', { hour: '2-digit', minute: '2-digit' }),
|
||||||
|
data: [
|
||||||
|
{ item: 'Inne', additional_info: '', finished: false, takeout: false },
|
||||||
|
],
|
||||||
},
|
},
|
||||||
mode: 'onBlur',
|
mode: 'all',
|
||||||
});
|
});
|
||||||
const { fields, append, remove } = useFieldArray({
|
const { fields, append, remove } = useFieldArray({
|
||||||
name: 'data',
|
name: 'data',
|
||||||
@ -45,7 +48,7 @@ export default function App() {
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
.then(({ status }) => console.log(status))
|
.then(({ status }) => console.log(status))
|
||||||
.then((_) => router.push(`/waiter/${id}`));
|
.then(() => router.push(`/waiter/${id}`));
|
||||||
};
|
};
|
||||||
|
|
||||||
if (error) return <div>Błąd przy ładowaniu danych</div>;
|
if (error) return <div>Błąd przy ładowaniu danych</div>;
|
||||||
@ -59,6 +62,26 @@ export default function App() {
|
|||||||
className="flex flex-col max-w-screen-md w-full my-4"
|
className="flex flex-col max-w-screen-md w-full my-4"
|
||||||
>
|
>
|
||||||
<p className="text-2xl text-center">Nowe zamówienie</p>
|
<p className="text-2xl text-center">Nowe zamówienie</p>
|
||||||
|
<p>
|
||||||
|
<label htmlFor={`client`}>Klient</label>
|
||||||
|
<input
|
||||||
|
placeholder="Klient"
|
||||||
|
type="text"
|
||||||
|
{...register(`client` as const, {
|
||||||
|
required: false,
|
||||||
|
})}
|
||||||
|
className={errors?.client ? 'error' : ''}
|
||||||
|
/>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<label htmlFor={`realization_time`}>Godzina realizacji</label>
|
||||||
|
<input
|
||||||
|
{...register(`realization_time` as const, {
|
||||||
|
required: false,
|
||||||
|
})}
|
||||||
|
className={errors?.realization_time ? 'error' : ''}
|
||||||
|
/>
|
||||||
|
</p>
|
||||||
{fields.map((field, index) => {
|
{fields.map((field, index) => {
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
@ -72,7 +95,7 @@ export default function App() {
|
|||||||
required: false,
|
required: false,
|
||||||
})}
|
})}
|
||||||
/>
|
/>
|
||||||
<p className="basis-1/3">
|
<div className="basis-1/3">
|
||||||
<label htmlFor={`data.${index}.item`}>Danie</label>
|
<label htmlFor={`data.${index}.item`}>Danie</label>
|
||||||
<select
|
<select
|
||||||
{...register(`data.${index}.item` as const, {
|
{...register(`data.${index}.item` as const, {
|
||||||
@ -87,8 +110,18 @@ export default function App() {
|
|||||||
</option>
|
</option>
|
||||||
))}
|
))}
|
||||||
</select>
|
</select>
|
||||||
</p>
|
<section className="flex flex-row my-2 gap-2">
|
||||||
<p className="basis-1/3">
|
<label htmlFor={`data.${index}.takeout`}>Na wynos</label>
|
||||||
|
<input
|
||||||
|
{...register(`data.${index}.takeout` as const, {
|
||||||
|
required: false,
|
||||||
|
})}
|
||||||
|
type="checkbox"
|
||||||
|
className={errors?.data?.[index]?.takeout ? 'error' : ''}
|
||||||
|
/>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
<div className="basis-1/3">
|
||||||
<label htmlFor={`data.${index}.additional_info`}>
|
<label htmlFor={`data.${index}.additional_info`}>
|
||||||
Dodatkowe informacje
|
Dodatkowe informacje
|
||||||
</label>
|
</label>
|
||||||
@ -101,7 +134,7 @@ export default function App() {
|
|||||||
errors?.data?.[index]?.additional_info ? 'error' : ''
|
errors?.data?.[index]?.additional_info ? 'error' : ''
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
</p>
|
</div>
|
||||||
{fields.length > 1 ? (
|
{fields.length > 1 ? (
|
||||||
<p className="basis-1/3 flex items-center justify-center">
|
<p className="basis-1/3 flex items-center justify-center">
|
||||||
<button type="button" onClick={() => remove(index)}>
|
<button type="button" onClick={() => remove(index)}>
|
||||||
@ -123,6 +156,7 @@ export default function App() {
|
|||||||
item: '',
|
item: '',
|
||||||
additional_info: '',
|
additional_info: '',
|
||||||
finished: false,
|
finished: false,
|
||||||
|
takeout: false,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
@ -141,7 +175,9 @@ export default function App() {
|
|||||||
Złóż zamówienie
|
Złóż zamówienie
|
||||||
</button>
|
</button>
|
||||||
</form>
|
</form>
|
||||||
<Link href={`/waiter/${id}`} className='mt-10'><button>Powrót</button></Link>
|
<Link href={`/waiter/${id}`} className="mt-10">
|
||||||
|
<button>Powrót</button>
|
||||||
|
</Link>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,8 @@ import { fetcher } from '@/app/api/tools';
|
|||||||
import useSWR from 'swr';
|
import useSWR from 'swr';
|
||||||
import { useParams } from 'next/navigation';
|
import { useParams } from 'next/navigation';
|
||||||
import Link from 'next/link';
|
import Link from 'next/link';
|
||||||
|
import { getDishBg, getOrderBg, Order } from '@/app/tools';
|
||||||
|
import { OrderID } from '@/app/components';
|
||||||
|
|
||||||
export default function Home() {
|
export default function Home() {
|
||||||
const { id } = useParams();
|
const { id } = useParams();
|
||||||
@ -27,59 +29,33 @@ export default function Home() {
|
|||||||
</p>
|
</p>
|
||||||
<p className="text-4xl">Zamówienia:</p>
|
<p className="text-4xl">Zamówienia:</p>
|
||||||
<ul className="max-w-screen-md w-full">
|
<ul className="max-w-screen-md w-full">
|
||||||
{data?.map(
|
{data?.map((order: Order) => (
|
||||||
(order: {
|
<li
|
||||||
id: number;
|
key={order.id}
|
||||||
created_on: string;
|
className={`m-2 p-2 rounded-md border-2 ${getOrderBg(order)}`}
|
||||||
updated_on: string;
|
>
|
||||||
waiter: number;
|
<OrderID order={order} />
|
||||||
waiter_name: string;
|
<h2 className="text-xl">Kelner: {order.waiter_name}</h2>
|
||||||
data: [
|
{ (order.client) ? <h2 className="text-xl">Klient: {order.client}</h2> : <></>}
|
||||||
{ item: string; additional_info: string; finished: boolean }
|
<h3>{order.status_name}</h3>
|
||||||
];
|
<div className="">
|
||||||
status: string;
|
<ul>
|
||||||
status_name: string;
|
{order.data.map((dish) => (
|
||||||
}) => (
|
<li
|
||||||
<li
|
key={dish.item}
|
||||||
key={order.id}
|
className={`p-2 m-2 flex gap-4 border-2 ${getDishBg(dish)}`}
|
||||||
className={`m-2 p-2 rounded-md border-2 ${
|
>
|
||||||
{
|
<input type="checkbox" checked={dish.finished} readOnly />
|
||||||
1: 'bg-red-200 border-red-400',
|
<div>
|
||||||
2: 'bg-purple-200 border-purple-400',
|
<p className="text-lg">{dish.item} - {dish.takeout ? 'Na wynos' : 'Na miejscu'}</p>
|
||||||
3: 'bg-green-200 border-green-400',
|
<div>{dish.additional_info}</div>
|
||||||
4: 'bg-gray-100 border-gray-400',
|
</div>
|
||||||
}[order.status]
|
</li>
|
||||||
}`}
|
))}
|
||||||
>
|
</ul>
|
||||||
<h1 className="text-xl">
|
</div>
|
||||||
<span className="font-mono">
|
</li>
|
||||||
{'['}
|
))}
|
||||||
{String(order.id % 1000).padStart(3, '0')}
|
|
||||||
{']'}
|
|
||||||
</span>{' '}
|
|
||||||
- {new Date(order.updated_on).toLocaleTimeString('pl-PL')}
|
|
||||||
</h1>
|
|
||||||
<h2 className="text-xl">{order.waiter_name}</h2>
|
|
||||||
<h3>{order.status_name}</h3>
|
|
||||||
<div className="">
|
|
||||||
<ul>
|
|
||||||
{order.data.map((dish) => (
|
|
||||||
<li
|
|
||||||
key={dish.item}
|
|
||||||
className="p-2 m-2 flex gap-4 bg-white border-2 border-gray-400"
|
|
||||||
>
|
|
||||||
<input type="checkbox" checked={dish.finished} readOnly />
|
|
||||||
<div>
|
|
||||||
<p className="text-lg">{dish.item}</p>
|
|
||||||
<div>{dish.additional_info}</div>
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
))}
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
)
|
|
||||||
)}
|
|
||||||
</ul>
|
</ul>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import type { NextConfig } from "next";
|
import type { NextConfig } from "next";
|
||||||
|
|
||||||
const nextConfig: NextConfig = {
|
const nextConfig: NextConfig = {
|
||||||
/* config options here */
|
output: 'standalone'
|
||||||
};
|
};
|
||||||
|
|
||||||
export default nextConfig;
|
export default nextConfig;
|
||||||
|
Reference in New Issue
Block a user