This commit is contained in:
MyNameIsBatman 2021-06-22 15:14:41 -03:00
parent 351571fdbe
commit 00bdafb42d
11 changed files with 185 additions and 43 deletions

View File

@ -8,9 +8,12 @@ import { NotificationCenterMessageHandler } from './NotificationCenterMessageHan
import { NotificationCenterViewProps } from './NotificationCenterView.types'; import { NotificationCenterViewProps } from './NotificationCenterView.types';
import { initialNotificationCenter, NotificationCenterActions, NotificationCenterReducer } from './reducers/NotificationCenterReducer'; import { initialNotificationCenter, NotificationCenterActions, NotificationCenterReducer } from './reducers/NotificationCenterReducer';
import { BroadcastMessageNotification } from './utils/BroadcastMessageNotification'; import { BroadcastMessageNotification } from './utils/BroadcastMessageNotification';
import { HotelWillShutdownNotification } from './utils/HotelWillShutdownNotification';
import { ModeratorMessageNotification } from './utils/ModeratorMessageNotification'; import { ModeratorMessageNotification } from './utils/ModeratorMessageNotification';
import { MOTDNotification } from './utils/MOTDNotification'; import { MOTDNotification } from './utils/MOTDNotification';
import { NitroNotification } from './utils/Notification';
import { BroadcastMessageView } from './views/broadcast-message/BroadcastMessageView'; import { BroadcastMessageView } from './views/broadcast-message/BroadcastMessageView';
import { HotelWillShutdownView } from './views/hotel-will-shutdown/HotelWillShutdownView';
import { ModeratorMessageView } from './views/moderator-message/ModeratorMessageView'; import { ModeratorMessageView } from './views/moderator-message/ModeratorMessageView';
import { MOTDView } from './views/motd/MOTDView'; import { MOTDView } from './views/motd/MOTDView';
@ -59,7 +62,15 @@ export const NotificationCenterView: FC<NotificationCenterViewProps> = props =>
switch(action) switch(action)
{ {
case 'dismiss_alert': case 'dismiss_notification':
dispatchNotificationCenterState({
type: NotificationCenterActions.DISMISS_NOTIFICATION,
payload: {
id: value
}
});
return;
case 'remove_notification':
dispatchNotificationCenterState({ dispatchNotificationCenterState({
type: NotificationCenterActions.REMOVE_NOTIFICATION, type: NotificationCenterActions.REMOVE_NOTIFICATION,
payload: { payload: {
@ -68,28 +79,38 @@ export const NotificationCenterView: FC<NotificationCenterViewProps> = props =>
}); });
return; return;
} }
}, []); }, [ notificationCenterState, dispatchNotificationCenterState ]);
const mapNotifications = useCallback((notifications: NitroNotification[], inTray: boolean) =>
{
if(!notifications) return null;
return notifications.map(notification =>
{
if(!inTray && notification.dismissed) return null;
if(notification instanceof BroadcastMessageNotification)
return <BroadcastMessageView key={ notification.id } inTray={ inTray } notification={ notification as BroadcastMessageNotification } onButtonClick={ (action) => handleButtonClick(action, notification.id) } />
if(notification instanceof MOTDNotification)
return <MOTDView key={ notification.id } inTray={ inTray } notification={ notification as MOTDNotification } onButtonClick={ (action) => handleButtonClick(action, notification.id) } />
if(notification instanceof ModeratorMessageNotification)
return <ModeratorMessageView key={ notification.id } inTray={ inTray } notification={ notification as ModeratorMessageNotification } onButtonClick={ (action) => handleButtonClick(action, notification.id) } />
if(notification instanceof HotelWillShutdownNotification)
return <HotelWillShutdownView key={ notification.id } inTray={ inTray } notification={ notification as HotelWillShutdownNotification } onButtonClick={ (action) => handleButtonClick(action, notification.id) } />
else
return null;
});
}, [ handleButtonClick ]);
return ( return (
<NotificationCenterContextProvider value={ { notificationCenterState, dispatchNotificationCenterState } }> <NotificationCenterContextProvider value={ { notificationCenterState, dispatchNotificationCenterState } }>
<NotificationCenterMessageHandler /> <NotificationCenterMessageHandler />
<TransitionAnimation className="nitro-notification-center-container" type={ TransitionAnimationTypes.SLIDE_RIGHT } inProp={ isVisible } timeout={ 300 }> <TransitionAnimation className="nitro-notification-center-container" type={ TransitionAnimationTypes.SLIDE_RIGHT } inProp={ isVisible } timeout={ 300 }>
<div className="nitro-notification-center"> <div className="nitro-notification-center pt-5 px-2">
{ mapNotifications(notifications, true) }
</div> </div>
</TransitionAnimation> </TransitionAnimation>
{ notifications && notifications.map(notification => { mapNotifications(notifications, false) }
{
if(notification instanceof BroadcastMessageNotification)
return <BroadcastMessageView key={ notification.id } notification={ notification as BroadcastMessageNotification } onCloseClick={ () => handleButtonClick('dismiss_alert', notification.id) } />
if(notification instanceof MOTDNotification)
return <MOTDView key={ notification.id } notification={ notification as MOTDNotification } onCloseClick={ () => handleButtonClick('dismiss_alert', notification.id) } />
if(notification instanceof ModeratorMessageNotification)
return <ModeratorMessageView key={ notification.id } notification={ notification as ModeratorMessageNotification } onCloseClick={ () => handleButtonClick('dismiss_alert', notification.id) } />
else
return null;
}) }
</NotificationCenterContextProvider> </NotificationCenterContextProvider>
); );
} }

