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:
@@ -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}
|
||||
|
||||
@@ -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">
|
||||
|
||||
Reference in New Issue
Block a user