From 0b4343bed2cace86552929f25202680c0d99c541 Mon Sep 17 00:00:00 2001 From: Vidhu Kant Sharma Date: Mon, 10 Oct 2022 22:45:28 +0530 Subject: added ItemTable for the invoice page --- src/components/pickers/item-picker.js | 56 +++++++++++------- src/components/pickers/scss/_picker.scss | 38 ------------- src/components/pickers/scss/item-picker.scss | 35 ++++++++++-- src/components/tables/invoice-item-table.js | 85 ++++++++++++++++++++++++++++ src/views/invoice/new.js | 9 ++- 5 files changed, 159 insertions(+), 64 deletions(-) create mode 100644 src/components/tables/invoice-item-table.js diff --git a/src/components/pickers/item-picker.js b/src/components/pickers/item-picker.js index 46310db..339319f 100644 --- a/src/components/pickers/item-picker.js +++ b/src/components/pickers/item-picker.js @@ -10,8 +10,7 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - - * You should have received a copy of the GNU General Public License +* You should have received a copy of the GNU General Public License * along with this program. If not, see . */ @@ -19,10 +18,11 @@ import { Item, InvoiceItem, getAllItems } from '../../classes/item'; import './scss/item-picker.scss'; import { useState, useEffect } from 'react'; +import { Link } from 'react-router-dom'; //import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' //import { faPhone, faEnvelope, faGlobe } from '@fortawesome/free-solid-svg-icons' -const ItemPicker = () => { +const ItemPicker = ({invoiceItems, addInvoiceItem}) => { const [items, setItems] = useState([new Item()]); const [item, setItem] = useState(new InvoiceItem()); @@ -44,30 +44,33 @@ const ItemPicker = () => { })); } + // add item to the invoice items list + const addItem = (e) => { + e.preventDefault(); + addInvoiceItem(item); + setItem(new InvoiceItem()); + } + + // input elements are sorted on the basis of + // how likely they are going to be edited return (

Add an Item

-
- {items && items.length > 0 && +
+ {items.length > 0 ? <> - -
+
); diff --git a/src/components/pickers/scss/_picker.scss b/src/components/pickers/scss/_picker.scss index 625a1e3..4d8d1b1 100644 --- a/src/components/pickers/scss/_picker.scss +++ b/src/components/pickers/scss/_picker.scss @@ -65,41 +65,3 @@ color: $primaryAccentColor; } } - -@mixin picker { - .picker { - padding-bottom: 2.5rem; - margin: auto; - display: flex; - flex-direction: row; - flex-wrap: wrap; - justify-content: space-evenly; - align-items: center; - min-width: 90%; - @include label; - - .buttons { - position: absolute; - display: flex; - justify-content: space-between; - width: 13.5rem; - input { - padding: 0.2rem 0; - width: 4rem; - background-color: $inputBackgroundColor; - border: 1px solid $primaryAccentColor; - color: $fgColor; - border-radius: 4px; - transition: background-color 0.4s, color 0.4s; - } - input:hover { - background-color: $primaryAccentColor; - color: $fgColorAlt; - } - bottom: 0; - left: 0; - right: 0; - margin: auto; - } - } -} diff --git a/src/components/pickers/scss/item-picker.scss b/src/components/pickers/scss/item-picker.scss index b04fb54..093b0e9 100644 --- a/src/components/pickers/scss/item-picker.scss +++ b/src/components/pickers/scss/item-picker.scss @@ -23,8 +23,13 @@ } .item-picker { - display: flex; - justify-content: space-evenly; + //display: flex; + //flex-wrap: wrap; + //justify-content: space-between; + //align-items: center; + display: grid; + grid-template-columns: auto auto auto auto; + .options { width: 27rem; flex-grow: 1; @@ -46,14 +51,36 @@ white-space: pre-line; } - input[type=number], input.narrow { + label.narrow { + max-width: 16rem; + input { width: 7rem; } + } + + input[type=number] { -moz-appearance: textfield; width: 7rem; } - input::-webkit-outer-spin-button, input::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; } + + input[type=button], input[type=submit] { + padding: 0.2rem 0; + width: 4rem; + height: 1.7rem; + margin-top: 0.3rem; + margin-left: auto; + background-color: $inputBackgroundColor; + border: 1px solid $primaryAccentColor; + color: $fgColor; + border-radius: 4px; + transition: background-color 0.4s, color 0.4s; + } + + input[type=button]:hover, input[type=submit]:hover { + background-color: $primaryAccentColor; + color: $fgColorAlt; + } } diff --git a/src/components/tables/invoice-item-table.js b/src/components/tables/invoice-item-table.js new file mode 100644 index 0000000..6b0a1a5 --- /dev/null +++ b/src/components/tables/invoice-item-table.js @@ -0,0 +1,85 @@ +/* OpenBills-web - Web based libre billing software + * Copyright (C) 2022 Vidhu Kant Sharma + + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +import './scss/table.scss'; +import { deleteItem } from './../../classes/item'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' +import { faPencil, faTrashCan } from '@fortawesome/free-solid-svg-icons' + +const ItemTable = ({items, setItems}) => { + const handleEdit = (i) => { + alert("coming soon; please delete and add item again"); + } + + const handleDelete = (item) => { + setItems(items.filter(i => i.Id !== item.Id)); + } + + /* TODO: all the math should be done here + * i.e CGST, IGST, total price (i.e price x quantity) + * discount/gst value (i.e number instead of percentage) + * + * the total cost and the like may be handled by + * parent component since they are needed + * by other things (probably) + * + * all the values will be calculated on runtime. + * the database will only store the unit price + * and gst/discount *percentages* and everything else + * will be calculated on runtime. i.e the + * database only store info required to re-produce + * those same values shown to the user while creating the invoice + */ + return ( + + + + + + + + + + + + {/* TODO: CGST, IGST, etc */} + + + + + {items && items.map((i, id=id+1) => ( + + + + + + + + + + + + ))} + +
S. NoNameDescriptionBrand NameUOMHSNUnit PriceGST %
{id+1}{i.Name}{i.Description}{i.Brand.Name}{i.UnitOfMeasure}{i.HSN}{i.UnitPrice}{i.GSTPercentage} + handleEdit(i)}/> + handleDelete(i)}/> +
+ ); +} + +export default ItemTable; diff --git a/src/views/invoice/new.js b/src/views/invoice/new.js index 57f3094..70bc545 100644 --- a/src/views/invoice/new.js +++ b/src/views/invoice/new.js @@ -17,6 +17,7 @@ import ClientPicker from '../../components/pickers/client-picker'; import ItemPicker from '../../components/pickers/item-picker'; +import ItemTable from '../../components/tables/invoice-item-table'; import { InvoiceClient } from '../../classes/client'; @@ -25,6 +26,7 @@ import { useState, useEffect } from 'react'; const NewInvoicePage = () => { const [client, setClient] = useState(new InvoiceClient()); const [shippingAddressId, setShippingAddressId] = useState(-1); + const [items, setItems] = useState([]); useEffect(() => { setShippingAddressId(-1); @@ -37,7 +39,12 @@ const NewInvoicePage = () => { setClient={setClient} shippingAddressId={shippingAddressId} setShippingAddressId={setShippingAddressId}/> - + setItems(prev => [...prev, item])} /> + ); } -- cgit v1.2.3