mirror of
https://github.com/Open-Dev-Society/OpenStock.git
synced 2026-05-31 22:22:55 +08:00
146 lines
5.2 KiB
TypeScript
146 lines
5.2 KiB
TypeScript
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
'use client';
|
|
|
|
import { useState } from 'react';
|
|
import { Control, Controller, FieldError } from 'react-hook-form';
|
|
import {
|
|
Popover,
|
|
PopoverContent,
|
|
PopoverTrigger,
|
|
} from '@/components/ui/popover';
|
|
import {
|
|
Command,
|
|
CommandEmpty,
|
|
CommandGroup,
|
|
CommandInput,
|
|
CommandItem,
|
|
CommandList,
|
|
} from '@/components/ui/command';
|
|
import { Button } from '@/components/ui/button';
|
|
import { Label } from '@/components/ui/label';
|
|
import { Check, ChevronsUpDown } from 'lucide-react';
|
|
import { cn } from '@/lib/utils';
|
|
import countryList from 'react-select-country-list';
|
|
|
|
type CountrySelectProps = {
|
|
name: string;
|
|
label: string;
|
|
control: Control<any>;
|
|
error?: FieldError;
|
|
required?: boolean;
|
|
};
|
|
|
|
const CountrySelect = ({
|
|
value,
|
|
onChange,
|
|
}: {
|
|
value: string;
|
|
onChange: (value: string) => void;
|
|
}) => {
|
|
const [open, setOpen] = useState(false);
|
|
|
|
// Get country options with flags
|
|
const countries = countryList().getData();
|
|
|
|
// Helper function to get flag emoji
|
|
const getFlagEmoji = (countryCode: string) => {
|
|
const codePoints = countryCode
|
|
.toUpperCase()
|
|
.split('')
|
|
.map((char) => 127397 + char.charCodeAt(0));
|
|
return String.fromCodePoint(...codePoints);
|
|
};
|
|
|
|
return (
|
|
<Popover open={open} onOpenChange={setOpen}>
|
|
<PopoverTrigger asChild>
|
|
<Button
|
|
variant='outline'
|
|
role='combobox'
|
|
aria-expanded={open}
|
|
className='country-select-trigger'
|
|
>
|
|
{value ? (
|
|
<span className='flex items-center gap-2'>
|
|
<span>{getFlagEmoji(value)}</span>
|
|
<span>{countries.find((c) => c.value === value)?.label}</span>
|
|
</span>
|
|
) : (
|
|
'Select your country...'
|
|
)}
|
|
<ChevronsUpDown className='ml-2 h-4 w-4 shrink-0 opacity-50' />
|
|
</Button>
|
|
</PopoverTrigger>
|
|
<PopoverContent
|
|
className='w-full p-0 bg-gray-800 border-gray-600'
|
|
align='start'
|
|
>
|
|
<Command className='bg-gray-800 border-gray-600'>
|
|
<CommandInput
|
|
placeholder='Search countries...'
|
|
className='country-select-input'
|
|
/>
|
|
<CommandEmpty className='country-select-empty'>
|
|
No country found.
|
|
</CommandEmpty>
|
|
<CommandList className='max-h-60 bg-gray-800 scrollbar-hide-default'>
|
|
<CommandGroup className='bg-gray-800'>
|
|
{countries.map((country) => (
|
|
<CommandItem
|
|
key={country.value}
|
|
value={`${country.label} ${country.value}`}
|
|
onSelect={() => {
|
|
onChange(country.value);
|
|
setOpen(false);
|
|
}}
|
|
className='country-select-item'
|
|
>
|
|
<Check
|
|
className={cn(
|
|
'mr-2 h-4 w-4 text-teal-500',
|
|
value === country.value ? 'opacity-100' : 'opacity-0'
|
|
)}
|
|
/>
|
|
<span className='flex items-center gap-2'>
|
|
<span>{getFlagEmoji(country.value)}</span>
|
|
<span>{country.label}</span>
|
|
</span>
|
|
</CommandItem>
|
|
))}
|
|
</CommandGroup>
|
|
</CommandList>
|
|
</Command>
|
|
</PopoverContent>
|
|
</Popover>
|
|
);
|
|
};
|
|
|
|
export const CountrySelectField = ({
|
|
name,
|
|
label,
|
|
control,
|
|
error,
|
|
required = false,
|
|
}: CountrySelectProps) => {
|
|
return (
|
|
<div className='space-y-2'>
|
|
<Label htmlFor={name} className='form-label'>
|
|
{label}
|
|
</Label>
|
|
<Controller
|
|
name={name}
|
|
control={control}
|
|
rules={{
|
|
required: required ? `Please select ${label.toLowerCase()}` : false,
|
|
}}
|
|
render={({ field }) => (
|
|
<CountrySelect value={field.value} onChange={field.onChange} />
|
|
)}
|
|
/>
|
|
{error && <p className='text-sm text-red-500'>{error.message}</p>}
|
|
<p className='text-xs text-gray-500'>
|
|
Helps us show market data and news relevant to you.
|
|
</p>
|
|
</div>
|
|
);
|
|
}; |