Skip to content

Commit

Permalink
refactor: update custom project form handling and schema references
Browse files Browse the repository at this point in the history
  • Loading branch information
atrincas committed Jan 15, 2025
1 parent 05c6e74 commit 2deb829
Show file tree
Hide file tree
Showing 14 changed files with 253 additions and 164 deletions.
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { LOSS_RATE_USED } from '@shared/schemas/custom-projects/create-custom-project.schema';
import { LOSS_RATE_USED } from '@shared/schemas/custom-projects/custom-project.schema';
import {
IsEnum,
IsNegative,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {
PROJECT_EMISSION_FACTORS,
} from '@api/modules/custom-projects/dto/conservation-project-params.dto';
import { AdditionalBaseData } from '@api/modules/calculations/data.repository';
import { LOSS_RATE_USED } from '@shared/schemas/custom-projects/create-custom-project.schema';
import { LOSS_RATE_USED } from '@shared/schemas/custom-projects/custom-project.schema';
import { GeneralProjectInputs } from '@api/modules/custom-projects/input-factory/custom-project.factory';
import {
ModelAssumptionsForCalculations,
Expand Down
7 changes: 6 additions & 1 deletion client/src/containers/nav/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,12 @@ const navItems = {
title: "My custom projects",
url: "/my-projects",
icon: ClipboardListIcon,
match: (pathname: string) => pathname === "/my-projects",
match: (pathname: string) =>
pathname === "/my-projects" ||
// edit project (ex. /projects/[uuid]/edit):
pathname.match(/^\/projects\/(?!new$)[\w-]+\/edit$/) ||
// view project (ex. /projects/[uuid]):
pathname.match(/^\/projects\/(?!new$)[\w-]+$/),
isAuth: true,
},
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,12 +47,12 @@ const ProjectDetails: FC<ProjectDetailsProps> = ({ data }) => {
} = data;
const featureFlags = useFeatureFlags();
const { id } = useParams<{ id?: string }>();

const showEditButton = featureFlags["edit-project"] && id;
return (
<Card className="flex-1 space-y-1">
<div className="flex items-center justify-between">
<h2 className="text-base font-semibold">Project details</h2>
{featureFlags["edit-project"] && (
{showEditButton && (
<Button type="button" variant="ghost" asChild>
<Link href={`/projects/${id}/edit`}>
<FileEdit />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ const ProjectSummary: FC<ProjectSummaryProps> = ({ data }) => {
const setProjectSummaryOpen = useSetAtom(projectsUIState);
const featureFlags = useFeatureFlags();
const { id } = useParams<{ id?: string }>();
const showEditButton = featureFlags["edit-project"] && id;
const closeProjectSummary = useCallback(() => {
setProjectSummaryOpen((prev) => ({
...prev,
Expand Down Expand Up @@ -106,7 +107,7 @@ const ProjectSummary: FC<ProjectSummaryProps> = ({ data }) => {
Calculations based on project setup parameters. For new calculations,
edit project details.
</p>
{featureFlags["edit-project"] && (
{showEditButton && (
<Button type="button" variant="outline" asChild>
<Link href={`/projects/${id}/edit`}>
<FileEdit />
Expand Down
68 changes: 64 additions & 4 deletions client/src/containers/projects/form/header.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,75 @@
import { useCallback } from "react";

import { useFormContext } from "react-hook-form";

import { useRouter } from "next/navigation";

import { useQueryClient } from "@tanstack/react-query";
import { useSession } from "next-auth/react";

import { queryKeys } from "@/lib/query-keys";
import { getAuthHeader } from "@/lib/utils";

import { CreateCustomProjectForm } from "@/containers/projects/form/setup";
import {
createCustomProject,
parseFormValues,
updateCustomProject,
} from "@/containers/projects/form/utils";

import { Button } from "@/components/ui/button";
import { SidebarTrigger } from "@/components/ui/sidebar";
import { useToast } from "@/components/ui/toast/use-toast";

interface HeaderProps {
name: string;
onSubmit: () => void;
id?: string;
}

export default function Header({ name, onSubmit }: HeaderProps) {
export default function Header({ name, id }: HeaderProps) {
const methods = useFormContext<CreateCustomProjectForm>();
const isEdit = name.length > 0;
const { data: session } = useSession();
const queryClient = useQueryClient();
const router = useRouter();
const { toast } = useToast();
const isEdit = !!id;
const handleSubmit = useCallback(
async (data: CreateCustomProjectForm) => {
try {
const formValues = parseFormValues(data);

if (isEdit) {
await updateCustomProject({
body: formValues,
params: { id: id as string },
extraHeaders: {
...getAuthHeader(session?.accessToken as string),
},
});
router.push(`/projects/${id}`);
} else {
const result = await createCustomProject({
body: formValues,
});

queryClient.setQueryData(
queryKeys.customProjects.cached.queryKey,
result,
);
router.push("/projects/preview");
}
} catch (e) {
toast({
variant: "destructive",
description:
e instanceof Error
? e.message
: "Something went wrong saving the project",
});
}
},
[id, session, router, queryClient, isEdit, toast],
);

return (
<div className="flex h-16 items-center justify-between py-3 pr-6">
Expand All @@ -24,7 +81,10 @@ export default function Header({ name, onSubmit }: HeaderProps) {
</div>
<div className="flex items-center gap-2">
<Button variant="secondary">Cancel</Button>
<Button disabled={!methods.formState.isValid} onClick={onSubmit}>
<Button
disabled={!methods.formState.isValid}
onClick={methods.handleSubmit(handleSubmit)}
>
{isEdit ? "Save" : "Continue"}
</Button>
</div>
Expand Down
24 changes: 7 additions & 17 deletions client/src/containers/projects/form/index.tsx
Original file line number Diff line number Diff line change
@@ -1,24 +1,18 @@
"use client";

import { useCallback, useEffect, useRef } from "react";
import { useEffect, useRef } from "react";

import { FormProvider, useForm } from "react-hook-form";

import { useRouter } from "next/navigation";

import { zodResolver } from "@hookform/resolvers/zod";
import { CreateCustomProjectSchema } from "@shared/schemas/custom-projects/create-custom-project.schema";
import { CustomProjectSchema } from "@shared/schemas/custom-projects/custom-project.schema";
import { ExtractAtomValue, useSetAtom } from "jotai";
import { useSession } from "next-auth/react";

import Header from "@/containers/projects/form/header";
import ProjectForm from "@/containers/projects/form/project-form";
import { CreateCustomProjectForm } from "@/containers/projects/form/setup";
import ProjectSidebar from "@/containers/projects/form/sidebar";
import {
onSubmit,
useDefaultFormValues,
} from "@/containers/projects/form/utils";
import { useDefaultFormValues } from "@/containers/projects/form/utils";
import { formStepAtom } from "@/containers/projects/store";

import { ScrollArea } from "@/components/ui/scroll-area";
Expand All @@ -30,18 +24,14 @@ interface CustomProjectFormProps {
export default function CustomProjectForm({ id }: CustomProjectFormProps) {
const ref = useRef<HTMLDivElement>(null);
const setIntersecting = useSetAtom(formStepAtom);
const router = useRouter();
const { data: session } = useSession();

const formValues = useDefaultFormValues(id);
const methods = useForm<CreateCustomProjectForm>({
resolver: zodResolver(CreateCustomProjectSchema),
resolver: zodResolver(CustomProjectSchema),
defaultValues: formValues,
mode: "all",
});
const activity = methods.watch("activity");
const handleOnSubmit = useCallback(() => {
methods.handleSubmit((data) => onSubmit({ id, data, router, session }))();
}, [methods, id, router, session]);

useEffect(() => {
if (!ref.current) return;
Expand Down Expand Up @@ -76,12 +66,12 @@ export default function CustomProjectForm({ id }: CustomProjectFormProps) {
return (
<FormProvider {...methods}>
<div className="ml-4 flex flex-1 flex-col">
<Header name={formValues.projectName} onSubmit={handleOnSubmit} />
<Header name={formValues.projectName} id={id} />
<div className="flex flex-1 gap-3 overflow-hidden" ref={ref}>
<ProjectSidebar />
<div className="mb-4 flex-1">
<ScrollArea className="flex h-full gap-3 pr-6">
<ProjectForm onSubmit={handleOnSubmit} />
<ProjectForm />
</ScrollArea>
</div>
</div>
Expand Down
4 changes: 2 additions & 2 deletions client/src/containers/projects/form/project-form/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,12 @@ export const useFormValues = () => {
};
};

export default function ProjectForm({ onSubmit }: { onSubmit: () => void }) {
export default function ProjectForm() {
const form = useFormContext<CreateCustomProjectForm>();
const { activity } = form.getValues();

return (
<form className="w-full space-y-8" onSubmit={onSubmit}>
<form className="w-full space-y-8">
<div className="flex flex-col gap-3" id="custom-project-steps-container">
<Card
className="flex flex-1 flex-col"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {
PROJECT_SPECIFIC_EMISSION,
} from "@shared/entities/custom-project.entity";
import { ECOSYSTEM } from "@shared/entities/ecosystem.enum";
import { LOSS_RATE_USED } from "@shared/schemas/custom-projects/create-custom-project.schema";
import { LOSS_RATE_USED } from "@shared/schemas/custom-projects/custom-project.schema";

import { CreateCustomProjectForm } from "@/containers/projects/form/setup";
import LossRate from "@/containers/projects/form/setup/conservation-project-details/loss-rate";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import * as React from "react";
import { useFormContext } from "react-hook-form";

import { ACTIVITY } from "@shared/entities/activity.enum";
import { LOSS_RATE_USED } from "@shared/schemas/custom-projects/create-custom-project.schema";
import { LOSS_RATE_USED } from "@shared/schemas/custom-projects/custom-project.schema";

import { toPercentageValue } from "@/lib/format";
import { client } from "@/lib/query-client";
Expand Down
4 changes: 2 additions & 2 deletions client/src/containers/projects/form/setup/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { EMISSION_FACTORS_TIER_TYPES } from "@shared/entities/carbon-inputs/emis
import { SEQUESTRATION_RATE_TIER_TYPES } from "@shared/entities/carbon-inputs/sequestration-rate.entity";
import { CARBON_REVENUES_TO_COVER } from "@shared/entities/custom-project.entity";
import { ECOSYSTEM } from "@shared/entities/ecosystem.enum";
import { CreateCustomProjectSchema } from "@shared/schemas/custom-projects/create-custom-project.schema";
import { CustomProjectSchema } from "@shared/schemas/custom-projects/custom-project.schema";
import { z } from "zod";

import { client } from "@/lib/query-client";
Expand Down Expand Up @@ -47,7 +47,7 @@ import {
SelectValue,
} from "@/components/ui/select";

export type CreateCustomProjectForm = z.infer<typeof CreateCustomProjectSchema>;
export type CreateCustomProjectForm = z.infer<typeof CustomProjectSchema>;

export default function SetupProjectForm() {
const { queryKey } = queryKeys.countries.all;
Expand Down
Loading

0 comments on commit 2deb829

Please sign in to comment.