aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/App.scss7
-rw-r--r--src/_colors.scss25
-rw-r--r--src/_styles.scss40
-rw-r--r--src/classes/brand.js8
-rw-r--r--src/classes/item.js6
-rw-r--r--src/components/editors/brand-editor.js19
-rw-r--r--src/components/editors/item-editor.js90
-rw-r--r--src/components/editors/scss/brand-editor.scss2
-rw-r--r--src/components/tables/brand-table.js6
-rw-r--r--src/components/tables/client-table.js2
-rw-r--r--src/components/tables/item-table.js2
-rw-r--r--src/views/manage/brands.js25
-rw-r--r--src/views/manage/items.js25
-rw-r--r--src/views/manage/scss/management-page.scss4
14 files changed, 196 insertions, 65 deletions
diff --git a/src/App.scss b/src/App.scss
index 489d354..b4fc72f 100644
--- a/src/App.scss
+++ b/src/App.scss
@@ -17,15 +17,12 @@
@import url('https://fonts.googleapis.com/css2?family=Open+Sans:wght@400;500&display=swap');
+@import "colors";
+
* {
font-family: 'Open Sans', sans-serif;
}
-$primaryAccentColor: #bd93f9;
-$backgroundColor: #282a36;
-$linkColor: $primaryAccentColor;
-$fgColor: #f8f8f2;
-
body {
margin: 0;
padding: 0;
diff --git a/src/_colors.scss b/src/_colors.scss
new file mode 100644
index 0000000..12e4b92
--- /dev/null
+++ b/src/_colors.scss
@@ -0,0 +1,25 @@
+/* OpenBills-web - Web based libre billing software
+ * Copyright (C) 2022 Vidhu Kant Sharma <vidhukant@vidhukant.xyz>
+
+ * 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 <https://www.gnu.org/licenses/>.
+ */
+
+$primaryAccentColor: #bd93f9;
+$backgroundColor: #282a36;
+$linkColor: $primaryAccentColor;
+
+$white: #f8f8f2;
+$black: black;
+
+$fgColor: $white;
diff --git a/src/_styles.scss b/src/_styles.scss
new file mode 100644
index 0000000..3faed12
--- /dev/null
+++ b/src/_styles.scss
@@ -0,0 +1,40 @@
+/* OpenBills-web - Web based libre billing software
+ * Copyright (C) 2022 Vidhu Kant Sharma <vidhukant@vidhukant.xyz>
+
+ * 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 <https://www.gnu.org/licenses/>.
+ */
+
+@import "colors";
+
+@mixin floating-window {
+ .floating-wrapper {
+ height: 100vh;
+ width: 100vw;
+ box-sizing: border-box;
+ position: fixed;
+ top: 0;
+ left: 0;
+ background-color: rgba($backgroundColor, 0.3);
+ z-index: 5;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ backdrop-filter: blur(2px);
+ .floating-window {
+ width: 90%;
+ max-width: 1000px;
+ z-index: 6;
+ }
+ }
+}
diff --git a/src/classes/brand.js b/src/classes/brand.js
index 967f9a1..f396c6f 100644
--- a/src/classes/brand.js
+++ b/src/classes/brand.js
@@ -43,8 +43,14 @@ export const getAllBrands = (ok, fail) => {
.catch(err => fail())
}
+export const editBrand = (brand, ok, fail) => {
+ axios.put(`/brand/${brand.id}`, brand)
+ .then(res => ok())
+ .catch(err => fail())
+}
+
export const saveBrand = (brand, ok, fail) => {
axios.post("/brand/new", brand)
.then(res => ok())
- .catch((err) => fail())
+ .catch(err => fail())
}
diff --git a/src/classes/item.js b/src/classes/item.js
index 1c59992..bfd0b7b 100644
--- a/src/classes/item.js
+++ b/src/classes/item.js
@@ -65,3 +65,9 @@ export const getAllItems = (ok, fail) => {
.then(res => ok(res.data))
.catch(err => fail())
}
+
+export const editItem = (item, ok, fail) => {
+ axios.put(`/item/${item.id}`, item)
+ .then(res => ok())
+ .catch(err => fail())
+}
diff --git a/src/components/editors/brand-editor.js b/src/components/editors/brand-editor.js
index 801a790..26f4cca 100644
--- a/src/components/editors/brand-editor.js
+++ b/src/components/editors/brand-editor.js
@@ -15,13 +15,13 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
-import { Brand, saveBrand } from './../../classes/brand'
+import { Brand, saveBrand, editBrand } from './../../classes/brand'
import './scss/brand-editor.scss'
import { useState, useEffect } from 'react';
const BrandEditor = (props) => {
- const [name, setName] = useState("");
+ const [name, setName] = useState(props.brand.Name);
const handleSubmit = (e) => {
e.preventDefault();
@@ -29,13 +29,15 @@ const BrandEditor = (props) => {
const brand = new Brand();
brand.Name = name;
- // TODO: Save is for new brands. implement modification too
- saveBrand(brand, handleSuccess, handleFail);
+ props.editing
+ ? editBrand(brand, handleSuccess, handleFail)
+ : saveBrand(brand, handleSuccess, handleFail);
}
const handleSuccess = () => {
clearAll();
props.callback();
+ props.editing && props.hide();
}
const handleFail = () => {
@@ -47,8 +49,8 @@ const BrandEditor = (props) => {
}
const handleCancel = () => {
- // TODO: hide this component or something
clearAll();
+ props.editing && props.hide();
}
const validateFloatInput = (e, callback) => {
@@ -57,7 +59,7 @@ const BrandEditor = (props) => {
}
return (
- <div className={"editor-wrapper"}>
+ <div className={`editor-wrapper ${props.className ? props.className : ''}`}>
<p>{props.heading}</p>
<form onSubmit={handleSubmit} className={"editor brand-editor"}>
<label>
@@ -67,8 +69,11 @@ const BrandEditor = (props) => {
value={name} onChange={(e) => setName(e.target.value)} />
</label>
- <span className={"buttons"}>
+ <span className={`buttons ${props.editing ? '' : 'narrow'}`}>
<input type="button" value="Clear" onClick={clearAll}/>
+ {props.editing &&
+ <input type="button" value="Cancel" onClick={handleCancel}/>
+ }
<input type="submit" value="Save" />
</span>
</form>
diff --git a/src/components/editors/item-editor.js b/src/components/editors/item-editor.js
index 6c5e976..e2d9d94 100644
--- a/src/components/editors/item-editor.js
+++ b/src/components/editors/item-editor.js
@@ -15,22 +15,22 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
-import { Item, saveItem } from './../../classes/item'
-import { Brand, getAllBrands } from './../../classes/brand'
-import './scss/item-editor.scss'
+import { Item, saveItem, editItem } from './../../classes/item';
+import { Brand, getAllBrands } from './../../classes/brand';
+import './scss/item-editor.scss';
import { useState, useEffect } from 'react';
const ItemEditor = (props) => {
- const [name, setName] = useState("");
- const [desc, setDesc] = useState("");
- const [HSN, setHSN] = useState("");
- const [unit, setUnit] = useState("");
- const [unitPrice, setUnitPrice] = useState(0.00);
- const [gstP, setGSTP] = useState(0.00);
- const [minQty, setMinQty] = useState(0.00);
- const [maxQty, setMaxQty] = useState(0.00);
- const [brand, setBrand] = useState(new Brand());
+ const [name, setName] = useState(props.item.Name);
+ const [desc, setDesc] = useState(props.item.Description);
+ const [HSN, setHSN] = useState(props.item.HSN);
+ const [unit, setUnit] = useState(props.item.UnitOfMeasure);
+ const [unitPrice, setUnitPrice] = useState(props.item.UnitPrice);
+ const [gstP, setGSTP] = useState(props.item.GSTPercentage);
+ const [minQty, setMinQty] = useState(props.item.MinQuantity);
+ const [maxQty, setMaxQty] = useState(props.item.MaxQuantity);
+ const [brand, setBrand] = useState(props.item.Brand);
const [savedBrands, setSavedBrands] = useState([]);
// get saved brands from API
@@ -48,19 +48,22 @@ const ItemEditor = (props) => {
item.Description = desc;
item.HSN = HSN;
item.UnitOfMeasure = unit;
- item.UnitPrice = unitPrice;
- item.GSTPercentage = gstP;
- item.MinQuantity = minQty;
- item.MaxQuantity = maxQty;
+ item.UnitPrice = parseFloat(unitPrice);
+ item.GSTPercentage = parseFloat(gstP);
+ item.MinQuantity = parseFloat(minQty);
+ item.MaxQuantity = parseFloat(maxQty);
item.Brand = brand;
// TODO: Save is for new items. implement modification too
- saveItem(item, handleSuccess, handleFail);
+ props.editing
+ ? editItem(item, handleSuccess, handleFail)
+ : saveItem(item, handleSuccess, handleFail);
}
const handleSuccess = () => {
clearAll();
props.callback();
+ props.editing && props.hide();
}
const handleFail = () => {
@@ -85,73 +88,80 @@ const ItemEditor = (props) => {
}
const handleCancel = () => {
- // TODO: hide this component or something
clearAll();
- }
-
- const validateFloatInput = (e, callback) => {
- const f = parseFloat(e.target.value);
- f && callback(f)
+ props.editing && props.hide();
}
return (
- <div className={"editor-wrapper"}>
+ <div className={`editor-wrapper ${props.className ? props.className : ''}`}>
<p>{props.heading}</p>
<form onSubmit={handleSubmit} className={"editor"}>
<label>
Product/Service:
<input
- type="text" name="name"
- value={name} onChange={(e) => setName(e.target.value)} />
+ type="text"
+ value={name}
+ onChange={(e) => setName(e.target.value)} />
</label>
<label>
Description:
<input
- type="text" name="desc"
- value={desc} onChange={(e) => setDesc(e.target.value)} />
+ type="text"
+ value={desc}
+ onChange={(e) => setDesc(e.target.value)} />
</label>
<label>
HSN:
<input
- type="text" name="hsn"
- value={HSN} onChange={(e) => setHSN(e.target.value)} />
+ type="text"
+ value={HSN}
+ onChange={(e) => setHSN(e.target.value)} />
</label>
<label>
Unit of Measurement:
<input
- type="text" name="unit"
- value={unit} onChange={(e) => setUnit(e.target.value)} />
+ type="text"
+ value={unit}
+ onChange={(e) => setUnit(e.target.value)} />
</label>
<label>
Unit Price:
<input
- type="number" name="unitprice"
- value={unitPrice} onChange={(e) => validateFloatInput(e, setUnitPrice)} />
+ type="number"
+ value={unitPrice}
+ min="0"
+ onChange={(e) => setUnitPrice(e.target.value)} />
</label>
<label>
GST %:
<input
- type="number" name="gstp"
- value={gstP} onChange={(e) => validateFloatInput(e, setGSTP)} />
+ type="number"
+ value={gstP}
+ min="0"
+ onChange={(e) => setGSTP(e.target.value)} />
</label>
<label>
Minimum Quantity:
<input
- type="number" name="minqty"
- value={minQty} onChange={(e) => validateFloatInput(e, setMinQty)} />
+ type="number"
+ value={minQty}
+ min="0"
+ onChange={(e) => setMinQty(e.target.value)} />
</label>
<label>
Maximum Quantity:
<input
- type="number" name="maxqty"
- value={maxQty} onChange={(e) => validateFloatInput(e, setMaxQty)} />
+ type="number"
+ value={maxQty}
+ min="0"
+ onChange={(e) => setMaxQty(e.target.value)} />
</label>
{savedBrands && savedBrands.length > 0 &&
diff --git a/src/components/editors/scss/brand-editor.scss b/src/components/editors/scss/brand-editor.scss
index 05b05a7..b9230a4 100644
--- a/src/components/editors/scss/brand-editor.scss
+++ b/src/components/editors/scss/brand-editor.scss
@@ -17,6 +17,6 @@
@import "editor";
-.brand-editor .buttons {
+.brand-editor .buttons.narrow {
width: 9.5rem;
}
diff --git a/src/components/tables/brand-table.js b/src/components/tables/brand-table.js
index 4b361a1..db8272c 100644
--- a/src/components/tables/brand-table.js
+++ b/src/components/tables/brand-table.js
@@ -19,8 +19,8 @@ import './scss/brand-table.scss';
import { deleteBrand } from './../../classes/brand';
const BrandTable = (props) => {
- const handleEdit = (i) => {
- alert("editing coming soon")
+ const handleEdit = (b) => {
+ props.setBrandToEdit(b)
}
const handleDelete = (b) => {
@@ -39,7 +39,7 @@ const BrandTable = (props) => {
return (
<div className={"brand-table"}>
{props.brands && props.brands.map(i =>
- <div className={"brand"}>
+ <div key={i.Id} className={"brand"}>
<p className={"brand-name"}>{i.Name}</p>
<div className={"buttons"}>
<input type="button" value="Edit" onClick={() => handleEdit(i)}/>
diff --git a/src/components/tables/client-table.js b/src/components/tables/client-table.js
index 466316a..ffbf5e8 100644
--- a/src/components/tables/client-table.js
+++ b/src/components/tables/client-table.js
@@ -20,7 +20,7 @@ import { deleteClient } from './../../classes/client';
const ClientTable = (props) => {
const handleEdit = (i) => {
- alert("editing coming soon")
+ props.setItemToEdit(i)
}
const handleDelete = (c) => {
diff --git a/src/components/tables/item-table.js b/src/components/tables/item-table.js
index e42b272..208fd9c 100644
--- a/src/components/tables/item-table.js
+++ b/src/components/tables/item-table.js
@@ -22,7 +22,7 @@ import { faPencil, faTrashCan } from '@fortawesome/free-solid-svg-icons'
const ItemTable = (props) => {
const handleEdit = (i) => {
- alert("editing coming soon")
+ props.setItemToEdit(i)
}
const handleDelete = (i) => {
diff --git a/src/views/manage/brands.js b/src/views/manage/brands.js
index 61afe16..dad21e2 100644
--- a/src/views/manage/brands.js
+++ b/src/views/manage/brands.js
@@ -18,11 +18,12 @@
import { useState, useEffect } from 'react';
import './scss/management-page.scss'
-import { getAllBrands } from '../../classes/brand';
+import { Brand, getAllBrands } from '../../classes/brand';
import BrandEditor from './../../components/editors/brand-editor';
import BrandTable from './../../components/tables/brand-table';
const ManageBrandsPage = () => {
+ const [brandToEdit, setBrandToEdit] = useState(new Brand());
const [allBrands, setAllBrands] = useState([]);
// TODO: handle error
const updateList = () =>
@@ -34,9 +35,27 @@ const ManageBrandsPage = () => {
return (
<>
- <BrandEditor heading={"Add New Brand"} callback={updateList}/>
+ <BrandEditor
+ heading={"Add New Brand"}
+ brand={new Brand()}
+ callback={updateList}/>
<hr/>
- <BrandTable refresh={updateList} brands={allBrands}/>
+ <BrandTable
+ refresh={updateList}
+ brands={allBrands}
+ setBrandToEdit={setBrandToEdit}/>
+
+ {JSON.stringify(brandToEdit) !== JSON.stringify(new Brand()) &&
+ <div className={"floating-wrapper"}>
+ <BrandEditor
+ className={"floating-window"}
+ heading={`Edit ${brandToEdit.Name ? brandToEdit.Name : 'Brand'}:`}
+ brand={brandToEdit}
+ hide={() => setBrandToEdit(new Brand())}
+ editing={true}
+ callback={updateList}/>
+ </div>
+ }
</>
);
}
diff --git a/src/views/manage/items.js b/src/views/manage/items.js
index b9bf339..567be7c 100644
--- a/src/views/manage/items.js
+++ b/src/views/manage/items.js
@@ -22,11 +22,12 @@
import { useState, useEffect } from 'react';
import './scss/management-page.scss'
-import { getAllItems } from '../../classes/item';
+import { Item, getAllItems } from '../../classes/item';
import ItemEditor from './../../components/editors/item-editor';
import ItemTable from './../../components/tables/item-table';
const ManageItemsPage = () => {
+ const [itemToEdit, setItemToEdit] = useState(new Item());
const [allItems, setAllItems] = useState([]);
// TODO: handle error
const updateList = () =>
@@ -38,9 +39,27 @@ const ManageItemsPage = () => {
return (
<>
- <ItemEditor heading={"Add New Item"} callback={updateList}/>
+ <ItemEditor
+ heading={"Add New Item"}
+ item={new Item()}
+ callback={updateList}/>
<hr/>
- <ItemTable refresh={updateList} items={allItems}/>
+ <ItemTable
+ refresh={updateList}
+ items={allItems}
+ setItemToEdit={setItemToEdit}/>
+
+ {JSON.stringify(itemToEdit) !== JSON.stringify(new Item()) &&
+ <div className={"floating-wrapper"}>
+ <ItemEditor
+ className={"floating-window"}
+ heading={`Edit ${itemToEdit.Name ? itemToEdit.Name : 'Item'}:`}
+ item={itemToEdit}
+ hide={() => setItemToEdit(new Item())}
+ editing={true}
+ callback={updateList}/>
+ </div>
+ }
</>
);
}
diff --git a/src/views/manage/scss/management-page.scss b/src/views/manage/scss/management-page.scss
index df26819..656d224 100644
--- a/src/views/manage/scss/management-page.scss
+++ b/src/views/manage/scss/management-page.scss
@@ -15,6 +15,10 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
+@import "../../../styles";
+
+@include floating-window;
+
hr {
margin: 0.8rem auto 1rem auto;
}