some minor fixes

This commit is contained in:
2025-02-10 20:56:55 +01:00
parent c3f306575f
commit 12308af1c4
9 changed files with 138 additions and 31 deletions

View File

@ -3,14 +3,15 @@
## Development ## Development
```bash ```bash
docker compose -f docker-compose.yaml.prod up -d --build docker compose up -d --build
docker compose exec -it backend python mange.py migrate docker compose exec -it backend python mange.py migrate
docker compose exec -it backend python mange.py createsuperuser docker compose exec -it backend python mange.py createsuperuser
``` ```
Po czym Po czym
- backend jest dostępny na porcie ```8000```
- frontend jest dostępny na porcie ```3000``` - backend jest dostępny na porcie ``8000``
- frontend jest dostępny na porcie ``3000``
## Produkcja ## Produkcja
@ -21,4 +22,4 @@ docker compose -f docker-compose.yaml.prod exec -it backend python mange.py crea
docker compose -f docker-compose.yaml.prod exec -it backend python manage.py collectstatic docker compose -f docker-compose.yaml.prod exec -it backend python manage.py collectstatic
``` ```
Po czym aplikacja jest dostępna na porcie ```8080``` Po czym aplikacja jest dostępna na porcie ``8080``

View File

@ -29,6 +29,7 @@ class Meal(models.Model):
class Meta: class Meta:
verbose_name = _('Danie') verbose_name = _('Danie')
verbose_name_plural = _('Dania') verbose_name_plural = _('Dania')
ordering = ['name',]
class Order(models.Model): class Order(models.Model):

View File

@ -55,6 +55,8 @@ class MealSerializer(serializers.ModelSerializer):
class MealViewSet(viewsets.ModelViewSet): class MealViewSet(viewsets.ModelViewSet):
queryset = Meal.objects.all() queryset = Meal.objects.all()
serializer_class = MealSerializer serializer_class = MealSerializer
filter_backends = [filters.OrderingFilter]
ordering = ['name']
class OrderSerializer(serializers.ModelSerializer): class OrderSerializer(serializers.ModelSerializer):
@ -88,9 +90,9 @@ class OrderViewSet(viewsets.ModelViewSet):
ordering = ['-created_on'] ordering = ['-created_on']
def get_queryset(self): def get_queryset(self):
five_minutes_ago = timezone.now() + datetime.timedelta(minutes=-5) five_minutes_ago = timezone.now() + datetime.timedelta(minutes=-15)
return Order.objects.filter( return Order.objects.filter(
~Q(status=Order.StatusChoices.FINALIZED) ~Q(status__gte=Order.StatusChoices.READY)
| Q(updated_on__gte=five_minutes_ago) | Q(updated_on__gte=five_minutes_ago)
) )

View File

@ -5,8 +5,6 @@ services:
restart: unless-stopped restart: unless-stopped
volumes: volumes:
- django_static_prod:/usr/src/app/static - django_static_prod:/usr/src/app/static
ports:
- "8000:8000"
environment: environment:
SECRET_KEY: ${SECRET_KEY} SECRET_KEY: ${SECRET_KEY}
DEBUG: False DEBUG: False
@ -24,8 +22,6 @@ services:
restart: unless-stopped restart: unless-stopped
volumes: volumes:
- ./frontend:/app - ./frontend:/app
ports:
- "3000:3000"
redis: redis:
restart: unless-stopped restart: unless-stopped

View File

@ -16,6 +16,10 @@ textarea {
@apply p-1 ps-2 transition ease-in-out focus:outline-none border-b-2 border-b-gray-400 mb-2 focus:bg-gray-100 focus:border-gray-600 appearance-none; @apply p-1 ps-2 transition ease-in-out focus:outline-none border-b-2 border-b-gray-400 mb-2 focus:bg-gray-100 focus:border-gray-600 appearance-none;
} }
.error {
@apply !bg-red-200 ring-2 ring-red-400;
}
form#form select { form#form select {
@apply p-2 ps-2 rounded-md bg-gray-100; @apply p-2 ps-2 rounded-md bg-gray-100;
} }

View File

@ -84,10 +84,10 @@ export default function Home() {
} }
className="form border-2 my-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 zrealizowane</option> {/* <option value="4">Zamówienie zrealizowane</option> */}
</select> </select>
</h3> </h3>
<div className=""> <div className="">
@ -103,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} - {dish.takeout ? 'Na wynos' : 'Na miejscu'}</p> <p className="text-lg">{dish.item}{dish.times > 1 ? ` - x${dish.times}`: ''} - {dish.takeout ? 'Na wynos' : 'Na miejscu'}</p>
<div>{dish.additional_info}</div> <div>{dish.additional_info}</div>
</div> </div>
</li> </li>

