Skip to content
This repository has been archived by the owner on Jul 25, 2022. It is now read-only.

Commit

Permalink
refactor: Notifications store (#64)
Browse files Browse the repository at this point in the history
  • Loading branch information
QuiiBz committed Mar 13, 2021
1 parent 6aae713 commit fbf771f
Show file tree
Hide file tree
Showing 16 changed files with 115 additions and 138 deletions.
File renamed without changes.
20 changes: 0 additions & 20 deletions app/store/notifications/actions.ts

This file was deleted.

15 changes: 15 additions & 0 deletions app/store/notifications/actions/NotificationsActions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { INotification } from '@common/notifications/notification';

export type NotificationsActions = AddNotificationAction | RemoveNotificationAction;

export type AddNotificationAction = {

type: 'ADD';
notification: INotification;
}

export type RemoveNotificationAction = {

type: 'REMOVE';
notification: INotification;
}
30 changes: 0 additions & 30 deletions app/store/notifications/reducer.ts

This file was deleted.

17 changes: 17 additions & 0 deletions app/store/notifications/reducers/NotificationsReducer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { INotification } from '@common/notifications/notification';
import { NotificationsActions } from '@app/store/notifications/actions/NotificationsActions';

export const notificationsReducer = (state: INotification[], action: NotificationsActions): INotification[] => {

switch(action.type) {

case 'ADD':
return [...state, action.notification];

case 'REMOVE':
return [...state].filter((current) => current !== action.notification);

default:
return state;
}
}
8 changes: 8 additions & 0 deletions app/store/notifications/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { INotification } from '@common/notifications/notification';
import { NotificationsActions } from '@app/store/notifications/actions/NotificationsActions';

export type NotificationsContextType = {

notifications: INotification[];
dispatch: (action: NotificationsActions) => void;
}
3 changes: 1 addition & 2 deletions app/store/store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,9 @@ import { createStore, combineReducers, Reducer, CombinedState } from 'redux';
import { AppState } from '@app/store/types';
import { windows } from '@app/store/windows/reducer';
import { selected } from '@app/store/selected/reducer';
import { notifications } from '@app/store/notifications/reducer';
import { hosts } from '@app/store/hosts/reducer';

// We combine all the reducers into one single reducer
const reducer: Reducer<CombinedState<AppState>> = combineReducers<AppState>({ windows, selected , notifications, hosts });
const reducer: Reducer<CombinedState<AppState>> = combineReducers<AppState>({ windows, selected, hosts });

export default createStore(reducer);
9 changes: 0 additions & 9 deletions app/store/types.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { INotification } from '@common/notifications/notification';
import { IWindow } from '@app/Terminal';
import { ISSHHost } from '@common/config/Config';

Expand All @@ -16,13 +15,6 @@ export type SelectedAction = {
selected: number;
}

export type NotificationsState = INotification[];
export type NotificationsAction = {

type: string;
notification: INotification;
}

export type HostsState = ISSHHost[];
export type HostsAction = {

Expand All @@ -34,6 +26,5 @@ export type AppState = {

windows: WindowsState;
selected: SelectedState;
notifications: NotificationsState;
hosts: HostsState;
}
20 changes: 6 additions & 14 deletions ui/components/notifications/Notification.tsx
Original file line number Diff line number Diff line change
@@ -1,27 +1,19 @@
import React, { CSSProperties, FC, ReactElement, useContext, useEffect } from 'react';
import { ITheme } from '@common/config/Config';
import { INotification, INotificationLevel } from '@common/notifications/notification';
import { Dispatch } from 'redux';
import { connect } from 'react-redux';
import { NotificationsAction } from '@app/store/types';
import { removeNotification } from '@app/store/notifications/actions';
import { INotification, INotificationLevel } from '@app/notifications/notification';
import NotificationButton from '@ui/components/notifications/NotificationButton';
import { ConfigContext } from '@ui/contexts/ConfigContext';
import { NotificationsContext } from '@ui/contexts/NotificationsContext';

interface Props {

notification: INotification;
dispatch: (action: NotificationsAction) => void;
}

const mapDispatchToProps = (dispatch: Dispatch) => {

return { dispatch: (action: NotificationsAction) => { dispatch(action) } }
}

const Notification: FC<Props> = ({ notification, dispatch }: Props): ReactElement => {
const Notification: FC<Props> = ({ notification }: Props): ReactElement => {

const { theme } = useContext(ConfigContext);
const { dispatch } = useContext(NotificationsContext);

/**
* Remove the notification when the configurated time has passed.
Expand All @@ -31,7 +23,7 @@ const Notification: FC<Props> = ({ notification, dispatch }: Props): ReactElemen
// The timeout of this notification in milliseconds
const timeout = notification.time * 1000;

setTimeout(() => dispatch(removeNotification(notification)), timeout);
setTimeout(() => dispatch({ type: 'REMOVE', notification }), timeout);

}, []);

Expand Down Expand Up @@ -83,4 +75,4 @@ const getColor = (level: INotificationLevel, theme: ITheme): string => {
}
}

export default connect(mapDispatchToProps)(Notification);
export default Notification;
2 changes: 1 addition & 1 deletion ui/components/notifications/NotificationButton.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React, { CSSProperties, FC, ReactElement } from 'react';
import { ITheme } from '@common/config/Config';
import { INotificationButton } from '@common/notifications/notification';
import { INotificationButton } from '@app/notifications/notification';

interface Props {

Expand Down
31 changes: 7 additions & 24 deletions ui/components/notifications/Notifications.tsx
Original file line number Diff line number Diff line change
@@ -1,31 +1,14 @@
import React, { FC, ReactElement, useEffect } from 'react';
import { INotification, updateNotification } from '@common/notifications/notification';
import React, { FC, ReactElement, useContext, useEffect } from 'react';
import { updateNotification } from '@app/notifications/notification';
import Notification from '@ui/components/notifications/Notification';
import { AppState, NotificationsAction } from '@app/store/types';
import { connect } from 'react-redux';
import { ipcRenderer } from 'electron';
import { IUpdateStatus } from '@common/types/types';
import { Dispatch } from 'redux'
import { addNotification } from '@app/store/notifications/actions';
import { NotificationsContext } from '@ui/contexts/NotificationsContext';
import '@ui/styles/notifications.scss';

interface Props {
const Notifications: FC = (): ReactElement => {

notifications: INotification[];
dispatch: (action: NotificationsAction) => void;
}

const mapStateToProps = (state: AppState) => ({

notifications: state.notifications,
});

const mapDispatchToProps = (dispatch: Dispatch) => {

return { dispatch: (action: NotificationsAction) => { dispatch(action) } }
}

const Notifications: FC<Props> = ({ notifications, dispatch }: Props): ReactElement => {
const { notifications, dispatch } = useContext(NotificationsContext);

/**
* Listen for updates coming from the main process
Expand All @@ -41,7 +24,7 @@ const Notifications: FC<Props> = ({ notifications, dispatch }: Props): ReactElem
ipcRenderer.on('update', (_, update: IUpdateStatus) => {

const notification = updateNotification(update, restart);
dispatch(addNotification(notification));
dispatch({ type: 'ADD', notification });
});
}, []);

Expand All @@ -57,4 +40,4 @@ const Notifications: FC<Props> = ({ notifications, dispatch }: Props): ReactElem
);
}

export default connect(mapStateToProps, mapDispatchToProps)(Notifications);
export default Notifications;
15 changes: 8 additions & 7 deletions ui/contexts/AuthContext.tsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
import React, { FC, ReactElement, useEffect, createContext, useReducer, Reducer } from 'react';
import { HostsAction, NotificationsAction } from '@app/store/types';
import React, { FC, ReactElement, useEffect, createContext, useReducer, Reducer, useContext } from 'react';
import { HostsAction } from '@app/store/types';
import { Dispatch } from 'redux';
import { connect } from 'react-redux';
import { initializeCloud } from '@app/cloud/cloud';
import { setHosts } from '@app/store/hosts/actions';
import { addNotification } from '@app/store/notifications/actions';
import { cloudUnreachable } from '@common/notifications/notification';
import { cloudUnreachable } from '@app/notifications/notification';
import { NotificationsContext } from '@ui/contexts/NotificationsContext';

interface Props {

children: ReactElement;
dispatch: (action: HostsAction | NotificationsAction) => void;
dispatch: (action: HostsAction) => void;
}

const mapDispatchToProps = (dispatch: Dispatch) => {

return { dispatch: (action: HostsAction | NotificationsAction) => { dispatch(action) } }
return { dispatch: (action: HostsAction) => { dispatch(action) } }
}

type Action = { type: 'SET', state: boolean };
Expand All @@ -27,6 +27,7 @@ export const AuthContext = createContext<AuthContextType>(defaultState);

const AuthProvider: FC<Props> = ({ children, dispatch }: Props): ReactElement => {

const { dispatch: dispatchNotification } = useContext(NotificationsContext);
const [auth, setAuth] = useReducer<Reducer<boolean, Action>>((state: boolean, action: Action) => action.state, false);

// Initialize cloud when mounted
Expand All @@ -44,7 +45,7 @@ const AuthProvider: FC<Props> = ({ children, dispatch }: Props): ReactElement =>
}).catch((err) => {

console.error(err);
dispatch(addNotification(cloudUnreachable()));
dispatchNotification({ type: 'ADD', notification: cloudUnreachable() });
});

}, []);
Expand Down
27 changes: 7 additions & 20 deletions ui/contexts/ConfigContext.tsx
Original file line number Diff line number Diff line change
@@ -1,27 +1,14 @@
import React, { FC, ReactElement, useEffect, useState, createContext } from 'react';
import React, { FC, ReactElement, useEffect, useState, createContext, useContext } from 'react';
import Config, { IConfig } from '@common/config/Config';
import { defaultConfig } from '@common/config/defaultConfig';
import { configReloadedNotification } from '@common/notifications/notification';
import { addNotification } from '@app/store/notifications/actions';
import { NotificationsAction, SelectedAction } from '@app/store/types';
import { Dispatch } from 'redux';
import { connect } from 'react-redux';

interface Props {

children: ReactElement;
dispatch: (action: NotificationsAction) => void;
}

const mapDispatchToProps = (dispatch: Dispatch) => {

return { dispatch: (action: SelectedAction) => { dispatch(action) } }
}
import { configReloadedNotification } from '@app/notifications/notification';
import { NotificationsContext } from '@ui/contexts/NotificationsContext';

export const ConfigContext = createContext<IConfig>(defaultConfig);

const ConfigProvider: FC<Props> = ({ children, dispatch }: Props): ReactElement => {
const ConfigProvider: FC = ({ children }): ReactElement => {

const { dispatch } = useContext(NotificationsContext);
const [config, setConfig] = useState<IConfig>(defaultConfig);

// Load the config on mount
Expand All @@ -31,7 +18,7 @@ const ConfigProvider: FC<Props> = ({ children, dispatch }: Props): ReactElement

// Add a notification when config is reloaded
const notification = configReloadedNotification(config === undefined);
dispatch(addNotification(notification));
dispatch({ type: 'ADD', notification });

if(config)
setConfig(config);
Expand All @@ -48,4 +35,4 @@ const ConfigProvider: FC<Props> = ({ children, dispatch }: Props): ReactElement
);
}

export default connect(mapDispatchToProps)(ConfigProvider);
export default ConfigProvider;
26 changes: 26 additions & 0 deletions ui/contexts/NotificationsContext.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import React, { FC, ReactElement, createContext, useReducer, Reducer } from 'react';
import { NotificationsContextType } from '@app/store/notifications/types';
import { INotification } from '@app/notifications/notification';
import { notificationsReducer } from '@app/store/notifications/reducers/NotificationsReducer';
import { NotificationsActions } from '@app/store/notifications/actions/NotificationsActions';

const defaultState: NotificationsContextType = {

notifications: [],
dispatch: (_: NotificationsActions) => null,
}

export const NotificationsContext = createContext<NotificationsContextType>(defaultState);

const NotificationsProvider: FC = ({ children }): ReactElement => {

const [notifications, dispatch] = useReducer<Reducer<INotification[], NotificationsActions>>(notificationsReducer, []);

return (
<NotificationsContext.Provider value={{ notifications, dispatch }}>
{ children }
</NotificationsContext.Provider>
);
}

export default NotificationsProvider;
13 changes: 8 additions & 5 deletions ui/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { Provider } from 'react-redux';
import store from '@app/store/store';
import ConfigContext from '@ui/contexts/ConfigContext';
import AuthContext from '@ui/contexts/AuthContext';
import BlocksProvider from '@ui/contexts/NotificationsContext';

if(module.hot)
module.hot.accept();
Expand All @@ -13,9 +14,11 @@ const root = document.getElementById('app');

render(
<Provider store={store}>
<ConfigContext>
<AuthContext>
<App />
</AuthContext>
</ConfigContext>
<BlocksProvider>
<ConfigContext>
<AuthContext>
<App />
</AuthContext>
</ConfigContext>
</BlocksProvider>
</Provider>, root);
Loading

0 comments on commit fbf771f

Please sign in to comment.