Front integration of the notification component done

This commit is contained in:
Hugo Lextrait 2023-02-22 12:00:01 +01:00
parent fa7bc24fed
commit cb59b9eef8
8 changed files with 79 additions and 52 deletions

View File

@ -23,7 +23,7 @@ export default class Toasts {
private toastList: IToast[] = []; private toastList: IToast[] = [];
private uid: number = 0; private uid: number = 0;
private defaultTime: IToast["time"] = 40000; private defaultTime: IToast["time"] = 5000;
private defaultClosable: IToast["closable"] = true; private defaultClosable: IToast["closable"] = true;
private defaultPriority: IToast["priority"] = EToastPriority.LOW; private defaultPriority: IToast["priority"] = EToastPriority.LOW;

View File

@ -0,0 +1,5 @@
<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
<circle cx="6" cy="6" r="6" fill="#FFB017"/>
<path d="M6 3V5.66667" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<circle cx="6" cy="9" r="1" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 295 B

View File

@ -26,3 +26,12 @@
overflow-y: auto; overflow-y: auto;
} }
} }
.background{
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: transparent;
}

View File

@ -27,40 +27,43 @@ export default class NotificationModal extends React.Component<IProps, IState> {
public override render(): JSX.Element | null { public override render(): JSX.Element | null {
if (!this.props.isOpen) return null; if (!this.props.isOpen) return null;
return <div className={classes["root"]}> return <>
<div className={classes["notification-header"]}> <div className={classes["background"]} onClick={this.props.closeModal}/>
<Typography typo={ITypo.P_16}> <div className={classes["root"]}>
Notifications <div className={classes["notification-header"]}>
</Typography> <Typography typo={ITypo.P_16}>
<div className={classes["close-icon"]} onClick={this.props.closeModal}> Notifications
<Image src={CloseIcon} alt="Close notification modal" className={classes["close-icon"]}></Image> </Typography>
</div> <div className={classes["close-icon"]} onClick={this.props.closeModal}>
</div>; <Image src={CloseIcon} alt="Close notification modal" className={classes["close-icon"]}></Image>
</div>
</div>;
<div className={classes["notification-body"]}> <div className={classes["notification-body"]}>
<> <>
{Toasts.getInstance().toasts.length === 0 {Toasts.getInstance().toasts.length === 0
? ?
<div> <div>
<Typography typo={ITypo.P_16}>No notification yet</Typography> <Typography typo={ITypo.P_16}>No notification yet</Typography>
</div> </div>
: <ToastHandler />} : <ToastHandler />}
</> </>
</div>
</div> </div>
</div> </>
} }
public override componentDidMount() { public override componentDidMount() {
this.removeOnToastChange = Toasts.getInstance().onChange(this.handleToastChange); this.removeOnToastChange = Toasts.getInstance().onChange(this.handleToastChange);
} }
public override componentWillUnmount() { public override componentWillUnmount() {
this.removeOnToastChange(); this.removeOnToastChange();
} }
private handleToastChange(toastList: IToast[] | null) { private handleToastChange(toastList: IToast[] | null) {
this.setState({ this.setState({
toastList, toastList,
}); });
} }
} }

View File

@ -3,6 +3,7 @@
.root { .root {
.icon-container{ .icon-container{
position: relative; position: relative;
cursor: pointer;
.notification-icon{ .notification-icon{
height: 24px; height: 24px;
@ -12,10 +13,6 @@
position: absolute; position: absolute;
top: 0; top: 0;
right: 0; right: 0;
height: 12px;
width: 12px;
border-radius: 50%;
background-color: $orange-flash;
} }
} }
} }

View File

