mirror of
https://github.com/Sendouc/sendou.ink.git
synced 2026-04-21 22:53:35 -05:00
Improve date inputs UI when creating / editing events
This commit is contained in:
parent
88e0649e79
commit
a6f62fa7b3
|
|
@ -57,6 +57,7 @@ import {
|
|||
import { MapPoolSelector } from "~/components/MapPoolSelector";
|
||||
import { Tags } from "./components/Tags";
|
||||
import { isDefined } from "~/utils/arrays";
|
||||
import { CrossIcon } from "~/components/icons/Cross";
|
||||
|
||||
const MIN_DATE = new Date(Date.UTC(2015, 4, 28));
|
||||
|
||||
|
|
@ -288,6 +289,16 @@ function DescriptionTextarea() {
|
|||
);
|
||||
}
|
||||
|
||||
function AddButton({ onAdd, id }: { onAdd: () => void; id?: string }) {
|
||||
const { t } = useTranslation();
|
||||
|
||||
return (
|
||||
<Button tiny variant="outlined" onClick={onAdd} id={id}>
|
||||
{t("actions.add")}
|
||||
</Button>
|
||||
);
|
||||
}
|
||||
|
||||
function DatesInput() {
|
||||
const { t } = useTranslation(["common", "calendar"]);
|
||||
const { eventToEdit } = useLoaderData<typeof loader>();
|
||||
|
|
@ -332,8 +343,7 @@ function DatesInput() {
|
|||
const lastValidDate = current
|
||||
.map((e) => e.date)
|
||||
.filter(isDefined)
|
||||
.reverse()
|
||||
.at(0);
|
||||
.reverse()[0];
|
||||
|
||||
const addedDate = lastValidDate
|
||||
? getDateWithHoursOffset(lastValidDate, NEW_CALENDAR_EVENT_HOURS_OFFSET)
|
||||
|
|
@ -344,64 +354,70 @@ function DatesInput() {
|
|||
|
||||
return (
|
||||
<div className="stack md items-start">
|
||||
<div>
|
||||
<Label htmlFor="date" required>
|
||||
{t("calendar:forms.dates")}
|
||||
</Label>
|
||||
<div className="stack sm">
|
||||
{datesInputState.map(({ date, key }, i) => {
|
||||
return (
|
||||
<div key={key} className="stack horizontal sm items-center">
|
||||
<DateInput
|
||||
id={`date-input-${key}`}
|
||||
name="date"
|
||||
defaultValue={date ?? undefined}
|
||||
min={MIN_DATE}
|
||||
max={MAX_DATE}
|
||||
required
|
||||
onChange={(newDate: Date | null) => {
|
||||
setDatesInputState((current) =>
|
||||
current.map((entry) =>
|
||||
entry.key === key ? { ...entry, date: newDate } : entry
|
||||
)
|
||||
);
|
||||
}}
|
||||
/>
|
||||
{i === datesCount - 1 && (
|
||||
<>
|
||||
{/* "Add" button */}
|
||||
<fieldset>
|
||||
<legend>
|
||||
{t("calendar:forms.dates")} <span className="text-error">*</span>
|
||||
</legend>
|
||||
<div className="stack sm items-start">
|
||||
<div className="stack sm">
|
||||
{datesInputState.map(({ date, key }, i) => {
|
||||
return (
|
||||
<div key={key} className="stack horizontal sm items-center">
|
||||
<label
|
||||
id={`date-input-${key}-label`}
|
||||
className="calendar-new__day-label"
|
||||
htmlFor={`date-input-${key}`}
|
||||
>
|
||||
{t("calendar:day", {
|
||||
number: i + 1,
|
||||
})}
|
||||
</label>
|
||||
<DateInput
|
||||
id={`date-input-${key}`}
|
||||
name="date"
|
||||
defaultValue={date ?? undefined}
|
||||
min={MIN_DATE}
|
||||
max={MAX_DATE}
|
||||
required
|
||||
onChange={(newDate: Date | null) => {
|
||||
setDatesInputState((current) =>
|
||||
current.map((entry) =>
|
||||
entry.key === key
|
||||
? { ...entry, date: newDate }
|
||||
: entry
|
||||
)
|
||||
);
|
||||
}}
|
||||
/>
|
||||
{/* "Remove" button */}
|
||||
{datesCount > 1 && (
|
||||
<Button
|
||||
tiny
|
||||
disabled={
|
||||
datesCount === CALENDAR_EVENT.MAX_AMOUNT_OF_DATES
|
||||
}
|
||||
onClick={addDate}
|
||||
>
|
||||
{t("common:actions.add")}
|
||||
</Button>
|
||||
|
||||
{/* "Remove" button */}
|
||||
{datesCount > 1 && (
|
||||
<Button
|
||||
tiny
|
||||
onClick={() => {
|
||||
setDatesInputState((current) => current.slice(0, -1));
|
||||
}}
|
||||
variant="destructive"
|
||||
>
|
||||
{t("common:actions.remove")}
|
||||
</Button>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
onClick={() => {
|
||||
setDatesInputState((current) =>
|
||||
current.filter((e) => e.key !== key)
|
||||
);
|
||||
}}
|
||||
aria-controls={`date-input-${key}`}
|
||||
aria-label={t("common:actions.remove")}
|
||||
aria-describedby={`date-input-${key}-label`}
|
||||
title={t("common:actions.remove")}
|
||||
icon={<CrossIcon />}
|
||||
variant="minimal-destructive"
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
{datesCount < CALENDAR_EVENT.MAX_AMOUNT_OF_DATES && (
|
||||
<AddButton onAdd={addDate} />
|
||||
)}
|
||||
<FormMessage type="info" className={clsx({ invisible: !isMounted })}>
|
||||
{t("calendar:inYourTimeZone")} {usersTimeZone}
|
||||
</FormMessage>
|
||||
</div>
|
||||
<FormMessage type="info" className={clsx({ invisible: !isMounted })}>
|
||||
{t("calendar:inYourTimeZone")} {usersTimeZone}
|
||||
</FormMessage>
|
||||
</div>
|
||||
</fieldset>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
@ -590,14 +606,7 @@ function MapPoolSection() {
|
|||
) : (
|
||||
<div>
|
||||
<label htmlFor={id}>{t("common:maps.mapPool")}</label>
|
||||
<Button
|
||||
id={id}
|
||||
variant="outlined"
|
||||
tiny
|
||||
onClick={() => setIncludeMapPool(true)}
|
||||
>
|
||||
{t("common:actions.add")}
|
||||
</Button>
|
||||
<AddButton onAdd={() => setIncludeMapPool(true)} id={id} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,3 +14,7 @@
|
|||
font-size: var(--fonts-sm);
|
||||
font-weight: var(--semi-bold);
|
||||
}
|
||||
|
||||
.calendar-new__day-label {
|
||||
margin: 0;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user