View File

@ -3,6 +3,7 @@ export type Dish = {
additional_info: string; additional_info: string;
finished: boolean; finished: boolean;
takeout: boolean; takeout: boolean;
times: number;
}; };
export type Order = { export type Order = {
@ -29,6 +30,8 @@ export function getOrderBg(order: Order): string {
} }
export function getDishBg(dish: Dish): string { export function getDishBg(dish: Dish): string {
if (dish.finished) return 'bg-red-200 border-red-400';
return dish.takeout return dish.takeout
? 'bg-blue-300 border-blue-500' ? 'bg-blue-300 border-blue-500'
: 'bg-green-300 border-green-500'; : 'bg-green-300 border-green-500';

View File

@ -8,10 +8,15 @@ import { fetcher } from '@/app/api/tools';
import useSWR from 'swr'; import useSWR from 'swr';
import { Dish } from '@/app/tools'; import { Dish } from '@/app/tools';
type FormDish = Dish & {
filter: string;
};
type FormValues = { type FormValues = {
status: number;
client: string; client: string;
realization_time: string; realization_time: string;
data: Dish[]; data: FormDish[];
}; };
export default function App() { export default function App() {
@ -24,22 +29,37 @@ export default function App() {
control, control,
handleSubmit, handleSubmit,
formState: { errors }, formState: { errors },
getValues,
setValue,
watch,
} = useForm<FormValues>({ } = useForm<FormValues>({
defaultValues: { defaultValues: {
status: 2,
client: '', client: '',
realization_time: new Date().toLocaleTimeString('pl-PL', { hour: '2-digit', minute: '2-digit' }), realization_time: new Date().toLocaleTimeString('pl-PL', {
hour: '2-digit',
minute: '2-digit',
}),
data: [ data: [
{ item: 'Inne', additional_info: '', finished: false, takeout: false }, {
item: '',
additional_info: '',
finished: false,
takeout: false,
times: 1,
filter: '',
},
], ],
}, },
mode: 'all', mode: 'all',
criteriaMode: 'all',
shouldFocusError: true
}); });
const { fields, append, remove } = useFieldArray({ const { fields, append, remove } = useFieldArray({
name: 'data', name: 'data',
control, control,
}); });
const onSubmit = (data: FormValues) => { const onSubmit = (data: FormValues) => {
console.log(data);
fetch('/api/orders', { fetch('/api/orders', {
method: 'POST', method: 'POST',
body: JSON.stringify({ waiter: id, ...data }), body: JSON.stringify({ waiter: id, ...data }),
@ -54,6 +74,8 @@ export default function App() {
if (error) return <div>Błąd przy ładowaniu danych</div>; if (error) return <div>Błąd przy ładowaniu danych</div>;
if (isLoading) return <div>Ładowanie</div>; if (isLoading) return <div>Ładowanie</div>;
watch('data')
return ( return (
<> <>
<form <form
@ -95,21 +117,56 @@ export default function App() {
required: false, required: false,
})} })}
/> />
<div className="basis-1/3"> <div className="basis-1/3 gap-2">
<label htmlFor={`data.${index}.item`}>Danie</label> <label htmlFor={`data.${index}.item`}>Danie</label>
<input
{...register(`data.${index}.filter` as const, {
required: false,
})}
placeholder='Wyszukaj danie'
className={errors?.data?.[index]?.filter ? 'error' : ''}
onChange={(e) => setValue(`data.${index}.item`, data
?.filter((data: { id: number; name: string }) =>
data.name
.toLowerCase()
.includes(
e.target.value.toLowerCase()
)
)[0].name, {shouldValidate: true})}
/>
<select <select
{...register(`data.${index}.item` as const, { {...register(`data.${index}.item` as const, {
required: true, required: true,
})} })}
className={errors?.data?.[index]?.item ? 'error' : ''} className={errors?.data?.[index]?.item ? 'error' : ''}
> >
{!!getValues(`data.${index}.filter`) ? (
null
) : (
<option value="Inne">Inne</option> <option value="Inne">Inne</option>
{data?.map((data: { id: number; name: string }) => ( )}
{data
?.filter((data: { id: number; name: string }) =>
data.name
.toLowerCase()
.includes(
getValues(`data.${index}.filter`).toLowerCase()
)
)
.map((data: { id: number; name: string }) => (
<option key={data.name} value={data.name}> <option key={data.name} value={data.name}>
{data.name} {data.name}
</option> </option>
))} ))}
</select> </select>
<label htmlFor={`data.${index}.times`}>Ilość</label>
<input
{...register(`data.${index}.times` as const, {
required: false,
})}
type="number"
className={errors?.data?.[index]?.times ? 'error' : ''}
/>
<section className="flex flex-row my-2 gap-2"> <section className="flex flex-row my-2 gap-2">
<label htmlFor={`data.${index}.takeout`}>Na wynos</label> <label htmlFor={`data.${index}.takeout`}>Na wynos</label>
<input <input
@ -157,6 +214,8 @@ export default function App() {
additional_info: '', additional_info: '',
finished: false, finished: false,
takeout: false, takeout: false,
times: 1,
filter: '',
}) })
} }
> >

View File

@ -9,7 +9,7 @@ import { OrderID } from '@/app/components';
export default function Home() { export default function Home() {
const { id } = useParams(); const { id } = useParams();
const { data, error, isLoading } = useSWR( const { data, error, isLoading, mutate } = useSWR(
`/api/orders?waiter=${id}`, `/api/orders?waiter=${id}`,
fetcher, fetcher,
{ {
@ -17,6 +17,30 @@ export default function Home() {
} }
); );
const update_finished = (o: number, i: number, v: boolean) => {
const d = data;
d[o].data[i].finished = v;
fetch(`/api/orders?id=${d[o].id}`, {
method: 'PUT',
body: JSON.stringify(d[o]),
headers: {
'Content-Type': 'application/json',
},
}).then(() => mutate(d));
};
const update_status = (o: number, v: number) => {
const d = data;
d[o].status = v;
fetch(`/api/orders?id=${d[o].id}`, {
method: 'PUT',
body: JSON.stringify(d[o]),
headers: {
'Content-Type': 'application/json',
},
}).then(() => mutate(d));
};
if (error) return <div>Błąd przy ładowaniu danych</div>; if (error) return <div>Błąd przy ładowaniu danych</div>;
if (isLoading) return <div>Ładowanie</div>; if (isLoading) return <div>Ładowanie</div>;
@ -29,25 +53,42 @@ 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((order: Order) => ( {data?.map((order: Order, oi: number) => (
<li <li
key={order.id} key={order.id}
className={`m-2 p-2 rounded-md border-2 ${getOrderBg(order)}`} className={`m-2 p-2 rounded-md border-2 ${getOrderBg(order)}`}
> >
<OrderID order={order} /> <OrderID order={order} />
<h2 className="text-xl">Kelner: {order.waiter_name}</h2> <h2 className="text-xl">{order.waiter_name}</h2>
{ (order.client) ? <h2 className="text-xl">Klient: {order.client}</h2> : <></>} { (order.client) ? <h2 className="text-xl">Klient: {order.client}</h2> : <></>}
<h3>{order.status_name}</h3> <h3>
<select
value={order.status}
onChange={(e) =>
update_status(oi, e.target.value as unknown as number)
}
className="form border-2 my-2 border-gray-500"
>
{/* <option value="1">Zamówienie złożone</option> */}
<option value="2">Zamówienie w trakcie przygotowywania</option>
<option value="3">Zamówienie gotowe</option>
{/* <option value="4">Zamówienie zrealizowane</option> */}
</select>
</h3>
<div className=""> <div className="">
<ul> <ul>
{order.data.map((dish) => ( {order.data.map((dish, i) => (
<li <li
key={dish.item} key={dish.item}
className={`p-2 m-2 flex gap-4 border-2 ${getDishBg(dish)}`} className={`p-2 m-2 flex gap-4 border-2 ${getDishBg(dish)}`}
> >
<input type="checkbox" checked={dish.finished} readOnly /> <input
type="checkbox"
checked={dish.finished}
onChange={(e) => update_finished(oi, i, e.target.checked)}
/>
<div> <div>
<p className="text-lg">{dish.item} - {dish.takeout ? 'Na wynos' : 'Na miejscu'}</p> <p className="text-lg">{dish.item}{dish.times > 1 ? ` - x${dish.times}`: ''} - {dish.takeout ? 'Na wynos' : 'Na miejscu'}</p>
<div>{dish.additional_info}</div> <div>{dish.additional_info}</div>
</div> </div>
</li> </li>