From 6d6f59c99a867f9d27ebc620517fd05adbd82e6a Mon Sep 17 00:00:00 2001 From: AmandeepMandal1077 <2023kucp1077@iiitkota.ac.in> Date: Sat, 11 Oct 2025 01:20:54 +0530 Subject: [PATCH 1/5] added editing for ocr extracted receipt --- backend/controllers/receiptController.js | 66 ++++++++--- backend/routes/receiptRoutes.js | 3 +- frontend/src/pages/ReceiptsPage.jsx | 141 +++++++++++++++++++++-- 3 files changed, 188 insertions(+), 22 deletions(-) diff --git a/backend/controllers/receiptController.js b/backend/controllers/receiptController.js index 4ad7c54..21c4fb7 100644 --- a/backend/controllers/receiptController.js +++ b/backend/controllers/receiptController.js @@ -59,19 +59,6 @@ const uploadReceipt = async (req, res) => { const savedReceipt = await newReceipt.save(); - // Automatically create a corresponding expense transaction - if (savedReceipt) { - const newTransaction = new IncomeExpense({ - user: req.user.id, - name: savedReceipt.extractedData.merchant, - category: savedReceipt.extractedData.category, - cost: savedReceipt.extractedData.amount, - addedOn: savedReceipt.extractedData.date, - isIncome: false, - }); - await newTransaction.save(); - } - res.status(201).json(savedReceipt); } catch (error) { @@ -83,6 +70,59 @@ const uploadReceipt = async (req, res) => { } }; +// @desc Save transaction after user confirmation and edits +// @route POST /api/receipts/save-transaction +// @access Private +const saveTransactionFromReceipt = async (req, res) => { + try { + const { receiptId, transactionData } = req.body; + + // Validate required fields + if (!receiptId || !transactionData) { + return res.status(400).json({ message: 'Receipt ID and transaction data are required' }); + } + + // Verify the receipt belongs to the user + const receipt = await Receipt.findOne({ _id: receiptId, user: req.user.id }); + if (!receipt) { + return res.status(404).json({ message: 'Receipt not found' }); + } + + // Create the transaction with user-confirmed data + const newTransaction = new IncomeExpense({ + user: req.user.id, + name: transactionData.name, + category: transactionData.category, + cost: transactionData.cost, + addedOn: new Date(transactionData.addedOn), + isIncome: transactionData.isIncome || false, + }); + + const savedTransaction = await newTransaction.save(); + + // update the receipt with the final confirmed data + receipt.extractedData = { + merchant: transactionData.name, + amount: transactionData.cost, + category: transactionData.category, + date: new Date(transactionData.addedOn), + isIncome: transactionData.isIncome || false, + }; + await receipt.save(); + + res.status(201).json({ + message: 'Transaction saved successfully', + transaction: savedTransaction, + receipt: receipt + }); + + } catch (error) { + console.error('Error saving transaction:', error); + res.status(500).json({ message: 'Failed to save transaction', error: error.message }); + } +}; + module.exports = { uploadReceipt, + saveTransactionFromReceipt, }; \ No newline at end of file diff --git a/backend/routes/receiptRoutes.js b/backend/routes/receiptRoutes.js index 8e192d3..c9849b3 100644 --- a/backend/routes/receiptRoutes.js +++ b/backend/routes/receiptRoutes.js @@ -1,9 +1,10 @@ const express = require('express'); const router = express.Router(); -const { uploadReceipt } = require('../controllers/receiptController'); +const { uploadReceipt, saveTransactionFromReceipt } = require('../controllers/receiptController'); const { protect } = require('../middleware/authMiddleware'); const upload = require('../middleware/uploadMiddleware'); router.post('/upload', protect, upload, uploadReceipt); +router.post('/save-transaction', protect, saveTransactionFromReceipt); module.exports = router; \ No newline at end of file diff --git a/frontend/src/pages/ReceiptsPage.jsx b/frontend/src/pages/ReceiptsPage.jsx index 5b7e8b2..3d2ed5d 100644 --- a/frontend/src/pages/ReceiptsPage.jsx +++ b/frontend/src/pages/ReceiptsPage.jsx @@ -1,6 +1,7 @@ -import React, { useState } from 'react'; +import React, { useState, useEffect } from 'react'; import { useNavigate } from 'react-router-dom'; import api from '../api/axios'; +import TransactionModal from '../components/TransactionModal'; const ReceiptsPage = () => { const [file, setFile] = useState(null); @@ -9,6 +10,25 @@ const ReceiptsPage = () => { const [error, setError] = useState(''); const navigate = useNavigate(); + const [openEditReceiptResult, setOpenEditReceiptResult] = useState(false); + const [categories, setCategories] = useState([]); + const [isEditingResult, setIsEditingResult] = useState(false); + const [isSaving, setIsSaving] = useState(false); + + // Fetch categories when component mounts + useEffect(() => { + const fetchCategories = async () => { + try { + const response = await api.get('/transactions/categories'); + setCategories(response.data); + } catch (error) { + console.error('Failed to fetch categories:', error); + } + }; + + fetchCategories(); + }, []); + const handleFileChange = (e) => { setFile(e.target.files[0]); setReceiptResult(null); @@ -34,8 +54,9 @@ const ReceiptsPage = () => { }, }); setReceiptResult(response.data); - alert('Receipt processed successfully and transaction created! Redirecting to dashboard...'); - navigate('/dashboard'); + + // Open the modal to allow user to edit the extracted data + setOpenEditReceiptResult(true); } catch (err) { setError('Upload failed. Please try again.'); console.error(err); @@ -44,6 +65,66 @@ const ReceiptsPage = () => { } }; + const handleEditReceiptSubmit = async (formData, transactionId) => { + try { + // Update the receiptResult with the edited data + const updatedReceiptResult = { + ...receiptResult, + extractedData: { + merchant: formData.name, + amount: parseFloat(formData.cost), + category: formData.category, + date: formData.addedOn, + isIncome: formData.isIncome + } + }; + + setReceiptResult(updatedReceiptResult); + setOpenEditReceiptResult(false); + } catch (err) { + setError('Failed to update receipt data. Please try again.'); + console.error(err); + } + }; + + // Handle final save to database (second verification step) + const handleFinalSave = async () => { + try { + setIsSaving(true); + + const transactionData = { + name: receiptResult.extractedData.merchant, + category: receiptResult.extractedData.category, + cost: receiptResult.extractedData.amount, + addedOn: receiptResult.extractedData.date, + isIncome: receiptResult.extractedData.isIncome || false + }; + + const response = await api.post('/receipts/save-transaction', { + receiptId: receiptResult._id, + transactionData: transactionData + }); + + alert('Transaction saved successfully! Redirecting to dashboard...'); + navigate('/dashboard'); + } catch (err) { + setError('Failed to save transaction. Please try again.'); + console.error(err); + } finally { + setIsSaving(false); + } + }; + + // Handle edit button in result div + const handleEditResult = () => { + setIsEditingResult(true); + setOpenEditReceiptResult(true); + }; + + const handleNewCategory = (newCategory) => { + setCategories(prev => [...prev, newCategory].sort()); + }; + return ( <>

Upload Receipt

@@ -63,7 +144,7 @@ const ReceiptsPage = () => { disabled={uploading} className="mt-4 w-full px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 disabled:bg-blue-300" > - {uploading ? 'Processing...' : 'Upload & Create Transaction'} + {uploading ? 'Processing...' : 'Upload & Extract Data'} {error &&

{error}

} @@ -73,10 +154,33 @@ const ReceiptsPage = () => {

Last Upload Result

{receiptResult ? (
-

Merchant: {receiptResult.extractedData.merchant}

-

Amount: {receiptResult.extractedData.amount.toFixed(2)}

-

Category: {receiptResult.extractedData.category}

-

Date: {new Date(receiptResult.extractedData.date).toLocaleDateString()}

+
+

Merchant: {receiptResult.extractedData.merchant}

+

Amount: {receiptResult.extractedData.amount.toFixed(2)}

+

Category: {receiptResult.extractedData.category}

+

Date: {new Date(receiptResult.extractedData.date).toLocaleDateString()}

+ {receiptResult.extractedData.isIncome && ( +

Income: Yes

+ )} +
+ +
+ + +
+ Uploaded Receipt
) : ( @@ -85,6 +189,27 @@ const ReceiptsPage = () => { + + {/* Transaction Modal for editing receipt data */} + {openEditReceiptResult && receiptResult && ( + { + setOpenEditReceiptResult(false); + setIsEditingResult(false); + }} + onSubmit={handleEditReceiptSubmit} + transaction={{ + name: receiptResult.extractedData.merchant || '', + category: receiptResult.extractedData.category || '', + cost: receiptResult.extractedData.amount || 0, + addedOn: receiptResult.extractedData.date || new Date().toISOString().split('T')[0], + isIncome: receiptResult.extractedData.isIncome || false + }} + categories={categories} + onNewCategory={handleNewCategory} + /> + )} ); }; From 3c2693bcd55d800166699449afbcdb16c88ad6fd Mon Sep 17 00:00:00 2001 From: AmandeepMandal1077 <2023kucp1077@iiitkota.ac.in> Date: Sat, 11 Oct 2025 01:33:09 +0530 Subject: [PATCH 2/5] removed unused parameter --- backend/controllers/receiptController.js | 2 +- frontend/src/pages/ReceiptsPage.jsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/backend/controllers/receiptController.js b/backend/controllers/receiptController.js index 21c4fb7..7ccbedd 100644 --- a/backend/controllers/receiptController.js +++ b/backend/controllers/receiptController.js @@ -100,7 +100,7 @@ const saveTransactionFromReceipt = async (req, res) => { const savedTransaction = await newTransaction.save(); - // update the receipt with the final confirmed data + // Update the receipt with the final confirmed data receipt.extractedData = { merchant: transactionData.name, amount: transactionData.cost, diff --git a/frontend/src/pages/ReceiptsPage.jsx b/frontend/src/pages/ReceiptsPage.jsx index 3d2ed5d..f498479 100644 --- a/frontend/src/pages/ReceiptsPage.jsx +++ b/frontend/src/pages/ReceiptsPage.jsx @@ -65,7 +65,7 @@ const ReceiptsPage = () => { } }; - const handleEditReceiptSubmit = async (formData, transactionId) => { + const handleEditReceiptSubmit = async (formData) => { try { // Update the receiptResult with the edited data const updatedReceiptResult = { From d56bee115476a888a053344101a1000067398b16 Mon Sep 17 00:00:00 2001 From: AmandeepMandal1077 <2023kucp1077@iiitkota.ac.in> Date: Wed, 22 Oct 2025 22:02:53 +0530 Subject: [PATCH 3/5] fix: resolved issues --- backend/controllers/receiptController.js | 10 +++++-- frontend/src/pages/ReceiptsPage.jsx | 37 ++++++++++-------------- 2 files changed, 24 insertions(+), 23 deletions(-) diff --git a/backend/controllers/receiptController.js b/backend/controllers/receiptController.js index 71f6139..42c63ae 100644 --- a/backend/controllers/receiptController.js +++ b/backend/controllers/receiptController.js @@ -108,13 +108,19 @@ const saveTransactionFromReceipt = async (req, res) => { return res.status(404).json({ message: 'Receipt not found' }); } + // Validate and parse the date + const transactionDate = new Date(transactionData.addedOn); + if (isNaN(transactionDate.getTime())) { + return res.status(400).json({ message: 'Invalid date format provided' }); + } + // Create the transaction with user-confirmed data const newTransaction = new IncomeExpense({ user: req.user.id, name: transactionData.name, category: transactionData.category, cost: transactionData.cost, - addedOn: new Date(transactionData.addedOn), + addedOn: transactionDate, isIncome: transactionData.isIncome || false, }); @@ -125,7 +131,7 @@ const saveTransactionFromReceipt = async (req, res) => { merchant: transactionData.name, amount: transactionData.cost, category: transactionData.category, - date: new Date(transactionData.addedOn), + date: transactionDate, isIncome: transactionData.isIncome || false, }; await receipt.save(); diff --git a/frontend/src/pages/ReceiptsPage.jsx b/frontend/src/pages/ReceiptsPage.jsx index f498479..c969a19 100644 --- a/frontend/src/pages/ReceiptsPage.jsx +++ b/frontend/src/pages/ReceiptsPage.jsx @@ -65,26 +65,21 @@ const ReceiptsPage = () => { } }; - const handleEditReceiptSubmit = async (formData) => { - try { - // Update the receiptResult with the edited data - const updatedReceiptResult = { - ...receiptResult, - extractedData: { - merchant: formData.name, - amount: parseFloat(formData.cost), - category: formData.category, - date: formData.addedOn, - isIncome: formData.isIncome - } - }; - - setReceiptResult(updatedReceiptResult); - setOpenEditReceiptResult(false); - } catch (err) { - setError('Failed to update receipt data. Please try again.'); - console.error(err); - } + const handleEditReceiptSubmit = (formData) => { + // Update the receiptResult with the edited data + const updatedReceiptResult = { + ...receiptResult, + extractedData: { + merchant: formData.name, + amount: parseFloat(formData.cost) || 0, + category: formData.category, + date: formData.addedOn, + isIncome: formData.isIncome + } + }; + + setReceiptResult(updatedReceiptResult); + setOpenEditReceiptResult(false); }; // Handle final save to database (second verification step) @@ -156,7 +151,7 @@ const ReceiptsPage = () => {

Merchant: {receiptResult.extractedData.merchant}

-

Amount: {receiptResult.extractedData.amount.toFixed(2)}

+

Amount: {(parseFloat(receiptResult.extractedData.amount) || 0).toFixed(2)}

Category: {receiptResult.extractedData.category}

Date: {new Date(receiptResult.extractedData.date).toLocaleDateString()}

{receiptResult.extractedData.isIncome && ( From 797fd4b405ae59a247909900ea442ae7b50eee54 Mon Sep 17 00:00:00 2001 From: AmandeepMandal1077 <2023kucp1077@iiitkota.ac.in> Date: Fri, 31 Oct 2025 18:14:54 +0530 Subject: [PATCH 4/5] Merge master changes --- frontend/src/pages/ReceiptsPage.jsx | 486 ++++++++++++++++------------ 1 file changed, 278 insertions(+), 208 deletions(-) diff --git a/frontend/src/pages/ReceiptsPage.jsx b/frontend/src/pages/ReceiptsPage.jsx index c969a19..9d73d57 100644 --- a/frontend/src/pages/ReceiptsPage.jsx +++ b/frontend/src/pages/ReceiptsPage.jsx @@ -1,212 +1,282 @@ -import React, { useState, useEffect } from 'react'; -import { useNavigate } from 'react-router-dom'; -import api from '../api/axios'; -import TransactionModal from '../components/TransactionModal'; +import React, { useState, useEffect } from "react"; +import { useNavigate } from "react-router-dom"; +import api from "../api/axios"; +import TransactionModal from "../components/TransactionModal"; +import { toast, Bounce } from "react-toastify"; const ReceiptsPage = () => { - const [file, setFile] = useState(null); - const [uploading, setUploading] = useState(false); - const [receiptResult, setReceiptResult] = useState(null); - const [error, setError] = useState(''); - const navigate = useNavigate(); - - const [openEditReceiptResult, setOpenEditReceiptResult] = useState(false); - const [categories, setCategories] = useState([]); - const [isEditingResult, setIsEditingResult] = useState(false); - const [isSaving, setIsSaving] = useState(false); - - // Fetch categories when component mounts - useEffect(() => { - const fetchCategories = async () => { - try { - const response = await api.get('/transactions/categories'); - setCategories(response.data); - } catch (error) { - console.error('Failed to fetch categories:', error); - } - }; - - fetchCategories(); - }, []); - - const handleFileChange = (e) => { - setFile(e.target.files[0]); - setReceiptResult(null); - setError(''); - }; - - const handleSubmit = async (e) => { - e.preventDefault(); - if (!file) { - setError('Please select a file to upload.'); - return; - } - - const formData = new FormData(); - formData.append('receipt', file); - - try { - setUploading(true); - setError(''); - const response = await api.post('/receipts/upload', formData, { - headers: { - 'Content-Type': 'multipart/form-data', - }, - }); - setReceiptResult(response.data); - - // Open the modal to allow user to edit the extracted data - setOpenEditReceiptResult(true); - } catch (err) { - setError('Upload failed. Please try again.'); - console.error(err); - } finally { - setUploading(false); - } - }; - - const handleEditReceiptSubmit = (formData) => { - // Update the receiptResult with the edited data - const updatedReceiptResult = { - ...receiptResult, - extractedData: { - merchant: formData.name, - amount: parseFloat(formData.cost) || 0, - category: formData.category, - date: formData.addedOn, - isIncome: formData.isIncome - } - }; - - setReceiptResult(updatedReceiptResult); - setOpenEditReceiptResult(false); - }; - - // Handle final save to database (second verification step) - const handleFinalSave = async () => { - try { - setIsSaving(true); - - const transactionData = { - name: receiptResult.extractedData.merchant, - category: receiptResult.extractedData.category, - cost: receiptResult.extractedData.amount, - addedOn: receiptResult.extractedData.date, - isIncome: receiptResult.extractedData.isIncome || false - }; - - const response = await api.post('/receipts/save-transaction', { - receiptId: receiptResult._id, - transactionData: transactionData - }); - - alert('Transaction saved successfully! Redirecting to dashboard...'); - navigate('/dashboard'); - } catch (err) { - setError('Failed to save transaction. Please try again.'); - console.error(err); - } finally { - setIsSaving(false); - } - }; - - // Handle edit button in result div - const handleEditResult = () => { - setIsEditingResult(true); - setOpenEditReceiptResult(true); - }; - - const handleNewCategory = (newCategory) => { - setCategories(prev => [...prev, newCategory].sort()); - }; - - return ( - <> -

Upload Receipt

-
- -
-
- - - - {error &&

{error}

} -
-
- -
-

Last Upload Result

- {receiptResult ? ( -
-
-

Merchant: {receiptResult.extractedData.merchant}

-

Amount: {(parseFloat(receiptResult.extractedData.amount) || 0).toFixed(2)}

-

Category: {receiptResult.extractedData.category}

-

Date: {new Date(receiptResult.extractedData.date).toLocaleDateString()}

- {receiptResult.extractedData.isIncome && ( -

Income: Yes

- )} -
- -
- - -
- - Uploaded Receipt -
- ) : ( -

Upload a receipt to see the extracted data here.

- )} -
- -
- - {/* Transaction Modal for editing receipt data */} - {openEditReceiptResult && receiptResult && ( - { - setOpenEditReceiptResult(false); - setIsEditingResult(false); - }} - onSubmit={handleEditReceiptSubmit} - transaction={{ - name: receiptResult.extractedData.merchant || '', - category: receiptResult.extractedData.category || '', - cost: receiptResult.extractedData.amount || 0, - addedOn: receiptResult.extractedData.date || new Date().toISOString().split('T')[0], - isIncome: receiptResult.extractedData.isIncome || false - }} - categories={categories} - onNewCategory={handleNewCategory} - /> - )} - - ); + const [isMobile, setIsMobile] = useState(window.innerWidth <= 767); + const [file, setFile] = useState(null); + const [uploading, setUploading] = useState(false); + const [receiptResult, setReceiptResult] = useState(null); + const [error, setError] = useState(""); + const navigate = useNavigate(); + + const [openEditReceiptResult, setOpenEditReceiptResult] = useState(false); + const [categories, setCategories] = useState([]); + const [isEditingResult, setIsEditingResult] = useState(false); + const [isSaving, setIsSaving] = useState(false); + + // Fetch categories when component mounts + useEffect(() => { + const fetchCategories = async () => { + try { + const response = await api.get("/transactions/categories"); + setCategories(response.data); + } catch (error) { + console.error("Failed to fetch categories:", error); + } + }; + + fetchCategories(); + }, []); + + // Handle mobile responsive resize + useEffect(() => { + const handleResize = () => { + return setIsMobile(window.innerWidth <= 767); + }; + window.addEventListener("resize", handleResize); + return () => window.removeEventListener("resize", handleResize); + }, []); + + const handleFileChange = (e) => { + setFile(e.target.files[0]); + setReceiptResult(null); + setError(""); + }; + + const handleSubmit = async (e) => { + e.preventDefault(); + if (!file) { + setError("Please select a file to upload."); + return; + } + + const formData = new FormData(); + formData.append("receipt", file); + + try { + setUploading(true); + setError(""); + const response = await api.post("/receipts/upload", formData, { + headers: { + "Content-Type": "multipart/form-data", + }, + }); + setReceiptResult(response.data); + + // Open the modal to allow user to edit the extracted data + setOpenEditReceiptResult(true); + } catch (err) { + setError("Upload failed. Please try again."); + console.error(err); + } finally { + setUploading(false); + } + }; + + const handleEditReceiptSubmit = (formData) => { + // Update the receiptResult with the edited data + const updatedReceiptResult = { + ...receiptResult, + extractedData: { + merchant: formData.name, + amount: parseFloat(formData.cost) || 0, + category: formData.category, + date: formData.addedOn, + isIncome: formData.isIncome, + }, + }; + + setReceiptResult(updatedReceiptResult); + setOpenEditReceiptResult(false); + }; + + // Handle final save to database (second verification step) + const handleFinalSave = async () => { + try { + setIsSaving(true); + + const transactionData = { + name: receiptResult.extractedData.merchant, + category: receiptResult.extractedData.category, + cost: receiptResult.extractedData.amount, + addedOn: receiptResult.extractedData.date, + isIncome: receiptResult.extractedData.isIncome || false, + }; + + const response = await api.post("/receipts/save-transaction", { + receiptId: receiptResult._id, + transactionData: transactionData, + }); + + toast.success("Transaction saved successfully!", { + position: "top-right", + autoClose: 3000, + hideProgressBar: false, + closeOnClick: false, + pauseOnHover: true, + draggable: true, + progress: undefined, + style: { + fontSize: "18px", + padding: "16px 24px", + minWidth: "500px", + }, + theme: "light", + transition: Bounce, + }); + + setTimeout(() => navigate("/dashboard"), 1000); + } catch (err) { + setError("Failed to save transaction. Please try again."); + console.error(err); + } finally { + setIsSaving(false); + } + }; + + // Handle edit button in result div + const handleEditResult = () => { + setIsEditingResult(true); + setOpenEditReceiptResult(true); + }; + + const handleNewCategory = (newCategory) => { + setCategories((prev) => [...prev, newCategory].sort()); + }; + + return ( + <> +

+ Upload Receipt +

+
+
+
+ + + + {error && ( +

{error}

+ )} +
+
+ +
+

+ Last Upload Result +

+ {receiptResult ? ( +
+
+

+ Merchant:{" "} + {receiptResult.extractedData.merchant} +

+

+ Amount:{" "} + {( + parseFloat( + receiptResult.extractedData.amount + ) || 0 + ).toFixed(2)} +

+

+ Category:{" "} + {receiptResult.extractedData.category} +

+

+ Date:{" "} + {new Date( + receiptResult.extractedData.date + ).toLocaleDateString()} +

+ {receiptResult.extractedData.isIncome && ( +

+ Income: Yes +

+ )} +
+ +
+ + +
+ + Uploaded Receipt +
+ ) : ( +

+ Upload a receipt to see the extracted data here. +

+ )} +
+
+ + {isMobile && ( + + )} + + {/* Transaction Modal for editing receipt data */} + {openEditReceiptResult && receiptResult && ( + { + setOpenEditReceiptResult(false); + setIsEditingResult(false); + }} + onSubmit={handleEditReceiptSubmit} + transaction={{ + name: receiptResult.extractedData.merchant || "", + category: receiptResult.extractedData.category || "", + cost: receiptResult.extractedData.amount || 0, + addedOn: + receiptResult.extractedData.date || + new Date().toISOString().split("T")[0], + isIncome: receiptResult.extractedData.isIncome || false, + }} + categories={categories} + onNewCategory={handleNewCategory} + /> + )} + + ); }; -export default ReceiptsPage; \ No newline at end of file +export default ReceiptsPage; From e8a018fe77216f7c27e01604d6cee7d07cf72407 Mon Sep 17 00:00:00 2001 From: AmandeepMandal1077 <2023kucp1077@iiitkota.ac.in> Date: Fri, 31 Oct 2025 18:29:47 +0530 Subject: [PATCH 5/5] fix: issues --- frontend/src/pages/ReceiptsPage.jsx | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/frontend/src/pages/ReceiptsPage.jsx b/frontend/src/pages/ReceiptsPage.jsx index 9d73d57..7082bf9 100644 --- a/frontend/src/pages/ReceiptsPage.jsx +++ b/frontend/src/pages/ReceiptsPage.jsx @@ -14,7 +14,6 @@ const ReceiptsPage = () => { const [openEditReceiptResult, setOpenEditReceiptResult] = useState(false); const [categories, setCategories] = useState([]); - const [isEditingResult, setIsEditingResult] = useState(false); const [isSaving, setIsSaving] = useState(false); // Fetch categories when component mounts @@ -34,7 +33,7 @@ const ReceiptsPage = () => { // Handle mobile responsive resize useEffect(() => { const handleResize = () => { - return setIsMobile(window.innerWidth <= 767); + setIsMobile(window.innerWidth <= 767); }; window.addEventListener("resize", handleResize); return () => window.removeEventListener("resize", handleResize); @@ -106,7 +105,7 @@ const ReceiptsPage = () => { isIncome: receiptResult.extractedData.isIncome || false, }; - const response = await api.post("/receipts/save-transaction", { + await api.post("/receipts/save-transaction", { receiptId: receiptResult._id, transactionData: transactionData, }); @@ -139,12 +138,15 @@ const ReceiptsPage = () => { // Handle edit button in result div const handleEditResult = () => { - setIsEditingResult(true); setOpenEditReceiptResult(true); }; - const handleNewCategory = (newCategory) => { - setCategories((prev) => [...prev, newCategory].sort()); + const handleNewCategory = (newCategory, isIncome) => { + setCategories((prev) => + [...prev, { name: newCategory, isIncome }].sort((a, b) => + a.name.localeCompare(b.name) + ) + ); }; return ( @@ -232,7 +234,10 @@ const ReceiptsPage = () => {
Uploaded Receipt @@ -259,7 +264,6 @@ const ReceiptsPage = () => { isOpen={openEditReceiptResult} onClose={() => { setOpenEditReceiptResult(false); - setIsEditingResult(false); }} onSubmit={handleEditReceiptSubmit} transaction={{ @@ -271,7 +275,12 @@ const ReceiptsPage = () => { new Date().toISOString().split("T")[0], isIncome: receiptResult.extractedData.isIncome || false, }} - categories={categories} + expenseCategories={categories + .filter((cat) => !cat.isIncome) + .map((cat) => cat.name || cat)} + incomeCategories={categories + .filter((cat) => cat.isIncome) + .map((cat) => cat.name || cat)} onNewCategory={handleNewCategory} /> )}