1
0
Fork 0
mirror of https://github.com/pawelmalak/flame.git synced 2025-08-07 03:35:18 +02:00

UI notification/alert system with global redux state

This commit is contained in:
unknown 2021-05-24 14:54:46 +02:00
parent c145888aec
commit 4eaf9659d1
17 changed files with 279 additions and 10 deletions

View file

@ -10,7 +10,10 @@ import {
// Categories
GetCategoriesAction,
AddCategoryAction,
AddBookmarkAction
AddBookmarkAction,
// Notifications
CreateNotificationAction,
ClearNotificationAction
} from './';
export enum ActionTypes {
@ -30,7 +33,10 @@ export enum ActionTypes {
getCategoriesSuccess = 'GET_CATEGORIES_SUCCESS',
getCategoriesError = 'GET_CATEGORIES_ERROR',
addCategory = 'ADD_CATEGORY',
addBookmark = 'ADD_BOOKMARK'
addBookmark = 'ADD_BOOKMARK',
// Notifications
createNotification = 'CREATE_NOTIFICATION',
clearNotification = 'CLEAR_NOTIFICATION'
}
export type Action =
@ -45,4 +51,7 @@ export type Action =
// Categories
GetCategoriesAction<any> |
AddCategoryAction |
AddBookmarkAction;
AddBookmarkAction |
// Notifications
CreateNotificationAction |
ClearNotificationAction;

View file

@ -2,6 +2,7 @@ import axios from 'axios';
import { Dispatch } from 'redux';
import { ActionTypes } from './actionTypes';
import { App, ApiResponse, NewApp } from '../../interfaces';
import { CreateNotificationAction } from './notification';
export interface GetAppsAction<T> {
type: ActionTypes.getApps | ActionTypes.getAppsSuccess | ActionTypes.getAppsError;
@ -36,9 +37,19 @@ export interface PinAppAction {
export const pinApp = (app: App) => async (dispatch: Dispatch) => {
try {
const { id, isPinned} = app;
const { id, isPinned, name } = app;
const res = await axios.put<ApiResponse<App>>(`/api/apps/${id}`, { isPinned: !isPinned });
const status = isPinned ? 'unpinned from Homescreen' : 'pinned to Homescreen';
dispatch<CreateNotificationAction>({
type: ActionTypes.createNotification,
payload: {
title: 'Success',
message: `App ${name} ${status}`
}
})
dispatch<PinAppAction>({
type: ActionTypes.pinApp,
payload: res.data.data
@ -57,6 +68,14 @@ export const addApp = (formData: NewApp) => async (dispatch: Dispatch) => {
try {
const res = await axios.post<ApiResponse<App>>('/api/apps', formData);
dispatch<CreateNotificationAction>({
type: ActionTypes.createNotification,
payload: {
title: 'Success',
message: `App ${formData.name} added`
}
})
dispatch<AddAppAction>({
type: ActionTypes.addAppSuccess,
payload: res.data.data
@ -75,6 +94,14 @@ export const deleteApp = (id: number) => async (dispatch: Dispatch) => {
try {
const res = await axios.delete<ApiResponse<{}>>(`/api/apps/${id}`);
dispatch<CreateNotificationAction>({
type: ActionTypes.createNotification,
payload: {
title: 'Success',
message: 'App deleted'
}
})
dispatch<DeleteAppAction>({
type: ActionTypes.deleteApp,
payload: id
@ -93,6 +120,14 @@ export const updateApp = (id: number, formData: NewApp) => async (dispatch: Disp
try {
const res = await axios.put<ApiResponse<App>>(`/api/apps/${id}`, formData);
dispatch<CreateNotificationAction>({
type: ActionTypes.createNotification,
payload: {
title: 'Success',
message: `App ${formData.name} updated`
}
})
dispatch<UpdateAppAction>({
type: ActionTypes.updateApp,
payload: res.data.data

View file

@ -1,4 +1,5 @@
export * from './theme';
export * from './app';
export * from './actionTypes';
export * from './bookmark';
export * from './bookmark';
export * from './notification';

View file

@ -0,0 +1,27 @@
import { Dispatch } from 'redux';
import { ActionTypes } from '.';
import { NewNotification } from '../../interfaces';
export interface CreateNotificationAction {
type: ActionTypes.createNotification,
payload: NewNotification
}
export const createNotification = (notification: NewNotification) => (dispatch: Dispatch) => {
dispatch<CreateNotificationAction>({
type: ActionTypes.createNotification,
payload: notification
})
}
export interface ClearNotificationAction {
type: ActionTypes.clearNotification,
payload: number
}
export const clearNotification = (id: number) => (dispatch: Dispatch) => {
dispatch<ClearNotificationAction>({
type: ActionTypes.clearNotification,
payload: id
})
}

View file

@ -5,11 +5,13 @@ import { GlobalState } from '../../interfaces/GlobalState';
import themeReducer from './theme';
import appReducer from './app';
import bookmarkReducer from './bookmark';
import notificationReducer from './notification';
const rootReducer = combineReducers<GlobalState>({
theme: themeReducer,
app: appReducer,
bookmark: bookmarkReducer
bookmark: bookmarkReducer,
notification: notificationReducer
})
export default rootReducer;

View file

@ -0,0 +1,45 @@
import { ActionTypes, Action } from '../actions';
import { Notification } from '../../interfaces';
export interface State {
notifications: Notification[];
idCounter: number;
}
const initialState: State = {
notifications: [],
idCounter: 0
}
const createNotification = (state: State, action: Action): State => {
const tmpNotifications = [...state.notifications, {
...action.payload,
id: state.idCounter
}];
return {
...state,
notifications: tmpNotifications,
idCounter: state.idCounter + 1
}
}
const clearNotification = (state: State, action: Action): State => {
const tmpNotifications = [...state.notifications]
.filter((notification: Notification) => notification.id !== action.payload);
return {
...state,
notifications: tmpNotifications
}
}
const notificationReducer = (state = initialState, action: Action) => {
switch (action.type) {
case ActionTypes.createNotification: return createNotification(state, action);
case ActionTypes.clearNotification: return clearNotification(state, action);
default: return state;
}
}
export default notificationReducer;