Skip to content

Commit

Permalink
feat: Add dynamic shopping cart which loads info from LocalStorage
Browse files Browse the repository at this point in the history
  • Loading branch information
ZeroWave022 committed Sep 6, 2024
1 parent 82dbb23 commit 7d856e8
Show file tree
Hide file tree
Showing 6 changed files with 129 additions and 43 deletions.
3 changes: 2 additions & 1 deletion messages/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,8 @@
"productName": "Product Name",
"location": "Location",
"unitsAvailable": "Units available",
"tableDescription": "A list of your shopping cart items."
"tableDescription": "A list of your shopping cart items.",
"cartEmpty": "Your shopping cart is empty."
}
}
}
3 changes: 2 additions & 1 deletion messages/no.json
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,8 @@
"productName": "Produktnavn",
"location": "Plass",
"unitsAvailable": "Stk tilgjengelig",
"tableDescription": "En liste over handlekurven din."
"tableDescription": "En liste over handlekurven din.",
"cartEmpty": "Handlekurven din er tom."
}
}
}
57 changes: 16 additions & 41 deletions src/app/[locale]/(default)/storage/shopping-cart/page.tsx
Original file line number Diff line number Diff line change
@@ -1,51 +1,26 @@
import { ShoppingCartTable } from '@/components/storage/ShoppingCartTable';
import ShoppingCartTableSkeleton from '@/components/storage/ShoppingCartTableSkeleton';
import { useTranslations } from 'next-intl';

import {
Table,
TableBody,
TableCaption,
TableCell,
TableHead,
TableHeader,
TableRow,
} from '@/components/ui/Table';
import { Suspense } from 'react';

export default function StorageShoppingCartPage() {
const t = useTranslations('storage.shoppingCart');

const tableMessages = {
tableDescription: t('tableDescription'),
productId: t('productId'),
productName: t('productName'),
location: t('location'),
unitsAvailable: t('unitsAvailable'),
cartEmpty: t('cartEmpty'),
};

return (
<>
<h1 className='my-4 md:text-center'>{t('title')}</h1>
<Table className='my-4'>
<TableCaption>{t('tableDescription')}</TableCaption>
<TableHeader>
<TableRow>
<TableHead className='w-[150px]'>{t('productId')}</TableHead>
<TableHead>{t('productName')}</TableHead>
<TableHead>{t('location')}</TableHead>
<TableHead className='text-right'>{t('unitsAvailable')}</TableHead>
</TableRow>
</TableHeader>
<TableBody>
<TableRow>
<TableCell className='font-medium'>01</TableCell>
<TableCell>Laptop</TableCell>
<TableCell>Storage Room A</TableCell>
<TableCell className='text-right'>15</TableCell>
</TableRow>
<TableRow>
<TableCell className='font-medium'>01</TableCell>
<TableCell>Laptop</TableCell>
<TableCell>Storage Room A</TableCell>
<TableCell className='text-right'>15</TableCell>
</TableRow>
<TableRow>
<TableCell className='font-medium'>01</TableCell>
<TableCell>Laptop</TableCell>
<TableCell>Storage Room A</TableCell>
<TableCell className='text-right'>15</TableCell>
</TableRow>
</TableBody>
</Table>
<Suspense fallback={<ShoppingCartTableSkeleton />}>
<ShoppingCartTable messages={tableMessages} />
</Suspense>
</>
);
}
62 changes: 62 additions & 0 deletions src/components/storage/ShoppingCartTable.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
'use client';

import {
Table,
TableBody,
TableCaption,
TableCell,
TableHead,
TableHeader,
TableRow,
} from '@/components/ui/Table';
import { useLocalStorage } from 'usehooks-ts';

// TODO: Must be replaced by the type provided from database ORM.
import type { StorageItem } from '@/components/storage/AddToCartButton';

type ShoppingCartTableProps = {
messages: {
tableDescription: string;
productId: string;
productName: string;
location: string;
unitsAvailable: string;
cartEmpty: string;
};
};

async function ShoppingCartTable({ messages }: ShoppingCartTableProps) {
const [cart] = useLocalStorage<StorageItem[]>('shopping-cart', []);

if (cart.length <= 0) {
return <h3 className='text-center'>{messages.cartEmpty}</h3>;
}

return (
<Table className='my-4'>
<TableCaption>{messages.tableDescription}</TableCaption>
<TableHeader>
<TableRow>
<TableHead className='w-[150px]'>{messages.productId}</TableHead>
<TableHead>{messages.productName}</TableHead>
<TableHead>{messages.location}</TableHead>
<TableHead className='text-right'>
{messages.unitsAvailable}
</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{cart.map((item) => (
<TableRow key={item.name}>
<TableCell className='font-medium'>{item.id}</TableCell>
<TableCell>{item.name}</TableCell>
<TableCell>{item.location}</TableCell>
<TableCell className='text-right'>{item.quantity}</TableCell>
</TableRow>
))}
</TableBody>
</Table>
);
}

export { ShoppingCartTable };
27 changes: 27 additions & 0 deletions src/components/storage/ShoppingCartTableSkeleton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { SkeletonCard } from '@/components/storage/SkeletonCard';
import { Skeleton } from '@/components/ui/Skeleton';

