Skip to content

Commit

Permalink
adds restoration fields
Browse files Browse the repository at this point in the history
  • Loading branch information
agnlez committed Dec 12, 2024
1 parent 0b70c02 commit 17332e7
Show file tree
Hide file tree
Showing 3 changed files with 230 additions and 87 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,15 @@ import * as React from "react";

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

import { RESTORATION_ACTIVITY_SUBTYPE } from "@shared/entities/activity.enum";
import {
ACTIVITY,
RESTORATION_ACTIVITY_SUBTYPE,
} from "@shared/entities/activity.enum";
import { SEQUESTRATION_RATE_TIER_TYPES } from "@shared/entities/carbon-inputs/sequestration-rate.entity";

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

import { CreateCustomProjectForm } from "@/containers/projects/form/setup";

import { Card } from "@/components/ui/card";
Expand All @@ -15,6 +21,7 @@ import {
FormLabel,
FormMessage,
} from "@/components/ui/form";
import { Input } from "@/components/ui/input";
import {
Select,
SelectContent,
Expand All @@ -26,98 +33,239 @@ import {
export default function RestorationProjectDetails() {
const form = useFormContext<CreateCustomProjectForm>();

const {
ecosystem,
countryCode,
activity,
// @ts-expect-error fix later
parameters: { tierSelector },
} = form.getValues();

const queryKey = queryKeys.customProjects.defaultActivityTypes({
ecosystem,
countryCode,
}).queryKey;

const { data } = client.customProjects.getActivityTypesDefaults.useQuery(
queryKey,
{ query: { ecosystem, countryCode } },
{
queryKey,
enabled: !!ecosystem && !!countryCode,
select: (response) => {
const { data } = response.body;
return data[activity as ACTIVITY.RESTORATION].sequestrationRate;
},
},
);

return (
<Card variant="secondary">
<div className="flex gap-3">
<div className="basis-1/2 space-y-2">
<div className="flex flex-col gap-4">
<div className="flex gap-4">
<div className="basis-1/2 space-y-2">
<FormField
control={form.control}
name="parameters.restorationActivity"
render={() => (
<FormItem className="basis-1/2">
<FormLabel
tooltip={{
title: "Project-specific emissions type",
content: "TBD",
}}
>
Restoration Activity type
</FormLabel>
<FormControl>
<Select
name="parameters.restorationActivity"
value={form.getValues("parameters.restorationActivity")}
onValueChange={async (v) => {
form.setValue(
"parameters.restorationActivity",
v as RESTORATION_ACTIVITY_SUBTYPE,
);
await form.trigger("parameters.restorationActivity");
}}
>
<SelectTrigger>
<SelectValue placeholder="Select restoration activity type" />
</SelectTrigger>
<SelectContent>
{Object.values(RESTORATION_ACTIVITY_SUBTYPE)?.map(
(option) => (
<SelectItem key={option} value={option}>
{option}
</SelectItem>
),
)}
</SelectContent>
</Select>
</FormControl>
<FormMessage />
</FormItem>
)}
/>
</div>
<div className="basis-1/2 space-y-2">
<FormField
control={form.control}
name="parameters.restorationActivity"
render={() => (
<FormItem className="basis-1/2">
<FormLabel
tooltip={{
title: "Project-specific emissions type",
content: "TBD",
}}
>
Sequestration Factor Used
</FormLabel>
<FormControl>
<Select
name="parameters.tierSelector"
value={form.getValues("parameters.tierSelector")}
onValueChange={async (v) => {
form.setValue(
"parameters.tierSelector",
v as SEQUESTRATION_RATE_TIER_TYPES,
);
await form.trigger("parameters.tierSelector");
}}
>
<SelectTrigger>
<SelectValue placeholder="Select sequestration tier" />
</SelectTrigger>
<SelectContent>
{Object.values(SEQUESTRATION_RATE_TIER_TYPES)?.map(
(option) => (
<SelectItem key={option} value={option}>
{option}
</SelectItem>
),
)}
</SelectContent>
</Select>
</FormControl>
<FormMessage />
</FormItem>
)}
/>
</div>
</div>

<div className="flex gap-4">
<FormField
control={form.control}
name="parameters.restorationActivity"
render={() => (
<FormItem className="basis-1/2">
control={form?.control}
name="parameters.plantingSuccessRate"
render={({ field }) => (
<FormItem className="basis-1/2 space-y-2">
<FormLabel
tooltip={{
title: "Project-specific emissions type",
title: "Project Specific Emission Factor",
content: "TBD",
}}
>
Restoration Activity type
Project Specific Emission Factor
</FormLabel>
<FormControl>
<Select
name="parameters.restorationActivity"
value={form.getValues("parameters.restorationActivity")}
onValueChange={async (v) => {
form.setValue(
"parameters.restorationActivity",
v as RESTORATION_ACTIVITY_SUBTYPE,
);
await form.trigger("parameters.restorationActivity");
}}
>
<SelectTrigger>
<SelectValue placeholder="Select restoration activity type" />
</SelectTrigger>
<SelectContent>
{Object.values(RESTORATION_ACTIVITY_SUBTYPE)?.map(
(option) => (
<SelectItem key={option} value={option}>
{option}
</SelectItem>
),
)}
</SelectContent>
</Select>
<FormControl className="relative after:absolute after:right-6 after:inline-block after:text-sm after:text-muted-foreground after:content-['%']">
<div className="relative flex flex-1 items-center">
<Input
{...field}
className="w-full pr-12"
type="number"
min={0}
onChange={(v) => {
form.setValue(
"parameters.plantingSuccessRate",
Number(v.target.value),
);
// await form.trigger("parameters.plantingSuccessRate");
}}
readOnly
disabled
/>
</div>
</FormControl>
<FormMessage />
</FormItem>
)}
/>
</div>
<div className="basis-1/2 space-y-2">
<FormField
control={form.control}
name="parameters.restorationActivity"
render={() => (
<FormItem className="basis-1/2">

<>
{tierSelector === SEQUESTRATION_RATE_TIER_TYPES.TIER_1 && (
<div className="basis-1/2 space-y-2">
<FormLabel
tooltip={{
title: "Project-specific emissions type",
title: "IPCC default value",
content: "TBD",
}}
>
Sequestration Factor Used
IPCC default value
</FormLabel>
<FormControl>
<Select
name="parameters.tierSelector"
value={form.getValues("parameters.tierSelector")}
onValueChange={async (v) => {
form.setValue(
"parameters.tierSelector",
v as SEQUESTRATION_RATE_TIER_TYPES,
);
await form.trigger("parameters.tierSelector");
}}
>
<SelectTrigger>
<SelectValue placeholder="Select sequestration tier" />
</SelectTrigger>
<SelectContent>
{Object.values(SEQUESTRATION_RATE_TIER_TYPES)?.map(
(option) => (
<SelectItem key={option} value={option}>
{option}
</SelectItem>
),
)}
</SelectContent>
</Select>
</FormControl>
<FormMessage />
</FormItem>
<div className="relative flex flex-1 items-center after:absolute after:right-6 after:inline-block after:text-sm after:text-muted-foreground after:content-['??']">
<Input
className="w-full pr-32 text-muted-foreground"
disabled
readOnly
value={data?.tier1}
/>
</div>
</div>
)}
/>
{tierSelector === SEQUESTRATION_RATE_TIER_TYPES.TIER_2 && (
<div className="basis-1/2 space-y-2">
<FormLabel
tooltip={{
title: "Country-specific rate",
content: "TBD",
}}
>
Country-specific rate
</FormLabel>
<div className="relative flex flex-1 items-center after:absolute after:right-6 after:inline-block after:text-sm after:text-muted-foreground after:content-['??']">
<Input
className="w-full pr-32 text-muted-foreground"
disabled
readOnly
value={data?.tier2}
/>
</div>
</div>
)}
{tierSelector === SEQUESTRATION_RATE_TIER_TYPES.TIER_3 && (
<FormField
control={form?.control}
name="parameters.projectSpecificSequestrationRate"
render={({ field }) => (
<FormItem className="basis-1/2 space-y-2">
<FormLabel
tooltip={{
title: "Project-specific sequestration rate",
content: "TBD",
}}
>
Project-specific sequestration rate
</FormLabel>
<FormControl className="relative after:absolute after:right-6 after:inline-block after:text-sm after:text-muted-foreground after:content-['%']">
<div className="relative flex flex-1 items-center">
<Input
{...field}
className="w-full pr-12"
type="number"
onChange={(v) => {
field.onChange(Number(v.target.value));
}}
/>
</div>
</FormControl>
<FormMessage />
</FormItem>
)}
/>
)}
</>
</div>
</div>
</Card>
Expand Down
2 changes: 2 additions & 0 deletions client/src/containers/projects/new/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,8 @@ export default function CreateCustomProject() {
projectSpecificEmissionFactor: 0,
emissionFactorSOC: 0,
emissionFactorAGB: 0,
// @ts-expect-error fix later
plantingSuccessRate: 80,
},
assumptions: {
baselineReassessmentFrequency: undefined,
Expand Down
23 changes: 8 additions & 15 deletions shared/schemas/custom-projects/create-custom-project.schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,28 +56,21 @@ export const RestorationCustomProjectSchema = z
.object({
restorationActivity: z.nativeEnum(RESTORATION_ACTIVITY_SUBTYPE),
tierSelector: z.nativeEnum(SEQUESTRATION_RATE_TIER_TYPES),
projectSpecificLossRate: z
.number({ message: "Project Specific Loss Rate should be a message" })
.negative({ message: "Project Specific Loss Rate should be negative" }),
projectSpecificSequestrationRate: z
.number({ message: "Project Specific Rate should be a number" }),
lossRateUsed: z.nativeEnum(LOSS_RATE_USED),
plantingSuccessRate: z.preprocess(parseNumber, z.number().nonnegative({
message: 'Planting Success Rate should be a non-negative number',
})),
})
.superRefine((data, ctx) => {
if (
data.lossRateUsed === LOSS_RATE_USED.PROJECT_SPECIFIC &&
!data.projectSpecificLossRate
data.tierSelector === SEQUESTRATION_RATE_TIER_TYPES.TIER_3 &&
!data.projectSpecificSequestrationRate
) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
message: `Project Specific Loss Rate is required when lossRateUsed is ${LOSS_RATE_USED.PROJECT_SPECIFIC}`,
});
}
if (
data.lossRateUsed === LOSS_RATE_USED.NATIONAL_AVERAGE &&
data.projectSpecificLossRate
) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
message: `Project Specific Loss Rate should not be provided when lossRateUsed is ${LOSS_RATE_USED.NATIONAL_AVERAGE}`,
message: 'Project Specific Rate is required',
});
}
});
Expand Down

0 comments on commit 17332e7

Please sign in to comment.