diff --git a/client/src/components/ExpensesTable.jsx b/client/src/components/ExpensesTable.jsx index 13716d1..fd48520 100644 --- a/client/src/components/ExpensesTable.jsx +++ b/client/src/components/ExpensesTable.jsx @@ -2,6 +2,7 @@ import React, { useContext, useEffect, useState } from "react"; import { useForm, Controller } from 'react-hook-form'; import { FormControl, FormLabel, Input, Button, Box, Text, Spinner } from "@chakra-ui/react"; import CreatableSelect from 'react-select/creatable'; +import Select from 'react-select'; import { AppContext } from "../context/AppContext.jsx"; import Transaction from "../models/Transaction.js"; import User from "../models/User.js"; @@ -9,7 +10,7 @@ import Updating from "./Updating.jsx"; import ExpenseChartJoyride from "./ExpenseChartJoyride.jsx"; const ExpensesForm = () => { - const { user, formData, setFormData, setUser, ocrData, setOcrData, setServerResponse, isUpdating, setIsUpdating } = useContext(AppContext); + const { user, formData, setFormData, setUser, ocrData, setOcrData, serverResponse, setServerResponse, isUpdating, setIsUpdating } = useContext(AppContext); const [vendors, setVendors] = useState([]); const [categories, setCategories] = useState([]); @@ -28,18 +29,36 @@ const ExpensesForm = () => { return lower.charAt(0).toUpperCase() + lower.slice(1); }; + const createOption = (label) => ({ + label, + value: label.toLowerCase(), + }); + + useEffect(() => { setVendors(user.returnVendorList().map(vendor => ({ value: vendor, label: vendor }))); setCategories(user.categories.map(cat => ({ value: toProperCase(cat.category_name), label: toProperCase(cat.category_name) }))); + }, [user]); - if (formData) { + useEffect(() => { + if(formData){ const listOfValues = formData.returnNonEmptyValues(); + listOfValues.forEach(([key, value]) => { setValue(key, value); + if(key.toLowerCase().includes("category")) { + const valueFromOCR = createOption(value) + setCategories(categories => [...categories, valueFromOCR]) + setValue('category', valueFromOCR); + } else if(key.toLowerCase().includes("vendor")) { + const valueFromOCR = createOption(value) + setVendors(vendors => [...vendors, valueFromOCR]) + setValue('vendor', valueFromOCR); + } }); setFormData(null); } - }, [user, formData, setValue]); + }, [formData, setFormData]); const onSubmit = async (data) => { if (Object.keys(errors).length > 0) { @@ -107,101 +126,119 @@ const ExpensesForm = () => { }; return ( - <> - < ExpenseChartJoyride /> - - {isUpdating && } {/* Show overlay when isUpdating is true */} - - Date - } - /> - - - - Vendor - ( - { - const newValue = selectedOption?.value || ''; - field.onChange(newValue); - if (newValue && !vendors.some(v => v.value === newValue)) { - setVendors([...vendors, { value: newValue, label: newValue }]); - } - }} - value={vendors.find(v => v.value === field.value) || null} - /> - )} - /> - {errors.vendor && {errors.vendor.message}} - - - - Category - ( - { - const newValue = selectedOption?.value || ''; - field.onChange(newValue); - if (newValue && !categories.some(c => c.value === newValue)) { - setCategories([...categories, { value: newValue, label: newValue }]); - } - }} - value={categories.find(c => c.value === field.value) || null} - /> - )} - /> - {errors.category && {errors.category.message}} - - - - Amount - { - const numberChecker = /^-?\d*(\.\d*)?$/; - return numberChecker.test(value) ? true : 'Please enter a valid amount. Enter a number without the "$" sign'; - } - }} - render={({ field, fieldState: { error } }) => ( - <> - - {error && {error.message}} - - )} - /> - - - - - + + < ExpenseChartJoyride /> + + {isUpdating && } {/* Show overlay when isUpdating is true */} + + Date + } + /> + + + + Vendor + ( + { + const newOption = { value: inputValue.toLowerCase(), label: inputValue }; + + // Add the new vendor to the list + setVendors(prevVendors => [...prevVendors, newOption]); + + // Update the form state with the new vendor + field.onChange(newOption); + setValue('vendor', newOption); // Sync the form state + }} + + // Handle selecting an existing vendor + onChange={(selectedOption) => { + field.onChange(selectedOption); // Set the whole option + setValue('vendor', selectedOption); // Sync with react-hook-form + }} + + // Ensure the correct value format is being passed + value={field.value && field.value.value ? field.value : null} + /> + )} + /> + {errors.vendor && {errors.vendor.message}} + + + + + Category + ( + { + const newOption = { value: inputValue, label: inputValue }; + setCategories(prevCategories => [...prevCategories, newOption]); + field.onChange(newOption); + setValue('category', newOption); + }} + onChange={(selectedOption) => { + field.onChange(selectedOption); // Set the whole option + setValue('category', selectedOption); // Sync with react-hook-form + }} + value={field.value && field.value.value ? field.value : null} // Ensure that field.value is properly formatted as an object + /> + )} + /> + {errors.category && {errors.category.message}} + + + + Amount + { + const numberChecker = /^-?\d*(\.\d*)?$/; + return numberChecker.test(value) ? true : 'Please enter a valid amount. Enter a number without the "$" sign'; + } + }} + render={({ field, fieldState: { error } }) => ( + <> + + {error && {error.message}} + + )} + /> + + + + ); }; diff --git a/client/src/models/FormData.js b/client/src/models/FormData.js index 012ca7b..ec11761 100644 --- a/client/src/models/FormData.js +++ b/client/src/models/FormData.js @@ -18,8 +18,14 @@ class FormData { } returnNonEmptyValues() { - return Object.entries(this).filter((entry, index) => entry[index] !== null && entry[index] !== undefined) + // return Object.entries(this).filter((entry, index) => { + // if(entry[index] !== null && entry[index] !== undefined && entry[index] !== ""){ + // console.log(entry[index]) + // } + // }) + return Object.entries(this).filter((entry, index) => entry[index - 1] !== null && entry[index - 1] !== undefined && entry[index - 1] !== "") } + } export default FormData \ No newline at end of file