File size: 2,593 Bytes
0b9dc2e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
import { ChevronDown, Globe, Search } from 'lucide-react';
import * as React from 'react';

import { Button } from '@/components/ui/button';
import {
	DropdownMenu,
	DropdownMenuContent,
	DropdownMenuItem,
	DropdownMenuTrigger,
} from '@/components/ui/dropdown-menu';
import { Input } from '@/components/ui/input';
import { cn } from '@/lib/utils.ts';

const LOCAL_TIMEZONE = Intl.DateTimeFormat().resolvedOptions().timeZone;

const ALL_TIMEZONES: string[] = Intl.supportedValuesOf('timeZone');

interface Props {
	className?: string;
	value?: string;
	onChange?: (value: string) => void;
	disabled?: boolean;
}

export function TimezoneSelect({ className, value, onChange, disabled }: Props) {
	const [search, setSearch] = React.useState('');
	const inputRef = React.useRef<HTMLInputElement>(null);

	const filtered = React.useMemo(() => {
		if (!search.trim()) return ALL_TIMEZONES;
		const q = search.toLowerCase();
		return ALL_TIMEZONES.filter((tz) => tz.toLowerCase().includes(q));
	}, [search]);

	const displayLabel = value || LOCAL_TIMEZONE;

	return (
		<DropdownMenu

			onOpenChange={(open) => {

				if (open) setSearch('');

			}}

		>

			<DropdownMenuTrigger asChild>

				<Button

					variant="outline"

					size="sm"

					className={cn('justify-between gap-1', className)}

					disabled={disabled}

				>

					<div className="flex flex-row items-center gap-x-2">

						<Globe className="size-3.5" />

						<span className="truncate text-xs">{displayLabel}</span>

					</div>

					<ChevronDown className="size-3.5 opacity-50" />

				</Button>

			</DropdownMenuTrigger>

			<DropdownMenuContent align="start" className="w-64">

				<div className="flex items-center gap-2 px-2 py-1.5 border-b">

					<Search className="size-3.5 opacity-50" />

					<Input

						ref={inputRef}

						value={search}

						onChange={(e) => setSearch(e.target.value)}

						placeholder="Search timezone..."

						className="h-6 border-0 shadow-none focus-visible:ring-0 text-xs px-0"

						onKeyDown={(e) => e.stopPropagation()}

					/>

				</div>

				<div className="max-h-60 overflow-y-auto">

					{filtered.length === 0 ? (

						<div className="px-2 py-4 text-center text-xs text-muted-foreground">

							No timezone found

						</div>

					) : (

						filtered.map((tz) => (

							<DropdownMenuItem

								key={tz}

								onSelect={() => onChange?.(tz)}

								className="text-xs"

							>

								{tz}

							</DropdownMenuItem>

						))

					)}

				</div>

			</DropdownMenuContent>

		</DropdownMenu>
	);
}