Skip to content

Commit 63fe68f

Browse files
committed
fix: telegram input fields allow negative numbers and complete clearing
1 parent 3de6285 commit 63fe68f

File tree

3 files changed

+261
-70
lines changed

3 files changed

+261
-70
lines changed

dashboard/src/pages/_dashboard.settings.cleanup.tsx

Lines changed: 93 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -129,8 +129,37 @@ export default function CleanupSettings() {
129129
const count = response?.count || 0
130130
toast.success(t('settings.cleanup.expiredUsers.deleteSuccess', { count }))
131131
},
132-
onError: () => {
133-
toast.error(t('settings.cleanup.expiredUsers.deleteFailed'))
132+
onError: (error: any) => {
133+
// Extract detailed error message
134+
let errorMessage = t('settings.cleanup.expiredUsers.deleteFailed')
135+
136+
if (error?.data?.detail) {
137+
const detail = error.data.detail
138+
if (typeof detail === 'string') {
139+
errorMessage = detail
140+
} else if (typeof detail === 'object' && !Array.isArray(detail)) {
141+
const fieldErrors = Object.entries(detail)
142+
.map(([field, message]) => `${field}: ${message}`)
143+
.join(', ')
144+
errorMessage = fieldErrors
145+
}
146+
} else if (error?.response?.data?.detail) {
147+
const detail = error.response.data.detail
148+
if (typeof detail === 'string') {
149+
errorMessage = detail
150+
} else if (typeof detail === 'object' && !Array.isArray(detail)) {
151+
const fieldErrors = Object.entries(detail)
152+
.map(([field, message]) => `${field}: ${message}`)
153+
.join(', ')
154+
errorMessage = fieldErrors
155+
}
156+
} else if (error?.message) {
157+
errorMessage = error.message
158+
}
159+
160+
toast.error(t('settings.cleanup.expiredUsers.deleteFailed'), {
161+
description: errorMessage,
162+
})
134163
},
135164
},
136165
)
@@ -152,8 +181,37 @@ export default function CleanupSettings() {
152181
onSuccess: () => {
153182
toast.success(t('settings.cleanup.resetUsage.resetSuccess'))
154183
},
155-
onError: () => {
156-
toast.error(t('settings.cleanup.resetUsage.resetFailed'))
184+
onError: (error: any) => {
185+
// Extract detailed error message
186+
let errorMessage = t('settings.cleanup.resetUsage.resetFailed')
187+
188+
if (error?.data?.detail) {
189+
const detail = error.data.detail
190+
if (typeof detail === 'string') {
191+
errorMessage = detail
192+
} else if (typeof detail === 'object' && !Array.isArray(detail)) {
193+
const fieldErrors = Object.entries(detail)
194+
.map(([field, message]) => `${field}: ${message}`)
195+
.join(', ')
196+
errorMessage = fieldErrors
197+
}
198+
} else if (error?.response?.data?.detail) {
199+
const detail = error.response.data.detail
200+
if (typeof detail === 'string') {
201+
errorMessage = detail
202+
} else if (typeof detail === 'object' && !Array.isArray(detail)) {
203+
const fieldErrors = Object.entries(detail)
204+
.map(([field, message]) => `${field}: ${message}`)
205+
.join(', ')
206+
errorMessage = fieldErrors
207+
}
208+
} else if (error?.message) {
209+
errorMessage = error.message
210+
}
211+
212+
toast.error(t('settings.cleanup.resetUsage.resetFailed'), {
213+
description: errorMessage,
214+
})
157215
},
158216
})
159217
}
@@ -177,8 +235,37 @@ export default function CleanupSettings() {
177235
onSuccess: () => {
178236
toast.success(t('settings.cleanup.clearUsageData.clearSuccess', { table: selectedTable }))
179237
},
180-
onError: () => {
181-
toast.error(t('settings.cleanup.clearUsageData.clearFailed'))
238+
onError: (error: any) => {
239+
// Extract detailed error message
240+
let errorMessage = t('settings.cleanup.clearUsageData.clearFailed')
241+
242+
if (error?.data?.detail) {
243+
const detail = error.data.detail
244+
if (typeof detail === 'string') {
245+
errorMessage = detail
246+
} else if (typeof detail === 'object' && !Array.isArray(detail)) {
247+
const fieldErrors = Object.entries(detail)
248+
.map(([field, message]) => `${field}: ${message}`)
249+
.join(', ')
250+
errorMessage = fieldErrors
251+
}
252+
} else if (error?.response?.data?.detail) {
253+
const detail = error.response.data.detail
254+
if (typeof detail === 'string') {
255+
errorMessage = detail
256+
} else if (typeof detail === 'object' && !Array.isArray(detail)) {
257+
const fieldErrors = Object.entries(detail)
258+
.map(([field, message]) => `${field}: ${message}`)
259+
.join(', ')
260+
errorMessage = fieldErrors
261+
}
262+
} else if (error?.message) {
263+
errorMessage = error.message
264+
}
265+
266+
toast.error(t('settings.cleanup.clearUsageData.clearFailed'), {
267+
description: errorMessage,
268+
})
182269
},
183270
},
184271
)

