Refactor Doc

使用 zod 替 response 跟 request body 以及 form schema

export const usageScenarioRequestBodySchema = z.object({
  name: z.string(),
  emissionClassification: z.nativeEnum(EMISSION_CLASSIFICATION).optional(),
 // ...
});
 
export const usageScenarioFormSchema = z.object({
  name: z.string(),
  emissionClassification: z.nativeEnum(EMISSION_CLASSIFICATION).optional(),
 // ...
});
 
export interface UsageScenarioDetail extends UsageScenarioRequestBody {
  id: string;
}
 
// src/modules/ProductSeries/domain/UsageScenario/UsageScenario.ts
  • 欄位的 name 可以不用照著 api 對應的 key 命名

  • UI 上的角度提供覺得最適合的欄位 name

統一地方處理 convert

  1. 避免 reuse component 時需要各別為了不同 API 做做欄位的判斷跟調整

  2. 減少後端格式調整時,必須修改分散邏輯的困擾

  3. 可在轉換階段將數據格式轉換為更適合前端使用的格式

  4. 解耦 API 與元件之間的關係

  function convertFromDataToRequest(formData: UsageScenarioForm): UsageScenarioRequestBody {}
 
  function convertResponseToFormData(response: UsageScenarioDetail): UsageScenarioForm {}

使用 zod 定義的 form schema 做 form validate

所有驗證相關的工作均在 resolver 的 callback 中完成

 const methods = useForm({
    resolver: async (values, context, options) => {
      if (values.metadata.relevance !== EmissionSourceRelevance.REL_TRUE) {
        return { errors: {}, values };
      }
 
      if (values.factors[0].type === EmissionSourceFactorType.DEFAULT) {
        return await zodResolver(
          settingRelevanceSchema.merge(z.object({ documents: z.array(documentSchema).optional() })),
        )(values, context, options);
      }
 
      return await zodResolver(settingRelevanceSchema)(values, context, options);
    },
  });
 
// src/app/[lng]/org-cfv/[projectId]/emission-sources/relevant/components/SettingRelevanceModal.tsx

form 的共用

  1. 小部分的共用欄位可以共用,但是提供 prefix 來處理可能在 form 中 name 一樣的問題

    type Props = {
      prefix?: string;
    };
     
    export const UnitFields = ({ prefix = 'default' }: Props) => {
      return (
        <>
          <input name={`${prefix}.unitType`} />
          <input name={`${prefix}.unit`} />
        </>
      );
    };
     
  2. 大型表單應分開並確實為每個大型表單定義 Schema

    // emission cat1.1
    const methods = useForm<Emission1_1Schema>()
    // emission cat1.2
    const methods = useForm<Emission1_2Schema>()