From b223750c4c67818c6ae992614468b8af80b1bbf8 Mon Sep 17 00:00:00 2001 From: G12001 Date: Mon, 5 Jun 2023 13:26:27 +0530 Subject: [PATCH] Commit Changes --- client/src/components/Invoice/Invoice.js | 1071 +++++++++-------- .../src/components/Settings/Form/Profile.js | 94 +- 2 files changed, 649 insertions(+), 516 deletions(-) diff --git a/client/src/components/Invoice/Invoice.js b/client/src/components/Invoice/Invoice.js index d89a05b7..a111018b 100644 --- a/client/src/components/Invoice/Invoice.js +++ b/client/src/components/Invoice/Invoice.js @@ -1,505 +1,630 @@ -import React, { useState, useEffect} from 'react' -import styles from './Invoice.module.css' -import { useDispatch, useSelector } from 'react-redux' -import { useParams } from 'react-router-dom' -import moment from 'moment' -import { useHistory } from 'react-router-dom' -import { toCommas } from '../../utils/utils' - -import IconButton from '@material-ui/core/IconButton'; -import DeleteOutlineRoundedIcon from '@material-ui/icons/DeleteOutlineRounded'; -import DateFnsUtils from '@date-io/date-fns'; -import { MuiPickersUtilsProvider, KeyboardDatePicker } from '@material-ui/pickers'; -import TextField from '@material-ui/core/TextField'; -import Autocomplete from '@material-ui/lab/Autocomplete'; -import { makeStyles } from '@material-ui/core/styles'; -import Table from '@material-ui/core/Table'; -import TableBody from '@material-ui/core/TableBody'; -import TableCell from '@material-ui/core/TableCell'; -import TableContainer from '@material-ui/core/TableContainer'; -import TableHead from '@material-ui/core/TableHead'; -import TableRow from '@material-ui/core/TableRow'; -import Paper from '@material-ui/core/Paper'; -import Typography from '@material-ui/core/Typography'; -import InputBase from '@material-ui/core/InputBase'; -import { Container, Grid } from '@material-ui/core'; -import Avatar from '@material-ui/core/Avatar'; -import Divider from '@material-ui/core/Divider'; -import SaveIcon from '@material-ui/icons/Save'; -import Button from '@material-ui/core/Button'; -import Chip from '@material-ui/core/Chip'; -import {initialState} from '../../initialState' -import currencies from '../../currencies.json' -import { createInvoice, getInvoice, updateInvoice } from '../../actions/invoiceActions'; -import { getClientsByUser } from '../../actions/clientActions' -import AddClient from './AddClient'; -import InvoiceType from './InvoiceType'; -import axios from 'axios' -import { useLocation } from 'react-router-dom' +import React, { useState, useEffect } from "react"; +import styles from "./Invoice.module.css"; +import { useDispatch, useSelector } from "react-redux"; +import { useParams } from "react-router-dom"; +import moment from "moment"; +import { useHistory } from "react-router-dom"; +import { toCommas } from "../../utils/utils"; + +import IconButton from "@material-ui/core/IconButton"; +import DeleteOutlineRoundedIcon from "@material-ui/icons/DeleteOutlineRounded"; +import DateFnsUtils from "@date-io/date-fns"; +import { + MuiPickersUtilsProvider, + KeyboardDatePicker, +} from "@material-ui/pickers"; +import TextField from "@material-ui/core/TextField"; +import Autocomplete from "@material-ui/lab/Autocomplete"; +import { makeStyles } from "@material-ui/core/styles"; +import Table from "@material-ui/core/Table"; +import TableBody from "@material-ui/core/TableBody"; +import TableCell from "@material-ui/core/TableCell"; +import TableContainer from "@material-ui/core/TableContainer"; +import TableHead from "@material-ui/core/TableHead"; +import TableRow from "@material-ui/core/TableRow"; +import Paper from "@material-ui/core/Paper"; +import Typography from "@material-ui/core/Typography"; +import InputBase from "@material-ui/core/InputBase"; +import { Container, Grid } from "@material-ui/core"; +import Avatar from "@material-ui/core/Avatar"; +import Divider from "@material-ui/core/Divider"; +import SaveIcon from "@material-ui/icons/Save"; +import Button from "@material-ui/core/Button"; +import Chip from "@material-ui/core/Chip"; +import { initialState } from "../../initialState"; +import currencies from "../../currencies.json"; +import { + createInvoice, + getInvoice, + updateInvoice, +} from "../../actions/invoiceActions"; +import { getClientsByUser } from "../../actions/clientActions"; +import AddClient from "./AddClient"; +import InvoiceType from "./InvoiceType"; +import axios from "axios"; +import { useLocation } from "react-router-dom"; const useStyles = makeStyles((theme) => ({ - root: { - display: 'flex', - '& > *': { - margin: theme.spacing(1), - }, + root: { + display: "flex", + "& > *": { + margin: theme.spacing(1), }, - large: { - width: theme.spacing(12), - height: theme.spacing(12), - }, - table: { - minWidth: 650, - }, - - headerContainer: { - // display: 'flex' - paddingTop: theme.spacing(1), - paddingLeft: theme.spacing(5), - paddingRight: theme.spacing(1), - } - })); + }, + large: { + width: theme.spacing(12), + height: theme.spacing(12), + }, + table: { + minWidth: 650, + }, + + headerContainer: { + // display: 'flex' + paddingTop: theme.spacing(1), + paddingLeft: theme.spacing(5), + paddingRight: theme.spacing(1), + }, +})); const Invoice = () => { + const location = useLocation(); + const [invoiceData, setInvoiceData] = useState(initialState); + const [rates, setRates] = useState(0); + const [vat, setVat] = useState(0); + const [currency, setCurrency] = useState(currencies[0].value); + const [subTotal, setSubTotal] = useState(0); + const [total, setTotal] = useState(0); + const today = new Date(); + const [selectedDate, setSelectedDate] = useState( + today.getTime() + 7 * 24 * 60 * 60 * 1000 + ); + const [client, setClient] = useState(null); + const [type, setType] = useState("Invoice"); + const [status, setStatus] = useState(""); + const { id } = useParams(); + const clients = useSelector((state) => state.clients.clients); + const { invoice } = useSelector((state) => state.invoices); + const dispatch = useDispatch(); + const history = useHistory(); + const user = JSON.parse(localStorage.getItem("profile")); + + useEffect(() => { + getTotalCount(); + // eslint-disable-next-line + }, [location]); + + const getTotalCount = async () => { + try { + const response = await axios.get( + `${process.env.REACT_APP_API}/invoices/count?searchQuery=${user?.result?._id}` + ); + // console.log(response.data); + //Get total count of invoice from the server and increment by one to serialized numbering of invoice + setInvoiceData({ + ...invoiceData, + invoiceNumber: (Number(response.data) + 1).toString().padStart(3, "0"), + }); + } catch (error) { + console.error(error); + } + }; + + useEffect(() => { + dispatch(getInvoice(id)); + // eslint-disable-next-line + }, [id]); + + useEffect(() => { + dispatch( + getClientsByUser({ search: user?.result._id || user?.result?.googleId }) + ); + // eslint-disable-next-line + }, [dispatch]); + + useEffect(() => { + if (invoice) { + //Automatically set the default invoice values as the ones in the invoice to be updated + setInvoiceData(invoice); + setRates(invoice.rates); + setClient(invoice.client); + setType(invoice.type); + setStatus(invoice.status); + setSelectedDate(invoice.dueDate); + } + }, [invoice]); - const location = useLocation() - const [invoiceData, setInvoiceData] = useState(initialState) - const [ rates, setRates] = useState(0) - const [vat, setVat] = useState(0) - const [currency, setCurrency] = useState(currencies[0].value) - const [subTotal, setSubTotal] = useState(0) - const [total, setTotal] = useState(0) - const today = new Date(); - const [selectedDate, setSelectedDate] = useState(today.getTime() + 7 * 24 * 60 * 60 * 1000); - const [ client, setClient] = useState(null) - const [type, setType] = useState('Invoice') - const [status, setStatus ] = useState('') - const { id } = useParams() - const clients = useSelector((state) => state.clients.clients) - const { invoice } = useSelector((state) => state.invoices); - const dispatch = useDispatch() - const history = useHistory() - const user = JSON.parse(localStorage.getItem('profile')) - - - useEffect(() => { - getTotalCount() - // eslint-disable-next-line - },[location]) - - - const getTotalCount = async() => { - try { - const response = await axios.get(`${process.env.REACT_APP_API}/invoices/count?searchQuery=${user?.result?._id}`); - // console.log(response.data); - //Get total count of invoice from the server and increment by one to serialized numbering of invoice - setInvoiceData({...invoiceData, invoiceNumber: (Number(response.data) + 1).toString().padStart(3, '0')}) - } catch (error) { - console.error(error); + useEffect(() => { + if (type === "Receipt") { + setStatus("Paid"); + } else { + setStatus("Unpaid"); + } + }, [type]); + + const defaultProps = { + options: currencies, + getOptionLabel: (option) => option.label, + }; + + const clientsProps = { + options: clients, + getOptionLabel: (option) => option.name, + }; + + const handleDateChange = (date) => { + setSelectedDate(date); + }; + + const handleRates = (e) => { + setRates(e.target.value); + setInvoiceData((prevState) => ({ ...prevState, tax: e.target.value })); + }; + + // console.log(invoiceData) + // Change handler for dynamically added input field + const handleChange = (index, e) => { + const values = [...invoiceData.items]; + values[index][e.target.name] = e.target.value; + setInvoiceData({ ...invoiceData, items: values }); + }; + + useEffect(() => { + //Get the subtotal + const subTotal = () => { + var arr = document.getElementsByName("amount"); + var subtotal = 0; + for (var i = 0; i < arr.length; i++) { + if (arr[i].value) { + subtotal += +arr[i].value; } + // document.getElementById("subtotal").value = subtotal; + setSubTotal(subtotal); } - - - - - useEffect(() => { - dispatch(getInvoice(id)); - // eslint-disable-next-line - }, [id]); - - useEffect(() => { - dispatch(getClientsByUser({search: user?.result._id || user?.result?.googleId})); - // eslint-disable-next-line - }, [dispatch]); - - - useEffect(() => { - if(invoice) { - //Automatically set the default invoice values as the ones in the invoice to be updated - setInvoiceData(invoice) - setRates(invoice.rates) - setClient(invoice.client) - setType(invoice.type) - setStatus(invoice.status) - setSelectedDate(invoice.dueDate) - } - }, [invoice]) - - - useEffect(() => { - if(type === 'Receipt') { - setStatus('Paid') - } else { - setStatus('Unpaid') - } - },[type]) - - const defaultProps = { - options: currencies, - getOptionLabel: (option) => option.label - }; - - const clientsProps = { - options: clients, - getOptionLabel: (option) => option.name - }; - - - const handleDateChange = (date) => { - setSelectedDate(date); }; - const handleRates =(e) => { - setRates(e.target.value) - setInvoiceData((prevState) => ({...prevState, tax: e.target.value})) - } + subTotal(); + }, [invoiceData]); - // console.log(invoiceData) - // Change handler for dynamically added input field - const handleChange =(index, e) => { - const values = [...invoiceData.items] - values[index][e.target.name] = e.target.value - setInvoiceData({...invoiceData, items: values}) - - } - - useEffect(() => { - //Get the subtotal - const subTotal =()=> { - var arr = document.getElementsByName("amount"); - var subtotal = 0; - for(var i = 0; i < arr.length; i++) { - if(arr[i].value) { - subtotal += +arr[i].value; - } - // document.getElementById("subtotal").value = subtotal; - setSubTotal(subtotal) - } - } - - subTotal() - - }, [invoiceData]) - - - useEffect(() => { - const total =() => { - - //Tax rate is calculated as (input / 100 ) * subtotal + subtotal - const overallSum = rates /100 * subTotal + subTotal - //VAT is calculated as tax rates /100 * subtotal - setVat(rates /100 * subTotal) - setTotal(overallSum) - - - } - total() - }, [invoiceData, rates, subTotal]) - - - const handleAddField = (e) => { - e.preventDefault() - setInvoiceData((prevState) => ({...prevState, items: [...prevState.items, {itemName: '', unitPrice: '', quantity: '', discount: '', amount: '' }]})) - } - - const handleRemoveField =(index) => { - const values = invoiceData.items - values.splice(index, 1) - setInvoiceData((prevState) => ({...prevState, values})) - // console.log(values) - } - - - console.log(invoiceData) - - const handleSubmit = async (e ) => { - e.preventDefault() - if(invoice) { - dispatch(updateInvoice( invoice._id, { - ...invoiceData, - subTotal: subTotal, - total: total, - vat: vat, - rates: rates, - currency: currency, - dueDate: selectedDate, - client, - type: type, - status: status - })) - history.push(`/invoice/${invoice._id}`) - } else { - - dispatch(createInvoice({ - ...invoiceData, - subTotal: subTotal, - total: total, - vat: vat, - rates: rates, - currency: currency, - dueDate: selectedDate, + useEffect(() => { + const total = () => { + //Tax rate is calculated as (input / 100 ) * subtotal + subtotal + const overallSum = (rates / 100) * subTotal + subTotal; + //VAT is calculated as tax rates /100 * subtotal + setVat((rates / 100) * subTotal); + setTotal(overallSum); + }; + total(); + }, [invoiceData, rates, subTotal]); + + const handleAddField = (e) => { + e.preventDefault(); + setInvoiceData((prevState) => ({ + ...prevState, + items: [ + ...prevState.items, + { itemName: "", unitPrice: "", quantity: "", discount: "", amount: "" }, + ], + })); + }; + + const handleRemoveField = (index) => { + const values = invoiceData.items; + values.splice(index, 1); + setInvoiceData((prevState) => ({ ...prevState, values })); + // console.log(values) + }; + + // console.log(invoiceData) + + const handleSubmit = async (e) => { + e.preventDefault(); + if (invoice) { + dispatch( + updateInvoice(invoice._id, { + ...invoiceData, + subTotal: subTotal, + total: total, + vat: vat, + rates: rates, + currency: currency, + dueDate: selectedDate, + client, + type: type, + status: status, + }) + ); + history.push(`/invoice/${invoice._id}`); + } else { + dispatch( + createInvoice( + { + ...invoiceData, + subTotal: subTotal, + total: total, + vat: vat, + rates: rates, + currency: currency, + dueDate: selectedDate, invoiceNumber: `${ - invoiceData.invoiceNumber < 100 ? - (Number(invoiceData.invoiceNumber)).toString().padStart(3, '0') + invoiceData.invoiceNumber < 100 + ? Number(invoiceData.invoiceNumber).toString().padStart(3, "0") : Number(invoiceData.invoiceNumber) }`, - client, - type: type, - status: status, - paymentRecords: [], - creator: [user?.result?._id || user?.result?.googleId] }, - history - )) - } - - // setInvoiceData(initialState) + client, + type: type, + status: status, + paymentRecords: [], + creator: [user?.result?._id || user?.result?.googleId], + }, + history + ) + ); } - const classes = useStyles() - const [open, setOpen] = useState(false); + // setInvoiceData(initialState) + }; - const CustomPaper = (props) => { - return ; - }; + const classes = useStyles(); + const [open, setOpen] = useState(false); + const CustomPaper = (props) => { + return ; + }; - if(!user) { - history.push('/login') - } - + if (!user) { + history.push("/login"); + } - return ( + return (
-
- - - - - - {/* */} - - - - Invoice #: -
setInvoiceData({ - ...invoiceData, invoiceNumber: e.currentTarget.textContent}) - } - > - {invoiceData.invoiceNumber} -
-
-
-
-
- - - - - - Bill to - - - {client && ( - <> - {client.name} - {client.email} - {client.phone} - {client.address} - - - )} -
- } - value={clients?.name} - onChange={(event, value) => setClient(value)} - - /> - -
- {!client && - <> - - +} - label="New Customer" - onClick={() => setOpen(true)} - variant="outlined" - /> - - - } -
+ + + + + + {/* */} + + + + Invoice #: +
+ setInvoiceData({ + ...invoiceData, + invoiceNumber: e.currentTarget.textContent, + }) + } + > + + {" "} + {invoiceData.invoiceNumber} + +
+
+
+
+
+ + + + + + + Bill to + + + {client && ( + <> + + {client.name} + + {client.email} + {client.phone} + {client.address} + + + )} +
+ ( + + )} + value={clients?.name} + onChange={(event, value) => setClient(value)} + /> +
+ {!client && ( + <> + + +} + label="New Customer" + onClick={() => setOpen(true)} + variant="outlined" + /> + + )} +
+
- - Status - {(type === 'Receipt' ? 'Paid' : 'Unpaid')} - Date - {moment().format("MMM Do YYYY")} - Due Date - {selectedDate? moment(selectedDate).format("MMM Do YYYY") : '27th Sep 2021'} - Amount - {currency} {toCommas(total)} - -
-
- - -
- - - - - - Item - Qty - Price - Disc(%) - Amount - Action - - - - {invoiceData.items.map((itemField, index) => ( - - handleChange(index, e)} value={itemField.itemName} placeholder="Item name or description" /> - handleChange(index, e)} value={itemField.quantity} placeholder="0" /> - handleChange(index, e)} value={itemField.unitPrice} placeholder="0" /> - handleChange(index, e)} value={itemField.discount} placeholder="0" /> - handleChange(index, e)} value={(itemField.quantity * itemField.unitPrice) - (itemField.quantity * itemField.unitPrice) * itemField.discount / 100} disabled /> - - handleRemoveField(index)}> - - - - + + + Status + + + {type === "Receipt" ? "Paid" : "Unpaid"} + + + Date + + + {moment().format("MMM Do YYYY")} + + + Due Date + + + {selectedDate + ? moment(selectedDate).format("MMM Do YYYY") + : "27th Sep 2021"} + + + Amount + + + {currency} {toCommas(total)} + + + + + +
+ +
+ + + Item + Qty + Price + Disc(%) + Amount + Action - ))} - -
-
-
- -
-
- + + + {invoiceData.items.map((itemField, index) => ( + + + {" "} + handleChange(index, e)} + value={itemField.itemName} + placeholder="Item name or description" + />{" "} + + + {" "} + handleChange(index, e)} + value={itemField.quantity} + placeholder="0" + />{" "} + + + {" "} + handleChange(index, e)} + value={itemField.unitPrice} + placeholder="0" + />{" "} + + + {" "} + handleChange(index, e)} + value={itemField.discount} + placeholder="0" + />{" "} + + + {" "} + handleChange(index, e)} + value={ + itemField.quantity * itemField.unitPrice - + (itemField.quantity * + itemField.unitPrice * + itemField.discount) / + 100 + } + disabled + />{" "} + + + handleRemoveField(index)}> + + + + + ))} + + + +
+ +
+
+
-
Invoice Summary
-
-

Sub total:

-

{subTotal}

-
-
-

VAT(%):

-

{vat}

-
-
-

Total

-

{currency} {toCommas(total)}

-
- +
Invoice Summary
+
+

Sub total:

+

{subTotal}

+
+
+

VAT(%):

+

{vat}

+
+
+

Total

+

+ {currency} {toCommas(total)} +

+
-
- - - - - - - - - - - - - } - value={currency.value} - onChange={(event, value) => setCurrency(value.value)} - - - /> - - - - -
-
-

Note/Payment Info

-