style(ui): align wallet and profile interactions
This commit is contained in:
@@ -350,7 +350,7 @@ export function AccountBindingsTab({
|
||||
<Button
|
||||
variant='ghost'
|
||||
size='sm'
|
||||
className='text-destructive hover:text-destructive h-7 shrink-0 px-2.5 text-xs'
|
||||
className='text-destructive h-7 shrink-0 px-2.5 text-xs'
|
||||
onClick={() => setUnbindTarget(binding)}
|
||||
>
|
||||
<Unlink className='mr-1 h-3 w-3' />
|
||||
|
||||
@@ -24,8 +24,8 @@ import { ROLE } from '@/lib/roles'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { Input } from '@/components/ui/input'
|
||||
import { Label } from '@/components/ui/label'
|
||||
import { RadioGroup, RadioGroupItem } from '@/components/ui/radio-group'
|
||||
import { Switch } from '@/components/ui/switch'
|
||||
import { ToggleGroup, ToggleGroupItem } from '@/components/ui/toggle-group'
|
||||
import { PasswordInput } from '@/components/password-input'
|
||||
import { updateUserSettings } from '../../api'
|
||||
import {
|
||||
@@ -35,13 +35,24 @@ import {
|
||||
import { parseUserSettings } from '../../lib'
|
||||
import type { UserProfile, UserSettings, NotifyType } from '../../types'
|
||||
|
||||
const NOTIFICATION_ICONS: Record<string, typeof Mail> = {
|
||||
const NOTIFICATION_ICONS: Record<NotifyType, typeof Mail> = {
|
||||
email: Mail,
|
||||
webhook: Webhook,
|
||||
bark: Bell,
|
||||
gotify: Server,
|
||||
}
|
||||
|
||||
const NOTIFICATION_VALUES = new Set<NotifyType>(
|
||||
NOTIFICATION_METHODS.map((method) => method.value)
|
||||
)
|
||||
|
||||
function normalizeNotifyType(value: unknown): NotifyType {
|
||||
return typeof value === 'string' &&
|
||||
NOTIFICATION_VALUES.has(value as NotifyType)
|
||||
? (value as NotifyType)
|
||||
: 'email'
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Settings Tab Component
|
||||
// ============================================================================
|
||||
@@ -82,7 +93,7 @@ export function NotificationTab({ profile, onUpdate }: NotificationTabProps) {
|
||||
if (profile?.setting) {
|
||||
const parsed = parseUserSettings(profile.setting)
|
||||
setSettings({
|
||||
notify_type: parsed.notify_type || 'email',
|
||||
notify_type: normalizeNotifyType(parsed.notify_type),
|
||||
quota_warning_threshold:
|
||||
parsed.quota_warning_threshold ?? DEFAULT_QUOTA_WARNING_THRESHOLD,
|
||||
notification_email: parsed.notification_email ?? '',
|
||||
@@ -119,44 +130,42 @@ export function NotificationTab({ profile, onUpdate }: NotificationTabProps) {
|
||||
}
|
||||
}
|
||||
|
||||
const notifyType = normalizeNotifyType(settings.notify_type)
|
||||
|
||||
return (
|
||||
<div className='space-y-4 sm:space-y-6'>
|
||||
{/* Notification Type */}
|
||||
<div className='space-y-2.5'>
|
||||
<Label>{t('Notification Method')}</Label>
|
||||
<RadioGroup
|
||||
value={settings.notify_type}
|
||||
onValueChange={(value) =>
|
||||
updateField('notify_type', value as NotifyType)
|
||||
}
|
||||
className='grid grid-cols-4 gap-1.5 sm:gap-3'
|
||||
<ToggleGroup
|
||||
value={[notifyType]}
|
||||
onValueChange={(value) => {
|
||||
const nextValue = value.find((item) => item !== notifyType)
|
||||
if (nextValue)
|
||||
updateField('notify_type', normalizeNotifyType(nextValue))
|
||||
}}
|
||||
aria-label={t('Notification Method')}
|
||||
variant='outline'
|
||||
size='lg'
|
||||
spacing={2}
|
||||
className='grid w-full grid-cols-2 gap-2 sm:grid-cols-4 sm:gap-3'
|
||||
>
|
||||
{NOTIFICATION_METHODS.map((method) => {
|
||||
const Icon = NOTIFICATION_ICONS[method.value]
|
||||
const isSelected = settings.notify_type === method.value
|
||||
return (
|
||||
<Label
|
||||
<ToggleGroupItem
|
||||
key={method.value}
|
||||
htmlFor={method.value}
|
||||
className={`flex min-h-16 cursor-pointer flex-col items-center justify-center gap-1.5 rounded-lg border p-2 text-center transition-colors sm:min-h-20 sm:gap-2 sm:border-2 sm:p-3 ${
|
||||
isSelected
|
||||
? 'border-primary bg-primary/5 text-primary'
|
||||
: 'border-muted hover:border-muted-foreground/25 hover:bg-muted/50'
|
||||
}`}
|
||||
value={method.value}
|
||||
className='h-auto min-h-14 w-full flex-col gap-1.5 px-3 py-3 sm:min-h-16'
|
||||
>
|
||||
<RadioGroupItem
|
||||
value={method.value}
|
||||
id={method.value}
|
||||
className='sr-only'
|
||||
/>
|
||||
<Icon className='h-4 w-4 sm:h-5 sm:w-5' />
|
||||
<span className='max-w-full truncate text-xs font-medium sm:text-sm'>
|
||||
{t(method.label)}
|
||||
</span>
|
||||
</Label>
|
||||
</ToggleGroupItem>
|
||||
)
|
||||
})}
|
||||
</RadioGroup>
|
||||
</ToggleGroup>
|
||||
</div>
|
||||
|
||||
{/* Warning Threshold */}
|
||||
@@ -178,7 +187,7 @@ export function NotificationTab({ profile, onUpdate }: NotificationTabProps) {
|
||||
</div>
|
||||
|
||||
{/* Email Settings */}
|
||||
{settings.notify_type === 'email' && (
|
||||
{notifyType === 'email' && (
|
||||
<div className='space-y-1.5'>
|
||||
<Label htmlFor='notifyEmail'>{t('Notification Email')}</Label>
|
||||
<Input
|
||||
@@ -193,7 +202,7 @@ export function NotificationTab({ profile, onUpdate }: NotificationTabProps) {
|
||||
)}
|
||||
|
||||
{/* Webhook Settings */}
|
||||
{settings.notify_type === 'webhook' && (
|
||||
{notifyType === 'webhook' && (
|
||||
<>
|
||||
<div className='space-y-1.5'>
|
||||
<Label htmlFor='webhookUrl'>{t('Webhook URL')}</Label>
|
||||
@@ -219,7 +228,7 @@ export function NotificationTab({ profile, onUpdate }: NotificationTabProps) {
|
||||
)}
|
||||
|
||||
{/* Bark Settings */}
|
||||
{settings.notify_type === 'bark' && (
|
||||
{notifyType === 'bark' && (
|
||||
<div className='space-y-1.5'>
|
||||
<Label htmlFor='barkUrl'>{t('Bark Push URL')}</Label>
|
||||
<Input
|
||||
@@ -237,7 +246,7 @@ export function NotificationTab({ profile, onUpdate }: NotificationTabProps) {
|
||||
)}
|
||||
|
||||
{/* Gotify Settings */}
|
||||
{settings.notify_type === 'gotify' && (
|
||||
{notifyType === 'gotify' && (
|
||||
<>
|
||||
<div className='space-y-1.5'>
|
||||
<Label htmlFor='gotifyUrl'>{t('Gotify Server URL')}</Label>
|
||||
@@ -300,7 +309,7 @@ export function NotificationTab({ profile, onUpdate }: NotificationTabProps) {
|
||||
href='https://gotify.net/'
|
||||
target='_blank'
|
||||
rel='noopener noreferrer'
|
||||
className='text-primary hover:underline'
|
||||
className='text-primary underline underline-offset-4'
|
||||
>
|
||||
{t('Gotify Documentation')}
|
||||
</a>
|
||||
|
||||
Reference in New Issue
Block a user