Last active
January 30, 2023 20:15
-
-
Save christian-kolb/a1a30cf61ad499a85527e435872cb929 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// -- Types | |
export interface Form<T extends FormControls> { | |
isValid: boolean; | |
submitted: SubmittedFunction; | |
controls: T; | |
} | |
export type FormControls = Record<string, FormControl<any>>; | |
export interface FormControl<T> { | |
label: FormControlLabel; | |
value: FormControlValue<T>; | |
rules: FormControlRules<T>; | |
} | |
export type SubmittedFunction = () => void; | |
export type FormControlLabel = string | (() => string); | |
export type FormControlValue<T> = T | null; | |
export type FormControlRule<T> = (value: FormControlValue<T>) => true | string; | |
export type FormControlRules<T> = FormControlRule<T>[]; | |
export type ValuesOfFormControls<T extends FormControls> = { | |
[K in keyof T]: T[K] extends FormControl<infer R> ? R | null : T[K] | |
}; | |
// -- Helpers | |
export function constructForm<T extends FormControls>( | |
formTemplate: Omit<Form<T>, 'isValid'> | |
): Form<T> { | |
const controls = Object | |
.entries(formTemplate.controls) | |
.map(([name, formControl]) => { | |
const rules = formControl.rules ?? []; | |
return { | |
name, | |
label: formControl.label, | |
value: formControl.value, | |
rules, | |
}; | |
}) | |
.reduce((map: FormControls, formControl) => { | |
map[formControl.name] = formControl; | |
return map; | |
}, {}); | |
return { | |
isValid: false, | |
submitted: formTemplate.submitted, | |
controls, | |
} as Form<T>; | |
} | |
export function getFormValues<T extends FormControls>(form: Form<T>): ValuesOfFormControls<T> { | |
return Object | |
.entries(form.controls) | |
.reduce((formValues, [name, formControl]) => { | |
formValues[name] = formControl.value; | |
return formValues; | |
}, {} as any) as ValuesOfFormControls<T>; | |
} | |
// -- Within dialog | |
interface Controls extends FormControls { | |
date: FormControl<Dayjs>; | |
numberOfHours: FormControl<number>; | |
description: FormControl<string>; | |
} | |
buildForm(): Form<Controls> { | |
return constructForm<Controls>({ | |
submitted: this.submitted, | |
controls: { | |
date: { | |
label: 'Datum', | |
value: dayjs().startOf('day'), | |
rules: [ | |
requiredRule(), | |
], | |
}, | |
numberOfHours: { | |
label: 'Stundenanzahl', | |
value: null, | |
rules: [ | |
requiredRule(), | |
positiveNumberRule(2), | |
minNumberRule(0.25), | |
], | |
}, | |
description: { | |
label: 'Beschreibung', | |
value: null, | |
rules: [ | |
requiredRule(), | |
], | |
}, | |
}, | |
}); | |
} | |
submitted(): void { | |
const formValues = getFormValues<Controls>(this.form!); | |
const command: CreateTimeEntryCommand = { | |
date: formValues.date!, | |
numberOfHours: formValues.numberOfHours!, | |
description: formValues.description!, | |
}; | |
this.state.createTimeEntry(command) | |
.then(() => showSuccessMessage('Der verrichtete Arbeitsdienst wurde eingetragen und die Hofverwalter wurden informiert.')) | |
.then(() => this.closeDialog()) | |
.catch((error) => showErrorResponse(error)); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment