From d6d7e7c919c1b5112ac598b1f219f0f362cf29d8 Mon Sep 17 00:00:00 2001 From: GotthardG <51994228+GotthardG@users.noreply.github.com> Date: Thu, 31 Oct 2024 10:25:46 +0100 Subject: [PATCH] Adjusted stepper for shipment tracking --- backend/main.py | 132 +++- frontend/fetch-openapi.js | 41 + frontend/package-lock.json | 801 +++++++++++++++++--- frontend/package.json | 9 +- frontend/src/components/DewarDetails.tsx | 8 +- frontend/src/components/DewarStepper.tsx | 92 ++- frontend/src/components/ShipmentDetails.tsx | 83 +- frontend/src/components/ShipmentForm.tsx | 15 +- frontend/src/pages/ShipmentView.tsx | 1 + frontend/src/tsconfig.json | 2 +- frontend/tsconfig.json | 2 +- frontend/vite.config.ts | 12 +- 12 files changed, 959 insertions(+), 239 deletions(-) create mode 100644 frontend/fetch-openapi.js diff --git a/backend/main.py b/backend/main.py index e26e95c..06b16d8 100644 --- a/backend/main.py +++ b/backend/main.py @@ -1,12 +1,10 @@ -from fastapi import FastAPI +from fastapi import FastAPI, HTTPException, status from fastapi.middleware.cors import CORSMiddleware -from fastapi import HTTPException, status from pydantic import BaseModel from typing import List, Optional import logging import uuid - logging.basicConfig(level=logging.INFO) app = FastAPI() @@ -21,7 +19,7 @@ app.add_middleware( class ContactPerson(BaseModel): - id: int + id: Optional[int] = None # Make id optional firstname: str lastname: str phone_number: str @@ -29,16 +27,18 @@ class ContactPerson(BaseModel): class Address(BaseModel): - id: int + id: Optional[int] = None # Make id optional street: str city: str zipcode: str country: str + class Proposal(BaseModel): - id: int + id: Optional[int] number: str + class Dewar(BaseModel): id: Optional[str] = None dewar_name: str @@ -51,8 +51,7 @@ class Dewar(BaseModel): ready_date: Optional[str] = None shipping_date: Optional[str] = None arrival_date: Optional[str] = None - shippingStatus: str - arrivalStatus: str + returning_date: Optional[str] = None qrcode: str @@ -85,8 +84,10 @@ class Shipment(BaseModel): # Example data for contacts contacts = [ - ContactPerson(id=1, firstname="Frodo", lastname="Baggins", phone_number="123-456-7890", email="frodo.baggins@lotr.com"), - ContactPerson(id=2, firstname="Samwise", lastname="Gamgee", phone_number="987-654-3210", email="samwise.gamgee@lotr.com"), + ContactPerson(id=1, firstname="Frodo", lastname="Baggins", phone_number="123-456-7890", + email="frodo.baggins@lotr.com"), + ContactPerson(id=2, firstname="Samwise", lastname="Gamgee", phone_number="987-654-3210", + email="samwise.gamgee@lotr.com"), ContactPerson(id=3, firstname="Aragorn", lastname="Elessar", phone_number="123-333-4444", email="aragorn.elessar@lotr.com"), ContactPerson(id=4, firstname="Legolas", lastname="Greenleaf", phone_number="555-666-7777", @@ -102,7 +103,7 @@ contacts = [ ContactPerson(id=9, firstname="Elrond", lastname="Half-elven", phone_number="777-888-9999", email="elrond.halfelven@lotr.com"), ContactPerson(id=10, firstname="Eowyn", lastname="Shieldmaiden of Rohan", phone_number="000-111-2222", - email="eowyn.rohan@lotr.com") + email="eowyn.rohan@lotr.com"), ] # Example data for return addresses @@ -121,12 +122,11 @@ dewars = [ number_of_samples=70, return_address=[return_addresses[0]], contact_person=[contacts[0]], - status='Ready', + status='Ready for Shipping', ready_date='2023-09-30', - shipping_date='2023-10-01', - arrival_date='2023-10-02', - shippingStatus='Shipped', - arrivalStatus='Arrived', + shipping_date='', + arrival_date='', + returning_date='', qrcode='QR123DEWAR001' ), Dewar( @@ -138,11 +138,10 @@ dewars = [ return_address=[return_addresses[1]], contact_person=[contacts[1]], status='In Preparation', - ready_date='2023-10-01', - shipping_date='2023-10-02', - arrival_date='2023-10-04', - shippingStatus='not shipped', - arrivalStatus='not arrived', + ready_date='', + shipping_date='', + arrival_date='', + returning_date='', qrcode='QR123DEWAR002' ), Dewar( @@ -153,9 +152,11 @@ dewars = [ number_of_samples=47, return_address=[return_addresses[0]], contact_person=[contacts[2]], - status='Pending', - shippingStatus='Ready for Shipping', - arrivalStatus='Pending', + status='Not Shipped', + ready_date='2024.01.01', + shipping_date='', + arrival_date='', + returning_date='', qrcode='QR123DEWAR003' ), Dewar( @@ -166,9 +167,11 @@ dewars = [ number_of_samples=47, return_address=[return_addresses[0]], contact_person=[contacts[2]], - status='In Preparation', - shippingStatus='not shipped', - arrivalStatus='not arrived', + status='Delayed', + ready_date='2024.01.01', + shipping_date='2024.01.02', + arrival_date='', + returning_date='', qrcode='QR123DEWAR003' ), Dewar( @@ -179,9 +182,11 @@ dewars = [ number_of_samples=47, return_address=[return_addresses[0]], contact_person=[contacts[2]], - status='Ready for Shipping', - shippingStatus='shipped', - arrivalStatus='not arrived', + status='Returned', + ready_date='2024.01.01', + shipping_date='2024.01.02', + arrival_date='2024.01.03', + returning_date='2024.01.07', qrcode='QR123DEWAR003' ), ] @@ -206,7 +211,6 @@ specific_dewars1 = [dewar for dewar in dewars if dewar.id in specific_dewar_ids1 specific_dewars2 = [dewar for dewar in dewars if dewar.id in specific_dewar_ids2] specific_dewars3 = [dewar for dewar in dewars if dewar.id in specific_dewar_ids3] - # Define shipments with the selected Dewars shipments = [ Shipment( @@ -242,17 +246,19 @@ shipments = [ comments='Contains the one ring', dewars=specific_dewars3 ) - ] + @app.get("/contacts", response_model=List[ContactPerson]) async def get_contacts(): return contacts + @app.get("/return_addresses", response_model=List[Address]) async def get_return_addresses(): return return_addresses + @app.get("/proposals", response_model=List[Proposal]) async def get_proposals(): return proposals @@ -262,29 +268,55 @@ async def get_proposals(): async def get_shipments(): return shipments + @app.delete("/shipments/{shipment_id}", status_code=status.HTTP_204_NO_CONTENT) async def delete_shipment(shipment_id: str): global shipments # Use global variable to access the shipments list shipments = [shipment for shipment in shipments if shipment.shipment_id != shipment_id] +@app.post("/shipments/{shipment_id}/add_dewar", response_model=Shipment) +async def add_dewar_to_shipment(shipment_id: str, dewar_id: str): + # Log received parameters for debugging + logging.info(f"Received request to add dewar {dewar_id} to shipment {shipment_id}") + + # Find the shipment by id + shipment = next((sh for sh in shipments if sh.shipment_id == shipment_id), None) + if not shipment: + logging.error("Shipment not found") + raise HTTPException(status_code=404, detail="Shipment not found") + + # Find the dewar by id + dewar = next((dw for dw in dewars if dw.id == dewar_id), None) + if not dewar: + logging.error("Dewar not found") + raise HTTPException(status_code=404, detail="Dewar not found") + + # Add the dewar to the shipment + if dewar not in shipment.dewars: + shipment.dewars.append(dewar) + + return shipment + @app.get("/dewars", response_model=List[Dewar]) async def get_dewars(): return dewars -@app.post("/dewars", response_model=List[Dewar], status_code=status.HTTP_201_CREATED) -async def create_dewar(shipment: Dewar): - dewar_id = f'SHIP-{uuid.uuid4().hex[:8].upper()}' # Generates a unique shipment ID - shipment.id = dewar_id # Set the generated ID on the shipment object - dewars.append(shipment) # Add the modified shipment object to the list +@app.post("/dewars", response_model=Dewar, status_code=status.HTTP_201_CREATED) +async def create_dewar(dewar: Dewar) -> Dewar: + dewar_id = f'DEWAR-{uuid.uuid4().hex[:8].upper()}' # Generates a unique dewar ID + dewar.id = dewar_id # Set the generated ID on the dewar object + + dewars.append(dewar) # Add the modified dewar object to the list + + return dewar # Return the newly created dewar - return dewars # Return the list of all dewars @app.get("/shipment_contact_persons") async def get_shipment_contact_persons(): - return [{"shipment_id": shipment.shipment_id, "contact_person": shipment.get_shipment_contact_persons()} for shipment in - shipments] + return [{"shipment_id": shipment.shipment_id, "contact_person": shipment.get_shipment_contact_persons()} for + shipment in shipments] @app.post("/shipments", response_model=Shipment, status_code=status.HTTP_201_CREATED) @@ -297,6 +329,7 @@ async def create_shipment(shipment: Shipment): shipments.append(shipment) return shipment + # Creation of a new contact @app.post("/contacts", response_model=ContactPerson, status_code=status.HTTP_201_CREATED) async def create_contact(contact: ContactPerson): @@ -305,16 +338,24 @@ async def create_contact(contact: ContactPerson): if any(c.email == contact.email for c in contacts): raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, - detail="Contact with this email already exists." + detail="This contact already exists." ) + # Find the next available id + if contacts: + max_id = max(c.id for c in contacts) + contact.id = max_id + 1 if contact.id is None else contact.id + else: + contact.id = 1 if contact.id is None else contact.id + contacts.append(contact) return contact + # Creation of a return address @app.post("/return_addresses", response_model=Address, status_code=status.HTTP_201_CREATED) async def create_return_address(address: Address): - logging.info(f"Received contact creation request: {address}") + logging.info(f"Received address creation request: {address}") # Check for duplicate address by city if any(a.city == address.city for a in return_addresses): raise HTTPException( @@ -322,5 +363,12 @@ async def create_return_address(address: Address): detail="Address in this city already exists." ) + # Find the next available id + if return_addresses: + max_id = max(a.id for a in return_addresses) + address.id = max_id + 1 if address.id is None else address.id + else: + address.id = 1 if address.id is None else address.id + return_addresses.append(address) return address diff --git a/frontend/fetch-openapi.js b/frontend/fetch-openapi.js new file mode 100644 index 0000000..bd18de2 --- /dev/null +++ b/frontend/fetch-openapi.js @@ -0,0 +1,41 @@ +// fetch-openapi.js +const fs = require('fs'); +const https = require('https'); +const { exec } = require('child_process'); + +// FastAPI server URL (make sure your server is running locally at this address) +const OPENAPI_URL = 'http://127.0.0.1:8000/openapi.json'; + +// Path to save the OpenAPI schema file and TypeScript types +const SCHEMA_PATH = './src/schema/openapi.json'; +const TYPES_PATH = './src/types/api-types.ts'; + +// Fetch OpenAPI JSON +https.get(OPENAPI_URL, (res) => { + let data = ''; + + res.on('data', chunk => { + data += chunk; + }); + + res.on('end', () => { + // Save the fetched OpenAPI JSON to a file + fs.writeFileSync(SCHEMA_PATH, data, 'utf8'); + console.log(`✅ OpenAPI schema saved to ${SCHEMA_PATH}`); + + // Run openapi-typescript to generate TypeScript types + exec(`npx openapi-typescript ${SCHEMA_PATH} --output ${TYPES_PATH}`, (error, stdout, stderr) => { + if (error) { + console.error(`❌ Error generating types: ${error}`); + return; + } + if (stderr) { + console.error(`⚠️ stderr: ${stderr}`); + return; + } + console.log(`✅ TypeScript types generated at ${TYPES_PATH}`); + }); + }); +}).on("error", (err) => { + console.error("Error fetching OpenAPI schema: " + err.message); +}); \ No newline at end of file diff --git a/frontend/package-lock.json b/frontend/package-lock.json index cb85833..63f1a72 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -19,7 +19,6 @@ "@fullcalendar/react": "^6.1.15", "@fullcalendar/timegrid": "^6.1.15", "@mui/icons-material": "^6.1.5", - "@mui/lab": "^6.0.0-beta.13", "@mui/material": "^6.1.5", "dayjs": "^1.11.13", "openapi-typescript-codegen": "^0.29.0", @@ -39,9 +38,11 @@ "eslint-plugin-react-hooks": "^5.1.0-rc.0", "eslint-plugin-react-refresh": "^0.4.12", "globals": "^15.9.0", + "openapi-typescript": "^7.4.2", "typescript": "^5.5.3", "typescript-eslint": "^8.7.0", - "vite": "^5.4.8" + "vite": "^5.4.8", + "vite-plugin-svgr": "^4.2.0" } }, "node_modules/@aldabil/react-scheduler": { @@ -1104,40 +1105,6 @@ "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/@floating-ui/core": { - "version": "1.6.8", - "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.6.8.tgz", - "integrity": "sha512-7XJ9cPU+yI2QeLS+FCSlqNFZJq8arvswefkZrYI1yQBbftw6FyrZOxYSh+9S7z7TpeWlRt9zJ5IhM1WIL334jA==", - "dependencies": { - "@floating-ui/utils": "^0.2.8" - } - }, - "node_modules/@floating-ui/dom": { - "version": "1.6.11", - "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.6.11.tgz", - "integrity": "sha512-qkMCxSR24v2vGkhYDo/UzxfJN3D4syqSjyuTFz6C7XcpU1pASPRieNI0Kj5VP3/503mOfYiGY891ugBX1GlABQ==", - "dependencies": { - "@floating-ui/core": "^1.6.0", - "@floating-ui/utils": "^0.2.8" - } - }, - "node_modules/@floating-ui/react-dom": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.2.tgz", - "integrity": "sha512-06okr5cgPzMNBy+Ycse2A6udMi4bqwW/zgBF/rwjcNqWkyr82Mcg8b0vjX8OJpZFy/FKjJmw6wV7t44kK6kW7A==", - "dependencies": { - "@floating-ui/dom": "^1.0.0" - }, - "peerDependencies": { - "react": ">=16.8.0", - "react-dom": ">=16.8.0" - } - }, - "node_modules/@floating-ui/utils": { - "version": "0.2.8", - "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.8.tgz", - "integrity": "sha512-kym7SodPp8/wloecOpcmSnWJsK7M0E5Wg8UcFA+uO4B9s5d0ywXOEro/8HM9x0rW+TljRzul/14UYz3TleT3ig==" - }, "node_modules/@fullcalendar/core": { "version": "6.1.15", "resolved": "https://registry.npmjs.org/@fullcalendar/core/-/core-6.1.15.tgz", @@ -1280,37 +1247,6 @@ "resolved": "https://registry.npmjs.org/@jsdevtools/ono/-/ono-7.1.3.tgz", "integrity": "sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg==" }, - "node_modules/@mui/base": { - "version": "5.0.0-beta.60", - "resolved": "https://registry.npmjs.org/@mui/base/-/base-5.0.0-beta.60.tgz", - "integrity": "sha512-w8twR3qCUI+uJHO5xDOuc1yB5l46KFbvNsTwIvEW9tQkKxVaiEFf2GAXHuvFJiHfZLqjzett6drZjghy8D1Z1A==", - "dependencies": { - "@babel/runtime": "^7.25.7", - "@floating-ui/react-dom": "^2.1.1", - "@mui/types": "^7.2.18", - "@mui/utils": "^6.1.5", - "@popperjs/core": "^2.11.8", - "clsx": "^2.1.1", - "prop-types": "^15.8.1" - }, - "engines": { - "node": ">=14.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/mui-org" - }, - "peerDependencies": { - "@types/react": "^17.0.0 || ^18.0.0", - "react": "^17.0.0 || ^18.0.0", - "react-dom": "^17.0.0 || ^18.0.0" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, "node_modules/@mui/core-downloads-tracker": { "version": "6.1.5", "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-6.1.5.tgz", @@ -1345,50 +1281,6 @@ } } }, - "node_modules/@mui/lab": { - "version": "6.0.0-beta.13", - "resolved": "https://registry.npmjs.org/@mui/lab/-/lab-6.0.0-beta.13.tgz", - "integrity": "sha512-gLcAL96KhV1aA7sCaganPitVb+NT42Y2KsmnHmCtCVqAgBgSmC4D6mcH7MjjR1UAQt+DfxeeoqrFIQjKTI/wmA==", - "dependencies": { - "@babel/runtime": "^7.25.7", - "@mui/base": "5.0.0-beta.60", - "@mui/system": "^6.1.5", - "@mui/types": "^7.2.18", - "@mui/utils": "^6.1.5", - "clsx": "^2.1.1", - "prop-types": "^15.8.1" - }, - "engines": { - "node": ">=14.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/mui-org" - }, - "peerDependencies": { - "@emotion/react": "^11.5.0", - "@emotion/styled": "^11.3.0", - "@mui/material": "^6.1.5", - "@mui/material-pigment-css": "^6.1.5", - "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", - "react": "^17.0.0 || ^18.0.0 || ^19.0.0", - "react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0" - }, - "peerDependenciesMeta": { - "@emotion/react": { - "optional": true - }, - "@emotion/styled": { - "optional": true - }, - "@mui/material-pigment-css": { - "optional": true - }, - "@types/react": { - "optional": true - } - } - }, "node_modules/@mui/material": { "version": "6.1.5", "resolved": "https://registry.npmjs.org/@mui/material/-/material-6.1.5.tgz", @@ -1708,6 +1600,84 @@ "url": "https://opencollective.com/popperjs" } }, + "node_modules/@redocly/ajv": { + "version": "8.11.2", + "resolved": "https://registry.npmjs.org/@redocly/ajv/-/ajv-8.11.2.tgz", + "integrity": "sha512-io1JpnwtIcvojV7QKDUSIuMN/ikdOUd1ReEnUnMKGfDVridQZ31J0MmIuqwuRjWDZfmvr+Q0MqCcfHM2gTivOg==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js-replace": "^1.0.1" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/@redocly/ajv/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true, + "license": "MIT" + }, + "node_modules/@redocly/config": { + "version": "0.15.0", + "resolved": "https://registry.npmjs.org/@redocly/config/-/config-0.15.0.tgz", + "integrity": "sha512-QmzuqbhzrbiktRGw+FV7iim+TsfQRU8crJb2s7ls8gP+BMkE1RHZnmJ1lAA/QwzyXbEmKZeGFTdM6PWuRwNlRA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@redocly/openapi-core": { + "version": "1.25.9", + "resolved": "https://registry.npmjs.org/@redocly/openapi-core/-/openapi-core-1.25.9.tgz", + "integrity": "sha512-tod9bhIxBJQOeGQ3Ot5Zk707Wcg5YgEcEG766cGxwHqjRUNF5kwZnleBO7CpaLusOMWnQefj7RfFWLZS+IqnhA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@redocly/ajv": "^8.11.2", + "@redocly/config": "^0.15.0", + "colorette": "^1.2.0", + "https-proxy-agent": "^7.0.4", + "js-levenshtein": "^1.1.6", + "js-yaml": "^4.1.0", + "lodash.isequal": "^4.5.0", + "minimatch": "^5.0.1", + "node-fetch": "^2.6.1", + "pluralize": "^8.0.0", + "yaml-ast-parser": "0.0.43" + }, + "engines": { + "node": ">=14.19.0", + "npm": ">=7.0.0" + } + }, + "node_modules/@redocly/openapi-core/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@redocly/openapi-core/node_modules/minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/@remix-run/router": { "version": "1.20.0", "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.20.0.tgz", @@ -1727,6 +1697,42 @@ "react": ">=16.8.0" } }, + "node_modules/@rollup/pluginutils": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.1.3.tgz", + "integrity": "sha512-Pnsb6f32CD2W3uCaLZIzDmeFyQ2b8UWMFI7xtwUezpcGBDVDW6y9XgAWIlARiGAo6eNF5FK5aQTr0LFyNyqq5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "estree-walker": "^2.0.2", + "picomatch": "^4.0.2" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "node_modules/@rollup/pluginutils/node_modules/picomatch": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", + "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/@rollup/rollup-android-arm-eabi": { "version": "4.24.0", "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.24.0.tgz", @@ -1935,6 +1941,258 @@ "win32" ] }, + "node_modules/@svgr/babel-plugin-add-jsx-attribute": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-add-jsx-attribute/-/babel-plugin-add-jsx-attribute-8.0.0.tgz", + "integrity": "sha512-b9MIk7yhdS1pMCZM8VeNfUlSKVRhsHZNMl5O9SfaX0l0t5wjdgu4IDzGB8bpnGBBOjGST3rRFVsaaEtI4W6f7g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-remove-jsx-attribute": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-attribute/-/babel-plugin-remove-jsx-attribute-8.0.0.tgz", + "integrity": "sha512-BcCkm/STipKvbCl6b7QFrMh/vx00vIP63k2eM66MfHJzPr6O2U0jYEViXkHJWqXqQYjdeA9cuCl5KWmlwjDvbA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-remove-jsx-empty-expression": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-empty-expression/-/babel-plugin-remove-jsx-empty-expression-8.0.0.tgz", + "integrity": "sha512-5BcGCBfBxB5+XSDSWnhTThfI9jcO5f0Ai2V24gZpG+wXF14BzwxxdDb4g6trdOux0rhibGs385BeFMSmxtS3uA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-replace-jsx-attribute-value": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-replace-jsx-attribute-value/-/babel-plugin-replace-jsx-attribute-value-8.0.0.tgz", + "integrity": "sha512-KVQ+PtIjb1BuYT3ht8M5KbzWBhdAjjUPdlMtpuw/VjT8coTrItWX6Qafl9+ji831JaJcu6PJNKCV0bp01lBNzQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-svg-dynamic-title": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-svg-dynamic-title/-/babel-plugin-svg-dynamic-title-8.0.0.tgz", + "integrity": "sha512-omNiKqwjNmOQJ2v6ge4SErBbkooV2aAWwaPFs2vUY7p7GhVkzRkJ00kILXQvRhA6miHnNpXv7MRnnSjdRjK8og==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-svg-em-dimensions": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-svg-em-dimensions/-/babel-plugin-svg-em-dimensions-8.0.0.tgz", + "integrity": "sha512-mURHYnu6Iw3UBTbhGwE/vsngtCIbHE43xCRK7kCw4t01xyGqb2Pd+WXekRRoFOBIY29ZoOhUCTEweDMdrjfi9g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-transform-react-native-svg": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-transform-react-native-svg/-/babel-plugin-transform-react-native-svg-8.1.0.tgz", + "integrity": "sha512-Tx8T58CHo+7nwJ+EhUwx3LfdNSG9R2OKfaIXXs5soiy5HtgoAEkDay9LIimLOcG8dJQH1wPZp/cnAv6S9CrR1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-transform-svg-component": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-transform-svg-component/-/babel-plugin-transform-svg-component-8.0.0.tgz", + "integrity": "sha512-DFx8xa3cZXTdb/k3kfPeaixecQLgKh5NVBMwD0AQxOzcZawK4oo1Jh9LbrcACUivsCA7TLG8eeWgrDXjTMhRmw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-preset": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-preset/-/babel-preset-8.1.0.tgz", + "integrity": "sha512-7EYDbHE7MxHpv4sxvnVPngw5fuR6pw79SkcrILHJ/iMpuKySNCl5W1qcwPEpU+LgyRXOaAFgH0KhwD18wwg6ug==", + "dev": true, + "license": "MIT", + "dependencies": { + "@svgr/babel-plugin-add-jsx-attribute": "8.0.0", + "@svgr/babel-plugin-remove-jsx-attribute": "8.0.0", + "@svgr/babel-plugin-remove-jsx-empty-expression": "8.0.0", + "@svgr/babel-plugin-replace-jsx-attribute-value": "8.0.0", + "@svgr/babel-plugin-svg-dynamic-title": "8.0.0", + "@svgr/babel-plugin-svg-em-dimensions": "8.0.0", + "@svgr/babel-plugin-transform-react-native-svg": "8.1.0", + "@svgr/babel-plugin-transform-svg-component": "8.0.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/core": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@svgr/core/-/core-8.1.0.tgz", + "integrity": "sha512-8QqtOQT5ACVlmsvKOJNEaWmRPmcojMOzCz4Hs2BGG/toAp/K38LcsMRyLp349glq5AzJbCEeimEoxaX6v/fLrA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.21.3", + "@svgr/babel-preset": "8.1.0", + "camelcase": "^6.2.0", + "cosmiconfig": "^8.1.3", + "snake-case": "^3.0.4" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + } + }, + "node_modules/@svgr/core/node_modules/cosmiconfig": { + "version": "8.3.6", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.3.6.tgz", + "integrity": "sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==", + "dev": true, + "license": "MIT", + "dependencies": { + "import-fresh": "^3.3.0", + "js-yaml": "^4.1.0", + "parse-json": "^5.2.0", + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/d-fischer" + }, + "peerDependencies": { + "typescript": ">=4.9.5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@svgr/hast-util-to-babel-ast": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/hast-util-to-babel-ast/-/hast-util-to-babel-ast-8.0.0.tgz", + "integrity": "sha512-EbDKwO9GpfWP4jN9sGdYwPBU0kdomaPIL2Eu4YwmgP+sJeXT+L7bMwJUBnhzfH8Q2qMBqZ4fJwpCyYsAN3mt2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.21.3", + "entities": "^4.4.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + } + }, + "node_modules/@svgr/plugin-jsx": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@svgr/plugin-jsx/-/plugin-jsx-8.1.0.tgz", + "integrity": "sha512-0xiIyBsLlr8quN+WyuxooNW9RJ0Dpr8uOnH/xrCVO8GLUcwHISwj1AG0k+LFzteTkAA0GbX0kj9q6Dk70PTiPA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.21.3", + "@svgr/babel-preset": "8.1.0", + "@svgr/hast-util-to-babel-ast": "8.0.0", + "svg-parser": "^2.0.4" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@svgr/core": "*" + } + }, "node_modules/@types/babel__core": { "version": "7.20.5", "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", @@ -2298,6 +2556,19 @@ "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, + "node_modules/agent-base": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz", + "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, "node_modules/ajv": { "version": "6.12.6", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", @@ -2314,6 +2585,16 @@ "url": "https://github.com/sponsors/epoberezkin" } }, + "node_modules/ansi-colors": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", + "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/ansi-styles": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", @@ -2485,6 +2766,13 @@ "node": ">=0.8.0" } }, + "node_modules/change-case": { + "version": "5.4.4", + "resolved": "https://registry.npmjs.org/change-case/-/change-case-5.4.4.tgz", + "integrity": "sha512-HRQyTk2/YPEkt9TnUPbOpr64Uw3KOicFWPVBb+xiHvd6eBx/qPr9xqfBFDT8P2vWsvvz4jbEkfDe71W3VyNu2w==", + "dev": true, + "license": "MIT" + }, "node_modules/clsx": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", @@ -2506,6 +2794,13 @@ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" }, + "node_modules/colorette": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.4.0.tgz", + "integrity": "sha512-Y2oEozpomLn7Q3HFP7dpww7AtMJplbM9lGZP6RDfHqmbeRjiwRg4n6VM6j4KLmRke85uWEI7JqF17f3pqdRA0g==", + "dev": true, + "license": "MIT" + }, "node_modules/commander": { "version": "12.1.0", "resolved": "https://registry.npmjs.org/commander/-/commander-12.1.0.tgz", @@ -2636,11 +2931,35 @@ "csstype": "^3.0.2" } }, + "node_modules/dot-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz", + "integrity": "sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==", + "dev": true, + "license": "MIT", + "dependencies": { + "no-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, "node_modules/electron-to-chromium": { "version": "1.5.43", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.43.tgz", "integrity": "sha512-NxnmFBHDl5Sachd2P46O7UJiMaMHMLSofoIWVJq3mj8NJgG0umiSeljAVP9lGzjI0UDLJJ5jjoGjcrB8RSbjLQ==" }, + "node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, "node_modules/error-ex": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", @@ -2935,6 +3254,13 @@ "node": ">=4.0" } }, + "node_modules/estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", + "dev": true, + "license": "MIT" + }, "node_modules/esutils": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", @@ -3206,6 +3532,20 @@ "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" }, + "node_modules/https-proxy-agent": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.5.tgz", + "integrity": "sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.0.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, "node_modules/ignore": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", @@ -3239,6 +3579,19 @@ "node": ">=0.8.19" } }, + "node_modules/index-to-position": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/index-to-position/-/index-to-position-0.1.2.tgz", + "integrity": "sha512-MWDKS3AS1bGCHLBA2VLImJz42f7bJh8wQsTGCzI3j519/CASStoDONUBVz2I/VID0MpiX3SGSnbOD2xUalbE5g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/inherits": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", @@ -3307,6 +3660,16 @@ "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", "dev": true }, + "node_modules/js-levenshtein": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/js-levenshtein/-/js-levenshtein-1.1.6.tgz", + "integrity": "sha512-X2BB11YZtrRqY4EnQcLX5Rh373zbK4alC1FW7D7MBhL2gtcC17cTnr6DmfHZeS0s2rTHjUTMMHfG7gO8SSdw+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -3436,6 +3799,13 @@ "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==" }, + "node_modules/lodash.isequal": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", + "integrity": "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==", + "dev": true, + "license": "MIT" + }, "node_modules/lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", @@ -3453,6 +3823,16 @@ "loose-envify": "cli.js" } }, + "node_modules/lower-case": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz", + "integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==", + "dev": true, + "license": "MIT", + "dependencies": { + "tslib": "^2.0.3" + } + }, "node_modules/lru-cache": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", @@ -3569,6 +3949,38 @@ "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==" }, + "node_modules/no-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz", + "integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==", + "dev": true, + "license": "MIT", + "dependencies": { + "lower-case": "^2.0.2", + "tslib": "^2.0.3" + } + }, + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, "node_modules/node-releases": { "version": "2.0.18", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.18.tgz", @@ -3582,6 +3994,27 @@ "node": ">=0.10.0" } }, + "node_modules/openapi-typescript": { + "version": "7.4.2", + "resolved": "https://registry.npmjs.org/openapi-typescript/-/openapi-typescript-7.4.2.tgz", + "integrity": "sha512-SvhmSTItcEAdDUcz+wzrcg6OENpMRkHqqY2hZB01FT+NOfgLcZ1B1ML6vcQrnipONHtG9AQELiKHgGTjpNGjiQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@redocly/openapi-core": "^1.25.3", + "ansi-colors": "^4.1.3", + "change-case": "^5.4.4", + "parse-json": "^8.1.0", + "supports-color": "^9.4.0", + "yargs-parser": "^21.1.1" + }, + "bin": { + "openapi-typescript": "bin/cli.js" + }, + "peerDependencies": { + "typescript": "^5.x" + } + }, "node_modules/openapi-typescript-codegen": { "version": "0.29.0", "resolved": "https://registry.npmjs.org/openapi-typescript-codegen/-/openapi-typescript-codegen-0.29.0.tgz", @@ -3597,6 +4030,37 @@ "openapi": "bin/index.js" } }, + "node_modules/openapi-typescript/node_modules/parse-json": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-8.1.0.tgz", + "integrity": "sha512-rum1bPifK5SSar35Z6EKZuYPJx85pkNaFrxBK3mwdfSJ1/WKbYrjoW/zTPSjRRamfmVX1ACBIdFAO0VRErW/EA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.22.13", + "index-to-position": "^0.1.2", + "type-fest": "^4.7.1" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/openapi-typescript/node_modules/supports-color": { + "version": "9.4.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-9.4.0.tgz", + "integrity": "sha512-VL+lNrEoIXww1coLPOmiEmK/0sGigko5COxI09KzHc2VJXJsQ37UaQ+8quuxjDeA7+KnLGTWRyOXSLLR2Wb4jw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, "node_modules/optionator": { "version": "0.9.4", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", @@ -3728,6 +4192,16 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/pluralize": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-8.0.0.tgz", + "integrity": "sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, "node_modules/postcss": { "version": "8.4.47", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.47.tgz", @@ -4000,6 +4474,16 @@ "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==" }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/resolve": { "version": "1.22.8", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", @@ -4134,6 +4618,17 @@ "node": ">=8" } }, + "node_modules/snake-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/snake-case/-/snake-case-3.0.4.tgz", + "integrity": "sha512-LAOh4z89bGQvl9pFfNF8V146i7o7/CqFPbqzYgP+yYzDIDeS9HaNFtXABamRW+AQzEVODcvE79ljJ+8a9YSdMg==", + "dev": true, + "license": "MIT", + "dependencies": { + "dot-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, "node_modules/source-map": { "version": "0.5.7", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", @@ -4232,6 +4727,13 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/svg-parser": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/svg-parser/-/svg-parser-2.0.4.tgz", + "integrity": "sha512-e4hG1hRwoOdRb37cIMSgzNsxyzKfayW6VOflrwvR+/bzrkyxY/31WkbgnQpgtrNp1SdpJvpUAGTa/ZoiPNDuRQ==", + "dev": true, + "license": "MIT" + }, "node_modules/text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", @@ -4250,6 +4752,13 @@ "node": ">=8.0" } }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "dev": true, + "license": "MIT" + }, "node_modules/ts-api-utils": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz", @@ -4279,6 +4788,19 @@ "node": ">= 0.8.0" } }, + "node_modules/type-fest": { + "version": "4.26.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.26.1.tgz", + "integrity": "sha512-yOGpmOAL7CkKe/91I5O3gPICmJNLJ1G4zFYVAsRHg7M64biSnPtRj0WNQt++bRkjYOqjWXrhnUw1utzmVErAdg==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/typescript": { "version": "5.6.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.3.tgz", @@ -4387,6 +4909,13 @@ "punycode": "^2.1.0" } }, + "node_modules/uri-js-replace": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/uri-js-replace/-/uri-js-replace-1.0.1.tgz", + "integrity": "sha512-W+C9NWNLFOoBI2QWDp4UT9pv65r2w5Cx+3sTYFvtMdDBxkKt1syCqsUdSFAChbEe1uK5TfS04wt/nGwmaeIQ0g==", + "dev": true, + "license": "MIT" + }, "node_modules/util": { "version": "0.10.4", "resolved": "https://registry.npmjs.org/util/-/util-0.10.4.tgz", @@ -4454,6 +4983,21 @@ } } }, + "node_modules/vite-plugin-svgr": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/vite-plugin-svgr/-/vite-plugin-svgr-4.2.0.tgz", + "integrity": "sha512-SC7+FfVtNQk7So0XMjrrtLAbEC8qjFPifyD7+fs/E6aaNdVde6umlVVh0QuwDLdOMu7vp5RiGFsB70nj5yo0XA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@rollup/pluginutils": "^5.0.5", + "@svgr/core": "^8.1.0", + "@svgr/plugin-jsx": "^8.1.0" + }, + "peerDependencies": { + "vite": "^2.6.0 || 3 || 4 || 5" + } + }, "node_modules/warning": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz", @@ -4462,6 +5006,24 @@ "loose-envify": "^1.0.0" } }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "dev": true, + "license": "BSD-2-Clause" + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dev": true, + "license": "MIT", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -4504,6 +5066,23 @@ "node": ">= 6" } }, + "node_modules/yaml-ast-parser": { + "version": "0.0.43", + "resolved": "https://registry.npmjs.org/yaml-ast-parser/-/yaml-ast-parser-0.0.43.tgz", + "integrity": "sha512-2PTINUwsRqSd+s8XxKaJWQlUuEMHJQyEuh2edBbW8KNJz0SJPwUSD2zRWqezFEdN7IzAgeuYHFUCF7o8zRdZ0A==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, "node_modules/yocto-queue": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", diff --git a/frontend/package.json b/frontend/package.json index bc3aef2..dc013c1 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -7,7 +7,9 @@ "dev": "node_modules/.bin/vite", "build": "node_modules/.bin/tsc -b && vite build", "lint": "node_modules/.bin/eslint .", - "preview": "node_modules/.bin/vite preview" + "preview": "node_modules/.bin/vite preview", + "fetch:types": "node fetch-openapi.js" + }, "dependencies": { "@aldabil/react-scheduler": "^2.9.5", @@ -21,7 +23,6 @@ "@fullcalendar/react": "^6.1.15", "@fullcalendar/timegrid": "^6.1.15", "@mui/icons-material": "^6.1.5", - "@mui/lab": "^6.0.0-beta.13", "@mui/material": "^6.1.5", "dayjs": "^1.11.13", "openapi-typescript-codegen": "^0.29.0", @@ -41,8 +42,10 @@ "eslint-plugin-react-hooks": "^5.1.0-rc.0", "eslint-plugin-react-refresh": "^0.4.12", "globals": "^15.9.0", + "openapi-typescript": "^7.4.2", "typescript": "^5.5.3", "typescript-eslint": "^8.7.0", - "vite": "^5.4.8" + "vite": "^5.4.8", + "vite-plugin-svgr": "^4.2.0" } } diff --git a/frontend/src/components/DewarDetails.tsx b/frontend/src/components/DewarDetails.tsx index bb160c5..e852d22 100644 --- a/frontend/src/components/DewarDetails.tsx +++ b/frontend/src/components/DewarDetails.tsx @@ -11,6 +11,7 @@ interface DewarDetailsProps { returnAddresses: Address[]; } + const DewarDetails: React.FC = ({ dewar, trackingNumber, @@ -23,7 +24,9 @@ const DewarDetails: React.FC = ({ const updateSelectedDetails = (contactPerson?: { firstname: string }, returnAddress?: Address) => { if (contactPerson) setSelectedContactPerson(contactPerson.firstname); - if (returnAddress) setSelectedReturnAddress(returnAddress.id.toString()); + if (returnAddress?.id != null) { + setSelectedReturnAddress(returnAddress.id.toString()); + }; }; React.useEffect(() => { @@ -132,7 +135,8 @@ const DewarDetails: React.FC = ({ > Select Return Address {returnAddresses.map((address) => ( - {address.street} + + {address.street} ))} Add New Return Address diff --git a/frontend/src/components/DewarStepper.tsx b/frontend/src/components/DewarStepper.tsx index 056ff5c..0445543 100644 --- a/frontend/src/components/DewarStepper.tsx +++ b/frontend/src/components/DewarStepper.tsx @@ -2,20 +2,32 @@ import React from 'react'; import { Stepper, Step, StepLabel, StepIconProps, Typography } from '@mui/material'; import AirplanemodeActiveIcon from '@mui/icons-material/AirplanemodeActive'; import StoreIcon from '@mui/icons-material/Store'; -import bottleIcon from '../assets/icons/bottle-svgrepo-com-grey.svg'; +import RecycleIcon from '@mui/icons-material/Restore'; import { Dewar } from "../../openapi"; -// Constants const ICON_STYLE = { width: 24, height: 24 }; +// Define the possible statuses +type DewarStatus = 'In Preparation' | 'Ready for Shipping' | 'Shipped' | 'Not Arrived' | 'Arrived' | 'Returned' | 'Delayed'; + +// Inline SVG Component +const BottleIcon: React.FC<{ fill: string }> = ({ fill }) => ( + + + +); + // Define types for icons mapping. const ICONS: { [key: number]: React.ReactElement } = { - 0: Bottle Icon, - 1: , - 2: , + 0: , + 1: , // 'Ready for Shipping' -> Active + 2: , // 'Not Arrived' + 3: , // 'Returned' + 4: , // 'Shipped' - Active + 5: , // 'Delayed' }; -// Define StepIconContainer to accept correct props and handle typing better +// Define StepIconContainer to accept correct props and handle typing better. interface StepIconContainerProps extends React.HTMLAttributes { color: string; } @@ -32,70 +44,72 @@ type StepIconComponentProps = { } & StepIconProps; const StepIconComponent = ({ icon, dewar, ...props }: StepIconComponentProps) => { - const { iconIndex, color } = getIconProperties(icon, dewar); + const { iconIndex, color, fill } = getIconProperties(icon, dewar); + + // Adjust icon color for the bottle especially since it's an SVG element + const IconComponent = ICONS[iconIndex]; + const iconProps = iconIndex === 0 ? { fill: color } : {}; return ( - {ICONS[iconIndex]} + {IconComponent + ? React.cloneElement(IconComponent, iconProps) + : Invalid icon + } ); }; // Extracted function to determine icon properties const getIconProperties = (icon: number, dewar: Dewar) => { - const iconIndex = icon - 1; - const color = determineIconColor(dewar, iconIndex); - return { iconIndex, color }; + const status = dewar.status as DewarStatus; + const iconIndex = status === 'Delayed' && icon === 1 ? 5 : icon; + const color = determineIconColor(icon, status); + const fill = status === 'In Preparation' ? color : undefined; + return { iconIndex, color, fill }; }; -// Original determineIconColor function remains unchanged -const determineIconColor = (dewar: Dewar, index: number) => { - let color = 'grey'; +const STATUS_TO_STEP: Record = { + 'In Preparation': 0, + 'Ready for Shipping': 1, + 'Shipped': 1, + 'Delayed': 1, + 'Not Arrived': 2, + 'Arrived': 2, + 'Returned': 3 +}; - if (index === 0) { - if (dewar.status === 'In Preparation') { - color = 'blue'; - } else if (dewar.status === 'Ready for Shipping') { - color = 'green'; - } +const getStatusStepIndex = (status: DewarStatus): number => STATUS_TO_STEP[status]; + +const determineIconColor = (iconIndex: number, status: DewarStatus): string => { + const statusIndex = getStatusStepIndex(status); + if (status === 'Delayed' && iconIndex === 1) { + return 'yellow'; } - if (index === 1) { - if (dewar.status === 'Ready for Shipping' && dewar.shippingStatus !== 'shipped') { - color = 'blue'; - } else if (dewar.shippingStatus === 'shipped') { - color = 'green'; - } - } - if (index === 2) { - if (dewar.shippingStatus === 'shipped' && dewar.arrivalStatus !== 'arrived') { - color = 'blue'; - } else if (dewar.arrivalStatus === 'arrived') { - color = 'green'; - } - } - return color; + return iconIndex <= statusIndex ? (iconIndex === statusIndex ? (status === 'Shipped' ? 'green' : 'blue') : 'green') : 'grey'; }; // Define your steps -const steps = ['In Preparation', 'Ready for Shipping', 'Arrived']; +const steps = ['In-House', 'Transit', 'At SLS', 'Returned']; const CustomStepper = ({ dewar }: { dewar: Dewar }) => { // Determine the current active step - const activeStep = steps.indexOf(dewar.status) !== -1 ? steps.indexOf(dewar.status) : 0; + const activeStep = getStatusStepIndex(dewar.status as DewarStatus); return ( {steps.map((label, index) => ( } + StepIconComponent={(stepProps) => } > {label} {index === 0 ? dewar.ready_date : index === 1 ? dewar.shipping_date : - index === 2 ? dewar.arrival_date : ''} + index === 2 ? dewar.arrival_date : + index === 3 ? dewar.returning_date : null} ))} diff --git a/frontend/src/components/ShipmentDetails.tsx b/frontend/src/components/ShipmentDetails.tsx index b21bbc6..a77a425 100644 --- a/frontend/src/components/ShipmentDetails.tsx +++ b/frontend/src/components/ShipmentDetails.tsx @@ -1,25 +1,25 @@ import React from 'react'; -import {Box, Typography, Button, Stack, TextField} from '@mui/material'; +import { Box, Typography, Button, Stack, TextField } from '@mui/material'; import QRCode from 'react-qr-code'; import DeleteIcon from "@mui/icons-material/Delete"; -import {Dewar, Shipment_Input, DefaultService} from "../../openapi"; -import {SxProps} from "@mui/system"; +import { Dewar, Shipment_Input, DefaultService } from "../../openapi"; +import { SxProps } from "@mui/system"; import CustomStepper from "./DewarStepper"; import DewarDetails from './DewarDetails'; - - interface ShipmentDetailsProps { isCreatingShipment: boolean; selectedShipment: Shipment_Input; selectedDewar: Dewar | null; setSelectedDewar: React.Dispatch>; + setSelectedShipment: React.Dispatch>; sx?: SxProps; } const ShipmentDetails: React.FC = ({ selectedShipment, setSelectedDewar, + setSelectedShipment, sx = {}, }) => { const [localSelectedDewar, setLocalSelectedDewar] = React.useState(null); @@ -33,11 +33,9 @@ const ShipmentDetails: React.FC = ({ const totalSamples = selectedShipment.dewars.reduce((acc, dewar) => acc + (dewar.number_of_samples || 0), 0); const handleDewarSelection = (dewar: Dewar) => { - if (setSelectedDewar) { - const newSelection = localSelectedDewar?.id === dewar.id ? null : dewar; - setLocalSelectedDewar(newSelection); - setSelectedDewar(newSelection); - } + const newSelection = localSelectedDewar?.id === dewar.id ? null : dewar; + setLocalSelectedDewar(newSelection); + setSelectedDewar(newSelection); }; const handleDeleteDewar = () => { @@ -45,41 +43,72 @@ const ShipmentDetails: React.FC = ({ const confirmed = window.confirm('Are you sure you want to delete this dewar?'); if (confirmed) { const updatedDewars = selectedShipment.dewars.filter(dewar => dewar.tracking_number !== localSelectedDewar.tracking_number); - console.log('Updated Dewars:', updatedDewars); + setSelectedShipment((prev) => ({ ...prev, dewars: updatedDewars })); setLocalSelectedDewar(null); } } }; const handleNewDewarChange = (e: React.ChangeEvent) => { - const {name, value} = e.target; + const { name, value } = e.target; setNewDewar((prev) => ({ ...prev, [name]: value, })); }; + const addDewarToList = (currentDewars: Array, newDewar: Dewar): Array => { + return [...currentDewars, newDewar]; + }; + + const updateDewarsState = (prev: Shipment_Input, createdDewar: Dewar): Shipment_Input => { + const updatedDewars = addDewarToList(prev.dewars, createdDewar); + return { ...prev, dewars: updatedDewars }; + }; + const handleAddDewar = async () => { if (selectedShipment && newDewar.dewar_name) { try { const newDewarToPost: Dewar = { + ...newDewar as Dewar, dewar_name: newDewar.dewar_name.trim() || 'Unnamed Dewar', number_of_pucks: newDewar.number_of_pucks ?? 0, number_of_samples: newDewar.number_of_samples ?? 0, return_address: selectedShipment.return_address, contact_person: selectedShipment.contact_person, status: 'In preparation', - shippingStatus: 'not shipped', - arrivalStatus: 'not arrived', qrcode: newDewar.qrcode || 'N/A', }; - await DefaultService.createDewarDewarsPost(newDewarToPost); + // Create a new dewar + const createdDewar = await DefaultService.createDewarDewarsPost(newDewarToPost); + + console.log('Created Dewar:', createdDewar); + + // Check IDs before calling backend + console.log('Adding dewar to shipment:', { + shipment_id: selectedShipment.shipment_id, + dewar_id: createdDewar.id, + }); + + // Make an API call to associate the dewar with the shipment + const updatedShipment = await DefaultService.addDewarToShipmentShipmentsShipmentIdAddDewarPost( + selectedShipment.shipment_id, + createdDewar.id + ); + + if (updatedShipment) { + setSelectedShipment(updatedShipment); + } else { + throw new Error("Failed to update shipment with new dewar"); + } + setIsAddingDewar(false); - setNewDewar({dewar_name: '', tracking_number: ''}); + setNewDewar({ dewar_name: '', tracking_number: '' }); + } catch (error) { - alert("Failed to add dewar. Please try again."); - console.error("Error adding dewar:", error); + alert("Failed to add dewar or update shipment. Please try again."); + console.error("Error adding dewar or updating shipment:", error); } } else { alert('Please fill in the Dewar Name'); @@ -87,19 +116,19 @@ const ShipmentDetails: React.FC = ({ }; return ( - + {!localSelectedDewar && !isAddingDewar && ( )} {isAddingDewar && ( - + Add New Dewar = ({ value={newDewar.dewar_name} onChange={handleNewDewarChange} fullWidth - sx={{marginBottom: 2}} + sx={{ marginBottom: 2 }} /> - )} diff --git a/frontend/src/components/ShipmentForm.tsx b/frontend/src/components/ShipmentForm.tsx index 175a653..a091a0f 100644 --- a/frontend/src/components/ShipmentForm.tsx +++ b/frontend/src/components/ShipmentForm.tsx @@ -30,7 +30,7 @@ const ShipmentForm: React.FC = ({ street: '', city: '', zipcode: '', - country: '', + country: '' }); const [newShipment, setNewShipment] = React.useState({ @@ -54,7 +54,7 @@ const ShipmentForm: React.FC = ({ try { const c: ContactPerson[] = await DefaultService.getContactsContactsGet(); setContactPersons(c); - } catch (err) { + } catch { setErrorMessage('Failed to load contact persons. Please try again later.'); } }; @@ -63,7 +63,7 @@ const ShipmentForm: React.FC = ({ try { const a: Address[] = await DefaultService.getReturnAddressesReturnAddressesGet(); setReturnAddresses(a); - } catch (err) { + } catch { setErrorMessage('Failed to load return addresses. Please try again later.'); } }; @@ -72,7 +72,7 @@ const ShipmentForm: React.FC = ({ try { const p: Proposal[] = await DefaultService.getProposalsProposalsGet(); setProposals(p); - } catch (err) { + } catch { setErrorMessage('Failed to load proposals. Please try again later.'); } }; @@ -155,6 +155,7 @@ const ShipmentForm: React.FC = ({ number: newShipment.proposal_number }] : [], return_address: newShipment.return_address ? newShipment.return_address.map(address => ({ + id: address.id, street: address.street, city: address.city, zipcode: address.zipcode, @@ -168,7 +169,7 @@ const ShipmentForm: React.FC = ({ await DefaultService.createShipmentShipmentsPost(payload); setErrorMessage(null); onCancel(); // close the form after saving - } catch (error) { + } catch { setErrorMessage('Failed to save shipment. Please try again.'); } }; @@ -224,7 +225,7 @@ const ShipmentForm: React.FC = ({ const c: ContactPerson = await DefaultService.createContactContactsPost(payload); setContactPersons([...contactPersons, c]); setErrorMessage(null); - } catch (err) { + } catch { setErrorMessage('Failed to create a new contact person. Please try again later.'); } @@ -250,7 +251,7 @@ const ShipmentForm: React.FC = ({ const a: Address = await DefaultService.createReturnAddressReturnAddressesPost(payload); setReturnAddresses([...returnAddresses, a]); setErrorMessage(null); - } catch (err) { + } catch { setErrorMessage('Failed to create a new return address. Please try again later.'); } diff --git a/frontend/src/pages/ShipmentView.tsx b/frontend/src/pages/ShipmentView.tsx index 9bcbd75..7c52a23 100644 --- a/frontend/src/pages/ShipmentView.tsx +++ b/frontend/src/pages/ShipmentView.tsx @@ -33,6 +33,7 @@ const ShipmentView: React.FC = () => { selectedShipment={selectedShipment} selectedDewar={selectedDewar} setSelectedDewar={setSelectedDewar} + setSelectedShipment={setSelectedShipment} /> ); } diff --git a/frontend/src/tsconfig.json b/frontend/src/tsconfig.json index 1c993e8..5111fc9 100644 --- a/frontend/src/tsconfig.json +++ b/frontend/src/tsconfig.json @@ -6,7 +6,7 @@ "strict": true, "esModuleInterop": true, "skipLibCheck": true, - "forceConsistentCasingInFileNames": true + "forceConsistentCasingInFileNames": true, }, "include": [ "src" diff --git a/frontend/tsconfig.json b/frontend/tsconfig.json index 9818dbe..c957027 100644 --- a/frontend/tsconfig.json +++ b/frontend/tsconfig.json @@ -3,5 +3,5 @@ "references": [ { "path": "./tsconfig.app.json"}, { "path": "./tsconfig.node.json"} - ] + ], } diff --git a/frontend/vite.config.ts b/frontend/vite.config.ts index 5a33944..8b96686 100644 --- a/frontend/vite.config.ts +++ b/frontend/vite.config.ts @@ -1,7 +1,7 @@ -import { defineConfig } from 'vite' -import react from '@vitejs/plugin-react' - -// https://vitejs.dev/config/ +import { defineConfig } from 'vite'; +import react from '@vitejs/plugin-react'; export default defineConfig({ - plugins: [react()], -}) + plugins: [ + react(), + ], +}); \ No newline at end of file