fix: Improve UX with searchable selects and higher modal z-index

 Issue 1: Modal Z-Index Fixed
- Increased dialog z-index: z-[9999] → z-[99999]
- Now properly appears above fullscreen mode (z-50)

 Issue 2: Searchable Select for Large Lists
- Replaced Select with SearchableSelect for:
  - Countries (200+ options)
  - Currencies (100+ options)
  - Timezones (400+ options)
- Users can now type to search instead of scrolling
- Better UX for large datasets

 Issue 3: Input Type Support
- Input component already supports type attribute
- No changes needed (already working)

 Issue 4: Timezone Options Fixed
- Replaced optgroup (not supported) with flat list
- SearchableSelect handles filtering by continent name
- Shows: 'Asia/Jakarta (UTC+7:00)'
- Search includes continent, city, and offset

📊 Result:
-  Modal always on top
-  Easy search for countries/currencies/timezones
-  No more scrolling through hundreds of options
-  Better accessibility

Addresses user feedback issues 1-4
This commit is contained in:
dwindown
2025-11-05 22:24:31 +07:00
parent 86821efcbd
commit 2006c8195c
2 changed files with 35 additions and 42 deletions

View File

@@ -19,7 +19,7 @@ const DialogOverlay = React.forwardRef<
<DialogPrimitive.Overlay
ref={ref}
className={cn(
"fixed inset-0 z-[9999] bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
"fixed inset-0 z-[99999] bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
className
)}
{...props}
@@ -36,7 +36,7 @@ const DialogContent = React.forwardRef<
<DialogPrimitive.Content
ref={ref}
className={cn(
"fixed left-[50%] top-[50%] z-[9999] grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg",
"fixed left-[50%] top-[50%] z-[99999] grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg",
className
)}
{...props}

View File

@@ -6,6 +6,7 @@ import { SettingsCard } from './components/SettingsCard';
import { SettingsSection } from './components/SettingsSection';
import { Input } from '@/components/ui/input';
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
import { SearchableSelect } from '@/components/ui/searchable-select';
import { toast } from 'sonner';
interface StoreSettings {
@@ -234,18 +235,16 @@ export default function StoreDetailsPage() {
description="Used for shipping origin, invoices, and tax calculations"
>
<SettingsSection label="Country/Region" required htmlFor="country">
<Select value={settings.country} onValueChange={(v) => updateSetting('country', v)}>
<SelectTrigger id="country">
<SelectValue />
</SelectTrigger>
<SelectContent>
{countries.map((country: { code: string; name: string }) => (
<SelectItem key={country.code} value={country.code}>
{country.name}
</SelectItem>
))}
</SelectContent>
</Select>
<SearchableSelect
value={settings.country}
onChange={(v) => updateSetting('country', v)}
options={countries.map((country: { code: string; name: string }) => ({
value: country.code,
label: country.name,
searchText: country.name,
}))}
placeholder="Select country..."
/>
</SettingsSection>
<SettingsSection label="Street address" htmlFor="address">
@@ -293,18 +292,16 @@ export default function StoreDetailsPage() {
description="How prices are displayed in your store"
>
<SettingsSection label="Currency" required htmlFor="currency">
<Select value={settings.currency} onValueChange={(v) => updateSetting('currency', v)}>
<SelectTrigger id="currency">
<SelectValue />
</SelectTrigger>
<SelectContent>
{currencies.map((currency: { code: string; name: string; symbol: string }) => (
<SelectItem key={currency.code} value={currency.code}>
{currency.name} ({currency.symbol})
</SelectItem>
))}
</SelectContent>
</Select>
<SearchableSelect
value={settings.currency}
onChange={(v) => updateSetting('currency', v)}
options={currencies.map((currency: { code: string; name: string; symbol: string }) => ({
value: currency.code,
label: `${currency.name} (${currency.symbol})`,
searchText: `${currency.code} ${currency.name} ${currency.symbol}`,
}))}
placeholder="Select currency..."
/>
</SettingsSection>
<SettingsSection label="Currency position" htmlFor="currencyPosition">
@@ -377,22 +374,18 @@ export default function StoreDetailsPage() {
description="Timezone and measurement units"
>
<SettingsSection label="Timezone" htmlFor="timezone">
<Select value={settings.timezone} onValueChange={(v) => updateSetting('timezone', v)}>
<SelectTrigger id="timezone">
<SelectValue />
</SelectTrigger>
<SelectContent>
{Object.entries(timezones).map(([continent, tzList]: [string, any]) => (
<optgroup key={continent} label={continent}>
{tzList.map((tz: { value: string; label: string; offset: string }) => (
<SelectItem key={tz.value} value={tz.value}>
{tz.label} ({tz.offset})
</SelectItem>
))}
</optgroup>
))}
</SelectContent>
</Select>
<SearchableSelect
value={settings.timezone}
onChange={(v) => updateSetting('timezone', v)}
options={Object.entries(timezones).flatMap(([continent, tzList]: [string, any]) =>
tzList.map((tz: { value: string; label: string; offset: string }) => ({
value: tz.value,
label: `${tz.label} (${tz.offset})`,
searchText: `${continent} ${tz.label} ${tz.offset}`,
}))
)}
placeholder="Select timezone..."
/>
</SettingsSection>
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">