import type { JSX } from "keycloakify/tools/JSX"; import * as reactlessApi from "./getUserProfileApi/index"; import type { PasswordPolicies, Attribute, Validators } from "keycloakify/login/KcContext"; import { useEffect, useState, useMemo, Fragment } from "react"; import { assert, type Equals } from "tsafe/assert"; import type { I18n } from "../i18n"; export { getButtonToDisplayForMultivaluedAttributeField } from "./getUserProfileApi/index"; export type FormFieldError = { errorMessage: JSX.Element; errorMessageStr: string; source: FormFieldError.Source; fieldIndex: number | undefined; }; { type A = Omit; type B = Omit; assert>(); } export namespace FormFieldError { export type Source = Source.Validator | Source.PasswordPolicy | Source.Server | Source.Other; export namespace Source { export type Validator = { type: "validator"; name: keyof Validators; }; export type PasswordPolicy = { type: "passwordPolicy"; name: keyof PasswordPolicies; }; export type Server = { type: "server"; }; export type Other = { type: "other"; rule: "passwordConfirmMatchesPassword" | "requiredField"; }; } } { type A = FormFieldError.Source; type B = reactlessApi.FormFieldError.Source; assert>(); } export type FormFieldState = { attribute: Attribute; displayableErrors: FormFieldError[]; valueOrValues: string | string[]; }; { type A = Omit; type B = Omit; assert>(); } export type FormState = { isFormSubmittable: boolean; formFieldStates: FormFieldState[]; }; { type A = Omit; type B = Omit; assert>(); } export type FormAction = | { action: "update"; name: string; valueOrValues: string | string[]; /** Default false */ displayErrorsImmediately?: boolean; } | { action: "focus lost"; name: string; fieldIndex: number | undefined; }; { type A = FormAction; type B = reactlessApi.FormAction; assert>(); } export type KcContextLike = reactlessApi.KcContextLike; export type I18nLike = Pick; export type ParamsOfUseUserProfileForm = { kcContext: KcContextLike; doMakeUserConfirmPassword: boolean; i18n: I18nLike; }; { type A = Omit; type B = reactlessApi.ParamsOfGetUserProfileApi; assert>(); } export type ReturnTypeOfUseUserProfileForm = { formState: FormState; dispatchFormAction: (action: FormAction) => void; }; export function useUserProfileForm(params: ParamsOfUseUserProfileForm): ReturnTypeOfUseUserProfileForm { const { doMakeUserConfirmPassword, i18n, kcContext } = params; const api = reactlessApi.getUserProfileApi({ kcContext, doMakeUserConfirmPassword }); const [formState_reactless, setFormState_reactless] = useState(() => api.getFormState()); useEffect(() => { const { unsubscribe } = api.subscribeToFormState(() => { setFormState_reactless(api.getFormState()); }); return () => unsubscribe(); }, [api]); const { advancedMsg, advancedMsgStr } = i18n; const formState = useMemo( (): FormState => ({ isFormSubmittable: formState_reactless.isFormSubmittable, formFieldStates: formState_reactless.formFieldStates.map(formFieldState_reactless => ({ attribute: formFieldState_reactless.attribute, valueOrValues: formFieldState_reactless.valueOrValues, displayableErrors: formFieldState_reactless.displayableErrors.map((formFieldError_reactless, i) => ({ errorMessage: ( {advancedMsg(...formFieldError_reactless.advancedMsgArgs)} ), errorMessageStr: advancedMsgStr(...formFieldError_reactless.advancedMsgArgs), source: formFieldError_reactless.source, fieldIndex: formFieldError_reactless.fieldIndex })) })) }), [formState_reactless] ); return { formState, dispatchFormAction: api.dispatchFormAction }; }