Skip to content

Instantly share code, notes, and snippets.

@christian-kolb
Last active January 30, 2023 20:15
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save christian-kolb/a1a30cf61ad499a85527e435872cb929 to your computer and use it in GitHub Desktop.
Save christian-kolb/a1a30cf61ad499a85527e435872cb929 to your computer and use it in GitHub Desktop.
// -- 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