aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVidhu Kant Sharma <vidhukant@vidhukant.xyz>2022-09-27 12:25:56 +0530
committerVidhu Kant Sharma <vidhukant@vidhukant.xyz>2022-09-27 12:25:56 +0530
commitaf0ef4c190f3967d2def0c65cc3a1fce4511044e (patch)
treebba973c45ca5197ebf336d5e2f7f0f599b74bccd
parent708862c94bd119ca7e86540fbc68595a6256c9e3 (diff)
added shipping address functionality to /manage/clients page
-rw-r--r--src/classes/client.js14
-rw-r--r--src/components/editors/address-editor.js37
-rw-r--r--src/components/editors/client-editor.js76
-rw-r--r--src/components/editors/contact-editor.js35
-rw-r--r--src/components/editors/scss/_colors.scss (renamed from src/components/editors/scss/colors.scss)2
-rw-r--r--src/components/editors/scss/address-editor.scss20
-rw-r--r--src/components/editors/scss/client-editor.scss7
-rw-r--r--src/views/manage/clients.js2
8 files changed, 156 insertions, 37 deletions
diff --git a/src/classes/client.js b/src/classes/client.js
index 524d0ce..cae528e 100644
--- a/src/classes/client.js
+++ b/src/classes/client.js
@@ -43,24 +43,24 @@ export class Client {
this.Contact = new Contact();
this.GSTIN = "";
this.BillingAddress = new Address();
- this.ShippingAddress = [];
+ this.ShippingAddresses = [];
}
}
export const saveClient = (item, ok, fail) => {
axios.post("/client/new", item)
- .then(res => { console.log(res);ok()})
- .catch((err) => fail())
+ .then(res => ok(res))
+ .catch(err => fail(err))
}
export const deleteClient = (id, ok, fail) => {
axios.delete(`/client/${id}`)
- .then(res => ok())
- .catch((err) => fail())
+ .then(res => ok(res))
+ .catch(err => fail(err))
}
export const getAllClients = (ok, fail) => {
axios.get("/client/all")
- .then(res => ok(res.data))
- .catch(err => fail())
+ .then(res => ok(res.Data))
+ .catch(err => fail(err))
}
diff --git a/src/components/editors/address-editor.js b/src/components/editors/address-editor.js
index d2b015f..3675f26 100644
--- a/src/components/editors/address-editor.js
+++ b/src/components/editors/address-editor.js
@@ -18,18 +18,31 @@
import { Address } from './../../classes/client';
import './scss/address-editor.scss';
-import { useState } from 'react';
+import { useState, useEffect } from 'react';
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
+import { faXmark } from '@fortawesome/free-solid-svg-icons';
const AddressEditor = (props) => {
- const [country, setCountry] = useState("");
- const [state, setState] = useState("");
- const [city, setCity] = useState("");
- const [address, setAddress] = useState("");
- const [postalCode, setPostalCode] = useState("");
+ const handleInput = (field, event) => {
+ const a = new Address();
+ const val = event.target.value;
+ a.Country = field === "country" ? val : props.address.Country;
+ a.State = field === "state" ? val : props.address.State;
+ a.City = field === "city" ? val : props.address.City;
+ a.Text = field === "address" ? val : props.address.Text;
+ a.PostalCode = field === "postal" ? val : props.address.PostalCode;
+ props.setAddress(a);
+ }
return (
<div className={"address-editor"}>
<p className={"heading"}>{props.heading}</p>
+ {props.isBillingAddress || // cross button
+ <FontAwesomeIcon
+ icon={faXmark}
+ className={"remove-button"}
+ onClick={props.deleteAddress}/>
+ }
<div className={"labels-wrapper"}>
<div>
@@ -37,21 +50,21 @@ const AddressEditor = (props) => {
Country:
<input
type="text" name="name"
- value={country} onChange={(e) => setCountry(e.target.value)} />
+ value={props.address.Country} onChange={(e) => handleInput("country", e)} />
</label>
<label>
State:
<input
type="text" name="name"
- value={state} onChange={(e) => setState(e.target.value)} />
+ value={props.address.State} onChange={(e) => handleInput("state", e)} />
</label>
<label>
City:
<input
type="text" name="name"
- value={city} onChange={(e) => setCity(e.target.value)} />
+ value={props.address.City} onChange={(e) => handleInput("city", e)} />
</label>
</div>
@@ -60,14 +73,14 @@ const AddressEditor = (props) => {
Address:
<textarea
type="text" name="name"
- value={address} onChange={(e) => setAddress(e.target.value)} />
+ value={props.address.Text} onChange={(e) => handleInput("address", e)} />
</label>
<label>
Postal Code:
<input
type="text" name="name"
- value={postalCode} onChange={(e) => setPostalCode(e.target.value)} />
+ value={props.address.PostalCode} onChange={(e) => handleInput("postal", e)} />
</label>
</div>
</div>
@@ -76,7 +89,7 @@ const AddressEditor = (props) => {
<input
type="checkbox"
checked={props.billingAddressIsShipping}
- onChange={props.callback()} />
+ onChange={() => props.setShipToBillingAddress(!props.billingAddressIsShipping)} />
Shipping address same as billing address
</label>
}
diff --git a/src/components/editors/client-editor.js b/src/components/editors/client-editor.js
index eccd9e8..f4535c2 100644
--- a/src/components/editors/client-editor.js
+++ b/src/components/editors/client-editor.js
@@ -15,24 +15,37 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
-import { Client, saveClient } from './../../classes/client';
+import { Client, saveClient, Contact, Address } from './../../classes/client';
import AddressEditor from './address-editor';
import ContactEditor from './contact-editor';
import './scss/client-editor.scss';
-import { useState } from 'react';
+import { useState, useEffect } from 'react';
const ClientEditor = (props) => {
const [name, setName] = useState("");
const [GSTIN, setGSTIN] = useState([]);
+ const [contact, setContact] = useState(new Contact());
+ const [billingAddress, setBillingAddress] = useState(new Address());
+ const [shippingAddresses, setShippingAddresses] = useState([]);
const [shipToBillingAddress, setShipToBillingAddress] = useState(true);
+ useEffect(() => {
+ // will delete existing shipping addresses if false
+ setShippingAddresses(shipToBillingAddress ? [] : [new Address()])
+ }, [shipToBillingAddress]);
+
const handleSubmit = (e) => {
e.preventDefault();
const client = new Client();
client.Name = name;
client.GSTIN = GSTIN;
+ client.Contact = contact;
+ client.BillingAddress = billingAddress;
+ client.ShippingAddresses = shipToBillingAddress
+ ? [billingAddress]
+ : shippingAddresses
// TODO: Save is for new items. implement modification too
saveClient(client, handleSuccess, handleFail);
@@ -40,16 +53,21 @@ const ClientEditor = (props) => {
const handleSuccess = () => {
clearAll();
- props.callback();
+ props.successCallback();
}
- const handleFail = () => {
+ const handleFail = (err) => {
alert("fail");
+ console.log(err);
}
const clearAll = () => {
setName("");
setGSTIN("")
+ setContact(new Contact());
+ setBillingAddress(new Address());
+ setShippingAddresses([new Address()]);
+ setShipToBillingAddress(true);
}
const handleCancel = () => {
@@ -57,6 +75,27 @@ const ClientEditor = (props) => {
clearAll();
}
+ const handleShippingAddressUpdate = (id, data) => {
+ setShippingAddresses([
+ ...shippingAddresses.slice(0, id),
+ data,
+ ...shippingAddresses.slice(id+1)
+ ]);
+ }
+
+ const handleShippingAddressDelete = (id) => {
+ // deleting the last address sets
+ // shipToBillingAddress to true
+ if (shippingAddresses.length === 1) {
+ setShipToBillingAddress(true);
+ } else {
+ setShippingAddresses([
+ ...shippingAddresses.slice(0, id),
+ ...shippingAddresses.slice(id+1)
+ ]);
+ }
+ }
+
return (
<div className={"editor-wrapper"}>
<p>{props.heading}</p>
@@ -77,14 +116,35 @@ const ClientEditor = (props) => {
</label>
</div>
- <ContactEditor heading={"Contact Details"}/>
+ <ContactEditor
+ heading={"Contact Details"}
+ contact={contact}
+ setContact={setContact} />
<AddressEditor
heading={"Billing Address"}
isBillingAddress={true}
billingAddressIsShipping={shipToBillingAddress}
- callback={setShipToBillingAddress} />
-
- <span className={"buttons"}>
+ setShipToBillingAddress={setShipToBillingAddress}
+ address={billingAddress}
+ setAddress={setBillingAddress} />
+
+ {shippingAddresses.length > 0 && shippingAddresses.map((i, id) =>
+ <AddressEditor
+ key={id}
+ heading={`Shipping Address ${shippingAddresses.length === 1 ? '' : id + 1}`}
+ address={i}
+ deleteAddress={() => handleShippingAddressDelete(id)}
+ setAddress={(data) => handleShippingAddressUpdate(id, data)} />
+ )}
+
+ <span className={`buttons ${shippingAddresses.length > 0 ? 'wide' : ''}`}>
+ {shippingAddresses.length > 0 &&
+ <input
+ className={"wide-button"}
+ type="button"
+ value="Add Shipping Address"
+ onClick={()=> setShippingAddresses([...shippingAddresses, new Address()])}/>
+ }
<input type="button" value="Clear" onClick={clearAll}/>
<input type="button" value="Cancel" onClick={handleCancel}/>
<input type="submit" value="Save" />
diff --git a/src/components/editors/contact-editor.js b/src/components/editors/contact-editor.js
index 325f4f4..3c9a1f9 100644
--- a/src/components/editors/contact-editor.js
+++ b/src/components/editors/contact-editor.js
@@ -18,13 +18,22 @@
import { Contact } from './../../classes/client';
import './scss/contact-editor.scss';
-import { useState } from 'react';
+import { useState, useEffect } from 'react';
const ContactEditor = (props) => {
- const [name, setName] = useState("");
- const [phones, setPhones] = useState("");
- const [emails, setEmails] = useState("");
- const [website, setWebsite] = useState("");
+ const handleInput = (field, event) => {
+ const c = new Contact();
+ const val = event.target.value;
+ c.Name = field === "name" ? val : props.contact.Name;
+ c.Website = field === "website" ? val : props.contact.Website;
+ c.Phones = field === "phones"
+ ? (val.length === 0 ? [] : val.split("\n"))
+ : props.contact.Phones;
+ c.Emails = field === "emails"
+ ? (val.length === 0 ? [] : val.split("\n"))
+ : props.contact.Emails;
+ props.setContact(c);
+ }
return (
<div className={"contact-editor"}>
@@ -35,28 +44,36 @@ const ContactEditor = (props) => {
Contact Name:
<input
type="text" name="name"
- value={name} onChange={(e) => setName(e.target.value)} />
+ value={props.contact.Name} onChange={(e) => handleInput("name", e)} />
</label>
<label>
Website:
<input
type="text" name="name"
- value={website} onChange={(e) => setWebsite(e.target.value)} />
+ value={props.contact.Website} onChange={(e) => handleInput("website", e)} />
</label>
<label>
Phone:
<textarea
type="text" name="name"
- value={phones} onChange={(e) => setPhones(e.target.value)} />
+ value={props.contact.Phones.length > 0
+ ? props.contact.Phones.forEach(i => i)
+ : ""
+ }
+ onChange={(e) => handleInput("phones", e)} />
</label>
<label>
E-mail:
<textarea
type="text" name="name"
- value={emails} onChange={(e) => setEmails(e.target.value)} />
+ value={props.contact.Emails.length > 0
+ ? props.contact.Emails.forEach(i => i)
+ : ""
+ }
+ onChange={(e) => handleInput("emails", e)} />
</label>
</div>
</div>
diff --git a/src/components/editors/scss/colors.scss b/src/components/editors/scss/_colors.scss
index 4e5b1c2..994dcf7 100644
--- a/src/components/editors/scss/colors.scss
+++ b/src/components/editors/scss/_colors.scss
@@ -22,3 +22,5 @@ $fgColor: white;
$fgColorAlt: black;
$inputBackgroundColor: #00000000;
+
+$warningColor: #ed4683;
diff --git a/src/components/editors/scss/address-editor.scss b/src/components/editors/scss/address-editor.scss
index 49b0a0a..50db4a9 100644
--- a/src/components/editors/scss/address-editor.scss
+++ b/src/components/editors/scss/address-editor.scss
@@ -20,6 +20,8 @@
.address-editor {
min-height: 18rem;
+ position: relative;
+
.heading {
font-size: 1.1rem;
color: $primaryAccentColor;
@@ -27,6 +29,20 @@
align: center;
}
+ .remove-button {
+ opacity: 0;
+ position: absolute;
+ font-size: 2rem;
+ top: 0.8rem;
+ right: 1rem;
+ color: $secondaryAccentColor;
+ transition: opacity 0.2s, color 0.3s;
+ }
+
+ .remove-button:hover {
+ color: $warningColor;
+ }
+
.checkbox-label {
border: none;
max-width: none;
@@ -63,3 +79,7 @@
}
}
}
+
+.address-editor:hover .remove-button {
+ opacity: 1;
+}
diff --git a/src/components/editors/scss/client-editor.scss b/src/components/editors/scss/client-editor.scss
index 52b7189..30919fd 100644
--- a/src/components/editors/scss/client-editor.scss
+++ b/src/components/editors/scss/client-editor.scss
@@ -25,4 +25,11 @@
display: flex;
justify-content: space-around;
}
+
+ .buttons.wide {
+ width: 24.5rem;
+ input.wide-button {
+ width: 11rem;
+ }
+ }
}
diff --git a/src/views/manage/clients.js b/src/views/manage/clients.js
index 74c1a38..4493902 100644
--- a/src/views/manage/clients.js
+++ b/src/views/manage/clients.js
@@ -38,7 +38,7 @@ const ManageClientsPage = () => {
return (
<>
- <ClientEditor heading={"Add New Client"} callback={updateList}/>
+ <ClientEditor heading={"Add New Client"} successCallback={updateList}/>
<hr/>
{false && <ClientTable refresh={updateList} items={allClients}/>}
</>