From efa98fca26f223ef5e6bf8c99c82c014ca31f3ad Mon Sep 17 00:00:00 2001 From: Thad Kerosky Date: Wed, 20 Mar 2024 01:01:04 +0000 Subject: [PATCH 1/5] WIP: explore abstract in zod types Co-authored-by: plocket Co-authored-by: Clayton Schneider Co-authored-by: Leopardfoot Co-authored-by: Camden Blatchly --- .../EnergyUseHistory.tsx | 9 ++++---- heat-stack/app/routes/_heat+/single.tsx | 22 ++++++++++++++----- heat-stack/types/{index.d.ts => index.ts} | 15 +++++++++++++ 3 files changed, 35 insertions(+), 11 deletions(-) rename heat-stack/types/{index.d.ts => index.ts} (76%) diff --git a/heat-stack/app/components/ui/heat/CaseSummaryComponents/EnergyUseHistory.tsx b/heat-stack/app/components/ui/heat/CaseSummaryComponents/EnergyUseHistory.tsx index 45d8096a..7ba4ea08 100644 --- a/heat-stack/app/components/ui/heat/CaseSummaryComponents/EnergyUseHistory.tsx +++ b/heat-stack/app/components/ui/heat/CaseSummaryComponents/EnergyUseHistory.tsx @@ -1,13 +1,12 @@ -import { AnalysisHeader } from './AnalysisHeader.tsx' -import { EnergyUseHistoryChart } from './EnergyUseHistoryChart.tsx' -import { Button } from '#/app/components/ui/button.tsx' - +import { FieldMetadata, useForm } from '@conform-to/react' import { Form } from '@remix-run/react' import { ErrorList } from "./ErrorList.tsx" import { Input } from '#/app/components/ui/input.tsx' import { Label } from '#/app/components/ui/label.tsx' -import { FieldMetadata, useForm } from '@conform-to/react' +import { Button } from '#/app/components/ui/button.tsx' +import { AnalysisHeader } from './AnalysisHeader.tsx' +import { EnergyUseHistoryChart } from './EnergyUseHistoryChart.tsx' export function EnergyUseHistory() { const titleClass = 'text-5xl font-extrabold tracking-wide mt-10' diff --git a/heat-stack/app/routes/_heat+/single.tsx b/heat-stack/app/routes/_heat+/single.tsx index 4d6e82dc..35edd1af 100644 --- a/heat-stack/app/routes/_heat+/single.tsx +++ b/heat-stack/app/routes/_heat+/single.tsx @@ -9,6 +9,7 @@ import { z } from 'zod' // Ours import { ErrorList } from '#app/components/ui/heat/CaseSummaryComponents/ErrorList.tsx' +import { HomeSchema } from '../../../types/index.ts' import { CurrentHeatingSystem } from '../../components/ui/heat/CaseSummaryComponents/CurrentHeatingSystem.tsx' import { EnergyUseHistory } from '../../components/ui/heat/CaseSummaryComponents/EnergyUseHistory.tsx' import { HomeInformation } from '../../components/ui/heat/CaseSummaryComponents/HomeInformation.tsx' @@ -20,19 +21,27 @@ const addressMaxLength = 100 /** Modeled off the conform example at * https://github.com/epicweb-dev/web-forms/blob/b69e441f5577b91e7df116eba415d4714daacb9d/exercises/03.schema-validation/03.solution.conform-form/app/routes/users%2B/%24username_%2B/notes.%24noteId_.edit.tsx#L48 */ -const HomeInformationSchema = z.object({ +const HomeInformationSchema = { name: z.string().min(1).max(nameMaxLength), address: z.string().min(1).max(addressMaxLength), livingSpace: z.number().min(1), -}) +} +// type Home = z.infer + +// TODO Next: Ask an LLM how we get fuelType out of HomeSchema from zod -const EnergyUseSchema = z.object({ - fuelType: z.string().min(1).max(nameMaxLength), +const EnergyUseSchema = { + fuelType: 'foo', efficiency: z.string().min(1).max(addressMaxLength), override: z.number().min(1), setpoint: z.string().min(1).max(nameMaxLength), setbackTemp: z.string().min(1).max(addressMaxLength), setbackHours: z.number().min(1), +} + +const Schema = z.object({ + ...HomeSchema, + ...EnergyUseSchema }) export async function action({ request, params }: ActionFunctionArgs) { @@ -41,7 +50,7 @@ export async function action({ request, params }: ActionFunctionArgs) { const formData = await request.formData() const submission = parseWithZod(formData, { - schema: HomeInformationSchema, + schema: Schema, }) if(submission.status !== "success") { @@ -62,6 +71,7 @@ export async function action({ request, params }: ActionFunctionArgs) { // TODO NEXT WEEK // - [x] Server side error checking/handling // - [x] ~Save to cookie and redirect to next form~ Put everything on the same page + // - [ ] - Get zod and Typescript to play nice // - [ ] (We're here) Build form #2 // - [ ] Build form #3 // - [ ] Form errors (if we think of a use case - 2 fields conflicting...) @@ -78,7 +88,7 @@ export default function Inputs() { const [form, fields] = useForm({ lastResult, onValidate({ formData }) { - return parseWithZod(formData, { schema: HomeInformationSchema }) + return parseWithZod(formData, { schema: Schema }) }, defaultValue: { diff --git a/heat-stack/types/index.d.ts b/heat-stack/types/index.ts similarity index 76% rename from heat-stack/types/index.d.ts rename to heat-stack/types/index.ts index 62bc01ab..841297c1 100644 --- a/heat-stack/types/index.d.ts +++ b/heat-stack/types/index.ts @@ -1,3 +1,5 @@ +import { z } from 'zod'; + export interface Case { firstName: string lastName: string @@ -16,6 +18,19 @@ export interface HeatLoadAnalysis { maximumHeatLoad: number } +export const HomeSchema = z.object({ + livingArea: z.number(), + fuelType: z.enum(['Natural Gas','Oil','Propane']), + designTemperatureOverride: z.number(), + heatingSystemEfficiency: z.number(), + thermostatSetPoint: z.number(), + setbackTemperature: z.number(), + setbackHoursPerDay: z.number(), + numberOfOccupants: z.number(), + estimatedWaterHeatingEfficiency: z.number(), + standByLosses: z.number(), +}); + export interface Home { livingArea: number fuelType: 'Natural Gas' | 'Oil' | 'Propane' From b176a47df45b6c2a1feda986d6125c61c283342a Mon Sep 17 00:00:00 2001 From: Thad Kerosky Date: Wed, 27 Mar 2024 01:01:33 +0000 Subject: [PATCH 2/5] Added zod types for CurrentHeatingSystem and change types/index.ts to zod. Co-authored-by: Camden Blatchly Co-authored-by: plocket --- .../CurrentHeatingSystem.tsx | 4 +- .../EnergyUseHistory.tsx | 4 + .../CaseSummaryComponents/HomeInformation.tsx | 14 +- heat-stack/app/routes/_heat+/inputs2.tsx | 2 +- heat-stack/app/routes/_heat+/single.tsx | 84 +++++++----- heat-stack/types/index.ts | 125 ++++++++---------- 6 files changed, 115 insertions(+), 118 deletions(-) diff --git a/heat-stack/app/components/ui/heat/CaseSummaryComponents/CurrentHeatingSystem.tsx b/heat-stack/app/components/ui/heat/CaseSummaryComponents/CurrentHeatingSystem.tsx index cc3427d1..9f1d9f97 100644 --- a/heat-stack/app/components/ui/heat/CaseSummaryComponents/CurrentHeatingSystem.tsx +++ b/heat-stack/app/components/ui/heat/CaseSummaryComponents/CurrentHeatingSystem.tsx @@ -4,7 +4,9 @@ import { Button } from '#/app/components/ui/button.tsx' import { Input } from '#/app/components/ui/input.tsx' import { Label } from '#/app/components/ui/label.tsx' -export function CurrentHeatingSystem() { +type CurrentHeatingSystemProps = {fields: any}; + +export function CurrentHeatingSystem(props: CurrentHeatingSystemProps) { const titleClass = 'text-5xl font-extrabold tracking-wide' const descriptiveClass = 'mt-2 text-sm text-slate-500' const componentMargin = 'mt-10' diff --git a/heat-stack/app/components/ui/heat/CaseSummaryComponents/EnergyUseHistory.tsx b/heat-stack/app/components/ui/heat/CaseSummaryComponents/EnergyUseHistory.tsx index 7ba4ea08..b378c532 100644 --- a/heat-stack/app/components/ui/heat/CaseSummaryComponents/EnergyUseHistory.tsx +++ b/heat-stack/app/components/ui/heat/CaseSummaryComponents/EnergyUseHistory.tsx @@ -8,6 +8,10 @@ import { Button } from '#/app/components/ui/button.tsx' import { AnalysisHeader } from './AnalysisHeader.tsx' import { EnergyUseHistoryChart } from './EnergyUseHistoryChart.tsx' + +// type EnergyUseProps = {fields: any}; + +// export function EnergyUseHistory(props: EnergyUseProps) { export function EnergyUseHistory() { const titleClass = 'text-5xl font-extrabold tracking-wide mt-10' const subtitleClass = 'text-2xl font-semibold text-zinc-950 mt-9' diff --git a/heat-stack/app/components/ui/heat/CaseSummaryComponents/HomeInformation.tsx b/heat-stack/app/components/ui/heat/CaseSummaryComponents/HomeInformation.tsx index 82c9f9d9..2f121dc1 100644 --- a/heat-stack/app/components/ui/heat/CaseSummaryComponents/HomeInformation.tsx +++ b/heat-stack/app/components/ui/heat/CaseSummaryComponents/HomeInformation.tsx @@ -42,19 +42,7 @@ import { FieldMetadata, useForm } from '@conform-to/react' // // return redirect(`/inputs1`) // } -type HomeInformationProps = {fields: { - name: FieldMetadata; - address: FieldMetadata; - livingSpace: FieldMetadata; -}}; +type HomeInformationProps = {fields: any}; export function HomeInformation(props: HomeInformationProps) { diff --git a/heat-stack/app/routes/_heat+/inputs2.tsx b/heat-stack/app/routes/_heat+/inputs2.tsx index 735b41a9..ec79460e 100644 --- a/heat-stack/app/routes/_heat+/inputs2.tsx +++ b/heat-stack/app/routes/_heat+/inputs2.tsx @@ -2,7 +2,7 @@ import { CurrentHeatingSystem } from '../../components/ui/heat/CaseSummaryCompon export default function Inputs2() { return (
- +
) } diff --git a/heat-stack/app/routes/_heat+/single.tsx b/heat-stack/app/routes/_heat+/single.tsx index 35edd1af..c2676cbc 100644 --- a/heat-stack/app/routes/_heat+/single.tsx +++ b/heat-stack/app/routes/_heat+/single.tsx @@ -9,7 +9,7 @@ import { z } from 'zod' // Ours import { ErrorList } from '#app/components/ui/heat/CaseSummaryComponents/ErrorList.tsx' -import { HomeSchema } from '../../../types/index.ts' +import { Home, Location, Case } from '../../../types/index.ts' import { CurrentHeatingSystem } from '../../components/ui/heat/CaseSummaryComponents/CurrentHeatingSystem.tsx' import { EnergyUseHistory } from '../../components/ui/heat/CaseSummaryComponents/EnergyUseHistory.tsx' import { HomeInformation } from '../../components/ui/heat/CaseSummaryComponents/HomeInformation.tsx' @@ -21,29 +21,33 @@ const addressMaxLength = 100 /** Modeled off the conform example at * https://github.com/epicweb-dev/web-forms/blob/b69e441f5577b91e7df116eba415d4714daacb9d/exercises/03.schema-validation/03.solution.conform-form/app/routes/users%2B/%24username_%2B/notes.%24noteId_.edit.tsx#L48 */ -const HomeInformationSchema = { - name: z.string().min(1).max(nameMaxLength), - address: z.string().min(1).max(addressMaxLength), - livingSpace: z.number().min(1), -} -// type Home = z.infer -// TODO Next: Ask an LLM how we get fuelType out of HomeSchema from zod +// const HomeInformationSchema = { +// name: z.string().min(1).max(nameMaxLength), +// address: z.string().min(1).max(addressMaxLength), +// livingSpace: z.number().min(1), +// } +// // type Home = z.infer -const EnergyUseSchema = { - fuelType: 'foo', - efficiency: z.string().min(1).max(addressMaxLength), - override: z.number().min(1), - setpoint: z.string().min(1).max(nameMaxLength), - setbackTemp: z.string().min(1).max(addressMaxLength), - setbackHours: z.number().min(1), -} +// // TODO Next: Ask an LLM how we get fuelType out of HomeSchema from zod -const Schema = z.object({ - ...HomeSchema, - ...EnergyUseSchema +const HomeFormSchema = Home.pick({ livingArea: true }) + .and(Location.pick({ address: true })) + .and(Case.pick({ name: true })) + +const CurrentHeatingSystemSchema = Home.pick({ + fuelType: true, + heatingSystemEfficiency: true, + thermostatSetPoint: true, + setbackTemperature: true, + setbackHoursPerDay: true, + designTemperatureOverride: true, }) +const Schema = HomeFormSchema.and(CurrentHeatingSystemSchema) + +// const EnergyUseSchema = ''; + export async function action({ request, params }: ActionFunctionArgs) { // Checks if url has a homeId parameter, throws 400 if not there // invariantResponse(params.homeId, 'homeId param is required') @@ -53,19 +57,19 @@ export async function action({ request, params }: ActionFunctionArgs) { schema: Schema, }) - if(submission.status !== "success") { + if (submission.status !== 'success') { return submission.reply() - // submission.reply({ - // // You can also pass additional error to the `reply` method - // formErrors: ['Submission failed'], - // fieldErrors: { - // address: ['Address is invalid'], - // }, - - // // or avoid sending the the field value back to client by specifying the field names - // hideFields: ['password'], - // }), - // {status: submission.status === "error" ? 400 : 200} + // submission.reply({ + // // You can also pass additional error to the `reply` method + // formErrors: ['Submission failed'], + // fieldErrors: { + // address: ['Address is invalid'], + // }, + + // // or avoid sending the the field value back to client by specifying the field names + // hideFields: ['password'], + // }), + // {status: submission.status === "error" ? 400 : 200} } // TODO NEXT WEEK @@ -76,7 +80,12 @@ export async function action({ request, params }: ActionFunctionArgs) { // - [ ] Build form #3 // - [ ] Form errors (if we think of a use case - 2 fields conflicting...) - const { name, address, livingSpace } = submission.value + const { name, address, livingArea, fuelType, + heatingSystemEfficiency, + thermostatSetPoint, + setbackTemperature, + setbackHoursPerDay, + designTemperatureOverride } = submission.value // await updateNote({ id: params.noteId, title, content }) @@ -90,15 +99,18 @@ export default function Inputs() { onValidate({ formData }) { return parseWithZod(formData, { schema: Schema }) }, - defaultValue: { - - }, + defaultValue: {}, shouldValidate: 'onBlur', }) return ( <> -
+ diff --git a/heat-stack/types/index.ts b/heat-stack/types/index.ts index 841297c1..ddc5182a 100644 --- a/heat-stack/types/index.ts +++ b/heat-stack/types/index.ts @@ -1,77 +1,68 @@ import { z } from 'zod'; -export interface Case { - firstName: string - lastName: string -} +// JS team wants to discuss this name +export const Case = z.object({ + name: z.string() +}) -export interface HeatLoadAnalysis { - rulesEngineVersion: string - estimatedBalancePoint: number - otherFuelUsage: number - averageIndoorTemperature: number - differenceBetweenTiAndTbp: number - designTemperature: number - wholeHomeHeatLossRate: number - standardDeviationHeatLossRate: number - averageHeatLoad: number - maximumHeatLoad: number -} - -export const HomeSchema = z.object({ - livingArea: z.number(), - fuelType: z.enum(['Natural Gas','Oil','Propane']), - designTemperatureOverride: z.number(), - heatingSystemEfficiency: z.number(), - thermostatSetPoint: z.number(), - setbackTemperature: z.number(), - setbackHoursPerDay: z.number(), - numberOfOccupants: z.number(), - estimatedWaterHeatingEfficiency: z.number(), - standByLosses: z.number(), +export const HeatLoadAnalysis = z.object({ + rulesEngineVersion: z.string(), + estimatedBalancePoint: z.number(), + otherFuelUsage: z.number(), + averageIndoorTemperature: z.number(), + differenceBetweenTiAndTbp: z.number(), + /** + * designTemperature in Fahrenheit + */ + designTemperature: z.number().max(-10).min(50), + wholeHomeHeatLossRate: z.number(), + standardDeviationHeatLossRate: z.number(), + averageHeatLoad: z.number(), + maximumHeatLoad: z.number(), }); -export interface Home { - livingArea: number - fuelType: 'Natural Gas' | 'Oil' | 'Propane' - designTemperatureOverride: number - heatingSystemEfficiency: number - thermostatSetPoint: number - setbackTemperature: number - setbackHoursPerDay: number - numberOfOccupants: number - estimatedWaterHeatingEfficiency: number - standByLosses: number -} +export const Home = z.object({ + /** + * unit: square feet + */ + livingArea: z.number().min(500).max(10000), + fuelType: z.enum(['Natural Gas','Oil','Propane']), + designTemperatureOverride: z.number(), + /** + * unit: percentage in decimal numbers, but not 0 to 1 + */ + heatingSystemEfficiency: z.number().min(60).max(100), + thermostatSetPoint: z.number(), + setbackTemperature: z.number(), + setbackHoursPerDay: z.number(), + numberOfOccupants: z.number(), + estimatedWaterHeatingEfficiency: z.number(), + standByLosses: z.number(), +}); -export interface Location { - address: string - addressLine2: string - city: string - state: string - zip: string - country: string -} +export const Location = z.object({ + address: z.string(), +}); -export interface NaturalGasBill { - provider: string -} +export const NaturalGasBill = z.object({ + provider: z.string(), +}); -export interface NaturalGasBillRecord { - periodStartDate: Date - periodEndDate: Date - usageTherms: number - inclusionOverride: 'Include' | 'Do not include' | 'Include in other analysis' -} +export const NaturalGasBillRecord = z.object({ + periodStartDate: z.date(), + periodEndDate: z.date(), + usageTherms: z.number(), + inclusionOverride: z.enum(['Include', 'Do not include', 'Include in other analysis']), +}); -export interface OilPropaneBill { - provider: string - precedingDeliveryDate: Date -} +export const OilPropaneBill = z.object({ + provider: z.string(), + precedingDeliveryDate: z.date(), +}); -export interface OilPropaneBillRecord { - periodStartDate: Date - periodEndDate: Date - gallons: number - inclusionOverride: 'Include' | 'Do not include' | 'Include in other analysis' -} +export const OilPropaneBillRecord = z.object({ + periodStartDate: z.date(), + periodEndDate: z.date(), + gallons: z.number(), + inclusionOverride: z.enum(['Include', 'Do not include', 'Include in other analysis']), +}); From fd864b322c5418067086eb256d17e2c8896847ab Mon Sep 17 00:00:00 2001 From: Thad Kerosky Date: Wed, 27 Mar 2024 02:06:40 +0000 Subject: [PATCH 3/5] fix display analysis+charts to use zod --- .../ui/heat/CaseSummaryComponents/AnalysisHeader.tsx | 4 +++- .../ui/heat/CaseSummaryComponents/EnergyUseHistoryChart.tsx | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/heat-stack/app/components/ui/heat/CaseSummaryComponents/AnalysisHeader.tsx b/heat-stack/app/components/ui/heat/CaseSummaryComponents/AnalysisHeader.tsx index fda3c915..095a1df4 100644 --- a/heat-stack/app/components/ui/heat/CaseSummaryComponents/AnalysisHeader.tsx +++ b/heat-stack/app/components/ui/heat/CaseSummaryComponents/AnalysisHeader.tsx @@ -1,5 +1,7 @@ -import { type HeatLoadAnalysis } from '#types/index.js' +import { type z } from 'zod' +import { type HeatLoadAnalysis as HeatLoadAnalysisZod} from '#types/index' +type HeatLoadAnalysis = z.infer export function AnalysisHeader() { const heatLoadAnalysis: HeatLoadAnalysis = { rulesEngineVersion: 'Beta 1', diff --git a/heat-stack/app/components/ui/heat/CaseSummaryComponents/EnergyUseHistoryChart.tsx b/heat-stack/app/components/ui/heat/CaseSummaryComponents/EnergyUseHistoryChart.tsx index 2e8d20bc..bcf8f910 100644 --- a/heat-stack/app/components/ui/heat/CaseSummaryComponents/EnergyUseHistoryChart.tsx +++ b/heat-stack/app/components/ui/heat/CaseSummaryComponents/EnergyUseHistoryChart.tsx @@ -1,4 +1,5 @@ -import { type NaturalGasBillRecord } from '#types/index.js' +import { type z } from 'zod' +import { type NaturalGasBillRecord as NaturalGasBillRecordZod } from '#types/index' import { Checkbox } from '../../../../components/ui/checkbox.tsx' import { @@ -10,6 +11,7 @@ import { TableRow, } from '../../../../components/ui/table.tsx' +type NaturalGasBillRecord = z.infer const naturalGasBillRecord01: NaturalGasBillRecord = { periodStartDate: new Date('12/08/2017'), periodEndDate: new Date('01/07/2018'), From 6dd361f33ebfea8112fd1e21ae80e3edc2d7518c Mon Sep 17 00:00:00 2001 From: Thad Kerosky Date: Wed, 3 Apr 2024 00:32:01 +0000 Subject: [PATCH 4/5] implement CurrentHeatingSystem form in zod/conform Co-authored-by: plocket Co-authored-by: Clayton Schneider --- .../CurrentHeatingSystem.tsx | 198 +++++++++++------- .../CaseSummaryComponents/HomeInformation.tsx | 2 +- heat-stack/app/routes/_heat+/single.tsx | 18 +- heat-stack/types/index.ts | 6 +- 4 files changed, 136 insertions(+), 88 deletions(-) diff --git a/heat-stack/app/components/ui/heat/CaseSummaryComponents/CurrentHeatingSystem.tsx b/heat-stack/app/components/ui/heat/CaseSummaryComponents/CurrentHeatingSystem.tsx index 9f1d9f97..9df07b8b 100644 --- a/heat-stack/app/components/ui/heat/CaseSummaryComponents/CurrentHeatingSystem.tsx +++ b/heat-stack/app/components/ui/heat/CaseSummaryComponents/CurrentHeatingSystem.tsx @@ -1,10 +1,11 @@ import { Form } from '@remix-run/react' import { Button } from '#/app/components/ui/button.tsx' +import { ErrorList } from './ErrorList.tsx' import { Input } from '#/app/components/ui/input.tsx' import { Label } from '#/app/components/ui/label.tsx' -type CurrentHeatingSystemProps = {fields: any}; +type CurrentHeatingSystemProps = { fields: any } export function CurrentHeatingSystem(props: CurrentHeatingSystemProps) { const titleClass = 'text-5xl font-extrabold tracking-wide' @@ -18,107 +19,154 @@ export function CurrentHeatingSystem(props: CurrentHeatingSystemProps) { Existing Heating System - -
Fuel Type
+ {/* */} +
+ {' '} +
- +
+
+ +
+
-
Heating system efficiency %
-
-
- + Heating system efficiency % + +
+
+ +
+ Typical natural gas efficiency is 80%-95% +
+
+ +
+
+
+ + +
+
+ +
- Typical natural gas efficiency is 80%-95% + 65°F is the 99% ASHRAE heating design temperature at this location
+
+ +
+
-
Design temperature override (°F)
-
-
+
+
Thermostat Settings
+
+
+ -
-
- 65°F is the 99% ASHRAE heating design temperature at this - location -
+
+ Usual thermostat setting for heating
-
-
- -
-
Thermostat Settings
-
-
- - + -
- Usual thermostat setting for heating -
-
- - +
+ + +
+ Enter if thermostat is programmed to a lower or higher temperature + during working or sleep hours +
+
+ -
- Enter if thermostat is programmed to a lower or higher - temperature during working or sleep hours -
-
- - +
+ + +
+ Typical natural gas efficiency is 80%-95% +
+
+ Average hours per day that a lower or higher temperature setting + is in effect +
+
+ -
- Typical natural gas efficiency is 80%-95% -
-
- Average hours per day that a lower or higher temperature setting - is in effect -
+
- - + {/* */} {/* removed temporarily for single page app format */} {/*
- -
*/} + +
*/}
) } diff --git a/heat-stack/app/components/ui/heat/CaseSummaryComponents/HomeInformation.tsx b/heat-stack/app/components/ui/heat/CaseSummaryComponents/HomeInformation.tsx index 2f121dc1..c6e3db27 100644 --- a/heat-stack/app/components/ui/heat/CaseSummaryComponents/HomeInformation.tsx +++ b/heat-stack/app/components/ui/heat/CaseSummaryComponents/HomeInformation.tsx @@ -42,7 +42,7 @@ import { FieldMetadata, useForm } from '@conform-to/react' // // return redirect(`/inputs1`) // } -type HomeInformationProps = {fields: any}; +type HomeInformationProps = {fields: Conform}; export function HomeInformation(props: HomeInformationProps) { diff --git a/heat-stack/app/routes/_heat+/single.tsx b/heat-stack/app/routes/_heat+/single.tsx index c2676cbc..b95dc65b 100644 --- a/heat-stack/app/routes/_heat+/single.tsx +++ b/heat-stack/app/routes/_heat+/single.tsx @@ -7,6 +7,14 @@ import { json, ActionFunctionArgs } from '@remix-run/node' import { Form, redirect, useActionData } from '@remix-run/react' import { z } from 'zod' +// TODO NEXT WEEK +// - [x] Server side error checking/handling +// - [x] ~Save to cookie and redirect to next form~ Put everything on the same page +// - [x] - Get zod and Typescript to play nice +// - [x] (We're here) Build form #2 +// - [ ] Build form #3 +// - [ ] Form errors (if we think of a use case - 2 fields conflicting...) + // Ours import { ErrorList } from '#app/components/ui/heat/CaseSummaryComponents/ErrorList.tsx' import { Home, Location, Case } from '../../../types/index.ts' @@ -38,10 +46,10 @@ const HomeFormSchema = Home.pick({ livingArea: true }) const CurrentHeatingSystemSchema = Home.pick({ fuelType: true, heatingSystemEfficiency: true, + designTemperatureOverride: true, thermostatSetPoint: true, setbackTemperature: true, setbackHoursPerDay: true, - designTemperatureOverride: true, }) const Schema = HomeFormSchema.and(CurrentHeatingSystemSchema) @@ -72,14 +80,6 @@ export async function action({ request, params }: ActionFunctionArgs) { // {status: submission.status === "error" ? 400 : 200} } - // TODO NEXT WEEK - // - [x] Server side error checking/handling - // - [x] ~Save to cookie and redirect to next form~ Put everything on the same page - // - [ ] - Get zod and Typescript to play nice - // - [ ] (We're here) Build form #2 - // - [ ] Build form #3 - // - [ ] Form errors (if we think of a use case - 2 fields conflicting...) - const { name, address, livingArea, fuelType, heatingSystemEfficiency, thermostatSetPoint, diff --git a/heat-stack/types/index.ts b/heat-stack/types/index.ts index ddc5182a..81533612 100644 --- a/heat-stack/types/index.ts +++ b/heat-stack/types/index.ts @@ -27,14 +27,14 @@ export const Home = z.object({ */ livingArea: z.number().min(500).max(10000), fuelType: z.enum(['Natural Gas','Oil','Propane']), - designTemperatureOverride: z.number(), + designTemperatureOverride: z.number().optional(), /** * unit: percentage in decimal numbers, but not 0 to 1 */ heatingSystemEfficiency: z.number().min(60).max(100), thermostatSetPoint: z.number(), - setbackTemperature: z.number(), - setbackHoursPerDay: z.number(), + setbackTemperature: z.number().optional(), + setbackHoursPerDay: z.number().optional(), numberOfOccupants: z.number(), estimatedWaterHeatingEfficiency: z.number(), standByLosses: z.number(), From ad5e98d2e50d92b8a42bdd88d23c342afc8f831b Mon Sep 17 00:00:00 2001 From: Thad Kerosky Date: Thu, 4 Apr 2024 17:36:42 +0000 Subject: [PATCH 5/5] update TODOs with upload Co-authored-by: plocket Co-authored-by: Clayton Schneider Co-authored-by: AISHWARYA RAJA --- heat-stack/app/routes/_heat+/single.tsx | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/heat-stack/app/routes/_heat+/single.tsx b/heat-stack/app/routes/_heat+/single.tsx index b95dc65b..6ca9490b 100644 --- a/heat-stack/app/routes/_heat+/single.tsx +++ b/heat-stack/app/routes/_heat+/single.tsx @@ -12,7 +12,15 @@ import { z } from 'zod' // - [x] ~Save to cookie and redirect to next form~ Put everything on the same page // - [x] - Get zod and Typescript to play nice // - [x] (We're here) Build form #2 -// - [ ] Build form #3 +// - [ ] Build upload form +// - https://www.epicweb.dev/workshops/professional-web-forms/file-upload/intro-to-file-upload +// - https://github.com/epicweb-dev/web-forms/tree/main/exercises/04.file-upload +// - https://github.com/epicweb-dev/web-forms/blob/2c10993e4acffe3dd9ad7b9cb0cdf89ce8d46ecf/exercises/04.file-upload/01.solution.multi-part/app/routes/users%2B/%24username_%2B/notes.%24noteId_.edit.tsx#L58 +// - createMemoryUploadHandler +// - parseMultipartFormData +// - avoid dealing with the server for now +// - pass the data to the rules engine/pyodide either in the component or the action (probably the action for validation, etc.) +// - [ ] (On hold) Build table form // - [ ] Form errors (if we think of a use case - 2 fields conflicting...) // Ours