export default function ShoppingCartTableSkeleton() {
return (
<>
<div className='mt-4 grid grid-cols-10 gap-2'>
<Skeleton className='col-span-1 h-5' />
<Skeleton className='col-span-3 h-5' />
<Skeleton className='col-span-5 h-5' />
<Skeleton className='col-span-1 h-5' />
</div>
{Array.from({ length: 4 }).map((_, index) => {
return (
// biome-ignore lint/suspicious/noArrayIndexKey: Skeleton items don't have a unique id to use.
<div key={index} className='my-4 grid grid-cols-10 gap-2'>
<Skeleton className='col-span-1 h-10' />
<Skeleton className='col-span-3 h-10' />
<Skeleton className='col-span-5 h-10' />
<Skeleton className='col-span-1 h-10' />
</div>
);
})}
<Skeleton className='mx-auto mt-2 h-5 w-[200px]' />
</>
);
}
20 changes: 20 additions & 0 deletions src/mock-data/items.ts
Original file line number Diff line number Diff line change
@@ -1,138 +1,158 @@
const items = [
{
id: 34872,
name: 'Laptop',
photo_url: 'https://example.com/photos/laptop.jpg',
status: 'Operational',
quantity: 15,
location: 'Storage Room A',
},
{
id: 58392,
name: 'Desktop PC',
photo_url: 'https://example.com/photos/desktop_pc.jpg',
status: 'Operational',
quantity: 10,
location: 'Workstation Area 1',
},
{
id: 72541,
name: 'Monitor',
photo_url: 'https://example.com/photos/monitor.jpg',
status: 'Operational',
quantity: 20,
location: 'Storage Room B',
},
{
id: 91834,
name: 'Keyboard',
photo_url: 'https://example.com/photos/keyboard.jpg',
status: 'Operational',
quantity: 50,
location: 'Storage Room A',
},
{
id: 12095,
name: 'Mouse',
photo_url: 'https://example.com/photos/mouse.jpg',
status: 'Operational',
quantity: 50,
location: 'Storage Room A',
},
{
id: 65738,
name: 'Router',
photo_url: 'https://example.com/photos/router.jpg',
status: 'Operational',
quantity: 5,
location: 'Networking Room',
},
{
id: 23984,
name: 'Ethernet Cable',
photo_url: 'https://example.com/photos/ethernet_cable.jpg',
status: 'Operational',
quantity: 100,
location: 'Networking Room',
},
{
id: 48152,
name: 'External Hard Drive',
photo_url: 'https://example.com/photos/external_hard_drive.jpg',
status: 'Operational',
quantity: 25,
location: 'Storage Room B',
},
{
id: 36829,
name: 'USB Flash Drive',
photo_url: 'https://example.com/photos/usb_flash_drive.jpg',
status: 'Operational',
quantity: 75,
location: 'Storage Room B',
},
{
id: 50273,
name: 'Power Supply Unit (PSU)',
photo_url: 'https://example.com/photos/psu.jpg',
status: 'Operational',
quantity: 30,
location: 'Storage Room C',
},
{
id: 17492,
name: 'Graphics Card',
photo_url: 'https://example.com/photos/graphics_card.jpg',
status: 'Operational',
quantity: 12,
location: 'Storage Room C',
},
{
id: 78356,
name: 'RAM Module',
photo_url: 'https://example.com/photos/ram_module.jpg',
status: 'Operational',
quantity: 40,
location: 'Storage Room C',
},
{
id: 92031,
name: 'Motherboard',
photo_url: 'https://example.com/photos/motherboard.jpg',
status: 'Operational',
quantity: 10,
location: 'Storage Room C',
},
{
id: 38627,
name: 'CPU',
photo_url: 'https://example.com/photos/cpu.jpg',
status: 'Operational',
quantity: 10,
location: 'Storage Room C',
},
{
id: 49082,
name: 'SSD',
photo_url: 'https://example.com/photos/ssd.jpg',
status: 'Operational',
quantity: 20,
location: 'Storage Room C',
},
{
id: 85731,
name: 'Network Switch',
photo_url: 'https://example.com/photos/network_switch.jpg',
status: 'Operational',
quantity: 5,
location: 'Networking Room',
},
{
id: 37429,
name: 'Soldering Iron',
photo_url: 'https://example.com/photos/soldering_iron.jpg',
status: 'Operational',
quantity: 8,
location: 'Repair Station',
},
{
id: 90321,
name: 'Multimeter',
photo_url: 'https://example.com/photos/multimeter.jpg',
status: 'Operational',
quantity: 10,
location: 'Repair Station',
},
{
id: 65704,
name: 'Screwdriver Set',
photo_url: 'https://example.com/photos/screwdriver_set.jpg',
status: 'Operational',
quantity: 20,
location: 'Toolbox 1',
},
{
id: 48139,
name: 'Anti-static Wrist Strap',
photo_url: 'https://example.com/photos/anti_static_wrist_strap.jpg',
status: 'Operational',
Expand Down

0 comments on commit 7d856e8

Please sign in to comment.