diff --git a/server/src/routes/add/root.ts b/server/src/routes/add/root.ts deleted file mode 100644 index e63f7ef..0000000 --- a/server/src/routes/add/root.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { TypeBoxTypeProvider, FastifyPluginAsyncTypebox } from '@fastify/type-provider-typebox' -import { AddResponseSchema, AddRequestSchema } from 'shared' -import { Value } from '@sinclair/typebox/value' - -// maybe use a generic argument for FastifyPluginAsync if we use options with fastify instance -const add: FastifyPluginAsyncTypebox = async (fastifyApp): Promise => { - const fastify = fastifyApp.withTypeProvider() - - fastify.get('/', { - schema: { - querystring: AddRequestSchema, - response: { - 200: AddResponseSchema - } - } - }, async (request, reply) => { - // Example of implementing the route - // const { a, b } = request.query - // const response = { result: a + b } - - // Example of mocking a route with Typebox - const response = Value.Create(AddResponseSchema) - - // eslint-disable-next-line @typescript-eslint/no-floating-promises - reply.status(200).send(response) - }) -} - -export default add diff --git a/server/src/routes/get-product/root.ts b/server/src/routes/get-product/root.ts index 6b1fbcc..9c49fdf 100644 --- a/server/src/routes/get-product/root.ts +++ b/server/src/routes/get-product/root.ts @@ -14,6 +14,7 @@ const getProduct: FastifyPluginAsyncTypebox = async (fastifyApp, querystring: GetProductRequestSchema, response: { 200: GetProductResponseSchema, + 400: ErrorResSchema, 404: ErrorResSchema } } diff --git a/server/src/routes/products/root.ts b/server/src/routes/products/root.ts index e400f59..ec55cd4 100644 --- a/server/src/routes/products/root.ts +++ b/server/src/routes/products/root.ts @@ -5,6 +5,7 @@ import { } from 'shared' import { getProducts } from '../../shopify/product' import { ServerOptions } from '../../server' +import { ErrorResSchema } from '../../models/errors.model' // maybe use a generic argument for FastifyPluginAsync if we use options with fastify instance const getProduct: FastifyPluginAsyncTypebox = async (fastifyApp, { shopifyClient }): Promise => { @@ -14,7 +15,8 @@ const getProduct: FastifyPluginAsyncTypebox = async (fastifyApp, schema: { querystring: GetProductsRequestSchema, response: { - 200: GetProductsResponseSchema + 200: GetProductsResponseSchema, + 400: ErrorResSchema } } }, async (request, reply) => { diff --git a/shared/src/model/image.model.ts b/shared/src/model/image.model.ts index c6b1921..6c5c184 100644 --- a/shared/src/model/image.model.ts +++ b/shared/src/model/image.model.ts @@ -2,6 +2,6 @@ import { Static, Type } from '@fastify/type-provider-typebox' export const ImageObjSchema = Type.Object({ url: Type.String(), - id: Type.String() + id: Type.Optional(Type.String()) }) export type ImageObj = Static diff --git a/web/apple-touch-icon.png b/web/apple-touch-icon.png new file mode 100644 index 0000000..70aee55 Binary files /dev/null and b/web/apple-touch-icon.png differ diff --git a/web/favicon-16x16.png b/web/favicon-16x16.png new file mode 100644 index 0000000..2cda934 Binary files /dev/null and b/web/favicon-16x16.png differ diff --git a/web/favicon-32x32.png b/web/favicon-32x32.png new file mode 100644 index 0000000..03ae2bc Binary files /dev/null and b/web/favicon-32x32.png differ diff --git a/web/favicon.ico b/web/favicon.ico new file mode 100644 index 0000000..ee45eaf Binary files /dev/null and b/web/favicon.ico differ diff --git a/web/index.html b/web/index.html index 790d463..be10c1e 100644 --- a/web/index.html +++ b/web/index.html @@ -3,7 +3,9 @@ - + + + diff --git a/web/src/app.css b/web/src/app.css index 4a60b9d..3b11ac8 100644 --- a/web/src/app.css +++ b/web/src/app.css @@ -63,6 +63,12 @@ header { justify-content: space-around; } +.clickableRow:hover td { + background-color: #fff4e6; /* Soft orange-beige background */ + transition: background-color 0.2s ease, border 0.2s ease; + cursor: pointer; +} + .inventoryPage { height: 100vh; } @@ -88,6 +94,5 @@ header { } .modal-content img { - max-width: 100%; - height: auto; -} \ No newline at end of file + max-width: 50%; +} diff --git a/web/src/components/ItemModal.tsx b/web/src/components/ItemModal.tsx index f74569a..22c9e05 100644 --- a/web/src/components/ItemModal.tsx +++ b/web/src/components/ItemModal.tsx @@ -1,4 +1,4 @@ -import React from 'react' +import React, { useEffect } from 'react' import { InventoryItem } from '../util/types' interface ItemModalProps { @@ -8,6 +8,23 @@ interface ItemModalProps { } export const ItemModal: React.FC = ({ item, isOpen, onClose }) => { + useEffect(() => { + // Function to close modal when you hit 'Esc' + const handleKeyDown = (event: KeyboardEvent): void => { + if (isOpen && event.key === 'Escape') { + onClose() // Call the onClose callback if Escape is pressed + } + } + + if (isOpen) { // Add event listener when the modal is open + document.addEventListener('keydown', handleKeyDown) + } + + return () => { // Clean up the event listener when the modal closes or unmounts + document.removeEventListener('keydown', handleKeyDown) + } + }, [isOpen, onClose]) + if (!isOpen || (item == null)) return null return ( diff --git a/web/src/components/Table.tsx b/web/src/components/Table.tsx index c5a6fad..b67ae14 100644 --- a/web/src/components/Table.tsx +++ b/web/src/components/Table.tsx @@ -104,7 +104,7 @@ export const Table: React.FC = ({ items, onRowClick }) => { {table.getRowModel().rows.map(row => ( - onRowClick(items[row.index])}> + onRowClick(items[row.index])} className='clickableRow'> {row.getVisibleCells().map(cell => ( {flexRender(cell.column.columnDef.cell, cell.getContext())} @@ -118,7 +118,7 @@ export const Table: React.FC = ({ items, onRowClick }) => { -
Viewing {pageIndex * pageSize}-{Math.min((pageIndex + 1) * pageSize, items.length)} Out Of {items.length} Items
+
Viewing {1 + (pageIndex * pageSize)}-{Math.min((pageIndex + 1) * pageSize, items.length)} out of {items.length} items
diff --git a/web/src/index.css b/web/src/index.css index a1c9aa3..da92873 100644 --- a/web/src/index.css +++ b/web/src/index.css @@ -10,4 +10,4 @@ body { code { font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', monospace; -} \ No newline at end of file +} diff --git a/web/src/pages/InventoryPage.tsx b/web/src/pages/InventoryPage.tsx index 99e8380..8a9d40b 100644 --- a/web/src/pages/InventoryPage.tsx +++ b/web/src/pages/InventoryPage.tsx @@ -25,7 +25,10 @@ export const InventoryPage: React.FC = () => { if (client == null) { return } - const response = await getProducts(client, { pageSize: 15 }) + // This page size is kind of silly now since we're just doing fake client-side pagination, ultimately we should be + // doing server-side pagination instead where we fetch each page from the server + // but I don't really want to do the work to refactor the frontend to do that so it's fine + const response = await getProducts(client, { pageSize: 200 }) return (response?.result ?? []).map((product) => ({ productName: product.title, imageUrl: product.images?.nodes?.[0]?.url,