Skip to content

Commit 1ddd10f

Browse files
x0sinaImMohammad20000
authored andcommitted
refactor(date-picker, user-modal): enhance date handling and improve mobile responsiveness
1 parent 6a6e85b commit 1ddd10f

File tree

2 files changed

+25
-29
lines changed

2 files changed

+25
-29
lines changed

dashboard/src/components/common/date-picker.tsx

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import { Input } from '@/components/ui/input'
1212
import { useTranslation } from 'react-i18next'
1313
import { Calendar as PersianCalendar } from '@/components/ui/persian-calendar'
1414
import { formatDateByLocale, formatDateShort, isDateDisabled } from '@/utils/datePickerUtils'
15+
import { useIsMobile } from '@/hooks/use-mobile'
1516

1617
export type DatePickerMode = 'single' | 'range'
1718

@@ -147,6 +148,7 @@ export function DatePicker({
147148
}: DatePickerProps) {
148149
const { t, i18n } = useTranslation()
149150
const isPersianLocale = i18n.language === 'fa'
151+
const isMobile = useIsMobile()
150152
const [internalOpen, setInternalOpen] = useState(false)
151153
const [internalDate, setInternalDate] = useState<Date | undefined>(date || undefined)
152154
const [internalRange, setInternalRange] = useState<DateRange | undefined>(
@@ -198,7 +200,11 @@ export function DatePicker({
198200
selectedDate = new Date(now)
199201
}
200202

201-
selectedDate.setHours(now.getHours(), now.getMinutes(), now.getSeconds(), now.getMilliseconds())
203+
if (internalDate && !showTime) {
204+
selectedDate.setHours(internalDate.getHours(), internalDate.getMinutes(), internalDate.getSeconds(), internalDate.getMilliseconds())
205+
} else {
206+
selectedDate.setHours(now.getHours(), now.getMinutes(), now.getSeconds(), now.getMilliseconds())
207+
}
202208

203209
setInternalDate(selectedDate)
204210
const value = useUtcTimestamp ? Math.floor(selectedDate.getTime() / 1000) : getLocalISOTime(selectedDate)
@@ -208,7 +214,7 @@ export function DatePicker({
208214
setIsOpen(false)
209215
}, 0)
210216
},
211-
[onDateChange, onFieldChange, fieldName, useUtcTimestamp, minDate],
217+
[onDateChange, onFieldChange, fieldName, useUtcTimestamp, minDate, internalDate, showTime],
212218
)
213219

214220
const handleDateSelectWrapper = useCallback(
@@ -285,7 +291,7 @@ export function DatePicker({
285291

286292
// Single date mode
287293
if (mode === 'single') {
288-
const displayDate = internalDate || (date ? new Date(date) : null)
294+
const displayDate = internalDate || (date ? new Date(date) : undefined)
289295
const timeValue = displayDate
290296
? `${String(displayDate.getHours()).padStart(2, '0')}:${String(displayDate.getMinutes()).padStart(2, '0')}`
291297
: ''
@@ -330,7 +336,8 @@ export function DatePicker({
330336
</PopoverTrigger>
331337
<PopoverContent
332338
className="w-auto p-0"
333-
align="start"
339+
align="end"
340+
side={isMobile ? 'bottom' : 'left'}
334341
onInteractOutside={() => {
335342
setIsOpen(false)
336343
}}
@@ -339,12 +346,12 @@ export function DatePicker({
339346
{isPersianLocale ? (
340347
<PersianCalendar
341348
mode="single"
342-
selected={displayDate || undefined}
349+
selected={displayDate}
343350
onSelect={handleDateSelectWrapper}
344351
disabled={dateDisabled}
345352
captionLayout="dropdown"
346353
defaultMonth={displayDate || now}
347-
startMonth={minDate || new Date(now.getFullYear(), now.getMonth(), 1)}
354+
startMonth={minDate || new Date(now.getFullYear(), 0, 1)}
348355
endMonth={maxDate || new Date(now.getFullYear() + 15, 11, 31)}
349356
formatters={{
350357
formatMonthDropdown: date => date.toLocaleString('fa-IR', { month: 'short' }),
@@ -353,12 +360,12 @@ export function DatePicker({
353360
) : (
354361
<Calendar
355362
mode="single"
356-
selected={displayDate || undefined}
363+
selected={displayDate}
357364
onSelect={handleDateSelectWrapper}
358365
disabled={dateDisabled}
359366
captionLayout="dropdown"
360367
defaultMonth={displayDate || now}
361-
startMonth={minDate || new Date(now.getFullYear(), now.getMonth(), 1)}
368+
startMonth={minDate || new Date(now.getFullYear(), 0, 1)}
362369
endMonth={maxDate || new Date(now.getFullYear() + 15, 11, 31)}
363370
formatters={{
364371
formatMonthDropdown: date => date.toLocaleString('default', { month: 'short' }),
@@ -367,7 +374,7 @@ export function DatePicker({
367374
)}
368375
{showTime && (
369376
<>
370-
<div className="hidden lg:flex items-center gap-1 flex-wrap border-t p-2">
377+
<div dir="ltr" className="hidden lg:flex items-center gap-1 flex-wrap border-t p-2">
371378
{[
372379
{ label: '+7d', days: 7 },
373380
{ label: '+1m', days: 30 },
@@ -457,7 +464,7 @@ export function DatePicker({
457464
)}
458465
</Button>
459466
</PopoverTrigger>
460-
<PopoverContent className="w-auto p-0" align="end">
467+
<PopoverContent className="w-auto p-0" align="start" side="bottom" sideOffset={4} collisionPadding={8}>
461468
{isPersianLocale ? (
462469
<PersianCalendar
463470
mode="range"

dashboard/src/components/dialogs/user-modal.tsx

Lines changed: 8 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import GroupsSelector from '@/components/common/groups-selector'
2-
32
import { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from '@/components/ui/accordion'
43
import { Button } from '@/components/ui/button'
54
import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle } from '@/components/ui/dialog'
@@ -116,11 +115,11 @@ const ExpiryDateField = ({
116115
if (date) {
117116
// Use the same logic as centralized DatePicker
118117
const value = useUtcTimestamp ? Math.floor(date.getTime() / 1000) : getLocalISOTime(date)
119-
field.onChange(value)
120-
handleFieldChange(fieldName, value)
118+
field.onChange(value)
119+
handleFieldChange(fieldName, value)
121120
} else {
122-
field.onChange('')
123-
handleFieldChange(fieldName, undefined)
121+
field.onChange('')
122+
handleFieldChange(fieldName, undefined)
124123
}
125124
},
126125
[field, handleFieldChange, useUtcTimestamp, fieldName],
@@ -161,14 +160,14 @@ const ExpiryDateField = ({
161160
<FormItem className="flex flex-1 flex-col">
162161
<FormLabel className='mb-0.5'>{label}</FormLabel>
163162
<div className="space-y-2 lg:!mt-0">
164-
<div className="flex lg:hidden items-center gap-1 flex-wrap">
163+
<div dir="ltr" className="flex lg:hidden items-center gap-1 flex-wrap">
165164
{shortcuts.map(({ label, days }) => (
166165
<Button
167166
key={label}
168167
type="button"
169168
variant="ghost"
170169
size="sm"
171-
className="h-5 px-1.5 text-[10px] text-muted-foreground hover:text-foreground"
170+
className="h-7 px-2.5 text-xs text-muted-foreground hover:text-foreground"
172171
onClick={(e) => {
173172
e.preventDefault()
174173
e.stopPropagation()
@@ -397,9 +396,6 @@ export default function UserModal({ isDialogOpen, onOpenChange, form, editingUse
397396
}
398397
}
399398
} else if (typeof value === 'number') {
400-
if (value <= 0) {
401-
return null
402-
}
403399
try {
404400
const dayjsDate = dateUtils.toDayjs(value)
405401
if (dayjsDate.isValid()) {
@@ -564,21 +560,14 @@ export default function UserModal({ isDialogOpen, onOpenChange, form, editingUse
564560
handleFieldChange('on_hold_expire_duration', defaultDuration)
565561
}
566562
// Clear expire field when switching to on_hold status
567-
form.setValue('expire', '')
568-
handleFieldChange('expire', undefined)
563+
form.setValue('expire', undefined)
569564
form.clearErrors('expire')
570565
} else {
571566
// Clear on_hold fields when switching away from on_hold status
572567
form.setValue('on_hold_expire_duration', undefined)
573568
form.clearErrors('on_hold_expire_duration')
574569
form.setValue('on_hold_timeout', undefined)
575570
form.clearErrors('on_hold_timeout')
576-
const currentExpire = form.getValues('expire')
577-
if (currentExpire === null || currentExpire === undefined || currentExpire === '' || (typeof currentExpire === 'number' && currentExpire <= 0)) {
578-
form.setValue('expire', '')
579-
handleFieldChange('expire', undefined)
580-
form.clearErrors('expire')
581-
}
582571
}
583572
}, [status, form, t, handleFieldChange])
584573

@@ -2117,4 +2106,4 @@ export default function UserModal({ isDialogOpen, onOpenChange, form, editingUse
21172106
{/* Subscription Clients Modal */}
21182107
</Dialog>
21192108
)
2120-
}
2109+
}

0 commit comments

Comments
 (0)