Redesign tables arrangement layout
Some checks are pending
Build Nginx-based docker image / build-static-assets (push) Waiting to run

This commit is contained in:
Manuel Bustillo 2025-09-21 21:07:04 +02:00
parent 043b763ad7
commit e45625e7fb
No known key found for this signature in database
GPG Key ID: A74BD9E346A80DDC
4 changed files with 98 additions and 21 deletions

View File

@ -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<Toast>(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<string | null>(null);
function createSimulation() {
const api = new AbstractApi<TableSimulation>();
const serializer = new TableSimulationSerializer();
api.create(serializer, new TableSimulation(), show);
}
return (
<>
<div className="flex flex-col w-full items-center justify-between">
<Toast ref={toast} />
<button onClick={createSimulation} className={classNames('primary')}>Add new</button>
<div className="flex flex-row w-full gap-4">
<div className="flex-1 border rounded-lg">
<ArrangementsTable onArrangementSelected={setCurrentArrangement} />
</div>
<div className="flex-1 border rounded-lg p-5 shadow-md">
<CalculatingSummary />
</div>
<div className="flex-1 border rounded-lg p-5 shadow-md">
<p className="text-lg font-semibold mb-4">Inventory</p>
</div>
</div>
<ArrangementsTable onArrangementSelected={setCurrentArrangement} />
<>
{currentArrangement && <Arrangement key={currentArrangement} id={currentArrangement} />}
</>
</>
)
}

View File

@ -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 = {

View File

@ -33,7 +33,7 @@ export class TableSimulation implements Entity {
export class TableSimulationSerializer implements Serializable<TableSimulation> {
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)),

View File

@ -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<number[]>([]);
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<Toast>(null);
function createSimulation() {
const api = new AbstractApi<TableSimulation>();
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 (
<>
<Toast ref={toast} />
<p className="text-lg font-semibold mb-4">Processing engine</p>
<p>{stats.in_progress || 0 } processing</p>
<div className="my-4">
<div className="flex flex-row items-center gap-2">
{inProgress.map((progress, index) => (
<div key={index} className="relative size-16 flex items-center justify-center">
<ProgressSpinner className="size-16" strokeWidth="4" animationDuration={`${Math.random() * 2 + 2}s`} />
<span className="absolute text-s">
{Math.round(progress * 100)}%
</span>
</div>
))}
</div>
</div>
<p>+{stats.not_started || 0 } in queue</p>
<div className="flex justify-center">
<button onClick={createSimulation} className={classNames('primary')}>Add new</button>
</div>
</>
);
}