diff --git a/app/api/abstract-api.tsx b/app/api/abstract-api.tsx index b43e72e..f67bea3 100644 --- a/app/api/abstract-api.tsx +++ b/app/api/abstract-api.tsx @@ -5,6 +5,7 @@ import { getCsrfToken, getSlug } from '@/app/lib/utils'; export interface Api { getAll(serializable: Serializable ,callback: (objets: T[]) => void): void; + get(serializable: Serializable, id: string, callback: (object: T) => void): void; create(serializable: Serializable, object: T, callback: () => void): void; update(serializable: Serializable, object: T, callback: () => void): void; destroy(serializable: Serializable, object: T, callback: () => void): void; @@ -29,6 +30,16 @@ export class AbstractApi implements Api { }); } + get(serializable: Serializable, id: string, callback: (object: T) => void): void { + fetch(`/api/${getSlug()}/${serializable.apiPath()}/${id}`) + .then((response) => response.json()) + .then((data) => { + callback(serializable.fromJson(data)); + }, (error) => { + return []; + }); + } + update(serializable: Serializable, object: T, callback: () => void): void { fetch(`/api/${getSlug()}/${serializable.apiPath()}/${object.id}`, { method: 'PUT', diff --git a/app/lib/definitions.ts b/app/lib/definitions.ts index 0e1fce7..f91127a 100644 --- a/app/lib/definitions.ts +++ b/app/lib/definitions.ts @@ -15,17 +15,6 @@ export type TableArrangement = { discomfort?: number } -export type guestsTable = { - id: string; - customer_id: string; - name: string; - email: string; - image_url: string; - date: string; - amount: number; - status: 'pending' | 'paid'; -}; - export type User = { id: string; email: string; diff --git a/app/lib/tableSimulation.tsx b/app/lib/tableSimulation.tsx new file mode 100644 index 0000000..cfe4fbf --- /dev/null +++ b/app/lib/tableSimulation.tsx @@ -0,0 +1,71 @@ +/* Copyright (C) 2024 Manuel Bustillo*/ + +import { Serializable } from "../api/abstract-api"; +import { Entity } from "./definitions"; +import { Guest } from "./guest"; + +export type Discomfort = { + discomfort: number; + breakdown: { + tableSizePenalty: number; + cohesionPenalty: number; + } +} + +export type Table = { + number: number; + guests: Guest[]; + discomfort: Discomfort; +} + +export class TableSimulation implements Entity { + id: string; + tables: Table[]; + + constructor(id: string, tables: Table[]) { + this.id = id; + this.tables = tables; + } +} + +export class TableSimulationSerializer implements Serializable { + fromJson(data: any): TableSimulation { + return new TableSimulation(data.id, data.tables.map((table: any) => { + return { + number: table.number, + guests: table.guests.map((guest: any) => new Guest(guest.id, guest.name, guest.group?.name, guest.group?.id, guest.color)), + discomfort: { + discomfort: table.discomfort.discomfort, + breakdown: { + tableSizePenalty: table.discomfort.breakdown.table_size_penalty, + cohesionPenalty: table.discomfort.breakdown.cohesion_penalty, + } + }, + } + })); + } + + toJson(simulation: TableSimulation): string { + return JSON.stringify({ simulation: { tables: simulation.tables.map((table) => { + return { + number: table.number, + guests: table.guests.map((guest) => { + return { + id: guest.id, + name: guest.name, + group_id: guest.groupId, + color: guest.color, + status: guest.status, + children: guest.children, + } + }), + discomfort: table.discomfort, + } + }) } }); + } + + apiPath(): string { + return 'tables_arrangements'; + } +} + diff --git a/app/ui/arrangements/arrangement.tsx b/app/ui/arrangements/arrangement.tsx index ad466b3..8f82d19 100644 --- a/app/ui/arrangements/arrangement.tsx +++ b/app/ui/arrangements/arrangement.tsx @@ -2,44 +2,37 @@ 'use client'; -import React, { useState } from 'react'; +import { AbstractApi } from '@/app/api/abstract-api'; import { TableArrangement } from '@/app/lib/definitions'; -import { lusitana } from '@/app/ui/fonts'; -import { Table } from '@/app/ui/components/table'; +import { TableSimulation, TableSimulationSerializer } from '@/app/lib/tableSimulation'; import { getSlug } from '@/app/lib/utils'; +import { Table } from '@/app/ui/components/table'; +import { lusitana } from '@/app/ui/fonts'; +import { useState, useEffect } from 'react'; export default function Arrangement({ id }: { id: string }) { - const [tables, setTables] = useState>([]); + const [simulation, setSimulation] = useState(undefined); - function loadTables() { - fetch(`/api/${getSlug()}/tables_arrangements/${id}`) - .then((response) => response.json()) - .then((data) => { - setTables(data.map((record: any) => { - return ({ - id: record.number, - guests: record.guests - }); - })); - }, (error) => { - return []; - }); - } + function loadSimulation() { + new AbstractApi().get(new TableSimulationSerializer(), id, (object: TableSimulation) => { + setSimulation(object); + }); + } - tables.length === 0 && loadTables(); + useEffect(loadSimulation, []); - return ( -
-
-

Table distributions

-
- {tables.map((table) => ( - - ))} - - + return ( +
+
+

Table distributions

+
+ {simulation && simulation.tables.map((table) => ( +
+ ))} - ) + + + ) } \ No newline at end of file diff --git a/app/ui/components/table.tsx b/app/ui/components/table.tsx index d884ed1..4272003 100644 --- a/app/ui/components/table.tsx +++ b/app/ui/components/table.tsx @@ -1,69 +1,107 @@ /* Copyright (C) 2024 Manuel Bustillo*/ import { Guest } from "@/app/lib/guest"; +import { Table as TableType } from "@/app/lib/tableSimulation"; +import { RectangleGroupIcon, UserGroupIcon } from "@heroicons/react/24/outline"; +import { v4 as uuidv4 } from 'uuid'; +import { Tooltip } from "primereact/tooltip"; +import clsx from "clsx"; function Dish({ guest, rotation }: { guest: Guest, rotation?: number }) { - rotation = rotation || 0 - return ( -
- {guest.name} -
- ) + rotation = rotation || 0 + return ( +
+ {guest.name} +
+ ) } - function GuestRow({ guests }: { guests: Guest[] }) { - return ( -
- {guests.map((guest) => )} -
- ) + return ( +
+ {guests.map((guest) => )} +
+ ) } -function RectangularTable({ guests }: { guests: Guest[] }) { - const halfwayThrough = Math.floor(guests.length / 2) - const arrayFirstHalf = guests.slice(0, halfwayThrough); - const arraySecondHalf = guests.slice(halfwayThrough, guests.length); +function RectangularTable({ table }: { table: TableType }) { + const guests = table.guests; + const halfwayThrough = Math.floor(guests.length / 2) + const arrayFirstHalf = guests.slice(0, halfwayThrough); + const arraySecondHalf = guests.slice(halfwayThrough, guests.length); - return ( -
- - -
- ) + return ( +
+ + +
+ ) } -function RoundedTable({ guests }: { guests: Guest[] }) { - const size = 500 - const rotation = 360 / guests.length - return ( -
- { - guests.map((guest, index) => { - return ( -
- -
- ) - }) - } -
- ) +function RoundedTable({ table }: { table: TableType }) { + const guests = table.guests; + const size = 500 + const rotation = 360 / guests.length + + const className = (penalty: number) => { + return clsx("px-2 tooltip-cohesion", { + "hidden": penalty === 0, + "text-orange-300": penalty <= 5, + "text-orange-500": penalty > 5 && penalty <= 10, + "text-orange-700": penalty > 10, + }) + } + + + return ( +
+ + { + guests.map((guest, index) => { + return ( +
+ +
+ ) + }) + } + +
+
{`Table #${table.number}`}
+ + + + + + + + +
+
+ ) } -export function Table({ guests, style }: { guests: Guest[], style: "rectangular" | "rounded" }) { - return ( - <> - {style === "rectangular" && } - {style === "rounded" && } - - ) +export function Table({ table, style }: { table: TableType, style: "rectangular" | "rounded" }) { + return ( + <> + {style === "rectangular" && } + {style === "rounded" && } + + ) } \ No newline at end of file diff --git a/package.json b/package.json index f5939df..1a55fdc 100644 --- a/package.json +++ b/package.json @@ -21,6 +21,7 @@ "tailwindcss": "3.4.16", "typescript": "5.7.2", "use-debounce": "^10.0.1", + "uuid": "11.0.3", "zod": "^3.23.8" }, "devDependencies": { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b1cb101..012188f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -53,6 +53,9 @@ importers: use-debounce: specifier: ^10.0.1 version: 10.0.4(react@19.0.0-rc-f38c22b244-20240704) + uuid: + specifier: 11.0.3 + version: 11.0.3 zod: specifier: ^3.23.8 version: 3.24.1 @@ -1117,6 +1120,10 @@ packages: util-deprecate@1.0.2: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + uuid@11.0.3: + resolution: {integrity: sha512-d0z310fCWv5dJwnX1Y/MncBAqGMKEzlBb1AOf7z9K8ALnd0utBX/msg/fA0+sbyN1ihbMsLhrBlnl1ak7Wa0rg==} + hasBin: true + webidl-conversions@3.0.1: resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} @@ -2116,6 +2123,8 @@ snapshots: util-deprecate@1.0.2: {} + uuid@11.0.3: {} + webidl-conversions@3.0.1: {} whatwg-url@5.0.0: