From 754dc3a7b9f790edc144134ac79efbdff532ca50 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 18 Jun 2021 10:38:05 +0200 Subject: [PATCH] Sorting settings. Sort apps on change/add/update --- client/.env | 2 +- .../Settings/OtherSettings/OtherSettings.tsx | 29 +++++++++-- client/src/interfaces/Category.ts | 1 + client/src/store/actions/actionTypes.ts | 9 ++-- client/src/store/actions/app.ts | 50 ++++++++++++++++--- client/src/store/reducers/app.ts | 23 +++++---- client/src/utility/index.ts | 3 +- client/src/utility/sortData.ts | 29 +++++++++++ models/Category.js | 5 ++ 9 files changed, 124 insertions(+), 27 deletions(-) create mode 100644 client/src/utility/sortData.ts diff --git a/client/.env b/client/.env index 3df1a71..69d1f92 100644 --- a/client/.env +++ b/client/.env @@ -1 +1 @@ -REACT_APP_VERSION=1.3.3 \ No newline at end of file +REACT_APP_VERSION=1.3.5 \ No newline at end of file diff --git a/client/src/components/Settings/OtherSettings/OtherSettings.tsx b/client/src/components/Settings/OtherSettings/OtherSettings.tsx index 5df8be7..50b04b5 100644 --- a/client/src/components/Settings/OtherSettings/OtherSettings.tsx +++ b/client/src/components/Settings/OtherSettings/OtherSettings.tsx @@ -2,7 +2,7 @@ import { useState, useEffect, ChangeEvent, FormEvent } from 'react'; // Redux import { connect } from 'react-redux'; -import { createNotification, updateConfig } from '../../../store/actions'; +import { createNotification, updateConfig, sortApps } from '../../../store/actions'; // Typescript import { GlobalState, NewNotification, SettingsForm } from '../../../interfaces'; @@ -17,6 +17,7 @@ import { searchConfig } from '../../../utility'; interface ComponentProps { createNotification: (notification: NewNotification) => void; updateConfig: (formData: SettingsForm) => void; + sortApps: () => void; loading: boolean; } @@ -26,7 +27,8 @@ const OtherSettings = (props: ComponentProps): JSX.Element => { customTitle: document.title, pinAppsByDefault: 1, pinCategoriesByDefault: 1, - hideHeader: 0 + hideHeader: 0, + useOrdering: 'createdAt' }) // Get config @@ -35,7 +37,8 @@ const OtherSettings = (props: ComponentProps): JSX.Element => { customTitle: searchConfig('customTitle', 'Flame'), pinAppsByDefault: searchConfig('pinAppsByDefault', 1), pinCategoriesByDefault: searchConfig('pinCategoriesByDefault', 1), - hideHeader: searchConfig('hideHeader', 0) + hideHeader: searchConfig('hideHeader', 0), + useOrdering: searchConfig('useOrdering', 'createdAt') }) }, [props.loading]); @@ -46,8 +49,11 @@ const OtherSettings = (props: ComponentProps): JSX.Element => { // Save settings await props.updateConfig(formData); - // update local page title + // Update local page title document.title = formData.customTitle; + + // Get sorted apps + props.sortApps(); } // Input handler @@ -113,6 +119,19 @@ const OtherSettings = (props: ComponentProps): JSX.Element => { + + + + ) @@ -124,4 +143,4 @@ const mapStateToProps = (state: GlobalState) => { } } -export default connect(mapStateToProps, { createNotification, updateConfig })(OtherSettings); \ No newline at end of file +export default connect(mapStateToProps, { createNotification, updateConfig, sortApps })(OtherSettings); \ No newline at end of file diff --git a/client/src/interfaces/Category.ts b/client/src/interfaces/Category.ts index 926987d..0f9f8f9 100644 --- a/client/src/interfaces/Category.ts +++ b/client/src/interfaces/Category.ts @@ -3,6 +3,7 @@ import { Model, Bookmark } from '.'; export interface Category extends Model { name: string; isPinned: boolean; + orderId: number; bookmarks: Bookmark[]; } diff --git a/client/src/store/actions/actionTypes.ts b/client/src/store/actions/actionTypes.ts index 42d863e..769bafa 100644 --- a/client/src/store/actions/actionTypes.ts +++ b/client/src/store/actions/actionTypes.ts @@ -7,7 +7,8 @@ import { AddAppAction, DeleteAppAction, UpdateAppAction, - ReorderAppAction, + ReorderAppsAction, + SortAppsAction, // Categories GetCategoriesAction, AddCategoryAction, @@ -38,7 +39,8 @@ export enum ActionTypes { addAppSuccess = 'ADD_APP_SUCCESS', deleteApp = 'DELETE_APP', updateApp = 'UPDATE_APP', - reorderApp = 'REORDER_APP', + reorderApps = 'REORDER_APPS', + sortApps = 'SORT_APPS', // Categories getCategories = 'GET_CATEGORIES', getCategoriesSuccess = 'GET_CATEGORIES_SUCCESS', @@ -68,7 +70,8 @@ export type Action = AddAppAction | DeleteAppAction | UpdateAppAction | - ReorderAppAction | + ReorderAppsAction | + SortAppsAction | // Categories GetCategoriesAction | AddCategoryAction | diff --git a/client/src/store/actions/app.ts b/client/src/store/actions/app.ts index 5c7db15..8dc9e94 100644 --- a/client/src/store/actions/app.ts +++ b/client/src/store/actions/app.ts @@ -1,7 +1,7 @@ import axios from 'axios'; import { Dispatch } from 'redux'; import { ActionTypes } from './actionTypes'; -import { App, ApiResponse, NewApp } from '../../interfaces'; +import { App, ApiResponse, NewApp, Config } from '../../interfaces'; import { CreateNotificationAction } from './notification'; export interface GetAppsAction { @@ -73,10 +73,13 @@ export const addApp = (formData: NewApp) => async (dispatch: Dispatch) => { } }) - dispatch({ + await dispatch({ type: ActionTypes.addAppSuccess, payload: res.data.data }) + + // Sort apps + dispatch(sortApps()) } catch (err) { console.log(err); } @@ -125,17 +128,20 @@ export const updateApp = (id: number, formData: NewApp) => async (dispatch: Disp } }) - dispatch({ + await dispatch({ type: ActionTypes.updateApp, payload: res.data.data }) + + // Sort apps + dispatch(sortApps()) } catch (err) { console.log(err); } } -export interface ReorderAppAction { - type: ActionTypes.reorderApp; +export interface ReorderAppsAction { + type: ActionTypes.reorderApps; payload: App[] } @@ -146,7 +152,7 @@ interface ReorderQuery { }[] } -export const reorderApp = (apps: App[]) => async (dispatch: Dispatch) => { +export const reorderApps = (apps: App[]) => async (dispatch: Dispatch) => { try { const updateQuery: ReorderQuery = { apps: [] } @@ -157,11 +163,39 @@ export const reorderApp = (apps: App[]) => async (dispatch: Dispatch) => { await axios.put<{}>('/api/apps/0/reorder', updateQuery); - dispatch({ - type: ActionTypes.reorderApp, + dispatch({ + type: ActionTypes.createNotification, + payload: { + title: 'Success', + message: 'New order saved' + } + }) + + dispatch({ + type: ActionTypes.reorderApps, payload: apps }) } catch (err) { console.log(err); } +} + +export interface SortAppsAction { + type: ActionTypes.sortApps; + payload: {}; +} + +export const sortApps = () => async (dispatch: Dispatch) => { + try { + const res = await axios.get>('/api/config/useOrdering'); + + console.log(res.data.data); + + dispatch({ + type: ActionTypes.sortApps, + payload: res.data.data.value + }) + } catch (err) { + console.log(err); + } } \ No newline at end of file diff --git a/client/src/store/reducers/app.ts b/client/src/store/reducers/app.ts index dcdb6ef..0935819 100644 --- a/client/src/store/reducers/app.ts +++ b/client/src/store/reducers/app.ts @@ -1,5 +1,6 @@ import { ActionTypes, Action } from '../actions'; import { App } from '../../interfaces/App'; +import { sortData } from '../../utility'; export interface State { loading: boolean; @@ -52,15 +53,9 @@ const pinApp = (state: State, action: Action): State => { } const addAppSuccess = (state: State, action: Action): State => { - const tmpApps: App[] = [...state.apps, action.payload].sort((a: App, b: App) => { - if (a.name.toLowerCase() < b.name.toLowerCase()) { return -1 } - if (a.name.toLowerCase() > b.name.toLowerCase()) { return 1 } - return 0; - }); - return { ...state, - apps: tmpApps + apps: [...state.apps, action.payload] } } @@ -89,13 +84,22 @@ const updateApp = (state: State, action: Action): State => { } } -const reorderApp = (state: State, action: Action): State => { +const reorderApps = (state: State, action: Action): State => { return { ...state, apps: action.payload } } +const sortApps = (state: State, action: Action): State => { + const sortedApps = sortData(state.apps, action.payload); + + return { + ...state, + apps: sortedApps + } +} + const appReducer = (state = initialState, action: Action) => { switch (action.type) { case ActionTypes.getApps: return getApps(state, action); @@ -105,7 +109,8 @@ const appReducer = (state = initialState, action: Action) => { case ActionTypes.addAppSuccess: return addAppSuccess(state, action); case ActionTypes.deleteApp: return deleteApp(state, action); case ActionTypes.updateApp: return updateApp(state, action); - case ActionTypes.reorderApp: return reorderApp(state, action); + case ActionTypes.reorderApps: return reorderApps(state, action); + case ActionTypes.sortApps: return sortApps(state, action); default: return state; } } diff --git a/client/src/utility/index.ts b/client/src/utility/index.ts index 1422624..a5407b2 100644 --- a/client/src/utility/index.ts +++ b/client/src/utility/index.ts @@ -1,4 +1,5 @@ export * from './iconParser'; export * from './urlParser'; export * from './searchConfig'; -export * from './checkVersion'; \ No newline at end of file +export * from './checkVersion'; +export * from './sortData'; \ No newline at end of file diff --git a/client/src/utility/sortData.ts b/client/src/utility/sortData.ts new file mode 100644 index 0000000..c1e9803 --- /dev/null +++ b/client/src/utility/sortData.ts @@ -0,0 +1,29 @@ +interface Data { + name: string; + orderId: number; + createdAt: Date; +} + +export const sortData = (array: T[], field: string): T[] => { + const sortedData = array.slice(); + + if (field === 'name') { + sortedData.sort((a: T, b: T) => { + return a.name.localeCompare(b.name, 'en', { sensitivity: 'base' }) + }) + } else if (field === 'orderId') { + sortedData.sort((a: T, b: T) => { + if (a.orderId < b.orderId) { return -1 } + if (a.orderId > b.orderId) { return 1 } + return 0; + }) + } else { + sortedData.sort((a: T, b: T) => { + if (a.createdAt < b.createdAt) { return -1 } + if (a.createdAt > b.createdAt) { return 1 } + return 0; + }) + } + + return sortedData; +} \ No newline at end of file diff --git a/models/Category.js b/models/Category.js index 5f82633..9c9eda6 100644 --- a/models/Category.js +++ b/models/Category.js @@ -9,6 +9,11 @@ const Category = sequelize.define('Category', { isPinned: { type: DataTypes.BOOLEAN, defaultValue: false + }, + orderId: { + type: DataTypes.INTEGER, + allowNull: true, + defaultValue: null } }, { tableName: 'categories'