@@ -8,8 +8,8 @@ import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from '
88import { Input } from '@/components/ui/input'
99import { LoaderButton } from '@/components/ui/loader-button'
1010import { Calendar as PersianCalendar } from '@/components/ui/persian-calendar'
11- import { Popover , PopoverContent , PopoverTrigger } from '@/components/ui/popover'
1211import { Select , SelectContent , SelectItem , SelectTrigger , SelectValue } from '@/components/ui/select'
12+ import { Popover , PopoverContent , PopoverTrigger } from '@/components/ui/popover'
1313import { Switch } from '@/components/ui/switch'
1414import { Textarea } from '@/components/ui/textarea'
1515import useDirDetection from '@/hooks/use-dir-detection'
@@ -30,7 +30,7 @@ import {
3030import { dateUtils , useRelativeExpiryDate } from '@/utils/dateFormatter'
3131import { formatBytes } from '@/utils/formatByte'
3232import { useQuery , useQueryClient } from '@tanstack/react-query'
33- import { CalendarIcon , Layers , ListStart , Lock , RefreshCcw , Users , X } from 'lucide-react'
33+ import { CalendarIcon , ChevronDown , Layers , ListStart , Lock , RefreshCcw , Users , X } from 'lucide-react'
3434import React , { useEffect , useState , useTransition } from 'react'
3535import { UseFormReturn } from 'react-hook-form'
3636import { useTranslation } from 'react-i18next'
@@ -275,7 +275,7 @@ const ExpiryDateField = ({
275275 < PopoverContent
276276 className = "w-auto p-0"
277277 align = "start"
278- onInteractOutside = { e => {
278+ onInteractOutside = { ( e : Event ) => {
279279 e . preventDefault ( )
280280 setCalendarOpen ( false )
281281 } }
@@ -373,6 +373,98 @@ const ExpiryDateField = ({
373373
374374export { ExpiryDateField }
375375
376+ // Custom Select component that works reliably on mobile
377+ const StatusSelect = ( {
378+ value,
379+ onValueChange,
380+ placeholder,
381+ children,
382+ disabled
383+ } : {
384+ value ?: string
385+ onValueChange ?: ( value : string ) => void
386+ placeholder ?: string
387+ children : React . ReactNode
388+ disabled ?: boolean
389+ } ) => {
390+ const [ open , setOpen ] = useState ( false )
391+ const { t } = useTranslation ( )
392+
393+ const handleSelect = ( selectedValue : string ) => {
394+ onValueChange ?.( selectedValue )
395+ setOpen ( false )
396+ }
397+
398+ const getStatusText = ( statusValue ?: string ) => {
399+ if ( ! statusValue ) return placeholder || t ( 'userDialog.selectStatus' , { defaultValue : 'Select status' } )
400+
401+ switch ( statusValue ) {
402+ case 'active' : return t ( 'status.active' , { defaultValue : 'Active' } )
403+ case 'disabled' : return t ( 'status.disabled' , { defaultValue : 'Disabled' } )
404+ case 'on_hold' : return t ( 'status.on_hold' , { defaultValue : 'On Hold' } )
405+ default : return placeholder || t ( 'userDialog.selectStatus' , { defaultValue : 'Select status' } )
406+ }
407+ }
408+
409+ return (
410+ < Popover open = { open } onOpenChange = { setOpen } >
411+ < PopoverTrigger asChild >
412+ < Button
413+ variant = "outline"
414+ role = "combobox"
415+ aria-expanded = { open }
416+ className = "w-full justify-between h-9 px-3 py-2 text-sm"
417+ disabled = { disabled }
418+ >
419+ < span className = "truncate" > { getStatusText ( value ) } </ span >
420+ < ChevronDown className = "h-4 w-4 shrink-0 opacity-50" />
421+ </ Button >
422+ </ PopoverTrigger >
423+ < PopoverContent className = "w-[--radix-popover-trigger-width] p-1" align = "start" >
424+ { React . Children . map ( children , ( child ) => {
425+ if ( React . isValidElement ( child ) && child . props . value ) {
426+ return React . cloneElement ( child , {
427+ onSelect : handleSelect
428+ } )
429+ }
430+ return child
431+ } ) }
432+ </ PopoverContent >
433+ </ Popover >
434+ )
435+ }
436+
437+ const StatusSelectItem = ( {
438+ value,
439+ children,
440+ onSelect
441+ } : {
442+ value : string
443+ children : React . ReactNode
444+ onSelect ?: ( value : string ) => void
445+ } ) => {
446+ const getDotColor = ( ) => {
447+ switch ( value ) {
448+ case 'active' : return 'bg-green-500'
449+ case 'disabled' : return 'bg-zinc-500'
450+ case 'on_hold' : return 'bg-violet-500'
451+ default : return 'bg-gray-500'
452+ }
453+ }
454+
455+ return (
456+ < div
457+ className = "relative flex w-full min-w-0 cursor-pointer select-none items-center rounded-sm py-2 px-2 text-sm outline-none hover:bg-accent hover:text-accent-foreground transition-colors"
458+ onClick = { ( ) => onSelect ?.( value ) }
459+ >
460+ < span className = "truncate min-w-0 flex-1 pr-2" > { children } </ span >
461+ < span className = "flex h-3.5 w-3.5 shrink-0 items-center justify-center" >
462+ < div className = { `h-2 w-2 rounded-full ${ getDotColor ( ) } ` } />
463+ </ span >
464+ </ div >
465+ )
466+ }
467+
376468export default function UserModal ( { isDialogOpen, onOpenChange, form, editingUser, editingUserId, onSuccessCallback } : UserModalProps ) {
377469 const { t } = useTranslation ( )
378470 const dir = useDirDetection ( )
@@ -494,14 +586,14 @@ export default function UserModal({ isDialogOpen, onOpenChange, form, editingUse
494586 } ,
495587 )
496588
497- // Fetch data for tabs with proper caching and refetch on page view
589+ // Fetch data for tabs without caching
498590 const { data : templatesData , isLoading : templatesLoading } = useGetUserTemplates ( undefined , {
499591 query : {
500- staleTime : 5 * 60 * 1000 , // 5 minutes
501- gcTime : 10 * 60 * 1000 , // 10 minutes
502- refetchOnWindowFocus : true ,
592+ staleTime : 0 , // No stale time - always fetch fresh data
593+ gcTime : 0 , // No garbage collection time - no caching
594+ refetchOnWindowFocus : false ,
503595 refetchOnMount : true ,
504- refetchOnReconnect : true ,
596+ refetchOnReconnect : false ,
505597 } ,
506598 } )
507599
@@ -1081,6 +1173,7 @@ export default function UserModal({ isDialogOpen, onOpenChange, form, editingUse
10811173 setUsePersianCalendar ( i18n . language === 'fa' )
10821174 } , [ i18n . language ] )
10831175
1176+
10841177 return (
10851178 < Dialog open = { isDialogOpen } onOpenChange = { handleModalOpenChange } >
10861179 < DialogContent className = { `lg:min-w-[900px] ${ editingUser ? 'h-full sm:h-auto' : 'h-auto' } ` } >
@@ -1154,23 +1247,18 @@ export default function UserModal({ isDialogOpen, onOpenChange, form, editingUse
11541247 < FormItem className = "w-1/3" >
11551248 < FormLabel > { t ( 'status' , { defaultValue : 'Status' } ) } </ FormLabel >
11561249 < FormControl >
1157- < Select
1250+ < StatusSelect
1251+ value = { field . value || '' }
11581252 onValueChange = { value => {
11591253 field . onChange ( value )
11601254 handleFieldChange ( 'status' , value )
1161- handleFieldBlur ( 'status' )
11621255 } }
1163- value = { field . value || '' }
1256+ placeholder = { t ( 'userDialog.selectStatus' , { defaultValue : 'Select status' } ) }
11641257 >
1165- < SelectTrigger >
1166- < SelectValue placeholder = { t ( 'userDialog.selectStatus' , { defaultValue : 'Select status' } ) } />
1167- </ SelectTrigger >
1168- < SelectContent >
1169- < SelectItem value = "active" > { t ( 'status.active' , { defaultValue : 'Active' } ) } </ SelectItem >
1170- { editingUser && < SelectItem value = "disabled" > { t ( 'status.disabled' , { defaultValue : 'Disabled' } ) } </ SelectItem > }
1171- < SelectItem value = "on_hold" > { t ( 'status.on_hold' , { defaultValue : 'On Hold' } ) } </ SelectItem >
1172- </ SelectContent >
1173- </ Select >
1258+ < StatusSelectItem value = "active" > { t ( 'status.active' , { defaultValue : 'Active' } ) } </ StatusSelectItem >
1259+ { editingUser && < StatusSelectItem value = "disabled" > { t ( 'status.disabled' , { defaultValue : 'Disabled' } ) } </ StatusSelectItem > }
1260+ < StatusSelectItem value = "on_hold" > { t ( 'status.on_hold' , { defaultValue : 'On Hold' } ) } </ StatusSelectItem >
1261+ </ StatusSelect >
11741262 </ FormControl >
11751263 < FormMessage />
11761264 </ FormItem >
@@ -1916,7 +2004,7 @@ export default function UserModal({ isDialogOpen, onOpenChange, form, editingUse
19162004 >
19172005 { t ( 'cancel' , { defaultValue : 'Cancel' } ) }
19182006 </ Button >
1919- < LoaderButton type = "submit" isLoading = { loading } disabled = { false } loadingText = { editingUser ? t ( 'modifying' ) : t ( 'creating' ) } >
2007+ < LoaderButton type = "submit" isLoading = { loading } disabled = { ! isFormValid } loadingText = { editingUser ? t ( 'modifying' ) : t ( 'creating' ) } >
19202008 { editingUser ? t ( 'modify' , { defaultValue : 'Modify' } ) : t ( 'create' , { defaultValue : 'Create' } ) }
19212009 </ LoaderButton >
19222010 </ div >
0 commit comments