aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVidhu Kant Sharma <vidhukant@vidhukant.xyz>2022-12-04 21:37:52 +0530
committerVidhu Kant Sharma <vidhukant@vidhukant.xyz>2022-12-04 21:37:52 +0530
commit1139da4da7f1bb0ee4a66d420e690beed36832c2 (patch)
treeb0e5fca2f13c691b0c42543d98a747289f527e52
parentbb38d843de17bb0b206a663e008c5dbb37f04708 (diff)
added notification system
-rw-r--r--package.json1
-rw-r--r--public/waifu_logo.pngbin0 -> 778004 bytes
-rw-r--r--src/App.js6
-rw-r--r--src/App.scss19
-rw-r--r--src/_colors.scss2
-rw-r--r--src/classes/item.js8
-rw-r--r--src/classes/notifications.js (renamed from src/_styles.scss)33
-rw-r--r--src/components/editors/brand-editor.js15
-rw-r--r--src/components/editors/client-editor.js24
-rw-r--r--src/components/editors/item-editor.js24
-rw-r--r--src/components/editors/multi-address-editor.js1
-rw-r--r--src/components/navbar/navbar.js2
-rw-r--r--src/components/navbar/navbar.scss3
-rw-r--r--src/components/tables/brand-table.js20
-rw-r--r--src/components/tables/client-table.js24
-rw-r--r--src/components/tables/item-table.js20
-rw-r--r--src/notifications_styles/_containers.scss100
-rw-r--r--src/notifications_styles/_types.scss91
-rw-r--r--src/notifications_styles/_variables.scss31
-rw-r--r--src/notifications_styles/notification.scss110
-rw-r--r--src/views/homepage.js15
-rw-r--r--src/views/login/register.js17
-rw-r--r--src/views/manage/brands.js12
-rw-r--r--src/views/manage/clients.js10
-rw-r--r--src/views/manage/items.js12
-rw-r--r--yarn.lock17
26 files changed, 540 insertions, 77 deletions
diff --git a/package.json b/package.json
index 50223ea..83eb09b 100644
--- a/package.json
+++ b/package.json
@@ -16,6 +16,7 @@
"node-sass": "^7.0.3",
"react": "^18.2.0",
"react-dom": "^18.2.0",
+ "react-notifications-component": "^4.0.1",
"react-router-dom": "^6.4.1",
"react-scripts": "5.0.1",
"web-vitals": "^2.1.0"
diff --git a/public/waifu_logo.png b/public/waifu_logo.png
new file mode 100644
index 0000000..11145bb
--- /dev/null
+++ b/public/waifu_logo.png
Binary files differ
diff --git a/src/App.js b/src/App.js
index 9fd5081..8dfbf81 100644
--- a/src/App.js
+++ b/src/App.js
@@ -16,7 +16,9 @@
*/
import { BrowserRouter, Route, Routes } from "react-router-dom";
-import './App.scss';
+import { ReactNotifications } from "react-notifications-component";
+import "./notifications_styles/notification.scss"
+
import Navbar from './components/navbar/navbar';
import HomePage from './views/homepage';
import RegisterPage from './views/login/register';
@@ -27,11 +29,13 @@ import ManageItemsPage from './views/manage/items';
import ManageClientsPage from './views/manage/clients';
import ManageBrandsPage from './views/manage/brands';
import ManageInvoicesPage from './views/manage/invoices';
+import './App.scss';
const App = () => {
return (
<BrowserRouter>
<Navbar/>
+ <ReactNotifications />
<main>
<Routes>
<Route exact path="/" element={<HomePage/>}/>
diff --git a/src/App.scss b/src/App.scss
index 1b37ffe..f7fdf46 100644
--- a/src/App.scss
+++ b/src/App.scss
@@ -86,3 +86,22 @@ $selectionColor: rgba($primaryAccentColor, 0.9)
}
}
+.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: 1200px;
+ z-index: 6;
+ }
+}
diff --git a/src/_colors.scss b/src/_colors.scss
index 08a700c..0b73ab9 100644
--- a/src/_colors.scss
+++ b/src/_colors.scss
@@ -30,6 +30,8 @@ $darkgray: #232627;
$black: black;
$warningColor: #ed4683;
+$infoColor: #e8b454;
+$successColor: #0ec685;
$fgColor: $white;
$darkFgColor: $black;
diff --git a/src/classes/item.js b/src/classes/item.js
index 63f65ca..53f4bcd 100644
--- a/src/classes/item.js
+++ b/src/classes/item.js
@@ -54,25 +54,25 @@ export class InvoiceItem extends Item {
export const saveItem = (item, ok, fail) => {
axios.post("/item/new", item)
.then(res => ok())
- .catch((err) => fail())
+ .catch(err => fail(err))
}
export const deleteItem = (id, ok, fail) => {
axios.delete(`/item/${id}`)
.then(res => ok())
- .catch((err) => fail())
+ .catch(err => fail(err))
}
export const getAllItems = (ok, fail) => {
axios.get("/item/all")
.then(res => ok(res.data))
- .catch(err => fail())
+ .catch(err => fail(err))
}
export const editItem = (item, ok, fail) => {
axios.put(`/item/${item.Id}`, item)
.then(res => ok())
- .catch(err => fail());
+ .catch(err => fail(err));
}
export const getDiscountValue = (item) =>
diff --git a/src/_styles.scss b/src/classes/notifications.js
index 064b9c6..5ffdec8 100644
--- a/src/_styles.scss
+++ b/src/classes/notifications.js
@@ -15,26 +15,17 @@
* 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: 1200px;
- z-index: 6;
- }
+// TODO: load defaults from config
+export function notificationConfig(type, duration=3000) {
+ return {
+ type: type,
+ insert: "top",
+ container: "top-right",
+ animationIn: ["animate__animated", "animate__fadeIn"],
+ animationOut: ["animate__animated", "animate__fadeOut"],
+ dismiss: {
+ duration: duration,
+ onScreen: true
}
+ };
}
diff --git a/src/components/editors/brand-editor.js b/src/components/editors/brand-editor.js
index 7796c68..2b7806e 100644
--- a/src/components/editors/brand-editor.js
+++ b/src/components/editors/brand-editor.js
@@ -16,8 +16,10 @@
*/
import { Brand, saveBrand, editBrand } from './../../classes/brand'
+import { notificationConfig } from "./../../classes/notifications";
import './scss/brand-editor.scss'
+import { Store } from "react-notifications-component";
import { useState } from 'react';
const BrandEditor = (props) => {
@@ -36,13 +38,22 @@ const BrandEditor = (props) => {
}
const handleSuccess = () => {
+ Store.addNotification({
+ title: `Successfully ${props.editing ? "edited" : "added"} brand!`,
+ message: `${name} has successfully been ${props.editing ? "edited" : "saved"}.`,
+ ...notificationConfig("success")
+ });
clearAll();
props.callback();
props.editing && props.hide();
}
- const handleFail = () => {
- alert("fail");
+ const handleFail = err => {
+ Store.addNotification({
+ title: "An error occoured",
+ message: `Failed to ${props.editing ? "edit" : "add"} brand '${name}'. ${err.message}`,
+ ...notificationConfig("danger")
+ });
}
const clearAll = () => {
diff --git a/src/components/editors/client-editor.js b/src/components/editors/client-editor.js
index 9a752c7..96ab639 100644
--- a/src/components/editors/client-editor.js
+++ b/src/components/editors/client-editor.js
@@ -16,11 +16,13 @@
*/
import { Client, saveClient, editClient, Contact, Address } from './../../classes/client';
+import { notificationConfig } from "./../../classes/notifications";
import MultiAddressEditor from './multi-address-editor';
import AddressEditor from './address-editor';
import ContactEditor from './contact-editor';
import './scss/client-editor.scss';
+import { Store } from "react-notifications-component";
import { useState, useEffect } from 'react';
const ClientEditor = (props) => {
@@ -37,8 +39,8 @@ const ClientEditor = (props) => {
// will delete existing shipping addresses if false
useEffect(() =>
- setShippingAddresses(shipToBillingAddress ? [] : (shippingAddresses.length > 0 ? shippingAddresses : [new Address()]))
- , [shipToBillingAddress, shippingAddresses]);
+ setShippingAddresses(i => shipToBillingAddress ? [] : (i.length > 0 ? i : [new Address()]))
+ , [shipToBillingAddress]);
const handleSubmit = (e) => {
e.preventDefault();
@@ -63,15 +65,23 @@ const ClientEditor = (props) => {
}
const handleSuccess = (res) => {
- console.log("Successfully saved client", res)
+ Store.addNotification({
+ title: `Successfully ${props.editing ? "edited" : "added"} client!`,
+ message: `${name} has successfully been ${props.editing ? "edited" : "saved"}.`,
+ ...notificationConfig("success")
+ });
clearAll();
- props.successCallback();
+ props.successCallback && props.successCallback();
props.editing && props.hide();
}
- const handleFail = (err) => {
- alert("error while saving client. please check logs");
- console.log(err);
+ const handleFail = err => {
+ Store.addNotification({
+ title: "An error occoured",
+ message: `Failed to edit client ${name}. ${err.message}`,
+ ...notificationConfig("danger")
+ });
+ console.log(err)
}
const clearAll = () => {
diff --git a/src/components/editors/item-editor.js b/src/components/editors/item-editor.js
index be0ac4f..c1d260d 100644
--- a/src/components/editors/item-editor.js
+++ b/src/components/editors/item-editor.js
@@ -17,9 +17,11 @@
import { Item, saveItem, editItem } from './../../classes/item';
import { Brand, getAllBrands } from './../../classes/brand';
+import { notificationConfig } from "./../../classes/notifications";
import './scss/item-editor.scss';
import { useState, useEffect } from 'react';
+import { Store } from "react-notifications-component";
const ItemEditor = (props) => {
const [name, setName] = useState(props.item.Name);
@@ -37,8 +39,13 @@ const ItemEditor = (props) => {
// get saved brands from API
// needed by the brands dropdown menu
useEffect(() => {
- // TODO: handle error
- getAllBrands(setSavedBrands, () => {});
+ getAllBrands(setSavedBrands, err => {
+ Store.addNotification({
+ title: "Error while getting Brands list.",
+ message: err.message,
+ ...notificationConfig("danger")
+ });
+ });
}, [])
const handleSubmit = (e) => {
@@ -76,13 +83,22 @@ const ItemEditor = (props) => {
}
const handleSuccess = () => {
+ Store.addNotification({
+ title: `Successfully ${props.editing ? "edited" : "added"} item!`,
+ message: `${name} has successfully been ${props.editing ? "edited" : "saved"}.`,
+ ...notificationConfig("success")
+ });
clearAll();
props.callback();
props.editing && props.hide();
}
- const handleFail = () => {
- alert("fail");
+ const handleFail = err => {
+ Store.addNotification({
+ title: "An error occoured",
+ message: `Failed to ${props.editing ? "edit" : "add"} item ${name}. ${err.message}`,
+ ...notificationConfig("danger")
+ });
}
const handleBrandSelect = (e) => {
diff --git a/src/components/editors/multi-address-editor.js b/src/components/editors/multi-address-editor.js
index 1159fab..1ea58b7 100644
--- a/src/components/editors/multi-address-editor.js
+++ b/src/components/editors/multi-address-editor.js
@@ -18,7 +18,6 @@
import AddressEditor from './address-editor';
const MultiAddressEditor = ({addresses, setAddresses, setShipToBillingAddress}) => {
- console.log(addresses)
const handleChange = (id, data) => {
const newAddresses = [...addresses];
newAddresses[id] = {
diff --git a/src/components/navbar/navbar.js b/src/components/navbar/navbar.js
index bf909e7..1254952 100644
--- a/src/components/navbar/navbar.js
+++ b/src/components/navbar/navbar.js
@@ -58,7 +58,7 @@ const Navbar = () => {
<div className={"navbar"}>
<span className={"logo"}>
<Link to="/">
- <img src="/logo.png" alt="App Logo"/>
+ <img src="/waifu_logo.png" alt="App Logo"/>
</Link>
</span>
diff --git a/src/components/navbar/navbar.scss b/src/components/navbar/navbar.scss
index 8173249..a7f560e 100644
--- a/src/components/navbar/navbar.scss
+++ b/src/components/navbar/navbar.scss
@@ -52,8 +52,9 @@
.logo {
flex: 1;
+ height: 3.5rem;
img {
- height: 4rem;
+ height: 3.5rem;
}
}
}
diff --git a/src/components/tables/brand-table.js b/src/components/tables/brand-table.js
index db8272c..3b38a5c 100644
--- a/src/components/tables/brand-table.js
+++ b/src/components/tables/brand-table.js
@@ -17,6 +17,9 @@
import './scss/brand-table.scss';
import { deleteBrand } from './../../classes/brand';
+import { notificationConfig } from "./../../classes/notifications";
+
+import { Store } from "react-notifications-component";
const BrandTable = (props) => {
const handleEdit = (b) => {
@@ -25,15 +28,24 @@ const BrandTable = (props) => {
const handleDelete = (b) => {
// TODO: add confirmation prompt
- deleteBrand(b.Id, handleDelSuccess, handleDelFail);
+ deleteBrand(b.Id, () => handleDelSuccess(b), err => handleDelFail(b, err));
}
- const handleDelSuccess = () => {
+ const handleDelSuccess = b => {
+ Store.addNotification({
+ title: "Successfully deleted brand!",
+ message: `Brand '${b.Name}' has successfully been deleted.`,
+ ...notificationConfig("success")
+ });
props.refresh();
}
- const handleDelFail = () => {
- alert("fail")
+ const handleDelFail = (b, err) => {
+ Store.addNotification({
+ title: "An error occoured",
+ message: `Failed to delete brand '${b.Name}'. ${err.message}`,
+ ...notificationConfig("danger")
+ });
}
return (
diff --git a/src/components/tables/client-table.js b/src/components/tables/client-table.js
index cea612d..1f51c88 100644
--- a/src/components/tables/client-table.js
+++ b/src/components/tables/client-table.js
@@ -17,23 +17,35 @@
import './scss/client-table.scss';
import { deleteClient } from './../../classes/client';
+import { notificationConfig } from "./../../classes/notifications";
+
+import { Store } from "react-notifications-component";
const ClientTable = (props) => {
- const handleEdit = (c) => {
+ const handleEdit = c => {
props.setClientToEdit(c)
}
- const handleDelete = (c) => {
+ const handleDelete = c => {
// TODO: add confirmation prompt
- deleteClient(c.Id, handleDelSuccess, handleDelFail);
+ deleteClient(c.Id, () => handleDelSuccess(c), err => handleDelFail(c, err));
}
- const handleDelSuccess = () => {
+ const handleDelSuccess = c => {
+ Store.addNotification({
+ title: "Successfully deleted client!",
+ message: `Client '${c.Name}' has successfully been deleted.`,
+ ...notificationConfig("success")
+ });
props.refresh();
}
- const handleDelFail = () => {
- alert("fail")
+ const handleDelFail = (c, err) => {
+ Store.addNotification({
+ title: "An error occoured",
+ message: `Failed to delete client '${c.Name}'. ${err.message}`,
+ ...notificationConfig("danger")
+ });
}
return (
diff --git a/src/components/tables/item-table.js b/src/components/tables/item-table.js
index 2fb7210..1b47f6f 100644
--- a/src/components/tables/item-table.js
+++ b/src/components/tables/item-table.js
@@ -17,6 +17,9 @@
import './scss/table.scss';
import { deleteItem } from './../../classes/item';
+import { notificationConfig } from "./../../classes/notifications";
+
+import { Store } from "react-notifications-component";
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import { faPencil, faTrashCan } from '@fortawesome/free-solid-svg-icons'
@@ -27,15 +30,24 @@ const ItemTable = (props) => {
const handleDelete = (i) => {
// TODO: add confirmation prompt
- deleteItem(i.Id, handleDelSuccess, handleDelFail);
+ deleteItem(i.Id, () => handleDelSuccess(i), err => handleDelFail(i, err));
}
- const handleDelSuccess = () => {
+ const handleDelSuccess = i => {
+ Store.addNotification({
+ title: "Successfully deleted item!",
+ message: `Item '${i.Name}' has successfully been deleted.`,
+ ...notificationConfig("success")
+ });
props.refresh();
}
- const handleDelFail = () => {
- alert("fail")
+ const handleDelFail = (i, err) => {
+ Store.addNotification({
+ title: "An error occoured",
+ message: `Failed to delete item '${i.Name}'. ${err.message}`,
+ ...notificationConfig("danger")
+ });
}
return (
diff --git a/src/notifications_styles/_containers.scss b/src/notifications_styles/_containers.scss
new file mode 100644
index 0000000..b0f00a4
--- /dev/null
+++ b/src/notifications_styles/_containers.scss
@@ -0,0 +1,100 @@
+.rnc__notification-container--top-center,
+.rnc__notification-container--top-left,
+.rnc__notification-container--top-right,
+.rnc__notification-container--bottom-center,
+.rnc__notification-container--bottom-left,
+.rnc__notification-container--bottom-right,
+.rnc__notification-container--center,
+.rnc__notification-container--top-full,
+.rnc__notification-container--bottom-full {
+ min-width: 325px;
+ position: absolute;
+ pointer-events: all;
+}
+
+.rnc__notification-container--center,
+.rnc__notification-container--top-center,
+.rnc__notification-container--bottom-center {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ flex-direction: column;
+ left: calc(50% - 175px);
+}
+
+.rnc__notification-container--center,
+.rnc__notification-container--top-center,
+.rnc__notification-container--bottom-center {
+ max-width: 350px;
+}
+
+.rnc__notification-container--center {
+ top: 20px;
+ height: 100%;
+ pointer-events: none;
+}
+
+.rnc__notification-container--top-full,
+.rnc__notification-container--bottom-full {
+ width: 100%;
+ min-width: 100%;
+}
+
+.rnc__notification-container--bottom-full {
+ bottom: 0;
+}
+
+.rnc__util--flex-center {
+ min-width: 325px;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ flex-direction: column;
+ pointer-events: all;
+}
+
+.rnc__notification-container--top-center {
+ top: 20px;
+}
+.rnc__notification-container--bottom-center {
+ bottom: 20px;
+}
+
+.rnc__notification-container--top-left {
+ left: 20px;
+ top: 20px;
+}
+
+.rnc__notification-container--top-right {
+ right: 20px;
+ top: 20px;
+}
+
+.rnc__notification-container--bottom-left {
+ left: 20px;
+ bottom: 20px;
+}
+
+.rnc__notification-container--bottom-right {
+ bottom: 20px;
+ right: 20px;
+}
+
+.rnc__notification-container--mobile-top,
+.rnc__notification-container--mobile-bottom {
+ pointer-events: all;
+ position: absolute;
+}
+
+.rnc__notification-container--mobile-top {
+ right: 20px;
+ left: 20px;
+ top: 20px;
+}
+
+.rnc__notification-container--mobile-bottom {
+ right: 20px;
+ left: 20px;
+ bottom: 20px;
+ margin-bottom: -15px;
+}
diff --git a/src/notifications_styles/_types.scss b/src/notifications_styles/_types.scss
new file mode 100644
index 0000000..ccfbee2
--- /dev/null
+++ b/src/notifications_styles/_types.scss
@@ -0,0 +1,91 @@
+@import "_variables.scss";
+
+.rnc__notification-item--default {
+ background-color: $default;
+ border-left: 8px solid $default_dark;
+
+ .rnc__notification-timer {
+ background-color: $default_timer;
+ }
+ .rnc__notification-timer-filler {
+ background-color: $default_timer_filler;
+ }
+ .rnc__notification-close-mark {
+ background-color: $default;
+ }
+}
+
+.rnc__notification-item--success {
+ background-color: $success;
+ border-left: 8px solid $success_dark;
+
+ .rnc__notification-timer {
+ background-color: $success_timer;
+ }
+ .rnc__notification-timer-filler {
+ background-color: $success_timer_filler;
+ }
+ .rnc__notification-close-mark {
+ background-color: $success;
+ }
+}
+
+.rnc__notification-item--danger {
+ background-color: $danger;
+ border-left: 8px solid $danger_dark;
+
+ .rnc__notification-timer {
+ background-color: $danger_timer;
+ }
+ .rnc__notification-timer-filler {
+ background-color: $danger_timer_filler;
+ }
+ .rnc__notification-close-mark {
+ background-color: $danger;
+ }
+}
+
+.rnc__notification-item--info {
+ background-color: $info;
+ border-left: 8px solid $info_dark;
+
+ .rnc__notification-timer {
+ background-color: $info_timer;
+ }
+ .rnc__notification-timer-filler {
+ background-color: $info_timer_filler;
+ }
+ .rnc__notification-close-mark {
+ background-color: $info;
+ }
+}
+
+.rnc__notification-item--warning {
+ background-color: $warning;
+ border-left: 8px solid $warning_dark;
+
+ .rnc__notification-timer {
+ background-color: $warning_timer;
+ }
+ .rnc__notification-timer-filler {
+ background-color: $warning_timer_filler;
+ }
+ .rnc__notification-close-mark {
+ background-color: $warning;
+ }
+}
+
+.rnc__notification-item--awesome {
+ background-color: $awesome;
+ border-left: 8px solid $awesome_dark;
+
+ .rnc__notification-timer {
+ background-color: $awesome_timer;
+ }
+ .rnc__notification-timer-filler {
+ background-color: $awesome_timer_filler;
+ }
+ .rnc__notification-close-mark {
+ background-color: $awesome;
+ }
+} \ No newline at end of file
diff --git a/src/notifications_styles/_variables.scss b/src/notifications_styles/_variables.scss
new file mode 100644
index 0000000..a65c811
--- /dev/null
+++ b/src/notifications_styles/_variables.scss
@@ -0,0 +1,31 @@
+@import "../colors";
+
+$default: $altBackgroundColor !default;
+$default_dark: $primaryAccentColor !default;
+$default_timer: $backgroundColor !default;
+$default_timer_filler: $primaryAccentColor !default;
+
+$success: $altBackgroundColor !default;
+$success_dark: $successColor !default;
+$success_timer: $backgroundColor !default;
+$success_timer_filler: $successColor !default;
+
+$danger: $altBackgroundColor !default;
+$danger_dark: $warningColor !default;
+$danger_timer: $backgroundColor !default;
+$danger_timer_filler: $warningColor !default;
+
+$warning: $altBackgroundColor !default;
+$warning_dark: $infoColor !default;
+$warning_timer: $backgroundColor !default;
+$warning_timer_filler: $infoColor !default;
+
+$info: $default;
+$info_dark: $default_dark;
+$info_timer: $default_timer;
+$info_timer_filler: $default_timer_filler;
+
+$awesome: $success;
+$awesome_dark: $success_dark;
+$awesome_timer: $success_timer;
+$awesome_timer_filler: $success_timer_filler;
diff --git a/src/notifications_styles/notification.scss b/src/notifications_styles/notification.scss
new file mode 100644
index 0000000..33d8efb
--- /dev/null
+++ b/src/notifications_styles/notification.scss
@@ -0,0 +1,110 @@
+@import "./_containers.scss";
+@import "./_types.scss";
+
+@keyframes timer {
+ 0% { width: 100%; }
+ 100% { width: 0%; }
+}
+
+.rnc__base {
+ position: fixed;
+ z-index: 9000;
+ pointer-events: none;
+ width: 100%;
+ height: 100%;
+}
+
+.rnc__notification-item {
+ display: flex;
+ position: relative;
+ border-radius: 3px;
+ margin-bottom: 15px;
+ box-shadow: 1px 3px 4px rgba(0, 0, 0, 0.2);
+ cursor: pointer;
+}
+
+.rnc__notification-container--top-full .rnc__notification-item,
+.rnc__notification-container--bottom-full .rnc__notification-item {
+ margin-bottom: 0;
+ border-radius: 0;
+}
+
+.rnc__notification-container--top-full .rnc__notification,
+.rnc__notification-container--bottom-full .rnc__notification {
+ width: 100% !important;
+}
+
+.rnc__notification-timer {
+ width: 100%;
+ height: 3px;
+ margin-top: 10px;
+ border-radius: 5px;
+}
+.rnc__notification-timer-filler {
+ height: 3px;
+ border-radius: 5px;
+}
+.rnc__notification-title {
+ color: #fff;
+ font-weight: 700;
+ font-size: 14px;
+ margin-top: 5px;
+ margin-bottom: 5px;
+}
+.rnc__notification-message {
+ color: #fff;
+ max-width: calc(100% - 15px);
+ font-size: 14px;
+ line-height: 150%;
+ word-wrap: break-word;
+ margin-bottom: 0;
+ margin-top: 0;
+}
+.rnc__notification-content {
+ padding: 8px 15px;
+ display: inline-block;
+ width: 100%;
+}
+.rnc__notification-close-mark {
+ width: 18px;
+ height: 18px;
+ border-radius: 50%;
+ display: inline-block;
+ position: absolute;
+ right: 10px;
+ top: 10px;
+
+ &::after {
+ content: '\D7';
+ position: absolute;
+ transform: translate(-50%, -50%);
+ color: #fff;
+ font-size: 12px;
+ left: 50%;
+ top: 50%;
+ }
+}
+
+.rnc__notification-container--mobile-top .rnc__notification-item,
+.rnc__notification-container--mobile-bottom .rnc__notification-item,
+.rnc__notification-container--mobile-top .notification,
+.rnc__notification-container--mobile-bottom .notification {
+ max-width: 100%;
+ width: 100%;
+}
+
+.rnc__notification-container--top-right .notification,
+.rnc__notification-container--bottom-right .notification {
+ margin-left: auto;
+}
+
+.rnc__notification-container--top-left .notification,
+.rnc__notification-container--bottom-left .notification {
+ margin-right: auto;
+}
+
+.rnc__notification-container--mobile-top .notification,
+.rnc__notification-container--mobile-bottom .notification {
+ margin-left: auto;
+ margin-right: auto;
+} \ No newline at end of file
diff --git a/src/views/homepage.js b/src/views/homepage.js
index a9cdb50..92f9544 100644
--- a/src/views/homepage.js
+++ b/src/views/homepage.js
@@ -15,9 +15,22 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
-import { Link } from 'react-router-dom';
+import { Link, useNavigate } from 'react-router-dom';
+import { notificationConfig } from "../classes/notifications";
+import { Store } from "react-notifications-component";
const HomePage = () => {
+ // this is temporary, just for testing
+ // TODO: find better way to do this
+ const navigate = useNavigate();
+ if (!localStorage.getItem("accessToken")) {
+ Store.addNotification({
+ title: "You are not logged in",
+ message: "You need to log in before accessing this page.",
+ ...notificationConfig("default")
+ });
+ navigate("/login")
+ }
return (
<>
<h1>Welcome to OpenBills</h1>
diff --git a/src/views/login/register.js b/src/views/login/register.js
index c747f59..1b1755b 100644
--- a/src/views/login/register.js
+++ b/src/views/login/register.js
@@ -17,12 +17,15 @@
import './scss/login.scss';
import { User, validateEmail, validateUsername, validatePassword, saveUser } from '../../classes/user';
+import { notificationConfig } from "./../../classes/notifications";
+import { Store } from "react-notifications-component";
import { Link } from 'react-router-dom';
import { useState } from 'react';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import { faEye } from '@fortawesome/free-solid-svg-icons'
+
const RegisterPage = () => {
const [user, setUser] = useState(new User());
const [showPassword, setShowPassword] = useState(false);
@@ -41,11 +44,19 @@ const RegisterPage = () => {
}
const handleSuccess = () => {
- alert("yay")
+ Store.addNotification({
+ title: "Created new account",
+ message: `Welcome to OpenBills, ${user.UserName}!`,
+ ...notificationConfig("default")
+ });
}
- const handleError = () => {
- alert("fail")
+ const handleError = err => {
+ Store.addNotification({
+ title: "An error occoured",
+ message: `Failed to create new account. ${err.message}`,
+ ...notificationConfig("danger")
+ });
}
return (
diff --git a/src/views/manage/brands.js b/src/views/manage/brands.js
index dad21e2..4ab3924 100644
--- a/src/views/manage/brands.js
+++ b/src/views/manage/brands.js
@@ -16,18 +16,26 @@
*/
import { useState, useEffect } from 'react';
+import { Store } from "react-notifications-component";
import './scss/management-page.scss'
import { Brand, getAllBrands } from '../../classes/brand';
import BrandEditor from './../../components/editors/brand-editor';
import BrandTable from './../../components/tables/brand-table';
+import { notificationConfig } from "./../../classes/notifications";
const ManageBrandsPage = () => {
const [brandToEdit, setBrandToEdit] = useState(new Brand());
const [allBrands, setAllBrands] = useState([]);
- // TODO: handle error
+
const updateList = () =>
- getAllBrands(setAllBrands, () => {});
+ getAllBrands(setAllBrands, err => {
+ Store.addNotification({
+ title: "Error while getting Brands list.",
+ message: err.message,
+ ...notificationConfig("danger")
+ });
+ });
useEffect(() => {
updateList();
diff --git a/src/views/manage/clients.js b/src/views/manage/clients.js
index 8445d80..89e5ade 100644
--- a/src/views/manage/clients.js
+++ b/src/views/manage/clients.js
@@ -20,18 +20,26 @@
*/
import { useState, useEffect } from 'react';
+import { Store } from "react-notifications-component";
import './scss/management-page.scss';
import { Client, getAllClients } from '../../classes/client';
import ClientEditor from './../../components/editors/client-editor';
import ClientTable from './../../components/tables/client-table';
+import { notificationConfig } from "./../../classes/notifications";
const ManageClientsPage = () => {
const [clientToEdit, setClientToEdit] = useState(new Client());
const [allClients, setAllClients] = useState([]);
// TODO: handle error
const updateList = () =>
- getAllClients(setAllClients, () => {});
+ getAllClients(setAllClients, err => {
+ Store.addNotification({
+ title: "Error while getting Clients list.",
+ message: err.message,
+ ...notificationConfig("danger")
+ });
+ });
useEffect(() => {
updateList();
diff --git a/src/views/manage/items.js b/src/views/manage/items.js
index 567be7c..2a862bc 100644
--- a/src/views/manage/items.js
+++ b/src/views/manage/items.js
@@ -20,18 +20,26 @@
*/
import { useState, useEffect } from 'react';
+import { Store } from "react-notifications-component";
import './scss/management-page.scss'
import { Item, getAllItems } from '../../classes/item';
import ItemEditor from './../../components/editors/item-editor';
import ItemTable from './../../components/tables/item-table';
+import { notificationConfig } from "./../../classes/notifications";
const ManageItemsPage = () => {
const [itemToEdit, setItemToEdit] = useState(new Item());
const [allItems, setAllItems] = useState([]);
- // TODO: handle error
+
const updateList = () =>
- getAllItems(setAllItems, () => {});
+ getAllItems(setAllItems, err => {
+ Store.addNotification({
+ title: "Error while getting Items list.",
+ message: err.message,
+ ...notificationConfig("danger")
+ });
+ });
useEffect(() => {
updateList();
diff --git a/yarn.lock b/yarn.lock
index c2626f1..e2e2464 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1210,11 +1210,6 @@
resolved "https://registry.yarnpkg.com/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.2.0.tgz#76467a94aa888aeb22aafa43eb6ff889df3a5a7f"
integrity sha512-rBevIsj2nclStJ7AxTdfsa3ovHb1H+qApwrxcTVo+NNdeJiB9V75hsKfrkG5AwNcRUNxrPPiScGYCNmLMoh8pg==
-"@fortawesome/fontawesome-common-types@6.2.1":
- version "6.2.1"
- resolved "https://registry.yarnpkg.com/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.2.1.tgz#411e02a820744d3f7e0d8d9df9d82b471beaa073"
- integrity sha512-Sz07mnQrTekFWLz5BMjOzHl/+NooTdW8F8kDQxjWwbpOJcnoSg4vUDng8d/WR1wOxM0O+CY9Zw0nR054riNYtQ==
-
"@fortawesome/fontawesome-svg-core@^6.2.0":
version "6.2.0"
resolved "https://registry.yarnpkg.com/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-6.2.0.tgz#11856eaf4dd1d865c442ddea1eed8ee855186ba2"
@@ -1222,13 +1217,6 @@
dependencies:
"@fortawesome/fontawesome-common-types" "6.2.0"
-"@fortawesome/free-regular-svg-icons@^6.2.1":
- version "6.2.1"
- resolved "https://registry.yarnpkg.com/@fortawesome/free-regular-svg-icons/-/free-regular-svg-icons-6.2.1.tgz#650e56d937755a8341f2eef258ecb6f95458820f"
- integrity sha512-wiqcNDNom75x+pe88FclpKz7aOSqS2lOivZeicMV5KRwOAeypxEYWAK/0v+7r+LrEY30+qzh8r2XDaEHvoLsMA==
- dependencies:
- "@fortawesome/fontawesome-common-types" "6.2.1"
-
"@fortawesome/free-solid-svg-icons@^6.2.0":
version "6.2.0"
resolved "https://registry.yarnpkg.com/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-6.2.0.tgz#8dcde48109354fd7a5ece8ea48d678bb91d4b5f0"
@@ -8176,6 +8164,11 @@ react-is@^18.0.0:
resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.2.0.tgz#199431eeaaa2e09f86427efbb4f1473edb47609b"
integrity sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==
+react-notifications-component@^4.0.1:
+ version "4.0.1"
+ resolved "https://registry.yarnpkg.com/react-notifications-component/-/react-notifications-component-4.0.1.tgz#c4cf71eb40375f346e2a4dc2b395a8590895d253"
+ integrity sha512-NRBkWO19AsXmN0b8YQ0L12eoCAhrnmIZtGm77ATWSfQEXPL5PYSyeACpx7tePP+R2De9b0IP4yk9vY4TtzC02w==
+
react-refresh@^0.11.0:
version "0.11.0"
resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.11.0.tgz#77198b944733f0f1f1a90e791de4541f9f074046"