Simulations life cycle improvements #191
@ -2,15 +2,41 @@
|
|||||||
|
|
||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
|
import { AbstractApi } from '@/app/api/abstract-api';
|
||||||
|
import { TableSimulation, TableSimulationSerializer } from '@/app/lib/tableSimulation';
|
||||||
import Arrangement from '@/app/ui/arrangements/arrangement';
|
import Arrangement from '@/app/ui/arrangements/arrangement';
|
||||||
import React, { useState } from 'react';
|
|
||||||
import ArrangementsTable from '@/app/ui/arrangements/arrangements-table';
|
import ArrangementsTable from '@/app/ui/arrangements/arrangements-table';
|
||||||
|
import { classNames } from '@/app/ui/components/button';
|
||||||
|
import { Toast } from 'primereact/toast';
|
||||||
|
import React, { useRef, useState } from 'react';
|
||||||
|
|
||||||
export default function Page() {
|
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);
|
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 (
|
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>
|
||||||
|
|
||||||
<ArrangementsTable onArrangementSelected={setCurrentArrangement} />
|
<ArrangementsTable onArrangementSelected={setCurrentArrangement} />
|
||||||
{currentArrangement && <Arrangement key={currentArrangement} id={currentArrangement} />}
|
{currentArrangement && <Arrangement key={currentArrangement} id={currentArrangement} />}
|
||||||
</>
|
</>
|
||||||
|
@ -12,6 +12,7 @@ export function loadTableSimulations(onLoad?: (tableSimulations: TableArrangemen
|
|||||||
id: record.id,
|
id: record.id,
|
||||||
name: record.name,
|
name: record.name,
|
||||||
discomfort: record.discomfort,
|
discomfort: record.discomfort,
|
||||||
|
valid: record.valid,
|
||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
}, (error) => {
|
}, (error) => {
|
||||||
|
@ -12,7 +12,8 @@ export type TableArrangement = {
|
|||||||
number: number;
|
number: number;
|
||||||
name: string;
|
name: string;
|
||||||
guests?: Guest[];
|
guests?: Guest[];
|
||||||
discomfort?: number
|
discomfort?: number;
|
||||||
|
valid?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type User = {
|
export type User = {
|
||||||
|
@ -19,12 +19,12 @@ export type Table = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class TableSimulation implements Entity {
|
export class TableSimulation implements Entity {
|
||||||
id: string;
|
id?: string;
|
||||||
tables: Table[];
|
tables: Table[];
|
||||||
|
|
||||||
constructor(id: string, tables: Table[]) {
|
constructor(id?: string, tables?: Table[]) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.tables = tables;
|
this.tables = tables || [];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,42 +7,57 @@ import { TableArrangement } from '@/app/lib/definitions';
|
|||||||
import { classNames } from "../components/button";
|
import { classNames } from "../components/button";
|
||||||
import TableOfContents from "../components/table-of-contents";
|
import TableOfContents from "../components/table-of-contents";
|
||||||
import { loadTableSimulations } from "@/app/api/tableSimulations";
|
import { loadTableSimulations } from "@/app/api/tableSimulations";
|
||||||
|
import { ArchiveBoxXMarkIcon, CheckBadgeIcon } from "@heroicons/react/24/outline";
|
||||||
|
import { Tooltip } from "primereact/tooltip";
|
||||||
|
import clsx from "clsx";
|
||||||
|
|
||||||
export default function ArrangementsTable ({onArrangementSelected}: {onArrangementSelected: (arrangementId: string) => void}) {
|
export default function ArrangementsTable({ onArrangementSelected }: { onArrangementSelected: (arrangementId: string) => void }) {
|
||||||
const [arrangements, setArrangements] = useState<Array<TableArrangement>>([]);
|
const [arrangements, setArrangements] = useState<Array<TableArrangement>>([]);
|
||||||
const [arrangementsLoaded, setArrangementsLoaded] = useState(false);
|
const [arrangementsLoaded, setArrangementsLoaded] = useState(false);
|
||||||
|
|
||||||
function refreshSimulations() {
|
function refreshSimulations() {
|
||||||
loadTableSimulations((arrangements) => {
|
loadTableSimulations((arrangements) => {
|
||||||
setArrangements(arrangements);
|
setArrangements(arrangements);
|
||||||
setArrangementsLoaded(true);
|
setArrangementsLoaded(true);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function arrangementClicked(e: React.MouseEvent<HTMLElement>) {
|
function arrangementClicked(e: React.MouseEvent<HTMLElement>) {
|
||||||
onArrangementSelected(e.currentTarget.getAttribute('data-arrangement-id') || '');
|
onArrangementSelected(e.currentTarget.getAttribute('data-arrangement-id') || '');
|
||||||
}
|
}
|
||||||
|
|
||||||
!arrangementsLoaded && refreshSimulations();
|
|
||||||
|
|
||||||
return(
|
!arrangementsLoaded && refreshSimulations();
|
||||||
<TableOfContents
|
|
||||||
headers={['Name', 'Discomfort', 'Actions']}
|
return (
|
||||||
caption='Simulations'
|
<TableOfContents
|
||||||
elements={arrangements}
|
headers={['Name', 'Discomfort', 'Actions', 'Status']}
|
||||||
rowRender={(arrangement) => (
|
caption='Simulations'
|
||||||
<tr key={arrangement.id} className="bg-white border-b odd:bg-white odd:dark:bg-gray-900 even:bg-gray-50 even:dark:bg-gray-800">
|
elements={arrangements}
|
||||||
<th scope="row" className="px-6 py-4 font-medium text-gray-900 whitespace-nowrap dark:text-white">
|
rowRender={(arrangement) => (
|
||||||
{arrangement.name}
|
<tr key={arrangement.id} className={clsx("border-b", {
|
||||||
</th>
|
"bg-white odd:bg-white even:bg-gray-50": arrangement.valid,
|
||||||
<td className="px-6 py-4">
|
"bg-red-50 odd:bg-red-50 even:bg-red-100": !arrangement.valid
|
||||||
{arrangement.discomfort}
|
})}>
|
||||||
</td>
|
<th scope="row" className="px-6 py-4 font-medium text-gray-900 whitespace-nowrap">
|
||||||
<td>
|
{arrangement.name}
|
||||||
<button data-arrangement-id={arrangement.id} onClick={arrangementClicked} className={classNames('primary')}>Load</button>
|
</th>
|
||||||
</td>
|
<td className="px-6 py-4">
|
||||||
</tr>
|
{arrangement.discomfort}
|
||||||
)}
|
</td>
|
||||||
/>
|
<td>
|
||||||
);
|
<button data-arrangement-id={arrangement.id} onClick={arrangementClicked} className={classNames('primary')}>Load</button>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<Tooltip target=".tooltip-status" />
|
||||||
|
|
||||||
|
{
|
||||||
|
arrangement.valid ?
|
||||||
|
<CheckBadgeIcon className='size-6 tooltip-status' data-pr-position="right" data-pr-tooltip="Simulation is valid" /> :
|
||||||
|
<ArchiveBoxXMarkIcon className='size-6 tooltip-status' data-pr-position="right" data-pr-tooltip="Simulation is expired due to attendance or affinity changes" />
|
||||||
|
}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
);
|
||||||
}
|
}
|
Loading…
x
Reference in New Issue
Block a user