diff --git a/client/package-lock.json b/client/package-lock.json index 05a4fd6..d5318da 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -28,7 +28,7 @@ "postcss": "^8.4.29", "tailwindcss": "^3.3.3", "typescript": "^5.0.2", - "vite": "^4.4.5" + "vite": "^4.4.11" } }, "node_modules/@aashutoshrathi/word-wrap": { @@ -578,12 +578,14 @@ } }, "node_modules/@swc/core": { - "version": "1.3.84", + "version": "1.3.92", + "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.3.92.tgz", + "integrity": "sha512-vx0vUrf4YTEw59njOJ46Ha5i0cZTMYdRHQ7KXU29efN1MxcmJH2RajWLPlvQarOP1ab9iv9cApD7SMchDyx2vA==", "devOptional": true, "hasInstallScript": true, - "license": "Apache-2.0", "dependencies": { - "@swc/types": "^0.1.4" + "@swc/counter": "^0.1.1", + "@swc/types": "^0.1.5" }, "engines": { "node": ">=10" @@ -593,16 +595,16 @@ "url": "https://opencollective.com/swc" }, "optionalDependencies": { - "@swc/core-darwin-arm64": "1.3.84", - "@swc/core-darwin-x64": "1.3.84", - "@swc/core-linux-arm-gnueabihf": "1.3.84", - "@swc/core-linux-arm64-gnu": "1.3.84", - "@swc/core-linux-arm64-musl": "1.3.84", - "@swc/core-linux-x64-gnu": "1.3.84", - "@swc/core-linux-x64-musl": "1.3.84", - "@swc/core-win32-arm64-msvc": "1.3.84", - "@swc/core-win32-ia32-msvc": "1.3.84", - "@swc/core-win32-x64-msvc": "1.3.84" + "@swc/core-darwin-arm64": "1.3.92", + "@swc/core-darwin-x64": "1.3.92", + "@swc/core-linux-arm-gnueabihf": "1.3.92", + "@swc/core-linux-arm64-gnu": "1.3.92", + "@swc/core-linux-arm64-musl": "1.3.92", + "@swc/core-linux-x64-gnu": "1.3.92", + "@swc/core-linux-x64-musl": "1.3.92", + "@swc/core-win32-arm64-msvc": "1.3.92", + "@swc/core-win32-ia32-msvc": "1.3.92", + "@swc/core-win32-x64-msvc": "1.3.92" }, "peerDependencies": { "@swc/helpers": "^0.5.0" @@ -613,12 +615,148 @@ } } }, + "node_modules/@swc/core-darwin-arm64": { + "version": "1.3.92", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.3.92.tgz", + "integrity": "sha512-v7PqZUBtIF6Q5Cp48gqUiG8zQQnEICpnfNdoiY3xjQAglCGIQCjJIDjreZBoeZQZspB27lQN4eZ43CX18+2SnA==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-darwin-x64": { + "version": "1.3.92", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.3.92.tgz", + "integrity": "sha512-Q3XIgQfXyxxxms3bPN+xGgvwk0TtG9l89IomApu+yTKzaIIlf051mS+lGngjnh9L0aUiCp6ICyjDLtutWP54fw==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-arm-gnueabihf": { + "version": "1.3.92", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.3.92.tgz", + "integrity": "sha512-tnOCoCpNVXC+0FCfG84PBZJyLlz0Vfj9MQhyhCvlJz9hQmvpf8nTdKH7RHrOn8VfxtUBLdVi80dXgIFgbvl7qA==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-arm64-gnu": { + "version": "1.3.92", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.3.92.tgz", + "integrity": "sha512-lFfGhX32w8h1j74Iyz0Wv7JByXIwX11OE9UxG+oT7lG0RyXkF4zKyxP8EoxfLrDXse4Oop434p95e3UNC3IfCw==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-arm64-musl": { + "version": "1.3.92", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.3.92.tgz", + "integrity": "sha512-rOZtRcLj57MSAbiecMsqjzBcZDuaCZ8F6l6JDwGkQ7u1NYR57cqF0QDyU7RKS1Jq27Z/Vg21z5cwqoH5fLN+Sg==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-x64-gnu": { + "version": "1.3.92", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.3.92.tgz", + "integrity": "sha512-qptoMGnBL6v89x/Qpn+l1TH1Y0ed+v0qhNfAEVzZvCvzEMTFXphhlhYbDdpxbzRmCjH6GOGq7Y+xrWt9T1/ARg==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-x64-musl": { + "version": "1.3.92", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.3.92.tgz", + "integrity": "sha512-g2KrJ43bZkCZHH4zsIV5ErojuV1OIpUHaEyW1gf7JWKaFBpWYVyubzFPvPkjcxHGLbMsEzO7w/NVfxtGMlFH/Q==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-win32-arm64-msvc": { + "version": "1.3.92", + "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.3.92.tgz", + "integrity": "sha512-3MCRGPAYDoQ8Yyd3WsCMc8eFSyKXY5kQLyg/R5zEqA0uthomo0m0F5/fxAJMZGaSdYkU1DgF73ctOWOf+Z/EzQ==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-win32-ia32-msvc": { + "version": "1.3.92", + "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.3.92.tgz", + "integrity": "sha512-zqTBKQhgfWm73SVGS8FKhFYDovyRl1f5dTX1IwSKynO0qHkRCqJwauFJv/yevkpJWsI2pFh03xsRs9HncTQKSA==", + "cpu": [ + "ia32" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=10" + } + }, "node_modules/@swc/core-win32-x64-msvc": { - "version": "1.3.84", + "version": "1.3.92", + "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.3.92.tgz", + "integrity": "sha512-41bE66ddr9o/Fi1FBh0sHdaKdENPTuDpv1IFHxSg0dJyM/jX8LbkjnpdInYXHBxhcLVAPraVRrNsC4SaoPw2Pg==", "cpu": [ "x64" ], - "license": "Apache-2.0 AND MIT", "optional": true, "os": [ "win32" @@ -627,10 +765,17 @@ "node": ">=10" } }, + "node_modules/@swc/counter": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@swc/counter/-/counter-0.1.2.tgz", + "integrity": "sha512-9F4ys4C74eSTEUNndnER3VJ15oru2NumfQxS8geE+f3eB5xvfxpWyqE5XlVnxb/R14uoXi6SLbBwwiDSkv+XEw==", + "devOptional": true + }, "node_modules/@swc/types": { - "version": "0.1.4", - "devOptional": true, - "license": "Apache-2.0" + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/@swc/types/-/types-0.1.5.tgz", + "integrity": "sha512-myfUej5naTBWnqOCc/MdVOLVjXUXtIA+NpDrDBKJtLLg2shUjBu3cZmB/85RyitKc55+lUUyl7oRfLOvkr2hsw==", + "devOptional": true }, "node_modules/@tsconfig/node10": { "version": "1.0.9", @@ -888,11 +1033,12 @@ } }, "node_modules/@vitejs/plugin-react-swc": { - "version": "3.3.2", + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react-swc/-/plugin-react-swc-3.4.0.tgz", + "integrity": "sha512-m7UaA4Uvz82N/0EOVpZL4XsFIakRqrFKeSNxa1FBLSXGvWrWRBwmZb4qxk+ZIVAZcW3c3dn5YosomDgx62XWcQ==", "dev": true, - "license": "MIT", "dependencies": { - "@swc/core": "^1.3.61" + "@swc/core": "^1.3.85" }, "peerDependencies": { "vite": "^4" @@ -3143,9 +3289,10 @@ "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==" }, "node_modules/vite": { - "version": "4.4.9", + "version": "4.4.11", + "resolved": "https://registry.npmjs.org/vite/-/vite-4.4.11.tgz", + "integrity": "sha512-ksNZJlkcU9b0lBwAGZGGaZHCMqHsc8OpgtoYhsQ4/I2v5cnpmmmqe5pM4nv/4Hn6G/2GhTdj0DhZh2e+Er1q5A==", "dev": true, - "license": "MIT", "dependencies": { "esbuild": "^0.18.10", "postcss": "^8.4.27", diff --git a/client/package.json b/client/package.json index 0bc8b2a..a580da2 100644 --- a/client/package.json +++ b/client/package.json @@ -5,6 +5,7 @@ "type": "module", "scripts": { "dev": "vite", + "start": "vite", "build": "tsc && vite build", "lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0", "preview": "vite preview" @@ -30,6 +31,6 @@ "postcss": "^8.4.29", "tailwindcss": "^3.3.3", "typescript": "^5.0.2", - "vite": "^4.4.5" + "vite": "^4.4.11" } } diff --git a/client/src/App.tsx b/client/src/App.tsx index b1f5666..1aa2f94 100644 --- a/client/src/App.tsx +++ b/client/src/App.tsx @@ -2,6 +2,7 @@ import { BrowserRouter as Router, Route, Routes } from "react-router-dom"; import HomePage from "./pages/HomePage"; import RequestsPage from "./pages/RequestsPage"; +import CollectionPage from './pages/CollectionsPage'; function App() { return ( @@ -9,6 +10,7 @@ function App() { } /> } /> + } /> ); diff --git a/client/src/components/CollectionForm.tsx b/client/src/components/CollectionForm.tsx new file mode 100644 index 0000000..901822f --- /dev/null +++ b/client/src/components/CollectionForm.tsx @@ -0,0 +1,142 @@ +import React, { useState, ChangeEvent, FormEvent } from 'react'; + +type Gift = { + name: string; + description: string; + price: number; +}; + +type Collection = { + id: number; + name: string; + gifts: Gift[]; +}; + +type EditFormProps = { + collection: Collection; + onSave: (collection: Collection) => void; + onClose: () => void; +}; + +const predefinedGifts: Gift[] = [ + { + name: "Gift 1", + description: "Description of Gift 1", + price: 10, + }, + { + name: "Gift 2", + description: "Description of Gift 2", + price: 20, + }, + { + name: "Gift 3", + description: "Description of Gift 3", + price: 30, + }, + { + name: "Gift 4", + description: "Description of Gift 4", + price: 40, + }, + { + name: "Gift 5", + description: "Description of Gift 5", + price: 50, + }, + { + name: "Gift 10", + description: "Description of Gift 1", + price: 10, + }, + { + name: "Gift 11", + description: "Description of Gift 2", + price: 20, + }, +]; + +function CollectionForm({ collection, onSave, onClose }: EditFormProps) { + const [editedName, setEditedName] = useState(collection.name); + const [editedGifts, setEditedGifts] = useState(collection.gifts); + + const handleNameChange = (e: ChangeEvent) => { + setEditedName(e.target.value); + }; + + const handleGiftsChange = (e: ChangeEvent) => { + const selectedOptions = Array.from(e.target.options); + const selectedGifts = selectedOptions + .filter((option) => option.selected) + .map((option) => ({ + name: option.value, + description: "", + price: 0, + })); + + // Here, we concatenate the selected gifts with the existing gifts + setEditedGifts([...editedGifts, ...selectedGifts]); + }; + + const handleSubmit = (e: FormEvent) => { + e.preventDefault(); + onSave({ + id: collection.id, + name: editedName, + gifts: editedGifts, + }); + onClose(); + }; + + return ( + + + + + Name: + + + + + + Select a Gift to Add: + + gift.name)} + onChange={handleGiftsChange} + > + {predefinedGifts.map((gift, index) => ( + + {gift.name} + + ))} + + + + Save + + + Cancel + + + + ); +} + +export default CollectionForm; diff --git a/client/src/components/CollectionItem.tsx b/client/src/components/CollectionItem.tsx new file mode 100644 index 0000000..a49369c --- /dev/null +++ b/client/src/components/CollectionItem.tsx @@ -0,0 +1,32 @@ +type Gift = { + name: string; + description: string; + price: number; +}; + +type CollectionItemProps = { + name: string; + gifts: Gift[]; +}; + +function CollectionItem({ name, gifts }: CollectionItemProps) { + return ( + + {name} + + {gifts.map((gift, index) => ( + + {gift.name} + + ))} + + + ); +} + +export default CollectionItem; + + + + + diff --git a/client/src/pages/CollectionsPage.tsx b/client/src/pages/CollectionsPage.tsx new file mode 100644 index 0000000..0d55fdc --- /dev/null +++ b/client/src/pages/CollectionsPage.tsx @@ -0,0 +1,211 @@ +import { useState } from 'react'; +import CollectionItem from '../components/CollectionItem'; +import EditForm from '../components/CollectionForm'; + +type Gift = { + name: string; + description: string; + price: number; +}; + +type Collection = { + id: number; + name: string; + gifts: Gift[]; +}; + +const predefinedGifts: Gift[] = [ + { + name: "Gift 1", + description: "Description of Gift 1", + price: 10, + }, + { + name: "Gift 2", + description: "Description of Gift 2", + price: 20, + }, + { + name: "Gift 3", + description: "Description of Gift 3", + price: 30, + }, + { + name: "Gift 4", + description: "Description of Gift 4", + price: 40, + }, + { + name: "Gift 5", + description: "Description of Gift 5", + price: 50, + }, +]; + +const predefinedGifts2: Gift[] = [ + { + name: "Gift 10", + description: "Description of Gift 1", + price: 10, + }, + { + name: "Gift 11", + description: "Description of Gift 2", + price: 20, + }, +]; + +const CollectionsPage = () => { + const [collections, setCollections] = useState([ + { + id: 1, + name: 'Birthday Gifts', + gifts: [], + }, + { + id: 2, + name: 'Christmas Gifts', + gifts: predefinedGifts, + }, + { + id: 3, + name: 'Birthday Gifts', + gifts: predefinedGifts2, + }, + { + id: 4, + name: 'Christmas Gifts', + gifts: predefinedGifts, + }, + { + id: 5, + name: 'Birthday Gifts', + gifts: predefinedGifts, + }, + { + id: 6, + name: 'Christmas Gifts', + gifts: predefinedGifts, + }, + { + id: 7, + name: 'Birthday Gifts', + gifts: predefinedGifts, + }, + { + id: 8, + name: 'Christmas Gifts', + gifts: predefinedGifts, + }, + { + id: 9, + name: 'Birthday Gifts', + gifts: predefinedGifts, + }, + { + id: 10, + name: 'Christmas Gifts', + gifts: predefinedGifts, + }, + { + id: 11, + name: 'Birthday Gifts', + gifts: predefinedGifts + }, + { + id: 12, + name: 'Christmas Gifts', + gifts: predefinedGifts + }, + { + id: 13, + name: 'Birthday Gifts', + gifts: predefinedGifts, + }, + { + id: 14, + name: 'Christmas Gifts', + gifts: predefinedGifts, + }, + + ]); + + const handleCreateCollection = () => { + const newCollection: Collection = { + id: Date.now(), + name: 'New Collection', + gifts: [], + }; + + // Add the new collection to the state + setCollections((prevCollections) => [...prevCollections, newCollection]); + setEditCollectionId(newCollection.id); + setShowEditForm(true); + }; + + const [showEditForm, setShowEditForm] = useState(false); + const [editCollectionId, setEditCollectionId] = useState(null); + + const handleEditCollection = (collectionId: number) => { + setEditCollectionId(collectionId); + setShowEditForm(true); + }; + + const handleSaveCollection = (updatedCollection: Collection) => { + setCollections((prevCollections) => + prevCollections.map((collection) => + collection.id === updatedCollection.id ? updatedCollection : collection + ) + ); + setShowEditForm(false); + }; + + const handleCloseEditForm = () => { + setEditCollectionId(null); + setShowEditForm(false); + }; + + const handleDeleteCollection = (collectionId: number) => { + setCollections((prevCollections) => prevCollections.filter((collection) => collection.id !== collectionId)); + }; + + return ( + + + + {collections.map((collection) => ( + + + + handleEditCollection(collection.id)} className="m-2"> + Edit + + handleDeleteCollection(collection.id)} className="m-2 text-red-500"> + Delete + + + + ))} + + + {showEditForm && ( + + + c.id === editCollectionId)!} + onSave={handleSaveCollection} + onClose={handleCloseEditForm} + /> + + + )} + + + Create New Collection + + + + ); +}; + +export default CollectionsPage; \ No newline at end of file diff --git a/client/src/pages/HomePage.tsx b/client/src/pages/HomePage.tsx index b57d552..915c1c5 100644 --- a/client/src/pages/HomePage.tsx +++ b/client/src/pages/HomePage.tsx @@ -1,9 +1,13 @@ const HomePage = () => { + + return ( Caits Curates + + ); } diff --git a/client/vite.config.ts b/client/vite.config.ts index e7d4c74..ec1ff02 100644 --- a/client/vite.config.ts +++ b/client/vite.config.ts @@ -5,6 +5,9 @@ import react from '@vitejs/plugin-react-swc' export default defineConfig({ plugins: [react()], server : { + hmr: { + overlay: false, + }, proxy : { '/api': { target: 'http://localhost:8080',
Caits Curates