114 lines
2.7 KiB
TypeScript
114 lines
2.7 KiB
TypeScript
import {
|
|
selectEmail,
|
|
selectFormValid,
|
|
selectPassword,
|
|
selectStatusIsLoading,
|
|
useAuthStore,
|
|
} from "../../model";
|
|
import {
|
|
type SubmitEvent,
|
|
type ChangeEvent,
|
|
type HTMLAttributes,
|
|
type InputHTMLAttributes,
|
|
type ButtonHTMLAttributes,
|
|
cloneElement,
|
|
type ReactElement,
|
|
} from "react";
|
|
|
|
export type InputAttributes = InputHTMLAttributes<HTMLInputElement>;
|
|
export type ButtonAttributes = ButtonHTMLAttributes<HTMLButtonElement>;
|
|
|
|
export interface Props {
|
|
InputComponent?: ReactElement<InputAttributes>;
|
|
ButtonComponent?: ReactElement<ButtonAttributes>;
|
|
}
|
|
|
|
const DefaultInputComponent = ({
|
|
value,
|
|
onChange,
|
|
["aria-label"]: ariaLabel,
|
|
}: InputAttributes) => (
|
|
<input
|
|
type="email"
|
|
value={value}
|
|
onChange={onChange}
|
|
aria-label={ariaLabel}
|
|
/>
|
|
);
|
|
|
|
const DefaultButtonComponent = ({ disabled }: ButtonAttributes) => (
|
|
<button type="submit" disabled={disabled} />
|
|
);
|
|
|
|
/**
|
|
* Login form component
|
|
*/
|
|
export function LoginForm({ InputComponent, ButtonComponent }: Props) {
|
|
const { setEmail, setPassword, login } = useAuthStore();
|
|
const email = useAuthStore(selectEmail);
|
|
const password = useAuthStore(selectPassword);
|
|
const formValid = useAuthStore(selectFormValid);
|
|
const isLoading = useAuthStore(selectStatusIsLoading);
|
|
|
|
const disabled = !formValid || isLoading;
|
|
|
|
const handleEmailChange = (e: ChangeEvent<HTMLInputElement>) => {
|
|
setEmail(e.target.value);
|
|
};
|
|
|
|
const handlePasswordChange = (e: ChangeEvent<HTMLInputElement>) => {
|
|
setPassword(e.target.value);
|
|
};
|
|
|
|
const handleSubmit = (e: SubmitEvent<HTMLFormElement>) => {
|
|
e.preventDefault();
|
|
login();
|
|
};
|
|
|
|
return (
|
|
<form aria-label="Login form" onSubmit={handleSubmit}>
|
|
{InputComponent ? (
|
|
cloneElement(InputComponent, {
|
|
type: "email",
|
|
value: email,
|
|
onChange: handleEmailChange,
|
|
"aria-label": "Email",
|
|
})
|
|
) : (
|
|
<DefaultInputComponent
|
|
type="email"
|
|
value={email}
|
|
onChange={handleEmailChange}
|
|
aria-label="Email"
|
|
/>
|
|
)}
|
|
{InputComponent ? (
|
|
cloneElement(InputComponent, {
|
|
type: "password",
|
|
value: password,
|
|
onChange: handlePasswordChange,
|
|
"aria-label": "Password",
|
|
})
|
|
) : (
|
|
<DefaultInputComponent
|
|
type="password"
|
|
value={password}
|
|
onChange={handlePasswordChange}
|
|
aria-label="Password"
|
|
/>
|
|
)}
|
|
{ButtonComponent ? (
|
|
cloneElement(ButtonComponent, {
|
|
type: "submit",
|
|
disabled: disabled,
|
|
children: "Login",
|
|
})
|
|
) : (
|
|
<DefaultButtonComponent type="submit" disabled={disabled}>
|
|
Login
|
|
</DefaultButtonComponent>
|
|
)}
|
|
</form>
|
|
);
|
|
}
|