Skip to content

Commit

Permalink
🦂 Update create wave ui
Browse files Browse the repository at this point in the history
  • Loading branch information
nezouse committed Mar 21, 2024
1 parent 87113ba commit 6577790
Show file tree
Hide file tree
Showing 8 changed files with 217 additions and 101 deletions.
4 changes: 1 addition & 3 deletions src/app/waves/create/createWaveAction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,7 @@ import { revalidatePath } from "next/cache";
import { redirect } from "next/navigation";
import { insertWave } from "@/drizzle/queries/waves";

import { createWaveSchema } from "./createWaveSchema";

export async function createWaveAction(data: createWaveSchema) {
export async function createWaveAction(data: any) {
const [{ id }] = await insertWave({
name: data.waveName,
startsAt: data.duration.from,
Expand Down
10 changes: 3 additions & 7 deletions src/app/waves/create/createWaveForm.tsx
Original file line number Diff line number Diff line change
@@ -1,22 +1,18 @@
import { BackButton } from "@/components/ui/backButton";
import { PageTitle } from "@/components/ui/pageTitle";
import { Stepper } from "@/components/ui/stepper";
import { CampaignIcon } from "@/components/icons/campaignIcon";
import { ClockIcon } from "@/components/icons/clockIcon";
import { ComputerIcon } from "@/components/icons/computerIcon";

import { MainDetails } from "./steps/mainDetails";
import { Timeline } from "./steps/timeline";

const stepsConfig = [
{ name: "Main details", icon: <ComputerIcon className="h-6 w-6" /> },
{
name: "Timeline",
icon: <ClockIcon className="h-6 w-6" />,
},
{
name: "Additional info",
icon: <CampaignIcon className="h-6 w-6" />,
},
];

export function CreateWaveForm() {
Expand All @@ -26,9 +22,9 @@ export function CreateWaveForm() {
<BackButton href="/" />
<PageTitle>Create new wave</PageTitle>
</div>
<Stepper currentStep={0} stepsConfig={stepsConfig}>
<MainDetails />
<Stepper currentStep={1} stepsConfig={stepsConfig}>
<MainDetails />
<Timeline />
</Stepper>
</>
);
Expand Down
15 changes: 0 additions & 15 deletions src/app/waves/create/createWaveSchema.ts

This file was deleted.

108 changes: 48 additions & 60 deletions src/app/waves/create/steps/mainDetails.tsx
Original file line number Diff line number Diff line change
@@ -1,47 +1,54 @@
"use client";

import { specificLengthStringSchema } from "@/constants/validationSchemas";
import { zodResolver } from "@hookform/resolvers/zod";
import { useForm } from "react-hook-form";
import { z } from "zod";

import {
addDays,
formatDate,
formatDateRange,
getStartOfDate,
} from "@/lib/dates";
import { Button } from "@/components/ui/button";
import { Calendar } from "@/components/ui/calendar";
import {
Form,
FormControl,
FormCounter,
FormField,
FormFooter,
FormItem,
FormLabel,
FormMessage,
} from "@/components/ui/form";
import { Input } from "@/components/ui/input";
import {
Popover,
PopoverContent,
PopoverTrigger,
} from "@/components/ui/popover";
import { CalendarIcon } from "@/components/icons/calendarIcon";
import { Textarea } from "@/components/ui/textarea";
import { ArrowIcon } from "@/components/icons/arrowIcon";

import { createWaveAction } from "../createWaveAction";
import { createWaveSchema } from "../createWaveSchema";

export function MainDetails() {
const todayDate = getStartOfDate(new Date());
const FORM_FIELD_PARAMS = {
waveName: {
min: 3,
max: 20,
},
waveSummary: {
min: 3,
max: 160,
},
};

export const mainDetailsSchema = z.object({
waveName: specificLengthStringSchema("Wave name", FORM_FIELD_PARAMS.waveName),
waveSummary: specificLengthStringSchema(
"Wave summary",
FORM_FIELD_PARAMS.waveSummary,
),
});

const form = useForm<createWaveSchema>({
resolver: zodResolver(createWaveSchema),
export type mainDetailsSchema = z.infer<typeof mainDetailsSchema>;

export function MainDetails() {
const form = useForm<mainDetailsSchema>({
resolver: zodResolver(mainDetailsSchema),
defaultValues: {
waveName: "",
duration: {
from: todayDate,
to: addDays(todayDate, 30),
},
waveSummary: "",
},
});

Expand All @@ -57,61 +64,42 @@ export function MainDetails() {
control={form.control}
name="waveName"
render={({ field }) => (
<FormItem>
<FormItem aria-required>
<FormLabel>Wave name</FormLabel>
<FormControl>
<Input {...field} />
</FormControl>
<FormCounter
current={field.value.length}
limit={FORM_FIELD_PARAMS[field.name].max}
/>
<FormMessage />
</FormItem>
)}
/>

<FormField
control={form.control}
name="duration"
name="waveSummary"
render={({ field }) => (
<FormItem className="flex flex-col">
<FormLabel>Wave duration</FormLabel>
<Popover>
<PopoverTrigger asChild>
<FormControl>
<Button
variant="outline"
className="pl-3 text-left font-normal"
>
{field.value.from ? (
field.value.to ? (
<>
{formatDateRange(field.value.from, field.value.to)}
</>
) : (
formatDate(field.value.from)
)
) : (
<span>Pick a date</span>
)}
<CalendarIcon className="ml-auto opacity-50" />
</Button>
</FormControl>
</PopoverTrigger>
<PopoverContent className="w-auto p-0" align="start">
<Calendar
mode="range"
numberOfMonths={2}
defaultMonth={field.value.from}
selected={field.value}
onSelect={field.onChange}
disabled={(date) => date < todayDate}
/>
</PopoverContent>
</Popover>
<FormItem aria-required>
<FormLabel>Wave summary</FormLabel>
<FormControl>
<Textarea {...field} />
</FormControl>
<FormCounter
current={field.value.length}
limit={FORM_FIELD_PARAMS[field.name].max}
/>
<FormMessage />
</FormItem>
)}
/>
<FormFooter className="justify-end">
<Button disabled={form.formState.isSubmitting}>Create wave</Button>
<Button disabled={form.formState.isSubmitting}>
Next
<ArrowIcon direction="right" />
</Button>
</FormFooter>
</form>
</Form>
Expand Down
150 changes: 150 additions & 0 deletions src/app/waves/create/steps/timeline.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
"use client";

import { zodResolver } from "@hookform/resolvers/zod";
import {
useForm,
type ControllerProps,
type FieldPath,
type FieldValues,
} from "react-hook-form";
import { z } from "zod";

import { formatDate, getStartOfDate } from "@/lib/dates";
import { Button } from "@/components/ui/button";
import { Calendar } from "@/components/ui/calendar";
import {
Form,
FormControl,
FormField,
FormFooter,
FormItem,
FormLabel,
FormMessage,
} from "@/components/ui/form";
import {
Popover,
PopoverContent,
PopoverTrigger,
} from "@/components/ui/popover";
import { ArrowIcon } from "@/components/icons/arrowIcon";
import { CalendarIcon } from "@/components/icons/calendarIcon";

import { createWaveAction } from "../createWaveAction";

export const timelineSchema = z.object({
openStartDate: z.date(),
denoisingStartDate: z.date(),
assesmentStartDate: z.date(),
closeDate: z.date(),
});

export type timelineSchema = z.infer<typeof timelineSchema>;

export function Timeline() {
const form = useForm<timelineSchema>({
resolver: zodResolver(timelineSchema),
});

return (
<Form {...form}>
<form
className="flex w-full flex-col gap-6"
onSubmit={form.handleSubmit(async (data) => {
await createWaveAction(data);
})}
>
<div className="grid grid-cols-2 gap-y-8 rounded-2xl border p-6">
<CalendarField
control={form.control}
name="openStartDate"
title="Open"
/>
<CalendarField
control={form.control}
name="denoisingStartDate"
title="Denoising"
/>
<CalendarField
control={form.control}
name="assesmentStartDate"
title="Assesment"
/>
<CalendarField
control={form.control}
name="closeDate"
label="Close date"
title="Close"
/>
</div>

<FormFooter>
<Button
disabled={form.formState.isSubmitting}
variant="secondary"
type="button"
>
<ArrowIcon direction="left" />
Back
</Button>

<Button disabled={form.formState.isSubmitting}>
Preview
<ArrowIcon direction="right" />
</Button>
</FormFooter>
</form>
</Form>
);
}

const CalendarField = <
TFieldValues extends FieldValues = FieldValues,
TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,
>({
name,
control,
label = "Start date",
title,
}: Pick<ControllerProps<TFieldValues, TName>, "control" | "name"> & {
label?: string;
title: string;
}) => {
const todayDate = getStartOfDate(new Date());

return (
<FormField
control={control}
name={name}
render={({ field }) => (
<FormItem aria-required>
<div className="mb-4 font-bold">{title}</div>
<FormLabel>{label}</FormLabel>
<Popover>
<PopoverTrigger asChild>
<FormControl>
<Button variant="outline" className="h-12 w-40 justify-start">
<CalendarIcon className="h-6 w-6" />
{field.value ? (
formatDate(field.value)
) : (
<span>Pick a date</span>
)}
</Button>
</FormControl>
</PopoverTrigger>
<PopoverContent align="start">
<Calendar
mode="single"
defaultMonth={field.value}
selected={field.value}
onSelect={field.onChange}
disabled={(date) => date < todayDate}
/>
</PopoverContent>
</Popover>
<FormMessage />
</FormItem>
)}
/>
);
};
6 changes: 3 additions & 3 deletions src/components/ui/form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,9 @@ const FormFieldContext = createContext<FormFieldContextValue>(
const FormField = <
TFieldValues extends FieldValues = FieldValues,
TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,
>({
...props
}: ControllerProps<TFieldValues, TName>) => {
>(
props: ControllerProps<TFieldValues, TName>,
) => {
return (
<FormFieldContext.Provider value={{ name: props.name }}>
<Controller {...props} />
Expand Down
3 changes: 1 addition & 2 deletions src/constants/validationSchemas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,7 @@ export const positiveNumberSchema = (fieldName: string) => {

export const specificLengthStringSchema = (
fieldName: string,
min: number,
max: number,
{ min, max }: { min: number; max: number },
) => {
return z
.string()
Expand Down
Loading

0 comments on commit 6577790

Please sign in to comment.