Files
auth-remote-react/src/features/auth/ui/LoginForm/LoginForm.tsx

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>
);
}