@@ -4,6 +4,7 @@ import { useEffect, useState } from 'react';
44import { notifierApi } from '../../../entity/notifiers' ;
55import type { Notifier } from '../../../entity/notifiers' ;
66import type { WorkspaceResponse } from '../../../entity/workspaces' ;
7+ import { useIsMobile } from '../../../shared/hooks' ;
78import { NotifierCardComponent } from './NotifierCardComponent' ;
89import { NotifierComponent } from './NotifierComponent' ;
910import { EditNotifierComponent } from './edit/EditNotifierComponent' ;
@@ -14,21 +15,47 @@ interface Props {
1415 isCanManageNotifiers : boolean ;
1516}
1617
18+ const SELECTED_NOTIFIER_STORAGE_KEY = 'selectedNotifierId' ;
19+
1720export const NotifiersComponent = ( { contentHeight, workspace, isCanManageNotifiers } : Props ) => {
21+ const isMobile = useIsMobile ( ) ;
1822 const [ isLoading , setIsLoading ] = useState ( true ) ;
1923 const [ notifiers , setNotifiers ] = useState < Notifier [ ] > ( [ ] ) ;
24+ const [ searchQuery , setSearchQuery ] = useState ( '' ) ;
2025
2126 const [ isShowAddNotifier , setIsShowAddNotifier ] = useState ( false ) ;
2227 const [ selectedNotifierId , setSelectedNotifierId ] = useState < string | undefined > ( undefined ) ;
23- const loadNotifiers = ( ) => {
24- setIsLoading ( true ) ;
28+
29+ const updateSelectedNotifierId = ( notifierId : string | undefined ) => {
30+ setSelectedNotifierId ( notifierId ) ;
31+ if ( notifierId ) {
32+ localStorage . setItem ( `${ SELECTED_NOTIFIER_STORAGE_KEY } _${ workspace . id } ` , notifierId ) ;
33+ } else {
34+ localStorage . removeItem ( `${ SELECTED_NOTIFIER_STORAGE_KEY } _${ workspace . id } ` ) ;
35+ }
36+ } ;
37+
38+ const loadNotifiers = ( isSilent = false , selectNotifierId ?: string ) => {
39+ if ( ! isSilent ) {
40+ setIsLoading ( true ) ;
41+ }
2542
2643 notifierApi
2744 . getNotifiers ( workspace . id )
2845 . then ( ( notifiers ) => {
2946 setNotifiers ( notifiers ) ;
30- if ( ! selectedNotifierId ) {
31- setSelectedNotifierId ( notifiers [ 0 ] ?. id ) ;
47+ if ( selectNotifierId ) {
48+ updateSelectedNotifierId ( selectNotifierId ) ;
49+ } else if ( ! selectedNotifierId && ! isSilent && ! isMobile ) {
50+ // On desktop, auto-select a notifier; on mobile, keep it unselected
51+ const savedNotifierId = localStorage . getItem (
52+ `${ SELECTED_NOTIFIER_STORAGE_KEY } _${ workspace . id } ` ,
53+ ) ;
54+ const notifierToSelect =
55+ savedNotifierId && notifiers . some ( ( n ) => n . id === savedNotifierId )
56+ ? savedNotifierId
57+ : notifiers [ 0 ] ?. id ;
58+ updateSelectedNotifierId ( notifierToSelect ) ;
3259 }
3360 } )
3461 . catch ( ( e ) => alert ( e . message ) )
@@ -37,6 +64,12 @@ export const NotifiersComponent = ({ contentHeight, workspace, isCanManageNotifi
3764
3865 useEffect ( ( ) => {
3966 loadNotifiers ( ) ;
67+
68+ const interval = setInterval ( ( ) => {
69+ loadNotifiers ( true ) ;
70+ } , 5 * 60_000 ) ;
71+
72+ return ( ) => clearInterval ( interval ) ;
4073 } , [ ] ) ;
4174
4275 if ( isLoading ) {
@@ -53,45 +86,89 @@ export const NotifiersComponent = ({ contentHeight, workspace, isCanManageNotifi
5386 </ Button >
5487 ) ;
5588
89+ const filteredNotifiers = notifiers . filter ( ( notifier ) =>
90+ notifier . name . toLowerCase ( ) . includes ( searchQuery . toLowerCase ( ) ) ,
91+ ) ;
92+
93+ // On mobile, show either the list or the notifier details
94+ const showNotifierList = ! isMobile || ! selectedNotifierId ;
95+ const showNotifierDetails = selectedNotifierId && ( ! isMobile || selectedNotifierId ) ;
96+
5697 return (
5798 < >
5899 < div className = "flex grow" >
59- < div
60- className = "mx-3 w-[250px] min-w-[250px] overflow-y-auto"
61- style = { { height : contentHeight } }
62- >
63- { notifiers . length >= 5 && isCanManageNotifiers && addNotifierButton }
64-
65- { notifiers . map ( ( notifier ) => (
66- < NotifierCardComponent
67- key = { notifier . id }
68- notifier = { notifier }
69- selectedNotifierId = { selectedNotifierId }
70- setSelectedNotifierId = { setSelectedNotifierId }
71- />
72- ) ) }
100+ { showNotifierList && (
101+ < div
102+ className = "w-full overflow-y-auto md:mx-3 md:w-[250px] md:min-w-[250px] md:pr-2"
103+ style = { { height : contentHeight } }
104+ >
105+ { notifiers . length >= 5 && (
106+ < >
107+ { isCanManageNotifiers && addNotifierButton }
73108
74- { notifiers . length < 5 && isCanManageNotifiers && addNotifierButton }
109+ < div className = "mb-2" >
110+ < input
111+ placeholder = "Search notifier"
112+ value = { searchQuery }
113+ onChange = { ( e ) => setSearchQuery ( e . target . value ) }
114+ className = "w-full border-b border-gray-300 p-1 text-gray-500 outline-none"
115+ />
116+ </ div >
117+ </ >
118+ ) }
75119
76- < div className = "mx-3 text-center text-xs text-gray-500" >
77- Notifier - is a place where notifications will be sent (email, Slack, Telegram, etc.)
120+ { filteredNotifiers . length > 0
121+ ? filteredNotifiers . map ( ( notifier ) => (
122+ < NotifierCardComponent
123+ key = { notifier . id }
124+ notifier = { notifier }
125+ selectedNotifierId = { selectedNotifierId }
126+ setSelectedNotifierId = { updateSelectedNotifierId }
127+ />
128+ ) )
129+ : searchQuery && (
130+ < div className = "mb-4 text-center text-sm text-gray-500" >
131+ No notifiers found matching "{ searchQuery } "
132+ </ div >
133+ ) }
134+
135+ { notifiers . length < 5 && isCanManageNotifiers && addNotifierButton }
136+
137+ < div className = "mx-3 text-center text-xs text-gray-500" >
138+ Notifier - is a place where notifications will be sent (email, Slack, Telegram, etc.)
139+ </ div >
78140 </ div >
79- </ div >
141+ ) }
80142
81- { selectedNotifierId && (
82- < NotifierComponent
83- notifierId = { selectedNotifierId }
84- onNotifierChanged = { ( ) => {
85- loadNotifiers ( ) ;
86- } }
87- onNotifierDeleted = { ( ) => {
88- loadNotifiers ( ) ;
89- setSelectedNotifierId (
90- notifiers . filter ( ( notifier ) => notifier . id !== selectedNotifierId ) [ 0 ] ?. id ,
91- ) ;
92- } }
93- isCanManageNotifiers = { isCanManageNotifiers }
94- />
143+ { showNotifierDetails && (
144+ < div className = "flex w-full flex-col md:flex-1" >
145+ { isMobile && (
146+ < div className = "mb-2" >
147+ < Button
148+ type = "default"
149+ onClick = { ( ) => updateSelectedNotifierId ( undefined ) }
150+ className = "w-full"
151+ >
152+ ← Back to notifiers
153+ </ Button >
154+ </ div >
155+ ) }
156+
157+ < NotifierComponent
158+ notifierId = { selectedNotifierId }
159+ onNotifierChanged = { ( ) => {
160+ loadNotifiers ( ) ;
161+ } }
162+ onNotifierDeleted = { ( ) => {
163+ const remainingNotifiers = notifiers . filter (
164+ ( notifier ) => notifier . id !== selectedNotifierId ,
165+ ) ;
166+ updateSelectedNotifierId ( remainingNotifiers [ 0 ] ?. id ) ;
167+ loadNotifiers ( ) ;
168+ } }
169+ isCanManageNotifiers = { isCanManageNotifiers }
170+ />
171+ </ div >
95172 ) }
96173 </ div >
97174
@@ -111,8 +188,8 @@ export const NotifiersComponent = ({ contentHeight, workspace, isCanManageNotifi
111188 isShowName
112189 isShowClose = { false }
113190 onClose = { ( ) => setIsShowAddNotifier ( false ) }
114- onChanged = { ( ) => {
115- loadNotifiers ( ) ;
191+ onChanged = { ( notifier ) => {
192+ loadNotifiers ( false , notifier . id ) ;
116193 setIsShowAddNotifier ( false ) ;
117194 } }
118195 />
0 commit comments