modified: docker-compose.yml

modified:   package-lock.json
	modified:   package.json
	modified:   src/screens/ImportExportScreen.tsx
	modified:   src/screens/ManageProductsScreen.tsx
	modified:   src/services/importExportService.test.ts
	modified:   src/services/importExportService.ts
This commit is contained in:
2025-11-25 09:15:30 +10:00
parent 2ec46c733b
commit fc55073ca6
7 changed files with 45 additions and 29 deletions
+16 -9
View File
@@ -6,7 +6,6 @@ import {
Checkbox,
Divider,
FormControlLabel,
Grid,
List,
ListItem,
ListItemText,
@@ -107,8 +106,14 @@ export const ImportExportScreen = () => {
<Typography variant="h4" gutterBottom>
Import / Export Data
</Typography>
<Grid container spacing={2}>
<Grid item xs={12} md={3}>
<Box
sx={{
display: 'grid',
gap: 2,
gridTemplateColumns: { xs: '1fr', md: 'repeat(12, 1fr)' },
}}
>
<Box sx={{ gridColumn: { xs: '1 / -1', md: 'span 3' } }}>
<Card>
<CardContent>
<Typography variant="h6" gutterBottom>
@@ -123,8 +128,9 @@ export const ImportExportScreen = () => {
</Stack>
</CardContent>
</Card>
</Grid>
<Grid item xs={12} md={5}>
</Box>
<Box sx={{ gridColumn: { xs: '1 / -1', md: 'span 5' } }}>
<Card>
<CardContent>
<Typography variant="h6" gutterBottom>
@@ -146,8 +152,9 @@ export const ImportExportScreen = () => {
</Stack>
</CardContent>
</Card>
</Grid>
<Grid item xs={12} md={4}>
</Box>
<Box sx={{ gridColumn: { xs: '1 / -1', md: 'span 4' } }}>
<Card>
<CardContent>
<Typography variant="h6" gutterBottom>
@@ -176,8 +183,8 @@ export const ImportExportScreen = () => {
</Stack>
</CardContent>
</Card>
</Grid>
</Grid>
</Box>
</Box>
<Box mt={3}>
<Card>
<CardContent>
+1 -1
View File
@@ -308,7 +308,7 @@ export const ManageProductsScreen = () => {
onClose={() => setFeedback(null)}
anchorOrigin={{ vertical: 'top', horizontal: 'center' }}
>
{feedback ? <Alert severity={feedback.severity}>{feedback.text}</Alert> : null}
{feedback ? <Alert severity={feedback.severity}>{feedback.text}</Alert> : undefined}
</Snackbar>
<Button component={RouterLink} to="/categories" variant="outlined" sx={{ alignSelf: 'flex-start' }}>
Edit Categories
+8 -7
View File
@@ -43,7 +43,7 @@ const createMockDb = (data?: {
const callback = args[args.length - 1];
return callback();
},
} as unknown as StockFillDB;
} as unknown as any;
return db;
};
@@ -52,9 +52,9 @@ const stubDownloads = () => {
const anchor = { href: '', download: '', click: vi.fn() } as unknown as HTMLAnchorElement;
const createObjectURL = vi.fn(() => 'blob:url');
const revokeObjectURL = vi.fn();
// @ts-expect-error jsdom stub
// @ts-ignore jsdom stub
vi.stubGlobal('document', { createElement: () => anchor });
// @ts-expect-error jsdom stub
// @ts-ignore jsdom stub
vi.stubGlobal('URL', { createObjectURL, revokeObjectURL });
return { anchor, createObjectURL, revokeObjectURL };
};
@@ -118,7 +118,7 @@ describe('import/export service', () => {
expect(productCsv).toContain('Clothing');
expect(pickItemsCsv).toContain('Shirt');
expect(db.importExportLogs.items).toHaveLength(1);
expect((db.importExportLogs as any).items).toHaveLength(1);
});
it('imports products while deduplicating by name and auto-creating categories', async () => {
@@ -155,8 +155,9 @@ describe('import/export service', () => {
);
expect(result.log.summary.inserted).toBeGreaterThanOrEqual(1);
expect(db.products.items.find((p) => p.name === 'Existing')).toBeTruthy();
expect(db.products.items.find((p) => p.name === 'New Shirt')).toBeTruthy();
expect(db.categories.items.find((c) => c.name === 'New Category')).toBeTruthy();
expect((db.products as any).items.find((p: any) => p.name === 'Existing')).toBeTruthy();
expect((db.products as any).items.find((p: any) => p.name === 'New Shirt')).toBeTruthy();
expect((db.categories as any).items.find((c: any) => c.name === 'New Category')).toBeTruthy();
});
});
+8 -11
View File
@@ -50,10 +50,11 @@ const inferTypeFromName = (name: string): DataType | undefined => {
const parseCsv = async (content: string) => {
const result = Papa.parse<Record<string, string>>(content, {
header: true,
skipEmptyLines: true,
transformHeader: (header) => header.trim().toLowerCase(),
});
header: true,
skipEmptyLines: true,
transformHeader: (header: string) => header.trim().toLowerCase(),
});
if (result.errors.length > 0) {
throw new Error(result.errors[0].message);
@@ -329,13 +330,9 @@ export const importFiles = async (
try {
await db.transaction(
'rw',
db.areas,
db.categories,
db.products,
db.pickLists,
db.pickItems,
async () => {
'rw',
[db.areas, db.categories, db.products, db.pickLists, db.pickItems],
async () => {
const parseTimestamp = (value?: string) =>
value && value.trim() !== '' ? Number(value) || now : now;