FastAPI backend (Python 3.11, MSSQL ODBC for SambaPOS, Azure DI OCR),
kitchen_db on central PG. React/TS/Vite frontend with navy sidebar layout.
Backend: auth.py (APP_SLUG=kitchen, SimpleNamespace — archive routes use
.kitchen_id/.is_admin without modification), main.py (51 migrations, scheduler,
internal router for KDS bookings feed), api/internal.py, full archive API
(31 routers: invoices, recipes, menus, sambapos, resos, newbook, disputes,
purchase_orders, etc.), models, migrations, OCR pipeline.
kitchen_id pinned to 1 (B1 — single hotel).
Frontend: AuthGate (app=kitchen, token shim for archive compat — B5b pending),
Layout (navy sidebar, 6 sections, Lucide icons, teal --app-primary),
App.tsx (Outlet pattern, UploadApp outside Layout), index.css (full :root block).
strict: false — archive components have type issues; build clean.
Note: 45 archive components call fetch('/api/...') without /kitchen/ prefix
(B5b). Runtime 404s; deferred until after initial testing.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
193 lines
6 KiB
JavaScript
193 lines
6 KiB
JavaScript
'use strict';
|
|
|
|
var jsxRuntime = require('react/jsx-runtime');
|
|
var react = require('react');
|
|
var chart_js = require('chart.js');
|
|
|
|
const defaultDatasetIdKey = 'label';
|
|
function reforwardRef(ref, value) {
|
|
if (typeof ref === 'function') {
|
|
ref(value);
|
|
} else if (ref) {
|
|
ref.current = value;
|
|
}
|
|
}
|
|
function setOptions(chart, nextOptions) {
|
|
const options = chart.options;
|
|
if (options && nextOptions) {
|
|
Object.assign(options, nextOptions);
|
|
}
|
|
}
|
|
function setLabels(currentData, nextLabels) {
|
|
currentData.labels = nextLabels;
|
|
}
|
|
function setDatasets(currentData, nextDatasets, datasetIdKey = defaultDatasetIdKey) {
|
|
const addedDatasets = [];
|
|
currentData.datasets = nextDatasets.map((nextDataset)=>{
|
|
// given the new set, find it's current match
|
|
const currentDataset = currentData.datasets.find((dataset)=>dataset[datasetIdKey] === nextDataset[datasetIdKey]);
|
|
// There is no original to update, so simply add new one
|
|
if (!currentDataset || !nextDataset.data || addedDatasets.includes(currentDataset)) {
|
|
return {
|
|
...nextDataset
|
|
};
|
|
}
|
|
addedDatasets.push(currentDataset);
|
|
Object.assign(currentDataset, nextDataset);
|
|
return currentDataset;
|
|
});
|
|
}
|
|
function cloneData(data, datasetIdKey = defaultDatasetIdKey) {
|
|
const nextData = {
|
|
labels: [],
|
|
datasets: []
|
|
};
|
|
setLabels(nextData, data.labels);
|
|
setDatasets(nextData, data.datasets, datasetIdKey);
|
|
return nextData;
|
|
}
|
|
/**
|
|
* Get dataset from mouse click event
|
|
* @param chart - Chart.js instance
|
|
* @param event - Mouse click event
|
|
* @returns Dataset
|
|
*/ function getDatasetAtEvent(chart, event) {
|
|
return chart.getElementsAtEventForMode(event.nativeEvent, 'dataset', {
|
|
intersect: true
|
|
}, false);
|
|
}
|
|
/**
|
|
* Get single dataset element from mouse click event
|
|
* @param chart - Chart.js instance
|
|
* @param event - Mouse click event
|
|
* @returns Dataset
|
|
*/ function getElementAtEvent(chart, event) {
|
|
return chart.getElementsAtEventForMode(event.nativeEvent, 'nearest', {
|
|
intersect: true
|
|
}, false);
|
|
}
|
|
/**
|
|
* Get all dataset elements from mouse click event
|
|
* @param chart - Chart.js instance
|
|
* @param event - Mouse click event
|
|
* @returns Dataset
|
|
*/ function getElementsAtEvent(chart, event) {
|
|
return chart.getElementsAtEventForMode(event.nativeEvent, 'index', {
|
|
intersect: true
|
|
}, false);
|
|
}
|
|
|
|
function ChartComponent(props, ref) {
|
|
const { height = 150, width = 300, redraw = false, datasetIdKey, type, data, options, plugins = [], fallbackContent, updateMode, ...canvasProps } = props;
|
|
const canvasRef = react.useRef(null);
|
|
const chartRef = react.useRef(null);
|
|
const renderChart = ()=>{
|
|
if (!canvasRef.current) return;
|
|
chartRef.current = new chart_js.Chart(canvasRef.current, {
|
|
type,
|
|
data: cloneData(data, datasetIdKey),
|
|
options: options && {
|
|
...options
|
|
},
|
|
plugins
|
|
});
|
|
reforwardRef(ref, chartRef.current);
|
|
};
|
|
const destroyChart = ()=>{
|
|
reforwardRef(ref, null);
|
|
if (chartRef.current) {
|
|
chartRef.current.destroy();
|
|
chartRef.current = null;
|
|
}
|
|
};
|
|
react.useEffect(()=>{
|
|
if (!redraw && chartRef.current && options) {
|
|
setOptions(chartRef.current, options);
|
|
}
|
|
}, [
|
|
redraw,
|
|
options
|
|
]);
|
|
react.useEffect(()=>{
|
|
if (!redraw && chartRef.current) {
|
|
setLabels(chartRef.current.config.data, data.labels);
|
|
}
|
|
}, [
|
|
redraw,
|
|
data.labels
|
|
]);
|
|
react.useEffect(()=>{
|
|
if (!redraw && chartRef.current && data.datasets) {
|
|
setDatasets(chartRef.current.config.data, data.datasets, datasetIdKey);
|
|
}
|
|
}, [
|
|
redraw,
|
|
data.datasets
|
|
]);
|
|
react.useEffect(()=>{
|
|
if (!chartRef.current) return;
|
|
if (redraw) {
|
|
destroyChart();
|
|
setTimeout(renderChart);
|
|
} else {
|
|
chartRef.current.update(updateMode);
|
|
}
|
|
}, [
|
|
redraw,
|
|
options,
|
|
data.labels,
|
|
data.datasets,
|
|
updateMode
|
|
]);
|
|
react.useEffect(()=>{
|
|
if (!chartRef.current) return;
|
|
destroyChart();
|
|
setTimeout(renderChart);
|
|
}, [
|
|
type
|
|
]);
|
|
react.useEffect(()=>{
|
|
renderChart();
|
|
return ()=>destroyChart();
|
|
}, []);
|
|
return /*#__PURE__*/ jsxRuntime.jsx("canvas", {
|
|
ref: canvasRef,
|
|
role: "img",
|
|
height: height,
|
|
width: width,
|
|
...canvasProps,
|
|
children: fallbackContent
|
|
});
|
|
}
|
|
const Chart = /*#__PURE__*/ react.forwardRef(ChartComponent);
|
|
|
|
function createTypedChart(type, registerables) {
|
|
chart_js.Chart.register(registerables);
|
|
return /*#__PURE__*/ react.forwardRef((props, ref)=>/*#__PURE__*/ jsxRuntime.jsx(Chart, {
|
|
...props,
|
|
ref: ref,
|
|
type: type
|
|
}));
|
|
}
|
|
const Line = /* #__PURE__ */ createTypedChart('line', chart_js.LineController);
|
|
const Bar = /* #__PURE__ */ createTypedChart('bar', chart_js.BarController);
|
|
const Radar = /* #__PURE__ */ createTypedChart('radar', chart_js.RadarController);
|
|
const Doughnut = /* #__PURE__ */ createTypedChart('doughnut', chart_js.DoughnutController);
|
|
const PolarArea = /* #__PURE__ */ createTypedChart('polarArea', chart_js.PolarAreaController);
|
|
const Bubble = /* #__PURE__ */ createTypedChart('bubble', chart_js.BubbleController);
|
|
const Pie = /* #__PURE__ */ createTypedChart('pie', chart_js.PieController);
|
|
const Scatter = /* #__PURE__ */ createTypedChart('scatter', chart_js.ScatterController);
|
|
|
|
exports.Bar = Bar;
|
|
exports.Bubble = Bubble;
|
|
exports.Chart = Chart;
|
|
exports.Doughnut = Doughnut;
|
|
exports.Line = Line;
|
|
exports.Pie = Pie;
|
|
exports.PolarArea = PolarArea;
|
|
exports.Radar = Radar;
|
|
exports.Scatter = Scatter;
|
|
exports.getDatasetAtEvent = getDatasetAtEvent;
|
|
exports.getElementAtEvent = getElementAtEvent;
|
|
exports.getElementsAtEvent = getElementsAtEvent;
|
|
//# sourceMappingURL=index.cjs.map
|