Skip to content

Commit

Permalink
refactor: notifications
Browse files Browse the repository at this point in the history
  • Loading branch information
apotdevin committed May 30, 2022
1 parent d4bce70 commit 8ffa13d
Show file tree
Hide file tree
Showing 7 changed files with 418 additions and 299 deletions.
10 changes: 7 additions & 3 deletions src/client/pages/_app.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useEffect } from 'react';
import { useEffect, VFC } from 'react';
import { ThemeProvider } from 'styled-components';
import { ModalProvider, BaseModalBackground } from 'styled-react-modal';
import { AppProps } from 'next/app';
Expand Down Expand Up @@ -36,6 +36,11 @@ const NotAuthenticated: React.FC = () => {
return null;
};

const Listener: VFC<{ isRoot: boolean }> = ({ isRoot }) => {
useListener(isRoot);
return null;
};

const Wrapper: React.FC<{ authenticated: boolean }> = ({
children,
authenticated,
Expand All @@ -45,15 +50,14 @@ const Wrapper: React.FC<{ authenticated: boolean }> = ({

const isRoot = pathname === '/login' || pathname === '/sso';

useListener(isRoot);

return (
<ThemeProvider theme={{ mode: isRoot ? 'light' : theme }}>
<ModalProvider backgroundComponent={BaseModalBackground}>
<GlobalStyles />
<PageWrapper>
<HeaderBodyWrapper>
<Header />
<Listener isRoot={isRoot} />
{authenticated ? children : <NotAuthenticated />}
</HeaderBodyWrapper>
<Footer />
Expand Down
17 changes: 10 additions & 7 deletions src/client/src/context/ContextProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,16 @@ import { PriceProvider } from './PriceContext';
import { ChatProvider } from './ChatContext';
import { RebalanceProvider } from './RebalanceContext';
import { DashProvider } from './DashContext';
import { NotificationProvider } from './NotificationContext';

export const ContextProvider: React.FC = ({ children }) => (
<DashProvider>
<PriceProvider>
<ChatProvider>
<RebalanceProvider>{children}</RebalanceProvider>
</ChatProvider>
</PriceProvider>
</DashProvider>
<NotificationProvider>
<DashProvider>
<PriceProvider>
<ChatProvider>
<RebalanceProvider>{children}</RebalanceProvider>
</ChatProvider>
</PriceProvider>
</DashProvider>
</NotificationProvider>
);
95 changes: 95 additions & 0 deletions src/client/src/context/NotificationContext.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import React, { createContext, useContext, useReducer, useEffect } from 'react';

const STORAGE_KEY = 'notificationSettings-v2';

type State = {
invoices: boolean;
payments: boolean;
channels: boolean;
forwards: boolean;
forwardAttempts: boolean;
autoClose: boolean;
};

type ActionType = {
type: 'change' | 'initChange';
invoices?: boolean;
payments?: boolean;
channels?: boolean;
forwards?: boolean;
forwardAttempts?: boolean;
autoClose?: boolean;
};

type Dispatch = (action: ActionType) => void;

const StateContext = createContext<State | undefined>(undefined);
const DispatchContext = createContext<Dispatch | undefined>(undefined);

const initialState: State = {
invoices: true,
payments: true,
channels: true,
forwards: false,
forwardAttempts: false,
autoClose: true,
};

const stateReducer = (state: State, action: ActionType): State => {
const { type, ...settings } = action;
switch (type) {
case 'initChange': {
return {
...state,
...settings,
};
}
case 'change': {
const newState = {
...state,
...settings,
};
localStorage.setItem(STORAGE_KEY, JSON.stringify(newState));
return newState;
}
default:
return state;
}
};

const NotificationProvider: React.FC = ({ children }) => {
const [state, dispatch] = useReducer(stateReducer, initialState);

useEffect(() => {
const savedConfig = JSON.parse(localStorage.getItem(STORAGE_KEY) || '{}');
dispatch({ type: 'initChange', ...savedConfig });
}, []);

return (
<DispatchContext.Provider value={dispatch}>
<StateContext.Provider value={state}>{children}</StateContext.Provider>
</DispatchContext.Provider>
);
};

const useNotificationState = () => {
const context = useContext(StateContext);
if (context === undefined) {
throw new Error(
'useNotificationState must be used within a NotificationProvider'
);
}
return context;
};

const useNotificationDispatch = () => {
const context = useContext(DispatchContext);
if (context === undefined) {
throw new Error(
'useNotificationDispatch must be used within a NotificationProvider'
);
}
return context;
};

export { NotificationProvider, useNotificationState, useNotificationDispatch };
8 changes: 4 additions & 4 deletions src/client/src/context/SocketContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ const SocketProvider: FC<{ authToken?: string }> = ({
socket.on('disconnect', handleDisconnect);

return { socket, cleanup };
}, []);
}, [authToken]);

const getLastMessage = (forEvent = '') => lastMessages[forEvent];
const setLastMessage = (forEvent: string, message: any) =>
Expand All @@ -86,12 +86,12 @@ const SocketProvider: FC<{ authToken?: string }> = ({
if (!sockets.current) return;
if (sockets.current.hasListeners(forEvent)) return;

sockets.current.on(forEvent, (message: any) =>
sockets.current.on(forEvent, (message: any) => {
setLastMessages(state => ({
...state,
[forEvent]: message,
}))
);
}));
});
};

return (
Expand Down
Loading

0 comments on commit 8ffa13d

Please sign in to comment.