mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-26 18:42:49 +00:00
feat(auth): Implement phone number login and introduce PhoneInput component
This commit is contained in:
@@ -0,0 +1,43 @@
|
||||
import { Field, FieldLabel, FieldError, Input } from "@edr/ui-common";
|
||||
|
||||
interface PhoneInputProps {
|
||||
disabled?: boolean;
|
||||
countryCode?: React.ComponentProps<typeof Input>;
|
||||
phone?: React.ComponentProps<typeof Input>;
|
||||
countryCodeError?: { message?: string };
|
||||
phoneError?: { message?: string };
|
||||
label?: string;
|
||||
}
|
||||
|
||||
export default function PhoneInput({
|
||||
disabled,
|
||||
countryCode: countryCodeProps,
|
||||
phone: phoneProps,
|
||||
countryCodeError,
|
||||
phoneError,
|
||||
label = "Phone Number",
|
||||
}: PhoneInputProps) {
|
||||
return (
|
||||
<Field data-invalid={Boolean(countryCodeError || phoneError)}>
|
||||
<FieldLabel>{label}</FieldLabel>
|
||||
<div className="flex gap-2">
|
||||
<Input
|
||||
type="text"
|
||||
disabled={disabled}
|
||||
className="w-20"
|
||||
aria-invalid={Boolean(countryCodeError)}
|
||||
{...countryCodeProps}
|
||||
/>
|
||||
<Input
|
||||
type="tel"
|
||||
placeholder="912345678"
|
||||
disabled={disabled}
|
||||
className="flex-1"
|
||||
aria-invalid={Boolean(phoneError)}
|
||||
{...phoneProps}
|
||||
/>
|
||||
</div>
|
||||
<FieldError errors={[countryCodeError, phoneError]} />
|
||||
</Field>
|
||||
);
|
||||
}
|
||||
@@ -11,6 +11,7 @@ import {
|
||||
FieldError,
|
||||
FieldGroup,
|
||||
} from "@edr/ui-common";
|
||||
import PhoneInput from "@/components/auth/PhoneInput";
|
||||
|
||||
type LoginMethod = "email" | "phone";
|
||||
|
||||
@@ -19,6 +20,8 @@ export default function LoginPage() {
|
||||
const { login } = useAuth();
|
||||
const [method, setMethod] = useState<LoginMethod>("email");
|
||||
const [identifier, setIdentifier] = useState("");
|
||||
const [countryCode, setCountryCode] = useState("+251");
|
||||
const [phoneNumber, setPhoneNumber] = useState("");
|
||||
const [password, setPassword] = useState("");
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
const [loading, setLoading] = useState(false);
|
||||
@@ -28,7 +31,10 @@ export default function LoginPage() {
|
||||
setError(null);
|
||||
setLoading(true);
|
||||
try {
|
||||
const result = await login({ email: identifier, password });
|
||||
const loginId = method === "email"
|
||||
? identifier
|
||||
: `${countryCode}${phoneNumber.startsWith("0") ? phoneNumber.slice(1) : phoneNumber}`;
|
||||
const result = await login({ email: loginId, password });
|
||||
if (result.success) {
|
||||
navigate("/");
|
||||
} else {
|
||||
@@ -97,19 +103,31 @@ export default function LoginPage() {
|
||||
</div>
|
||||
|
||||
<FieldGroup>
|
||||
<Field>
|
||||
<FieldLabel>
|
||||
{method === "email" ? "Email Address" : "Phone Number"}
|
||||
</FieldLabel>
|
||||
<Input
|
||||
type={method === "email" ? "email" : "tel"}
|
||||
placeholder={method === "email" ? "name@company.com" : "+251..."}
|
||||
value={identifier}
|
||||
onChange={(e) => setIdentifier(e.target.value)}
|
||||
required
|
||||
{method === "email" ? (
|
||||
<Field>
|
||||
<FieldLabel>Email Address</FieldLabel>
|
||||
<Input
|
||||
type="email"
|
||||
placeholder="name@company.com"
|
||||
value={identifier}
|
||||
onChange={(e) => setIdentifier(e.target.value)}
|
||||
required
|
||||
disabled={loading}
|
||||
/>
|
||||
</Field>
|
||||
) : (
|
||||
<PhoneInput
|
||||
disabled={loading}
|
||||
countryCode={{
|
||||
value: countryCode,
|
||||
onChange: (e: React.ChangeEvent<HTMLInputElement>) => setCountryCode(e.target.value),
|
||||
}}
|
||||
phone={{
|
||||
value: phoneNumber,
|
||||
onChange: (e: React.ChangeEvent<HTMLInputElement>) => setPhoneNumber(e.target.value),
|
||||
}}
|
||||
/>
|
||||
</Field>
|
||||
)}
|
||||
|
||||
<Field>
|
||||
<div className="flex items-center justify-between">
|
||||
|
||||
@@ -8,6 +8,7 @@ import { userType } from "@/enums/userType";
|
||||
import useAuth from "@/hooks/useAuth";
|
||||
import type { SignupPayload } from "@/types/auth";
|
||||
import AuthLayout from "@/components/auth/AuthLayout";
|
||||
import PhoneInput from "@/components/auth/PhoneInput";
|
||||
import {
|
||||
Button,
|
||||
Input,
|
||||
@@ -150,27 +151,13 @@ export default function SignupPage() {
|
||||
</Field>
|
||||
</div>
|
||||
|
||||
<Field data-invalid={Boolean(errors.countryCode || errors.phone)}>
|
||||
<FieldLabel>Phone Number</FieldLabel>
|
||||
<div className="flex gap-2">
|
||||
<Input
|
||||
type="text"
|
||||
disabled={loading}
|
||||
className="w-20"
|
||||
aria-invalid={Boolean(errors.countryCode)}
|
||||
{...register("countryCode")}
|
||||
/>
|
||||
<Input
|
||||
type="tel"
|
||||
placeholder="912345678"
|
||||
disabled={loading}
|
||||
className="flex-1"
|
||||
aria-invalid={Boolean(errors.phone)}
|
||||
{...register("phone")}
|
||||
/>
|
||||
</div>
|
||||
<FieldError errors={[errors.countryCode, errors.phone]} />
|
||||
</Field>
|
||||
<PhoneInput
|
||||
disabled={loading}
|
||||
countryCode={{ ...register("countryCode") }}
|
||||
phone={{ ...register("phone") }}
|
||||
countryCodeError={errors.countryCode}
|
||||
phoneError={errors.phone}
|
||||
/>
|
||||
</FieldGroup>
|
||||
|
||||
<Button
|
||||
|
||||
Reference in New Issue
Block a user