View File

@ -5,5 +5,6 @@ export interface NotificationCenterViewProps
export class NotificationViewProps export class NotificationViewProps
{ {
onCloseClick: () => void; inTray?: boolean = false;
onButtonClick: (action: string) => void;
} }

View File

@ -19,6 +19,7 @@ export class NotificationCenterActions
{ {
public static ADD_NOTIFICATION: string = 'NCA_ADD_NOTIFICATION'; public static ADD_NOTIFICATION: string = 'NCA_ADD_NOTIFICATION';
public static REMOVE_NOTIFICATION: string = 'NCA_REMOVE_NOTIFICATION'; public static REMOVE_NOTIFICATION: string = 'NCA_REMOVE_NOTIFICATION';
public static DISMISS_NOTIFICATION: string = 'NCA_DISMISS_NOTIFICATION';
} }
export const initialNotificationCenter: INotificationCenterState = { export const initialNotificationCenter: INotificationCenterState = {
@ -34,7 +35,7 @@ export const NotificationCenterReducer: Reducer<INotificationCenterState, INotif
if(!notification) return state; if(!notification) return state;
if(state.notifications) return {...state, notifications: [...state.notifications, notification]}; if(state.notifications) return {...state, notifications: [notification, ...state.notifications]};
return {...state, notifications: [notification]}; return {...state, notifications: [notification]};
} }
@ -54,6 +55,22 @@ export const NotificationCenterReducer: Reducer<INotificationCenterState, INotif
return {...state, notifications}; return {...state, notifications};
} }
case NotificationCenterActions.DISMISS_NOTIFICATION: {
const id = (action.payload.id || null);
if(!id) return state;
if(!state.notifications) return state;
const notifications = Array.from(state.notifications);
const notificationIndex = notifications.findIndex(notification => notification.id === id);
if(notificationIndex === -1) return state;
notifications[notificationIndex].dismiss();
return {...state, notifications};
}
default: default:
return state; return state;
} }

View File

@ -5,15 +5,23 @@ export class NitroNotification
private _id: number; private _id: number;
private _title: string; private _title: string;
private _message: string; private _message: string;
private _dismissed: boolean = false;
private _timestamp: number;
constructor(message: string = null, title: string = null) constructor(message: string = null, title: string = null)
{ {
this._id = ++NitroNotification.CURRENT_ID; this._id = ++NitroNotification.CURRENT_ID;
this._title = title; this._title = title;
this._timestamp = Date.now();
if(message) this._message = message.replace(/\r\n|\r|\n/g, '<br />'); if(message) this._message = message.replace(/\r\n|\r|\n/g, '<br />');
} }
public dismiss(): void
{
this._dismissed = true;
}
public get id(): number public get id(): number
{ {
return this._id; return this._id;
@ -28,4 +36,14 @@ export class NitroNotification
{ {
return this._message; return this._message;
} }
public get dismissed(): boolean
{
return this._dismissed;
}
public get timestamp(): number
{
return this._timestamp;
}
} }

View File