dashboard/src/pages/_dashboard.settings.notifications.tsx

Lines changed: 142 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { Label } from '@/components/ui/label'
44
import { Input } from '@/components/ui/input'
55
import { PasswordInput } from '@/components/ui/password-input'
66
import { Button } from '@/components/ui/button'
7-
import { useEffect } from 'react'
7+
import { useEffect, useState } from 'react'
88
import { z } from 'zod'
99
import { useForm } from 'react-hook-form'
1010
import { zodResolver } from '@hookform/resolvers/zod'
@@ -43,6 +43,7 @@ const notificationSettingsSchema = z.object({
4343

4444
type NotificationSettingsForm = z.infer<typeof notificationSettingsSchema>
4545

46+
4647
export default function NotificationSettings() {
4748
const { t } = useTranslation()
4849

@@ -396,18 +397,47 @@ export default function NotificationSettings() {
396397
<FormField
397398
control={form.control}
398399
name="notification_settings.telegram_admin_id"
399-
render={({ field }) => (
400-
<FormControl>
401-
<Input
402-
type="number"
403-
{...field}
404-
value={field.value || ''}
405-
onChange={(e) => field.onChange(e.target.value ? parseInt(e.target.value) : undefined)}
406-
className="w-full"
407-
placeholder="123456789"
408-
/>
409-
</FormControl>
410-
)}
400+
render={({ field }) => {
401+
const [inputValue, setInputValue] = useState(field.value?.toString() ?? '');
402+
403+
// Sync input value when field value changes (e.g., from form reset)
404+
useEffect(() => {
405+
setInputValue(field.value?.toString() ?? '');
406+
}, [field.value]);
407+
408+
return (
409+
<FormControl>
410+
<Input
411+
type="text"
412+
name={field.name}
413+
ref={field.ref}
414+
value={inputValue}
415+
onChange={(e) => {
416+
const value = e.target.value;
417+
setInputValue(value);
418+
419+
// Update form value for valid inputs or empty
420+
if (value === '') {
421+
field.onChange(undefined);
422+
} else if (/^-?\d+$/.test(value)) {
423+
field.onChange(parseInt(value));
424+
}
425+
// Keep invalid input in display but don't update form
426+
}}
427+
onBlur={() => {
428+
// On blur, ensure the display matches the form value
429+
// If current input is invalid, reset display to form value
430+
if (inputValue !== '' && !/^-?\d+$/.test(inputValue)) {
431+
setInputValue(field.value?.toString() ?? '');
432+
}
433+
field.onBlur();
434+
}}
435+
className="w-full"
436+
placeholder="123456789"
437+
/>
438+
</FormControl>
439+
);
440+
}}
411441
/>
412442
</div>
413443

@@ -419,18 +449,47 @@ export default function NotificationSettings() {
419449
<FormField
420450
control={form.control}
421451
name="notification_settings.telegram_channel_id"
422-
render={({ field }) => (
423-
<FormControl>
424-
<Input
425-
type="number"
426-
{...field}
427-
value={field.value || ''}
428-
onChange={(e) => field.onChange(e.target.value ? parseInt(e.target.value) : undefined)}
429-
className="w-full"
430-
placeholder="-1001234567890"
431-
/>
432-
</FormControl>
433-
)}
452+
render={({ field }) => {
453+
const [inputValue, setInputValue] = useState(field.value?.toString() ?? '');
454+
455+
// Sync input value when field value changes (e.g., from form reset)
456+
useEffect(() => {
457+
setInputValue(field.value?.toString() ?? '');
458+
}, [field.value]);
459+
460+
return (
461+
<FormControl>
462+
<Input
463+
type="text"
464+
name={field.name}
465+
ref={field.ref}
466+
value={inputValue}
467+
onChange={(e) => {
468+
const value = e.target.value;
469+
setInputValue(value);
470+
471+
// Update form value for valid inputs or empty
472+
if (value === '') {
473+
field.onChange(undefined);
474+
} else if (/^-?\d+$/.test(value)) {
475+
field.onChange(parseInt(value));
476+
}
477+
// Keep invalid input in display but don't update form
478+
}}
479+
onBlur={() => {
480+
// On blur, ensure the display matches the form value
481+
// If current input is invalid, reset display to form value
482+
if (inputValue !== '' && !/^-?\d+$/.test(inputValue)) {
483+
setInputValue(field.value?.toString() ?? '');
484+
}
485+
field.onBlur();
486+
}}
487+
className="w-full"
488+
placeholder="-1001234567890"
489+
/>
490+
</FormControl>
491+
);
492+
}}
434493
/>
435494
</div>
436495

@@ -442,18 +501,47 @@ export default function NotificationSettings() {
442501
<FormField
443502
control={form.control}
444503
name="notification_settings.telegram_topic_id"
445-
render={({ field }) => (
446-
<FormControl>
447-
<Input
448-
type="number"
449-
{...field}
450-
value={field.value || ''}
451-
onChange={(e) => field.onChange(e.target.value ? parseInt(e.target.value) : undefined)}
452-
className="w-full"
453-
placeholder="123"
454-
/>
455-
</FormControl>
456-
)}
504+
render={({ field }) => {
505+
const [inputValue, setInputValue] = useState(field.value?.toString() ?? '');
506+
507+
// Sync input value when field value changes (e.g., from form reset)
508+
useEffect(() => {
509+
setInputValue(field.value?.toString() ?? '');
510+
}, [field.value]);
511+
512+
return (
513+
<FormControl>
514+
<Input
515+
type="text"
516+
name={field.name}
517+
ref={field.ref}
518+
value={inputValue}
519+
onChange={(e) => {
520+
const value = e.target.value;
521+
setInputValue(value);
522+
523+
// Update form value for valid inputs or empty
524+
if (value === '') {
525+
field.onChange(undefined);
526+
} else if (/^-?\d+$/.test(value)) {
527+
field.onChange(parseInt(value));
528+
}
529+
// Keep invalid input in display but don't update form
530+
}}
531+
onBlur={() => {
532+
// On blur, ensure the display matches the form value
533+
// If current input is invalid, reset display to form value
534+
if (inputValue !== '' && !/^-?\d+$/.test(inputValue)) {
535+
setInputValue(field.value?.toString() ?? '');
536+
}
537+
field.onBlur();
538+
}}
539+
className="w-full"
540+
placeholder="123"
541+
/>
542+
</FormControl>
543+
);
544+
}}
457545
/>
458546
</div>
459547
</div>
@@ -550,12 +638,24 @@ export default function NotificationSettings() {
550638
name="notification_settings.max_retries"
551639
render={({ field }) => (
552640
<FormControl>
553-
<Input
554-
type="number"
555-
min="1"
641+
<Input
642+
type="number"
643+
min="1"
556644
max="10"
557-
{...field}
558-
onChange={(e) => field.onChange(parseInt(e.target.value))}
645+
name={field.name}
646+
ref={field.ref}
647+
value={field.value ?? ''}
648+
onChange={(e) => {
649+
const value = e.target.value;
650+
// Allow typing any characters, but only set valid positive numbers or empty (defaults to 3)
651+
if (value === '') {
652+
field.onChange(3);
653+
} else if (/^\d+$/.test(value)) {
654+
field.onChange(parseInt(value));
655+
}
656+
// Ignore invalid input
657+
}}
658+
onBlur={field.onBlur}
559659
className="w-full"
560660
placeholder="3"
561661
/>

0 commit comments

Comments
 (0)