diff --git a/eslint.config.js b/eslint.config.js index 4fa125d..cefc303 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -7,7 +7,7 @@ import { defineConfig, globalIgnores } from 'eslint/config' export default defineConfig([ globalIgnores(['dist']), { - files: ['**/*.{js,jsx}'], + files: ['src/**/*.{js,jsx}'], extends: [ js.configs.recommended, reactHooks.configs.flat.recommended, @@ -26,4 +26,21 @@ export default defineConfig([ 'no-unused-vars': ['error', { varsIgnorePattern: '^[A-Z_]' }], }, }, + { + files: ['server.js', 'migrate.js'], + extends: [ + js.configs.recommended, + ], + languageOptions: { + ecmaVersion: 2020, + globals: globals.node, + parserOptions: { + ecmaVersion: 'latest', + sourceType: 'module', + }, + }, + rules: { + 'no-unused-vars': ['error', { varsIgnorePattern: '^[A-Z_]' }], + }, + } ]) diff --git a/public/items.xlsx b/public/items.xlsx index 66e6a46..08be525 100644 Binary files a/public/items.xlsx and b/public/items.xlsx differ diff --git a/public/itemsold.xlsx b/public/itemsold.xlsx new file mode 100644 index 0000000..66e6a46 Binary files /dev/null and b/public/itemsold.xlsx differ diff --git a/quotes.json b/quotes.json index 34635ca..6751347 100644 --- a/quotes.json +++ b/quotes.json @@ -641,5 +641,54 @@ } ], "shippingCost": 0 + }, + { + "id": 5690, + "date": "June 3, 2026", + "customer": { + "name": "PERFECT POST", + "contactName": "", + "address": "", + "city": "", + "province": "", + "postalCode": "", + "phone": "", + "email": "" + }, + "items": [ + { + "Item ID": "MDL-5HPR7", + "Description": "Earth Drill, 5.5HP Honda EnginRoll Cage and Flat Free Tires", + "Weight": 161, + "Price": 5342.1757875, + "quantity": 1, + "discount": 0 + }, + { + "Item ID": "10X42-SSC", + "Description": "Auger, Snap-on, Carbide Point", + "Weight": 28, + "Price": 855.1449449999998, + "quantity": 1, + "discount": 0 + }, + { + "Item ID": "4064", + "Description": "Rivet, 3/16\" Aluminum Pop Rivet1/4\" Grip", + "Weight": 0.01, + "Price": 0.9523655999999998, + "quantity": 1, + "discount": 0 + }, + { + "Item ID": "16X42-SSPF", + "Description": "Auger, Snap-On, Full Flighted,Pengo Style", + "Weight": 60, + "Price": 1410.691545, + "quantity": 1, + "discount": 0 + } + ], + "shippingCost": 0 } ] \ No newline at end of file diff --git a/src/App.jsx b/src/App.jsx index 388f708..c02a3ce 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -10,8 +10,8 @@ import './index.css'; function App() { const [catalogItems, setCatalogItems] = useState([]); const [quoteItems, setQuoteItems] = useState([]); - const [quoteId, setQuoteId] = useState(''); - const [quoteDate, setQuoteDate] = useState(''); + const [quoteId, setQuoteId] = useState(() => Math.floor(Math.random() * 10000) + 1000); + const [quoteDate, setQuoteDate] = useState(() => new Date().toLocaleDateString('en-US', { year: 'numeric', month: 'long', day: 'numeric' })); const [savedQuotes, setSavedQuotes] = useState([]); const [shippingCost, setShippingCost] = useState(0); const [isWorkOrderMode, setIsWorkOrderMode] = useState(false); @@ -27,9 +27,25 @@ function App() { email: '' }); + const generateNewQuoteId = () => { + setQuoteId(Math.floor(Math.random() * 10000) + 1000); + setQuoteDate(new Date().toLocaleDateString('en-US', { year: 'numeric', month: 'long', day: 'numeric' })); + }; + // Initialize quote ID and date useEffect(() => { - generateNewQuoteId(); + const loadSavedQuotes = async () => { + try { + const response = await fetch('/api/quotes'); + if (response.ok) { + const data = await response.json(); + setSavedQuotes(data); + } + } catch (error) { + console.error("Error loading quotes:", error); + } + }; + loadSavedQuotes(); const handleAfterPrint = () => { @@ -47,23 +63,6 @@ function App() { fetchCatalog(); }, []); - const generateNewQuoteId = () => { - setQuoteId(Math.floor(Math.random() * 10000) + 1000); - setQuoteDate(new Date().toLocaleDateString('en-US', { year: 'numeric', month: 'long', day: 'numeric' })); - }; - - const loadSavedQuotes = async () => { - try { - const response = await fetch('/api/quotes'); - if (response.ok) { - const data = await response.json(); - setSavedQuotes(data); - } - } catch (error) { - console.error("Error loading quotes:", error); - } - }; - const handleAddItem = (item) => { setQuoteItems([...quoteItems, item]); }; diff --git a/src/components/QuoteSummary.jsx b/src/components/QuoteSummary.jsx index 3d9f619..e1a059d 100644 --- a/src/components/QuoteSummary.jsx +++ b/src/components/QuoteSummary.jsx @@ -39,6 +39,16 @@ export default function QuoteSummary({ items, customer, quoteId, quoteDate, ship const tax = (subtotal + shipping) * taxRate; const total = subtotal + shipping + tax; + const calculateTotalWeight = () => { + return items.reduce((total, item) => { + const qty = parseInt(item.quantity, 10) || 0; + const weight = parseFloat(item.Weight) || 0; + return total + (weight * qty); + }, 0); + }; + + const totalWeight = calculateTotalWeight(); + const formatCurrency = (amount) => { return new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD' }).format(amount); }; @@ -174,35 +184,41 @@ export default function QuoteSummary({ items, customer, quoteId, quoteDate, ship - {!isWorkOrderMode && ( -