From 679cbbbcb6135bcea830afb731ca8d4c580e5b72 Mon Sep 17 00:00:00 2001 From: Dmitriy Lazarev Date: Wed, 23 Aug 2023 17:52:05 +0400 Subject: [PATCH] Add search to notifications Signed-off-by: Dmitriy Lazarev --- .../components/notification/Notifications.tsx | 16 ++ .../notification/NotificationsListHeader.tsx | 188 ++++++++++++------ .../src/components/notification/reducer.ts | 13 ++ .../src/stores/slices/notificationsSlice.ts | 15 +- plugins/parodos/src/stores/types.ts | 1 + 5 files changed, 165 insertions(+), 68 deletions(-) diff --git a/plugins/parodos/src/components/notification/Notifications.tsx b/plugins/parodos/src/components/notification/Notifications.tsx index 9b943d91..833c9de1 100644 --- a/plugins/parodos/src/components/notification/Notifications.tsx +++ b/plugins/parodos/src/components/notification/Notifications.tsx @@ -65,6 +65,7 @@ export const Notification = () => { useEffect(() => { fetchNotifications({ filter: state.notificationFilter, + search: state.notificationSearch, page: state.page, rowsPerPage: state.rowsPerPage, fetch, @@ -75,6 +76,7 @@ export const Notification = () => { state.page, state.rowsPerPage, state.notificationFilter, + state.notificationSearch, fetch, ]); @@ -93,6 +95,16 @@ export const Notification = () => { }); }; + const searchChangeHandler = useCallback( + (e: ChangeEvent) => { + dispatch({ + type: 'CHANGE_SEARCH', + payload: { search: e.target.value }, + }); + }, + [dispatch], + ); + const handleChangePage = ( _event: MouseEvent | null, newPage: number, @@ -167,6 +179,7 @@ export const Notification = () => { fetchNotifications({ filter: state.notificationFilter, + search: state.notificationSearch, page: state.page, rowsPerPage: state.rowsPerPage, fetch, @@ -185,6 +198,7 @@ export const Notification = () => { notifications, state.action, state.notificationFilter, + state.notificationSearch, state.page, state.rowsPerPage, state.selectedNotifications, @@ -224,6 +238,8 @@ export const Notification = () => { ; +type TextFieldProps = PropsFromComponent; type View = 'Filter' | 'Actions'; interface NotificationListHeaderProps { filterChangeHandler: SelectProps['onChange']; filter: SelectProps['selected']; + searchChangeHandler: TextFieldProps['onChange']; + search: TextFieldProps['value']; selected: number; deleteHandler: MouseEventHandler; archiveHandler: MouseEventHandler; @@ -32,12 +48,8 @@ const useStyles = makeStyles(theme => ({ selected: { marginLeft: theme.spacing(2), color: theme.palette.error.main, - position: 'relative', - top: theme.spacing(2), }, actions: { - position: 'relative', - top: theme.spacing(2), display: 'flex', justifyContent: 'flex-end', marginRight: theme.spacing(1), @@ -51,11 +63,18 @@ const useStyles = makeStyles(theme => ({ filterIcon: { color: theme.palette.primary.main, }, + progress: { + position: 'relative', + top: theme.spacing(1), + height: theme.spacing(0.5), + }, })); export function NotificationListHeader({ filterChangeHandler, filter, + searchChangeHandler, + search, selected, deleteHandler, archiveHandler, @@ -65,74 +84,111 @@ export function NotificationListHeader({ const styles = useStyles(); const view: View = selected === 0 ? 'Filter' : 'Actions'; + const [searchValue, setSearchValue] = useState(search); + + const debouncedSearchHandler = useMemo( + () => searchChangeHandler && debounce(searchChangeHandler, 500), + [searchChangeHandler], + ); + const isLoading = searchValue !== search; + + const handleSearchChange = useCallback( + (event: React.ChangeEvent) => { + setSearchValue(event.target.value); + debouncedSearchHandler?.(event); + }, + [debouncedSearchHandler], + ); + + useEffect(() => { + setSearchValue(search); + }, [search]); + return ( - - - {view === 'Filter' ? ( - + + + + + ) : ( - - {filter !== 'ARCHIVED' && ( - - - - )} - {filter !== 'UNREAD' && ( + + + {selected} selected + + + )} + + {view === 'Filter' ? ( + + + + ) : ( + + {filter !== 'ARCHIVED' && ( + + + + )} + {filter !== 'UNREAD' && ( + + + + )} - + - )} - - - - - )} + + )} + - +
{isLoading && }
+ ); } diff --git a/plugins/parodos/src/components/notification/reducer.ts b/plugins/parodos/src/components/notification/reducer.ts index 877f5265..3a971c0e 100644 --- a/plugins/parodos/src/components/notification/reducer.ts +++ b/plugins/parodos/src/components/notification/reducer.ts @@ -45,6 +45,12 @@ type Actions = payload: { filter: NotificationState; }; + } + | { + type: 'CHANGE_SEARCH'; + payload: { + search: string; + }; }; export const initialState = { @@ -55,6 +61,7 @@ export const initialState = { selectedNotifications: [] as string[], action: 'ARCHIVE' as Action, notificationFilter: 'ALL' as NotificationState, + notificationSearch: '', }; export type State = typeof initialState; @@ -127,6 +134,12 @@ export const reducer = (draft: State, action: Actions) => { break; } + case 'CHANGE_SEARCH': { + draft.notificationSearch = action.payload.search; + draft.page = 0; + + break; + } default: { throw new Error(`unknown action type`); } diff --git a/plugins/parodos/src/stores/slices/notificationsSlice.ts b/plugins/parodos/src/stores/slices/notificationsSlice.ts index d75da62c..7207ec33 100644 --- a/plugins/parodos/src/stores/slices/notificationsSlice.ts +++ b/plugins/parodos/src/stores/slices/notificationsSlice.ts @@ -8,11 +8,14 @@ async function fetchNotifications( baseUrl: string, options: Parameters[0], ) { - const { filter, page, rowsPerPage, fetch } = options; + const { filter, search, page, rowsPerPage, fetch } = options; let urlQuery = `?page=${page}&size=${rowsPerPage}&sort=notificationMessage.createdOn,desc`; if (filter !== 'ALL') { urlQuery += `&state=${filter}`; } + if (search) { + urlQuery += `&searchTerm=${search}`; + } const response = await fetch(`${baseUrl}${urls.Notifications}${urlQuery}`); @@ -34,6 +37,7 @@ export const createNotificationsSlice: StateCreator< try { const notifications = await fetchNotifications(get().baseUrl as string, { filter: 'UNREAD', + search: '', page: 0, rowsPerPage: 0, fetch, @@ -46,7 +50,13 @@ export const createNotificationsSlice: StateCreator< console.error('Error fetching notifications', e); } }, - async fetchNotifications({ filter = 'ALL', page, rowsPerPage, fetch }) { + async fetchNotifications({ + filter = 'ALL', + search, + page, + rowsPerPage, + fetch, + }) { if (get().notificationsLoading) { return; } @@ -58,6 +68,7 @@ export const createNotificationsSlice: StateCreator< try { const notifications = await fetchNotifications(get().baseUrl as string, { filter, + search, page, rowsPerPage, fetch, diff --git a/plugins/parodos/src/stores/types.ts b/plugins/parodos/src/stores/types.ts index 954a0d8b..317b3b84 100644 --- a/plugins/parodos/src/stores/types.ts +++ b/plugins/parodos/src/stores/types.ts @@ -70,6 +70,7 @@ export interface NotificationsSlice { fetchNotifications(params: { fetch: FetchApi['fetch']; filter: NotificationState; + search: string; page: number; rowsPerPage: number; }): Promise;