diff --git a/app/[slug]/dashboard/tables/page.tsx b/app/[slug]/dashboard/tables/page.tsx index 42dffd9..13688b7 100644 --- a/app/[slug]/dashboard/tables/page.tsx +++ b/app/[slug]/dashboard/tables/page.tsx @@ -6,39 +6,35 @@ import { AbstractApi } from '@/app/api/abstract-api'; import { TableSimulation, TableSimulationSerializer } from '@/app/lib/tableSimulation'; import Arrangement from '@/app/ui/arrangements/arrangement'; import ArrangementsTable from '@/app/ui/arrangements/arrangements-table'; +import CalculatingSummary from '@/app/ui/arrangements/calculating-summary'; import { classNames } from '@/app/ui/components/button'; import { Toast } from 'primereact/toast'; import React, { useEffect, useRef, useState } from 'react'; export default function Page() { - const toast = useRef(null); - const show = () => { - toast.current?.show({ - severity: 'success', - summary: 'Simulation created', - detail: 'Table distributions will be calculated shortly, please come back in some minutes' - }); - }; const [currentArrangement, setCurrentArrangement] = useState(null); - function createSimulation() { - const api = new AbstractApi(); - const serializer = new TableSimulationSerializer(); - api.create(serializer, new TableSimulation(), show); - } + return ( <> - -
- - +
+
+ +
+
+ +
+
+

Inventory

+
- - {currentArrangement && } + <> + {currentArrangement && } + ) } \ No newline at end of file diff --git a/app/api/tableSimulations.tsx b/app/api/tableSimulations.tsx index f8048a2..6892ba4 100644 --- a/app/api/tableSimulations.tsx +++ b/app/api/tableSimulations.tsx @@ -4,7 +4,7 @@ import { TableArrangement } from '@/app/lib/definitions'; import { getSlug } from '../lib/utils'; export function loadTableSimulations(onLoad?: (tableSimulations: TableArrangement[]) => void) { - fetch(`/api/${getSlug()}/tables_arrangements`) + fetch(`/api/${getSlug()}/tables_arrangements?limit=3&status=completed`) .then((response) => response.json()) .then((data) => { onLoad && onLoad(data.map((record: any) => { diff --git a/app/lib/definitions.ts b/app/lib/definitions.ts index a9d81a9..9341693 100644 --- a/app/lib/definitions.ts +++ b/app/lib/definitions.ts @@ -7,6 +7,8 @@ export interface Entity { id?: string; } +export type TableArrangementStatus = 'in_progress' | 'completed' | 'not_started'; + export type TableArrangement = { id: string; number: number; @@ -15,7 +17,7 @@ export type TableArrangement = { discomfort?: number; valid?: boolean; progress: number; - status: 'in_progress' | 'completed' | 'not_started'; + status: TableArrangementStatus; } export type User = { diff --git a/app/lib/tableSimulation.tsx b/app/lib/tableSimulation.tsx index 06c18db..4ffaca6 100644 --- a/app/lib/tableSimulation.tsx +++ b/app/lib/tableSimulation.tsx @@ -33,7 +33,7 @@ export class TableSimulation implements Entity { export class TableSimulationSerializer implements Serializable { fromJson(data: any): TableSimulation { - return new TableSimulation(data.id, data.tables.map((table: any) => { + 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.color, guest.status, [], guest.group)), diff --git a/app/ui/arrangements/arrangements-table.tsx b/app/ui/arrangements/arrangements-table.tsx index db65d1e..8563408 100644 --- a/app/ui/arrangements/arrangements-table.tsx +++ b/app/ui/arrangements/arrangements-table.tsx @@ -2,18 +2,12 @@ 'use client' -import React, { useState } from "react" -import { TableArrangement } from '@/app/lib/definitions'; -import { classNames } from "../components/button"; -import TableOfContents from "../components/table-of-contents"; import { loadTableSimulations } from "@/app/api/tableSimulations"; -import { ArchiveBoxXMarkIcon, CheckBadgeIcon } from "@heroicons/react/24/outline"; -import { Tooltip } from "primereact/tooltip"; +import { TableArrangement } from '@/app/lib/definitions'; +import { ArrowsPointingOutIcon } from "@heroicons/react/24/outline"; import clsx from "clsx"; -import { ProgressBar } from "primereact/progressbar"; -import { useEffect } from "react"; -import { TableSimulation, TableSimulationSerializer } from "@/app/lib/tableSimulation"; -import { AbstractApi } from "@/app/api/abstract-api"; +import { useEffect, useState } from "react"; +import TableOfContents from "../components/table-of-contents"; export default function ArrangementsTable({ onArrangementSelected }: { onArrangementSelected: (arrangementId: string) => void }) { const [arrangements, setArrangements] = useState>([]); @@ -32,14 +26,14 @@ export default function ArrangementsTable({ onArrangementSelected }: { onArrange }); } - function arrangementClicked(e: React.MouseEvent) { - onArrangementSelected(e.currentTarget.getAttribute('data-arrangement-id') || ''); + function arrangementClicked(arrangement: TableArrangement) { + onArrangementSelected(arrangement.id); } return ( ( {arrangement.discomfort} - - - - <> - { arrangement.valid && arrangement.status === 'not_started' && } - { arrangement.valid && arrangement.status !== 'not_started' && } - - { !arrangement.valid && 'The list of potential guests has changed since this simulation.' } - - - + arrangementClicked(arrangement)} className='size-6 cursor-pointer' title="Load" /> )} diff --git a/app/ui/arrangements/calculating-summary.tsx b/app/ui/arrangements/calculating-summary.tsx new file mode 100644 index 0000000..55f2d79 --- /dev/null +++ b/app/ui/arrangements/calculating-summary.tsx @@ -0,0 +1,79 @@ +/* Copyright (C) 2024-2025 LibreWeddingPlanner contributors*/ + +'use client' + +import { AbstractApi } from "@/app/api/abstract-api"; +import { TableArrangementStatus } from "@/app/lib/definitions"; +import { TableSimulation, TableSimulationSerializer } from "@/app/lib/tableSimulation"; +import { getSlug } from "@/app/lib/utils"; +import { Toast } from "primereact/toast"; +import { useEffect, useRef, useState } from "react"; +import { ProgressSpinner } from 'primereact/progressspinner'; +import { classNames } from "../components/button"; + +export default function CalculatingSummary() { + const [stats, setStats] = useState<{ [key in TableArrangementStatus]: number }>({ + in_progress: 0, + completed: 0, + not_started: 0, + }); + + const [inProgress, setInProgress] = useState([]); + + useEffect(() => { + const fetchStats = () => { + fetch(`/api/${getSlug()}/tables_arrangements/stats`) + .then((response) => response.json()) + .then((data) => { + setStats(data.count); + setInProgress(data.in_progress); + }); + }; + + fetchStats(); + const interval = setInterval(fetchStats, 10000); + + return () => clearInterval(interval); + }, []); + + const toast = useRef(null); + + function createSimulation() { + const api = new AbstractApi(); + const serializer = new TableSimulationSerializer(); + api.create(serializer, new TableSimulation(), () => { + toast.current?.show({ + severity: 'success', + summary: 'Simulation created', + detail: 'Table distributions will be calculated shortly, please come back in some minutes' + }); + }); + } + + return ( + <> + +

Processing engine

+

{stats.in_progress || 0 } processing

+ +
+
+ {inProgress.map((progress, index) => ( +
+ + + {Math.round(progress * 100)}% + +
+ ))} +
+
+ +

+{stats.not_started || 0 } in queue

+ +
+ +
+ + ); +} \ No newline at end of file