Skip to content

Commit 2463cb7

Browse files
committed
improve ux for timezones
1 parent 41141c8 commit 2463cb7

File tree

6 files changed

+118
-9
lines changed

6 files changed

+118
-9
lines changed

app/components/forms.tsx

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,37 @@ export function Field({
6868
)
6969
}
7070

71+
export function SelectField({
72+
labelProps,
73+
selectProps,
74+
errors,
75+
className,
76+
}: {
77+
labelProps: React.LabelHTMLAttributes<HTMLLabelElement>
78+
selectProps: React.SelectHTMLAttributes<HTMLSelectElement>
79+
errors?: ListOfErrors
80+
className?: string
81+
}) {
82+
const fallbackId = useId()
83+
const id = selectProps.id ?? fallbackId
84+
const errorId = errors?.length ? `${id}-error` : undefined
85+
return (
86+
<div className={className}>
87+
<Label htmlFor={id} {...labelProps} />
88+
<select
89+
id={id}
90+
aria-invalid={errorId ? true : undefined}
91+
aria-describedby={errorId}
92+
className="flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 aria-[invalid]:border-input-invalid"
93+
{...selectProps}
94+
/>
95+
<div className="min-h-[32px] px-4 pb-3 pt-1">
96+
{errorId ? <ErrorList id={errorId} errors={errors} /> : null}
97+
</div>
98+
</div>
99+
)
100+
}
101+
71102
export function OTPField({
72103
labelProps,
73104
inputProps,

app/routes/recipients+/$recipientId_.edit.tsx

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,9 @@ export async function loader({ params, request }: LoaderFunctionArgs) {
3030
})
3131
invariantResponse(recipient, 'Not found', { status: 404 })
3232

33-
return json({ recipient })
33+
const supportedTimeZones = Intl.supportedValuesOf('timeZone')
34+
35+
return json({ recipient, supportedTimeZones })
3436
}
3537

3638
export const meta: MetaFunction<typeof loader> = ({ data }) => {
@@ -44,7 +46,12 @@ export const meta: MetaFunction<typeof loader> = ({ data }) => {
4446
export default function NoteEdit() {
4547
const data = useLoaderData<typeof loader>()
4648

47-
return <RecipientEditor recipient={data.recipient} />
49+
return (
50+
<RecipientEditor
51+
recipient={data.recipient}
52+
supportedTimeZones={data.supportedTimeZones}
53+
/>
54+
)
4855
}
4956

5057
export function ErrorBoundary() {

app/routes/recipients+/__editor.tsx

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,17 @@
1-
import { getFormProps, getInputProps, useForm } from '@conform-to/react'
1+
import {
2+
getFormProps,
3+
getInputProps,
4+
getSelectProps,
5+
useForm,
6+
} from '@conform-to/react'
27
import { getZodConstraint, parseWithZod } from '@conform-to/zod'
38
import { type Recipient } from '@prisma/client'
49
import { type SerializeFrom } from '@remix-run/node'
510
import { Form, useActionData, useFetcher } from '@remix-run/react'
611
import { z } from 'zod'
712
import { GeneralErrorBoundary } from '#app/components/error-boundary.tsx'
813
import { floatingToolbarClassName } from '#app/components/floating-toolbar.tsx'
9-
import { ErrorList, Field } from '#app/components/forms.tsx'
14+
import { ErrorList, Field, SelectField } from '#app/components/forms.tsx'
1015
import { Icon } from '#app/components/ui/icon.js'
1116
import { StatusButton } from '#app/components/ui/status-button.tsx'
1217
import { useDoubleCheck, useIsPending } from '#app/utils/misc.tsx'
@@ -34,8 +39,10 @@ export const DeleteRecipientSchema = z.object({
3439
})
3540

3641
export function RecipientEditor({
42+
supportedTimeZones,
3743
recipient,
3844
}: {
45+
supportedTimeZones: Array<string>
3946
recipient?: SerializeFrom<
4047
Pick<
4148
Recipient,
@@ -105,10 +112,15 @@ export function RecipientEditor({
105112
}}
106113
errors={fields.scheduleCron.errors}
107114
/>
108-
<Field
115+
<SelectField
109116
labelProps={{ children: 'Time Zone' }}
110-
inputProps={{
111-
...getInputProps(fields.timeZone, { type: 'text' }),
117+
selectProps={{
118+
...getSelectProps(fields.timeZone),
119+
children: supportedTimeZones.map(tz => (
120+
<option key={tz} value={tz}>
121+
{tz}
122+
</option>
123+
)),
112124
}}
113125
errors={fields.timeZone.errors}
114126
/>

app/routes/recipients+/new.tsx

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import {
44
json,
55
type LoaderFunctionArgs,
66
} from '@remix-run/node'
7+
import { useLoaderData } from '@remix-run/react'
78
import { requireUserId } from '#app/utils/auth.server.ts'
89
import { RecipientEditor } from './__editor.tsx'
910

@@ -15,11 +16,16 @@ export const handle: SEOHandle = {
1516

1617
export async function loader({ request }: LoaderFunctionArgs) {
1718
await requireUserId(request)
18-
return json({})
19+
const supportedTimeZones = Intl.supportedValuesOf('timeZone')
20+
return json({ supportedTimeZones })
1921
}
2022

2123
export const meta: MetaFunction = () => {
2224
return [{ title: `Create New Recipient | GratiText` }]
2325
}
2426

25-
export default RecipientEditor
27+
export default function NewRecipientEditor() {
28+
const data = useLoaderData<typeof loader>()
29+
30+
return <RecipientEditor supportedTimeZones={data.supportedTimeZones} />
31+
}

package-lock.json

Lines changed: 51 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@
5151
"@paralleldrive/cuid2": "^2.2.2",
5252
"@prisma/client": "^5.15.0",
5353
"@radix-ui/react-checkbox": "^1.0.4",
54+
"@radix-ui/react-dialog": "^1.0.5",
5455
"@radix-ui/react-dropdown-menu": "^2.0.6",
5556
"@radix-ui/react-label": "^2.0.2",
5657
"@radix-ui/react-popover": "^1.0.7",
@@ -70,6 +71,7 @@
7071
"class-variance-authority": "^0.7.0",
7172
"close-with-grace": "^1.3.0",
7273
"clsx": "^2.1.1",
74+
"cmdk": "^1.0.0",
7375
"compression": "^1.7.4",
7476
"cookie": "^0.6.0",
7577
"cron-parser": "^4.9.0",

0 commit comments

Comments
 (0)