diff --git a/frontend/package-lock.json b/frontend/package-lock.json index e2f9304..7454672 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -1,11 +1,11 @@ { - "name": "mheidi-frontend-v2", + "name": "heidi-frontend-v2", "version": "0.0.0", "lockfileVersion": 3, "requires": true, "packages": { "": { - "name": "mheidi-frontend-v2", + "name": "heidi-frontend-v2", "version": "0.0.0", "dependencies": { "@aldabil/react-scheduler": "^2.9.5", @@ -27,6 +27,7 @@ "dotenv": "^16.4.7", "exceljs": "^4.4.0", "file-saver": "^2.0.5", + "fuse.js": "^7.0.0", "openapi-typescript-codegen": "^0.29.0", "react": "^18.3.1", "react-big-calendar": "^1.15.0", @@ -1160,9 +1161,9 @@ } }, "node_modules/@eslint/plugin-kit": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.2.tgz", - "integrity": "sha512-CXtq5nR4Su+2I47WPOlWud98Y5Lv8Kyxp2ukhgFx/eW6Blm18VXJO5WuQylPugRo8nbluoi6GvvxBLqHcvqUUw==", + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.4.tgz", + "integrity": "sha512-zSkKow6H5Kdm0ZUQUB2kV5JIXqoG0+uH5YADhaEHswm664N9Db8dXSi0nMJpacpMf+MyyglF1vnZohpEg5yUtg==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -4225,6 +4226,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/fuse.js": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/fuse.js/-/fuse.js-7.0.0.tgz", + "integrity": "sha512-14F4hBIxqKvD4Zz/XjDc3y94mNZN6pRv3U13Udo0lNLCWRBUsrMv2xwcF/y/Z5sV6+FQW+/ow68cHpm4sunt8Q==", + "license": "Apache-2.0", + "engines": { + "node": ">=10" + } + }, "node_modules/gensync": { "version": "1.0.0-beta.2", "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", @@ -5071,9 +5081,9 @@ "license": "MIT" }, "node_modules/nanoid": { - "version": "3.3.7", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", - "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", + "version": "3.3.8", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.8.tgz", + "integrity": "sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==", "dev": true, "funding": [ { diff --git a/frontend/package.json b/frontend/package.json index bc9936f..ac0fa28 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -12,7 +12,7 @@ "start-test": "vite --mode test", "start-prod": "vite --mode prod", "watch:openapi": "node fetch-openapi.js" -}, + }, "dependencies": { "@aldabil/react-scheduler": "^2.9.5", "@bitnoi.se/react-scheduler": "^0.3.1", @@ -33,6 +33,7 @@ "dotenv": "^16.4.7", "exceljs": "^4.4.0", "file-saver": "^2.0.5", + "fuse.js": "^7.0.0", "openapi-typescript-codegen": "^0.29.0", "react": "^18.3.1", "react-big-calendar": "^1.15.0", diff --git a/frontend/src/components/CountryList.tsx b/frontend/src/components/CountryList.tsx new file mode 100644 index 0000000..0520f5e --- /dev/null +++ b/frontend/src/components/CountryList.tsx @@ -0,0 +1,198 @@ +export const CountryList = [ + 'Afghanistan', + 'Albania', + 'Algeria', + 'Andorra', + 'Angola', + 'Antigua and Barbuda', + 'Argentina', + 'Armenia', + 'Australia', + 'Austria', + 'Azerbaijan', + 'Bahamas', + 'Bahrain', + 'Bangladesh', + 'Barbados', + 'Belarus', + 'Belgium', + 'Belize', + 'Benin', + 'Bhutan', + 'Bolivia', + 'Bosnia and Herzegovina', + 'Botswana', + 'Brazil', + 'Brunei', + 'Bulgaria', + 'Burkina Faso', + 'Burundi', + 'Cabo Verde', + 'Cambodia', + 'Cameroon', + 'Canada', + 'Central African Republic', + 'Chad', + 'Chile', + 'China', + 'Colombia', + 'Comoros', + 'Congo (Congo-Brazzaville)', + 'Costa Rica', + 'Croatia', + 'Cuba', + 'Cyprus', + 'Czechia (Czech Republic)', + 'Denmark', + 'Djibouti', + 'Dominica', + 'Dominican Republic', + 'Ecuador', + 'Egypt', + 'El Salvador', + 'Equatorial Guinea', + 'Eritrea', + 'Estonia', + 'Eswatini (fmr. "Swaziland")', + 'Ethiopia', + 'Fiji', + 'Finland', + 'France', + 'Gabon', + 'Gambia', + 'Georgia', + 'Germany', + 'Ghana', + 'Greece', + 'Grenada', + 'Guatemala', + 'Guinea', + 'Guinea-Bissau', + 'Guyana', + 'Haiti', + 'Holy See', + 'Honduras', + 'Hungary', + 'Iceland', + 'India', + 'Indonesia', + 'Iran', + 'Iraq', + 'Ireland', + 'Israel', + 'Italy', + 'Jamaica', + 'Japan', + 'Jordan', + 'Kazakhstan', + 'Kenya', + 'Kiribati', + 'Korea (North)', + 'Korea (South)', + 'Kosovo', + 'Kuwait', + 'Kyrgyzstan', + 'Laos', + 'Latvia', + 'Lebanon', + 'Lesotho', + 'Liberia', + 'Libya', + 'Liechtenstein', + 'Lithuania', + 'Luxembourg', + 'Madagascar', + 'Malawi', + 'Malaysia', + 'Maldives', + 'Mali', + 'Malta', + 'Marshall Islands', + 'Mauritania', + 'Mauritius', + 'Mexico', + 'Micronesia', + 'Moldova', + 'Monaco', + 'Mongolia', + 'Montenegro', + 'Morocco', + 'Mozambique', + 'Myanmar (formerly Burma)', + 'Namibia', + 'Nauru', + 'Nepal', + 'Netherlands', + 'New Zealand', + 'Nicaragua', + 'Niger', + 'Nigeria', + 'North Macedonia (formerly Macedonia)', + 'Norway', + 'Oman', + 'Pakistan', + 'Palau', + 'Palestine State', + 'Panama', + 'Papua New Guinea', + 'Paraguay', + 'Peru', + 'Philippines', + 'Poland', + 'Portugal', + 'Qatar', + 'Romania', + 'Russia', + 'Rwanda', + 'Saint Kitts and Nevis', + 'Saint Lucia', + 'Saint Vincent and the Grenadines', + 'Samoa', + 'San Marino', + 'Sao Tome and Principe', + 'Saudi Arabia', + 'Senegal', + 'Serbia', + 'Seychelles', + 'Sierra Leone', + 'Singapore', + 'Slovakia', + 'Slovenia', + 'Solomon Islands', + 'Somalia', + 'South Africa', + 'South Sudan', + 'Spain', + 'Sri Lanka', + 'Sudan', + 'Suriname', + 'Sweden', + 'Switzerland', + 'Syria', + 'Tajikistan', + 'Tanzania', + 'Thailand', + 'Timor-Leste', + 'Togo', + 'Tonga', + 'Trinidad and Tobago', + 'Tunisia', + 'Turkey', + 'Turkmenistan', + 'Tuvalu', + 'Uganda', + 'Ukraine', + 'United Arab Emirates', + 'United Kingdom', + 'United States of America', + 'Uruguay', + 'Uzbekistan', + 'Vanuatu', + 'Venezuela', + 'Vietnam', + 'Yemen', + 'Zambia', + 'Zimbabwe', +]; + +export default CountryList \ No newline at end of file diff --git a/frontend/src/components/ShipmentForm.tsx b/frontend/src/components/ShipmentForm.tsx index 339f7c5..dfa5a02 100644 --- a/frontend/src/components/ShipmentForm.tsx +++ b/frontend/src/components/ShipmentForm.tsx @@ -1,4 +1,5 @@ import * as React from 'react'; +import Fuse from 'fuse.js'; import { Box, Button, TextField, Typography, Select, MenuItem, Stack, FormControl, InputLabel } from '@mui/material'; @@ -9,6 +10,7 @@ import { OpenAPI, ShipmentCreate, ShipmentsService } from '../../openapi'; import { useEffect } from 'react'; +import { CountryList } from './CountryList'; // Import the list of countries const MAX_COMMENTS_LENGTH = 200; @@ -18,7 +20,14 @@ interface ShipmentFormProps { refreshShipments: () => void; } +// Set up Fuse.js for fuzzy searching +const fuse = new Fuse(CountryList, { + threshold: 0.3, + includeScore: true, +}); + const ShipmentForm: React.FC = ({ sx = {}, onCancel, refreshShipments }) => { + const [countrySuggestions, setCountrySuggestions] = React.useState([]); const [contactPersons, setContactPersons] = React.useState([]); const [returnAddresses, setReturnAddresses] = React.useState([]); const [proposals, setProposals] = React.useState([]); @@ -95,6 +104,19 @@ const ShipmentForm: React.FC = ({ sx = {}, onCancel, refreshS getProposals(); }, []); + const handleCountryInputChange = (event: React.ChangeEvent) => { + const value = event.target.value; + + setNewReturnAddress({ ...newReturnAddress, country: value }); + + if (value) { + const suggestions = fuse.search(value).map((result) => result.item); + setCountrySuggestions(suggestions); + } else { + setCountrySuggestions([]); + } + }; + const validateEmail = (email: string) => /\S+@\S+\.\S+/.test(email); const validatePhoneNumber = (phone: string) => /^\+?[1-9]\d{1,14}$/.test(phone); const validateZipCode = (zipcode: string) => { @@ -410,10 +432,37 @@ const ShipmentForm: React.FC = ({ sx = {}, onCancel, refreshS label="Country" name="country" value={newReturnAddress.country} - onChange={(e) => setNewReturnAddress({ ...newReturnAddress, country: e.target.value })} + onChange={handleCountryInputChange} // Ensure this matches the function name exactly fullWidth required + error={!newReturnAddress.country} // Optional: Add an error indicator if the input is empty + helperText={!newReturnAddress.country ? 'Country is required' : ''} /> + + {/* Render country suggestions below the input field */} + {countrySuggestions.length > 0 && ( + + {countrySuggestions.map((suggestion, index) => ( + { + // Update country field with selected suggestion + setNewReturnAddress({ ...newReturnAddress, country: suggestion }); + setCountrySuggestions([]); // Clear suggestions + }} + > + {suggestion} + + ))} + + )}