@ -2,37 +2,61 @@ import React from "react";
import classes from "./classes.module.scss"; import classes from "./classes.module.scss";
import Image from "next/image"; import Image from "next/image";
import NotificationIcon from "@Assets/icons/notification.svg"; import NotificationIcon from "@Assets/icons/notification.svg";
import Toasts from "@Front/Stores/Toasts"; import Toasts, { IToast } from "@Front/Stores/Toasts";
import NotificationModal from "./NotificationModal"; import NotificationModal from "./NotificationModal";
import InfoIcon from "@Assets/icons/info.svg";
type IProps = {}; type IProps = {};
type IState = { type IState = {
hasNotifications: boolean; hasNotifications: boolean;
isModalOpen: boolean; isModalOpen: boolean;
toastList: IToast[] | null;
}; };
export default class Notifications extends React.Component<IProps, IState> { export default class Notifications extends React.Component<IProps, IState> {
private removeOnToastChange: () => void = () => { };
constructor(props: IProps) { constructor(props: IProps) {
super(props); super(props);
this.state = { this.state = {
hasNotifications: true, isModalOpen: false,
isModalOpen: true, toastList: Toasts.getInstance().toasts, //TODO : Get from bbd
hasNotifications: Toasts.getInstance().toasts.length > 0, // TODO: Change this when we have notification stored in bbd, unread notifications
}; };
this.openModal = this.openModal.bind(this); this.openModal = this.openModal.bind(this);
this.closeModal = this.closeModal.bind(this); this.closeModal = this.closeModal.bind(this);
this.handleToastChange = this.handleToastChange.bind(this);
} }
public override render(): JSX.Element { public override render(): JSX.Element {
const hasNotifications = Toasts.getInstance().toasts.length;
console.log(hasNotifications)
return <div className={classes["root"]}> return <div className={classes["root"]}>
<div className={classes["icon-container"]} onClick={this.openModal}> <div className={classes["icon-container"]} onClick={this.openModal}>
<Image alt="notifications" src={NotificationIcon} className={classes["notification-icon"]} /> <Image alt="notifications" src={NotificationIcon} className={classes["notification-icon"]} />
{this.state.hasNotifications && <div className={classes["notification-dot"]}></div>} {this.state.hasNotifications &&
<Image className={classes["notification-dot"]} src={InfoIcon} alt="Unread notification" />
}
</div> </div>
{this.state.isModalOpen && <NotificationModal isOpen={this.state.isModalOpen} closeModal={this.closeModal} />} {this.state.isModalOpen && <NotificationModal isOpen={this.state.isModalOpen} closeModal={this.closeModal} />}
</div>; </div>;
} }
public override componentDidMount() {
this.removeOnToastChange = Toasts.getInstance().onChange(this.handleToastChange);
}
public override componentWillUnmount() {
this.removeOnToastChange();
}
private handleToastChange(toastList: IToast[] | null) {
this.setState({
toastList,
hasNotifications: toastList ? toastList.length > 0 : false
});
}
private openModal() { private openModal() {
this.setState({ isModalOpen: true }); this.setState({ isModalOpen: true });
}; };

View File

@ -1,14 +1,5 @@
@import "@Themes/constants.scss"; @import "@Themes/constants.scss";
// @keyframes loadbar-animation {
// from {
// transform: scaleX(1);
// }
// to {
// transform: scaleX(0);
// }
// }
@keyframes slide-left { @keyframes slide-left {
from { from {
opacity: 0; opacity: 0;

View File

@ -8,9 +8,7 @@ export default class Home extends BasePage {
return ( return (
<DefaultTemplate title={"HomePage"}> <DefaultTemplate title={"HomePage"}>
<div className={classes["root"]}> <div className={classes["root"]}>
<div style={{ fontSize: "20px" }}>JDJADJIZDIAZN?DIAZ?</div> <Typography typo={ITypo.H1}>HomePage</Typography>
<Typography typo={ITypo.H1}>COUCOU JE SUIS UNE TYPO</Typography>
<Typography typo={ITypo.H1Bis}>COUCOU JE SUIS UNE TYPO</Typography>
</div> </div>
</DefaultTemplate> </DefaultTemplate>
); );