@ -2,21 +2,27 @@ import { FC } from 'react';
import { NitroCardContentView, NitroCardView } from '../../../../layout'; import { NitroCardContentView, NitroCardView } from '../../../../layout';
import { NitroCardSimpleHeaderView } from '../../../../layout/card/simple-header'; import { NitroCardSimpleHeaderView } from '../../../../layout/card/simple-header';
import { LocalizeText } from '../../../../utils/LocalizeText'; import { LocalizeText } from '../../../../utils/LocalizeText';
import { NotificationTrayItemView } from '../tray-item/NotificationTrayItemView';
import { BroadcastMessageViewProps } from './BroadcastMessageView.types'; import { BroadcastMessageViewProps } from './BroadcastMessageView.types';
export const BroadcastMessageView: FC<BroadcastMessageViewProps> = props => export const BroadcastMessageView: FC<BroadcastMessageViewProps> = props =>
{ {
const { notification = null, onCloseClick = null } = props; const { notification = null, inTray = null, onButtonClick = null } = props;
if(!notification) return null; if(!notification) return null;
const content = <div dangerouslySetInnerHTML={ {__html: notification.message } } />;
if(inTray)
return (
<NotificationTrayItemView title={ LocalizeText('mod.alert.title') } content={ content } timestamp={ notification.timestamp } onCloseClick={ () => onButtonClick('remove_notification') } />
);
return ( return (
<NitroCardView className="nitro-notification"> <NitroCardView className="nitro-notification">
<NitroCardSimpleHeaderView headerText={ LocalizeText('mod.alert.title') } onCloseClick={ onCloseClick } /> <NitroCardSimpleHeaderView headerText={ LocalizeText('mod.alert.title') } onCloseClick={ () => onButtonClick('dismiss_notification') } />
<NitroCardContentView> <NitroCardContentView className="text-black">
<div className="text-black"> { content }
<div dangerouslySetInnerHTML={ {__html: notification.message } } />
</div>
</NitroCardContentView> </NitroCardContentView>
</NitroCardView> </NitroCardView>
); );

View File

@ -0,0 +1,29 @@
import { FC } from 'react';
import { NitroCardContentView, NitroCardView } from '../../../../layout';
import { NitroCardSimpleHeaderView } from '../../../../layout/card/simple-header';
import { LocalizeText } from '../../../../utils/LocalizeText';
import { NotificationTrayItemView } from '../tray-item/NotificationTrayItemView';
import { HotelWillShutdownViewProps } from './HotelWillShutdownView.types';
export const HotelWillShutdownView: FC<HotelWillShutdownViewProps> = props =>
{
const { notification = null, inTray = null, onButtonClick = null } = props;
if(!notification) return null;
const content = <>{ LocalizeText('opening.hours.shutdown', ['m'], [notification.minutes.toString()]) }</>;
if(inTray)
return (
<NotificationTrayItemView title={ LocalizeText('mod.alert.title') } content={ content } timestamp={ notification.timestamp } onCloseClick={ () => onButtonClick('remove_notification') } />
);
return (
<NitroCardView className="nitro-notification">
<NitroCardSimpleHeaderView headerText={ LocalizeText('mod.alert.title') } onCloseClick={ () => onButtonClick('dismiss_notification') } />
<NitroCardContentView className="text-black">
{ content }
</NitroCardContentView>
</NitroCardView>
);
};

View File

@ -0,0 +1,7 @@
import { NotificationViewProps } from '../../NotificationCenterView.types';
import { HotelWillShutdownNotification } from './../../utils/HotelWillShutdownNotification';
export class HotelWillShutdownViewProps extends NotificationViewProps
{
notification: HotelWillShutdownNotification;
}

View File

@ -2,24 +2,32 @@ import { FC } from 'react';
import { NitroCardContentView, NitroCardView } from '../../../../layout'; import { NitroCardContentView, NitroCardView } from '../../../../layout';
import { NitroCardSimpleHeaderView } from '../../../../layout/card/simple-header'; import { NitroCardSimpleHeaderView } from '../../../../layout/card/simple-header';
import { LocalizeText } from '../../../../utils/LocalizeText'; import { LocalizeText } from '../../../../utils/LocalizeText';
import { NotificationTrayItemView } from '../tray-item/NotificationTrayItemView';
import { ModeratorMessageViewProps } from './ModeratorMessageView.types'; import { ModeratorMessageViewProps } from './ModeratorMessageView.types';
export const ModeratorMessageView: FC<ModeratorMessageViewProps> = props => export const ModeratorMessageView: FC<ModeratorMessageViewProps> = props =>
{ {
const { notification = null, onCloseClick = null } = props; const { notification = null, inTray = null, onButtonClick = null } = props;
if(!notification) return null; if(!notification) return null;
return ( const content = <>
<NitroCardView className="nitro-notification">
<NitroCardSimpleHeaderView headerText={ LocalizeText('mod.alert.title') } onCloseClick={ onCloseClick } />
<NitroCardContentView>
<div className="text-black">
<div dangerouslySetInnerHTML={ {__html: notification.message } } /> <div dangerouslySetInnerHTML={ {__html: notification.message } } />
<div className="fw-bold text-center"> <div className="fw-bold text-center">
<a href={ notification.link } rel="noreferrer" target="_blank" onClick={ onCloseClick }>{ LocalizeText('mod.alert.link') }</a> <a href={ notification.link } rel="noreferrer" target="_blank" onClick={ () => onButtonClick('dismiss_notification') }>{ LocalizeText('mod.alert.link') }</a>
</div>
</div> </div>
</>;
if(inTray)
return (
<NotificationTrayItemView title={ LocalizeText('mod.alert.title') } content={ content } timestamp={ notification.timestamp } onCloseClick={ () => onButtonClick('remove_notification') } />
);
return (
<NitroCardView className="nitro-notification">
<NitroCardSimpleHeaderView headerText={ LocalizeText('mod.alert.title') } onCloseClick={ () => onButtonClick('dismiss_notification') } />
<NitroCardContentView className="text-black">
{ content }
</NitroCardContentView> </NitroCardContentView>
</NitroCardView> </NitroCardView>
); );

View File

@ -2,24 +2,30 @@ import { FC } from 'react';
import { NitroCardContentView, NitroCardView } from '../../../../layout'; import { NitroCardContentView, NitroCardView } from '../../../../layout';
import { NitroCardSimpleHeaderView } from '../../../../layout/card/simple-header'; import { NitroCardSimpleHeaderView } from '../../../../layout/card/simple-header';
import { LocalizeText } from '../../../../utils/LocalizeText'; import { LocalizeText } from '../../../../utils/LocalizeText';
import { NotificationTrayItemView } from '../tray-item/NotificationTrayItemView';
import { MOTDViewProps } from './MOTDView.types'; import { MOTDViewProps } from './MOTDView.types';
export const MOTDView: FC<MOTDViewProps> = props => export const MOTDView: FC<MOTDViewProps> = props =>
{ {
const { notification = null, onCloseClick = null } = props; const { notification = null, inTray = null, onButtonClick = null } = props;
if(!notification) return null; if(!notification) return null;
return ( const content = notification.messages.map((message, index) =>
<NitroCardView className="nitro-notification">
<NitroCardSimpleHeaderView headerText={ LocalizeText('mod.alert.title') } onCloseClick={ onCloseClick } />
<NitroCardContentView>
<div className="text-black">
{ notification.messages.map((message, index) =>
{ {
return <div key={ index } dangerouslySetInnerHTML={ {__html: message } } /> return <div key={ index } dangerouslySetInnerHTML={ {__html: message } } />
}) } });
</div>
if(inTray)
return (
<NotificationTrayItemView title={ LocalizeText('mod.alert.title') } content={ content } timestamp={ notification.timestamp } onCloseClick={ () => onButtonClick('remove_notification') } />
);
return (
<NitroCardView className="nitro-notification">
<NitroCardSimpleHeaderView headerText={ LocalizeText('mod.alert.title') } onCloseClick={ () => onButtonClick('dismiss_notification') } />
<NitroCardContentView className="text-black">
{ content }
</NitroCardContentView> </NitroCardContentView>
</NitroCardView> </NitroCardView>
); );

View File

@ -0,0 +1,22 @@
import { FC } from 'react';
import { NotificationTrayItemViewProps } from './NotificationTrayItemView.types';
export const NotificationTrayItemView: FC<NotificationTrayItemViewProps> = props =>
{
const { title = null, content = null, timestamp = null, onCloseClick = null } = props;
return (
<div className="rounded bg-muted mb-2 text-black">
<div className="py-1 px-2 fw-bold d-flex justify-content-between align-items-center">
<div className="me-2">{ title }</div>
<i className="fas fa-times cursor-pointer" onClick={ onCloseClick }></i>
</div>
<div className="py-1 px-2">
{ content }
</div>
<div className="py-1 px-2">
<i className="far fa-clock"></i> { timestamp }
</div>
</div>
);
};

View File

@ -0,0 +1,7 @@
export class NotificationTrayItemViewProps
{
title: string;
content: any;
timestamp: number;
onCloseClick: () => void;
}