-
Notifications
You must be signed in to change notification settings - Fork 80
added editing for ocr extracted receipt #117
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from 3 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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; |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -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) => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 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 = 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), | |
| category: formData.category, | |
| date: formData.addedOn, | |
| isIncome: formData.isIncome | |
| } | |
| }; | |
| setReceiptResult(updatedReceiptResult); | |
| setOpenEditReceiptResult(false); |
Outdated
Copilot
AI
Oct 22, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Potential runtime error if receiptResult.extractedData.amount is null or undefined. Since the amount comes from user-edited data and parseFloat can return NaN, consider adding a fallback: {(receiptResult.extractedData.amount || 0).toFixed(2)}
| <p className="text-gray-700 dark:text-gray-300"><strong>Amount:</strong> {receiptResult.extractedData.amount.toFixed(2)}</p> | |
| <p className="text-gray-700 dark:text-gray-300"><strong>Amount:</strong> {(parseFloat(receiptResult.extractedData.amount) || 0).toFixed(2)}</p> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If
transactionData.addedOnis an invalid date string,new Date()will create an Invalid Date object, which could cause issues downstream. Add validation to ensure the date is valid before creating the transaction.