diff options
-rw-r--r-- | .gitignore | 2 | ||||
-rw-r--r-- | server/database/database.go | 58 | ||||
-rw-r--r-- | server/main.go | 23 | ||||
-rw-r--r-- | server/openbills.db | bin | 8192 -> 12288 bytes | |||
-rw-r--r-- | src/components/BillingPage.js | 14 | ||||
-rw-r--r-- | src/components/Form/AddNewItemForm.js | 10 | ||||
-rw-r--r-- | src/components/Form/Form.css | 28 | ||||
-rw-r--r-- | src/components/Form/Form.scss | 53 | ||||
-rw-r--r-- | src/components/Form/RegisterItemForm.js | 103 |
9 files changed, 252 insertions, 39 deletions
@@ -25,6 +25,8 @@ yarn-error.log* /server/openbills /server/build /server/app +/server/openbills.db +/server/database/openbills.db /build /app diff --git a/server/database/database.go b/server/database/database.go index 16b6f65..8b7c7f6 100644 --- a/server/database/database.go +++ b/server/database/database.go @@ -12,43 +12,67 @@ package database import ( - _ "github.com/mattn/go-sqlite3" "database/sql" + _ "github.com/mattn/go-sqlite3" ) type Item struct { Model string Desc string `json:"Description"` - Price int // *float32 + Price float64 HSN int } - var myDatabase *sql.DB +var registered_items *sql.Stmt +var register_item *sql.Stmt func init() { myDatabase, _ = sql.Open("sqlite3", "./openbills.db") -} -var myItems *sql.Stmt -var addToMyItems *sql.Stmt -func init() { - myItems, _ = myDatabase.Prepare("CREATE TABLE IF NOT EXISTS RegisteredItems (id INTEGER PRIMARY KEY, model TEXT, desc TEXT, price INTEGER, HSN INTEGER)") - myItems.Exec() + registered_items, _ = myDatabase.Prepare( + `CREATE TABLE IF NOT EXISTS registered_items + (id INTEGER PRIMARY KEY AUTOINCREMENT, + model TEXT NOT NULL, + desc TEXT, + price REAL, + hsn BLOB)`, + ) + registered_items.Exec() - addToMyItems, _ = myDatabase.Prepare("INSERT INTO RegisteredItems (id, model, desc, price, hsn) VALUES (?, ?, ?, ?, ?)") + register_item, _ = myDatabase.Prepare( + `INSERT INTO registered_items + (model, desc, price, hsn) + VALUES (?, ?, ?, ?)`, + ) } func GetAllItems() []Item { var allItems []Item - rows, _ := myDatabase.Query("SELECT model, desc, price, hsn FROM RegisteredItems") + rows, _ := myDatabase.Query( + `SELECT model, desc, price, hsn FROM registered_items`, + ) + + var ( + model, desc string + price float64 + HSN int + ) - var model string - var desc string - var price int - var hsn int for rows.Next() { - rows.Scan(&model, &desc, &price, &hsn) - allItems = append(allItems, Item{model, desc, price, hsn}) + rows.Scan(&model, &desc, &price, &HSN) + allItems = append(allItems, Item{model, desc, price, HSN}) } + return allItems } + +func RegisterItem(model string, desc string, price float64, HSN int) { + /* + var item Item = Item{ + model, desc, price, HSN, + } + + register_item.Exec(item.Model, item.Desc, item.Price, item.HSN) + */ + register_item.Exec(model, desc, price, HSN) +} diff --git a/server/main.go b/server/main.go index b514a31..1aa34c3 100644 --- a/server/main.go +++ b/server/main.go @@ -16,7 +16,7 @@ import ( "github.com/gin-gonic/contrib/static" "net/http" - // this handles all the database functions + "strconv" db "github.com/MikunoNaka/openbills/database" ) @@ -33,6 +33,9 @@ func main() { items := api.Group("/items") items.GET("/", getAllItems) + items.POST("/", registerItem) + + // items.POST("/", registerItem) myRouter.Run(":8080") } @@ -41,3 +44,21 @@ func getAllItems(ctx *gin.Context) { ctx.Header("Content-Type", "application/json") ctx.JSON(http.StatusOK, db.GetAllItems()) } + +func registerItem(ctx *gin.Context) { + // extract data + model := ctx.Query("model") + desc := ctx.Query("desc") + price, _ := strconv.ParseFloat(ctx.Query("price"), 64) + hsn, _ := strconv.Atoi(ctx.Query("hsn")) + + // why does it show warnings + item := db.Item { + model, + desc, + price, + hsn, + } + + db.RegisterItem(item.Model, item.Desc, item.Price, item.HSN) +} diff --git a/server/openbills.db b/server/openbills.db Binary files differindex 1f2afd2..4f15f57 100644 --- a/server/openbills.db +++ b/server/openbills.db diff --git a/src/components/BillingPage.js b/src/components/BillingPage.js index 7f97b32..fc09694 100644 --- a/src/components/BillingPage.js +++ b/src/components/BillingPage.js @@ -10,15 +10,15 @@ import React, { useState, useEffect } from "react"; import axios from "axios"; import AddNewItemForm from "./Form/AddNewItemForm"; +import RegisterItemForm from "./Form/RegisterItemForm"; +import MetaInfoForm from "./Form/MetaInfoForm"; import ItemsDisplay from "./Display/ItemsDisplay"; import SummaryDisplay from "./Display/SummaryDisplay"; -import MetaInfoForm from "./Form/MetaInfoForm"; const BillingPage = () => { const [savedItems, getSavedItems] = useState([]) - // get data from server on startup - useEffect(() => { + const getRegisteredItems = () => { axios.get(`/api/items`) .then((res) => { getSavedItems(res.data); @@ -27,8 +27,13 @@ const BillingPage = () => { alert("The promise returned an error idk what to do"); console.log(res); }) + } + + // get data from server on startup + useEffect(() => { + getRegisteredItems(); }, []); - // to be handled by backend + // TODO: to be handled by backend const defGSTValue = 18; // update the items from AddNewItemForm @@ -42,6 +47,7 @@ const BillingPage = () => { return ( <> <AddNewItemForm savedItems={savedItems} addItem={getItems} defGSTValue={defGSTValue}/> + <RegisterItemForm/> <ItemsDisplay items={items} defGSTValue={defGSTValue}/> <div className={"BillingPageFlex"}> <MetaInfoForm/> diff --git a/src/components/Form/AddNewItemForm.js b/src/components/Form/AddNewItemForm.js index afd5259..5028af2 100644 --- a/src/components/Form/AddNewItemForm.js +++ b/src/components/Form/AddNewItemForm.js @@ -80,7 +80,7 @@ const AddNewItemForm = (props) => { }> <div className={"textInputs"}> <label> - Item: + Item/Service: <select value={itemNameValue} onChange={ @@ -110,7 +110,7 @@ const AddNewItemForm = (props) => { <div className={"numericInputs"}> <label> - Quantity: <input type="number" min="1" value={itemQtyValue} onInput={ + Quantity:<input type="number" min="1" value={itemQtyValue} onInput={ (event) => { const value = event.target.value; setItemQtyValue(value); @@ -156,10 +156,12 @@ const AddNewItemForm = (props) => { </div> <div className={"menuButtons"}> + <input type="button" value="Register New Item" onClick={() => { + alert("Coming Soon") + }} /> <input type="button" value="Placeholder1" /> <input type="button" value="Placeholder2" /> - <input type="button" value="Placeholder3" /> - <input type="submit" value="Panic" /> + <input type="submit" value="Force Add" /> <input type="submit" value="add" diff --git a/src/components/Form/Form.css b/src/components/Form/Form.css index def42e5..ce94de4 100644 --- a/src/components/Form/Form.css +++ b/src/components/Form/Form.css @@ -1,3 +1,10 @@ +/* + * OpenBills - Self hosted browser app to generate and keep track of simple invoices + * Version - 0 + * Licensed under the MIT license - https://opensource.org/licenses/MIT + * + * Copyright (c) 2021 Vidhu Kant Sharma +*/ @import url("https://fonts.googleapis.com/css2?family=Quicksand:wght@500&display=swap"); /* Experimental color scheme */ /* light theme */ @@ -82,6 +89,27 @@ input[type=number] { padding: 0.8rem 0; border-bottom: 1px dotted lightblue; } +.RegisterItemFormContainer { + /*display: none;*/ + position: fixed; + width: 95%; + height: 70vh; + left: 0; + right: 0; + margin: auto; + top: 15vh; + background-color: #383A59; } + +.RegisterItemForm .textInputs, +.RegisterItemForm .numericInputs { + width: 40%; } + +.RegisterItemForm { + width: 95%; + height: 60vh; + margin: 1rem auto; + justify-content: space-around; } + .MetaInfoForm { width: 60%; } diff --git a/src/components/Form/Form.scss b/src/components/Form/Form.scss index 92f227a..f7a2d2e 100644 --- a/src/components/Form/Form.scss +++ b/src/components/Form/Form.scss @@ -10,6 +10,20 @@ $inputBorders: 1px solid $altBorderColor; +/* hide arrows in numericInputs */ +/* Chrome, Safari, Edge, Opera */ +input::-webkit-outer-spin-button, +input::-webkit-inner-spin-button { + -webkit-appearance: none; + margin: 0; +} + +/* Firefox */ +input[type=number] { + -moz-appearance: textfield; +} + + .formContainer { /*border: 1px solid pink;*/ /*padding: 2rem;*/ @@ -72,19 +86,6 @@ label { scrollbar-width: none; /* Firefox */ } -/* hide arrows in numericInputs */ -/* Chrome, Safari, Edge, Opera */ -input::-webkit-outer-spin-button, -input::-webkit-inner-spin-button { - -webkit-appearance: none; - margin: 0; -} - -/* Firefox */ -input[type=number] { - -moz-appearance: textfield; -} - .addNewItemForm label { display: flex; justify-content: space-between; @@ -92,6 +93,32 @@ input[type=number] { border-bottom: 1px dotted $labelUnderlineColor; } +.RegisterItemFormContainer { + /*display: none;*/ + position: fixed; + + width: 95%; + height: 70vh; + + left: 0;right: 0; + margin: auto; + top: 15vh; + + background-color: $altBG; +} + +.RegisterItemForm .textInputs, +.RegisterItemForm .numericInputs { + width: 40%; +} + +.RegisterItemForm { + width: 95%; + height: 60vh; + margin: 1rem auto; + justify-content: space-around; +} + .MetaInfoForm { width: 60%; } diff --git a/src/components/Form/RegisterItemForm.js b/src/components/Form/RegisterItemForm.js new file mode 100644 index 0000000..1b38c8d --- /dev/null +++ b/src/components/Form/RegisterItemForm.js @@ -0,0 +1,103 @@ +/* + * OpenBills - Self hosted browser app to generate and keep track of simple invoices + * Version - 0 + * Licensed under the MIT license - https://opensource.org/licenses/MIT + * + * Copyright (c) 2021 Vidhu Kant Sharma +*/ + +// TODO: Code isn't tested properly +// I'd be surprised if it has no bugs + +import React, { useState } from "react"; +import axios from "axios"; +import "./Form.css"; + + +const RegisterItemForm = () => { + // show/hide this component + const [visibility, setVisibility] = useState(true)// useState(props.visibility); + + const [newItemNameValue, setNewItemNameValue] = useState(""); + const [newItemDescValue, setNewItemDescValue] = useState(""); + // const [newItemBrandValue, setNewItemBrandValue] = useState(""); + // const [newItemTypeValue, setNewItemTypeValue] = useState(""); + const [newItemPriceValue, setNewItemPriceValue] = useState(""); + const [newItemHSNValue, setNewItemHSNValue] = useState(""); + const [newItemGSTValue, setNewItemGSTValue] = useState(""); + + + return ( + <div className={"formContainer RegisterItemFormContainer"} style={{display: visibility ? "fixed" : "none"}}> + <form className={"addNewItemForm RegisterItemForm"} onSubmit={ + (event) => { + event.preventDefault(); + setVisibility(false); + + axios.post(`/api/items/?model=${newItemNameValue}&desc=${newItemDescValue}&price=${newItemPriceValue}&hsn=${newItemHSNValue}&gst=${newItemGSTValue}`) + .then((res) => { + console.log(res); + }) + .catch((err) => { + console.log(err); + }); + } + }> + <div className={"textInputs"}> + <label> + Item/Service: <input type="text" value={newItemNameValue} onChange={ + (event) => { + setNewItemNameValue(event.target.value); + } + } required /> + </label> + + <label> + Description: <input type="text" value={newItemDescValue} onChange={ + (event) => { + setNewItemDescValue(event.target.value); + } + } /> + </label> + </div> + + <div className={"numericInputs"}> + <label> + Price: <input type="number" min="1.00" step="0.001" value={newItemPriceValue} onChange={ + (event) => { + const value = event.target.value; + setNewItemPriceValue(value); + } + } /> + </label> + + <label> + HSN: <input type="number" min="0" value={newItemHSNValue} onChange={ + (event) => { + const value = event.target.value; + setNewItemHSNValue(value); + } + } /> + </label> + + <label> + GST: <input type="number" min="0" value={newItemGSTValue} onChange={ + (event) => { + const value = event.target.value; + setNewItemGSTValue(value); + } + } /> + </label> + </div> + + <input + type="submit" + value="Register/Add" + disabled={newItemNameValue !== "" ? "" : "disabled"} + /> + </form> + </div> + ); +} + +export default RegisterItemForm; |