fix: not working form and selections
This commit is contained in:
@@ -100,7 +100,7 @@ export function PhotoUpload({
|
||||
|
||||
return (
|
||||
<section className="border-t border-wedding-line pt-10">
|
||||
<div className="grid gap-4 wedding-lg:grid-cols-3">
|
||||
<div className="grid gap-4 max-w-3xl mx-auto">
|
||||
<p className="wedding-section-label">04</p>
|
||||
<div>
|
||||
<h2 className="font-wedding-display text-wedding-medium">{labels.title}</h2>
|
||||
@@ -109,7 +109,7 @@ export function PhotoUpload({
|
||||
<p className="font-wedding-ui text-sm">{labels.requirements}</p>
|
||||
</div>
|
||||
|
||||
<div className="mt-6 wedding-lg:ml-60">
|
||||
<div className="mt-6 max-w-3xl mx-auto">
|
||||
{filename ? (
|
||||
<p className="bg-wedding-cream px-4 py-3 font-wedding-ui text-sm text-wedding-ink">
|
||||
{labels.current.replace("{filename}", filename)}
|
||||
|
||||
@@ -30,7 +30,7 @@ export function RsvpForm({
|
||||
<RsvpTravelFields response={detail.response} dictionary={dictionary} disabled={closed} />
|
||||
<RsvpToastFields members={detail.members} toastRequest={toastRequest} dictionary={dictionary} disabled={closed} />
|
||||
<div className="py-10"><PhotoUpload token={token} labels={dictionary.upload} disabled={closed} existingFilename={filename} /></div>
|
||||
{!closed ? <button type="submit" className="wedding-primary-cta w-full">{dictionary.form.submit} →</button> : null}
|
||||
{!closed ? <div className="max-w-3xl mx-auto"><button type="submit" className="wedding-primary-cta w-full">{dictionary.form.submit} →</button></div> : null}
|
||||
</form>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
import { RsvpGuestResponse } from "@/components/invite/rsvp-guest-response"
|
||||
import type { InvitationMember } from "@/lib/db/types"
|
||||
import type { GuestDictionary } from "@/lib/i18n/dictionaries"
|
||||
import type { MealPreference } from "@/lib/validation/response"
|
||||
|
||||
const mealOptions: MealPreference[] = ["meat", "fish", "vegetarian", "vegan", "kids", "other"]
|
||||
|
||||
export function RsvpGuestFields({
|
||||
members,
|
||||
@@ -16,16 +14,13 @@ export function RsvpGuestFields({
|
||||
return (
|
||||
<section className="border-t border-wedding-line pt-10">
|
||||
{members.map((member, index) => (
|
||||
<fieldset className="grid gap-6 border-b border-wedding-line py-10 wedding-lg:grid-cols-3" disabled={disabled} key={member.id}>
|
||||
<legend className="sr-only">{member.name}</legend>
|
||||
<p className="wedding-section-label">0{index + 1}</p>
|
||||
<div><h3 className="font-wedding-display text-wedding-medium">{member.name}</h3><p className="mt-2 font-wedding-ui text-sm">{dictionary.form.attending}</p></div>
|
||||
<div className="grid gap-6 wedding-md:grid-cols-2">
|
||||
<div className="flex gap-3"><label className="flex flex-1 cursor-pointer items-center justify-center border border-wedding-line p-3 font-wedding-display text-lg"><input className="sr-only" type="radio" name={`attending-${member.id}`} value="yes" defaultChecked={member.attending === true} required />{dictionary.form.yes}</label><label className="flex flex-1 cursor-pointer items-center justify-center border border-wedding-line p-3 font-wedding-display text-lg"><input className="sr-only" type="radio" name={`attending-${member.id}`} value="no" defaultChecked={member.attending === false} required />{dictionary.form.no}</label></div>
|
||||
<label className="font-wedding-ui text-sm"><span>{dictionary.form.mealPreference}</span><select name={`meal-${member.id}`} defaultValue={member.meal_preference ?? ""} className="mt-2 w-full border border-wedding-line bg-wedding-ivory p-3"><option value="">{dictionary.form.mealPlaceholder}</option>{mealOptions.map((meal) => <option key={meal} value={meal}>{dictionary.meals[meal]}</option>)}</select></label>
|
||||
<label className="font-wedding-ui text-sm wedding-md:col-span-2"><span>{dictionary.form.dietaryRestrictions}</span><input name={`dietary-${member.id}`} defaultValue={member.dietary_restrictions ?? ""} placeholder={dictionary.form.noRestrictions} className="mt-2 w-full border-b border-wedding-line bg-transparent p-3" /></label>
|
||||
</div>
|
||||
</fieldset>
|
||||
<RsvpGuestResponse
|
||||
key={member.id}
|
||||
member={member}
|
||||
index={index}
|
||||
dictionary={dictionary}
|
||||
disabled={disabled}
|
||||
/>
|
||||
))}
|
||||
</section>
|
||||
)
|
||||
|
||||
@@ -0,0 +1,94 @@
|
||||
"use client"
|
||||
|
||||
import { useState } from "react"
|
||||
|
||||
import type { InvitationMember } from "@/lib/db/types"
|
||||
import type { GuestDictionary } from "@/lib/i18n/dictionaries"
|
||||
import type { MealPreference } from "@/lib/validation/response"
|
||||
|
||||
const mealOptions: MealPreference[] = ["meat", "fish", "vegetarian", "vegan", "kids", "other"]
|
||||
|
||||
export function RsvpGuestResponse({
|
||||
member,
|
||||
index,
|
||||
dictionary,
|
||||
disabled,
|
||||
}: {
|
||||
member: InvitationMember
|
||||
index: number
|
||||
dictionary: GuestDictionary
|
||||
disabled: boolean
|
||||
}) {
|
||||
const [attending, setAttending] = useState(member.attending)
|
||||
|
||||
return (
|
||||
<fieldset
|
||||
className="grid gap-6 border-b border-wedding-line py-10 disabled:opacity-60 max-w-3xl mx-auto"
|
||||
disabled={disabled}
|
||||
>
|
||||
<legend className="sr-only">{member.name}</legend>
|
||||
<p className="wedding-section-label">0{index + 1}</p>
|
||||
<div>
|
||||
<h3 className="font-wedding-display text-wedding-medium">{member.name}</h3>
|
||||
<p id={`attendance-label-${member.id}`} className="mt-2 font-wedding-ui text-sm">
|
||||
{dictionary.form.attending}
|
||||
</p>
|
||||
</div>
|
||||
<div className="grid gap-6 wedding-md:grid-cols-2">
|
||||
<div
|
||||
role="radiogroup"
|
||||
aria-labelledby={`attendance-label-${member.id}`}
|
||||
className="flex flex-wrap gap-3"
|
||||
>
|
||||
{[true, false].map((value) => (
|
||||
<label
|
||||
key={String(value)}
|
||||
className={`flex flex-1 items-center justify-center gap-2 border p-3 font-wedding-display text-lg focus-within:outline-2 focus-within:outline-offset-2 focus-within:outline-wedding-terracotta ${
|
||||
disabled ? "cursor-not-allowed" : "cursor-pointer"
|
||||
} ${
|
||||
attending === value
|
||||
? "border-wedding-terracotta bg-wedding-cream"
|
||||
: "border-wedding-line"
|
||||
}`}
|
||||
>
|
||||
<input
|
||||
className="size-4 shrink-0 accent-wedding-terracotta"
|
||||
type="radio"
|
||||
name={`attending-${member.id}`}
|
||||
value={value ? "yes" : "no"}
|
||||
checked={attending === value}
|
||||
onChange={() => setAttending(value)}
|
||||
required
|
||||
/>
|
||||
{value ? dictionary.form.yes : dictionary.form.no}
|
||||
</label>
|
||||
))}
|
||||
</div>
|
||||
<label className="font-wedding-ui text-sm">
|
||||
<span>{dictionary.form.mealPreference}{attending === true ? " *" : ""}</span>
|
||||
<select
|
||||
name={`meal-${member.id}`}
|
||||
defaultValue={member.meal_preference ?? ""}
|
||||
required={attending === true}
|
||||
disabled={attending === false}
|
||||
className="mt-2 w-full border border-wedding-line bg-wedding-ivory p-3 disabled:opacity-50"
|
||||
>
|
||||
<option value="">{dictionary.form.mealPlaceholder}</option>
|
||||
{mealOptions.map((meal) => (
|
||||
<option key={meal} value={meal}>{dictionary.meals[meal]}</option>
|
||||
))}
|
||||
</select>
|
||||
</label>
|
||||
<label className="font-wedding-ui text-sm wedding-md:col-span-2">
|
||||
<span>{dictionary.form.dietaryRestrictions}</span>
|
||||
<input
|
||||
name={`dietary-${member.id}`}
|
||||
defaultValue={member.dietary_restrictions ?? ""}
|
||||
placeholder={dictionary.form.noRestrictions}
|
||||
className="mt-2 w-full border-b border-wedding-line bg-transparent p-3"
|
||||
/>
|
||||
</label>
|
||||
</div>
|
||||
</fieldset>
|
||||
)
|
||||
}
|
||||
@@ -19,7 +19,7 @@ export function RsvpSection(props: {
|
||||
submitted?: string
|
||||
error?: string
|
||||
}) {
|
||||
const message = props.submitted ? props.dictionary.form.submitted : props.error === "closed" ? props.dictionary.errors.closed : props.error ? props.dictionary.errors.generic : null
|
||||
const message = props.closed ? props.dictionary.deadline.closed : props.submitted ? props.dictionary.form.submitted : props.error === "closed" ? props.dictionary.errors.closed : props.error ? props.dictionary.errors.generic : null
|
||||
return (
|
||||
<section id="rsvp" className="bg-wedding-ivory pt-wedding-section">
|
||||
<WeddingContainer wide>
|
||||
|
||||
@@ -19,7 +19,7 @@ export function RsvpToastFields({
|
||||
const [enabled, setEnabled] = useState(Boolean(toastRequest))
|
||||
|
||||
return (
|
||||
<fieldset className="grid gap-6 border-b border-wedding-line py-10 wedding-lg:grid-cols-3" disabled={disabled}>
|
||||
<fieldset className="grid gap-6 border-b border-wedding-line py-10 max-w-3xl mx-auto" disabled={disabled}>
|
||||
<legend className="sr-only">{dictionary.interactions.toastTitle}</legend>
|
||||
<p className="wedding-section-label">03</p>
|
||||
<div><h3 className="font-wedding-display text-wedding-medium">{dictionary.interactions.toastTitle}</h3><p className="mt-2 font-wedding-ui text-sm leading-wedding-body">{dictionary.interactions.toastDescription}</p></div>
|
||||
|
||||
@@ -15,7 +15,7 @@ export function RsvpTravelFields({
|
||||
disabled: boolean
|
||||
}) {
|
||||
return (
|
||||
<fieldset className="grid gap-6 border-b border-wedding-line py-10 wedding-lg:grid-cols-3" disabled={disabled}>
|
||||
<fieldset className="grid gap-6 border-b border-wedding-line py-10 max-w-3xl mx-auto" disabled={disabled}>
|
||||
<legend className="sr-only">{dictionary.sections.travel}</legend>
|
||||
<p className="wedding-section-label">02</p>
|
||||
<div><h3 className="font-wedding-display text-wedding-medium">{dictionary.sections.travel}</h3></div>
|
||||
|
||||
Reference in New Issue
Block a user