mirror of
https://github.com/Tria-plc/emaui.git
synced 2026-08-26 19:12:50 +00:00
feat: support phone number input for password recovery and move route to public access
This commit is contained in:
@@ -70,6 +70,10 @@ export const router = createBrowserRouter([
|
|||||||
{ path: "/set-password", element: <SetPasswordPage /> },
|
{ path: "/set-password", element: <SetPasswordPage /> },
|
||||||
{ path: "/reset-password", element: <SetPasswordPage /> },
|
{ path: "/reset-password", element: <SetPasswordPage /> },
|
||||||
|
|
||||||
|
// Reached from the login page by a logged-out user, so it must stay
|
||||||
|
// public — ProtectedRoute would bounce them straight to the landing page.
|
||||||
|
{ path: "/forgot-password", element: <ForgotPasswordPage /> },
|
||||||
|
|
||||||
// Protected auth pages
|
// Protected auth pages
|
||||||
{
|
{
|
||||||
element: (
|
element: (
|
||||||
@@ -79,14 +83,6 @@ export const router = createBrowserRouter([
|
|||||||
),
|
),
|
||||||
path: "/otp-verify",
|
path: "/otp-verify",
|
||||||
},
|
},
|
||||||
{
|
|
||||||
element: (
|
|
||||||
<ProtectedRoute>
|
|
||||||
<ForgotPasswordPage />
|
|
||||||
</ProtectedRoute>
|
|
||||||
),
|
|
||||||
path: "/forgot-password",
|
|
||||||
},
|
|
||||||
// The two-step setup wizard is gone. Signing up lands on the dashboard, and
|
// The two-step setup wizard is gone. Signing up lands on the dashboard, and
|
||||||
// profile details are collected where they are actually needed: on /profile,
|
// profile details are collected where they are actually needed: on /profile,
|
||||||
// via the dashboard nudge, or inline in an application flow. The path stays
|
// via the dashboard nudge, or inline in an application flow. The path stays
|
||||||
|
|||||||
@@ -23,11 +23,25 @@ import { z } from 'zod';
|
|||||||
import { Link } from 'react-router-dom';
|
import { Link } from 'react-router-dom';
|
||||||
import { useApiMutation } from '@ema-platform/api';
|
import { useApiMutation } from '@ema-platform/api';
|
||||||
import { notify, useErrorHandler } from '@ema-platform/ui';
|
import { notify, useErrorHandler } from '@ema-platform/ui';
|
||||||
|
import { isValidPhoneNumber, parsePhoneNumberFromString } from 'libphonenumber-js';
|
||||||
import { AuthShell } from '../components/AuthShell';
|
import { AuthShell } from '../components/AuthShell';
|
||||||
import { useAuthConfig } from '../AuthConfig';
|
import { useAuthConfig } from '../AuthConfig';
|
||||||
|
|
||||||
|
// Same email-or-phone rule as LoginPage: a phone-looking value normalizes to
|
||||||
|
// E.164 (bare Ethiopian national numbers default to +251) so the backend
|
||||||
|
// always gets a value it can look the account up by, under the `email` key.
|
||||||
|
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
||||||
const schema = z.object({
|
const schema = z.object({
|
||||||
email: z.string().email({ message: 'Enter a valid email' }),
|
email: z
|
||||||
|
.string()
|
||||||
|
.trim()
|
||||||
|
.transform((value) => {
|
||||||
|
if (emailRegex.test(value)) return value;
|
||||||
|
return parsePhoneNumberFromString(value, 'ET')?.number ?? value;
|
||||||
|
})
|
||||||
|
.refine((value) => emailRegex.test(value) || isValidPhoneNumber(value), {
|
||||||
|
message: 'Enter a valid email or phone number',
|
||||||
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
type FormValues = z.infer<typeof schema>;
|
type FormValues = z.infer<typeof schema>;
|
||||||
@@ -156,8 +170,8 @@ export function ForgotPasswordPage() {
|
|||||||
Forgot your password?
|
Forgot your password?
|
||||||
</Title>
|
</Title>
|
||||||
<Text c="dimmed" mt={6}>
|
<Text c="dimmed" mt={6}>
|
||||||
Enter the email linked to your account and we'll send you a link
|
Enter the email or phone number linked to your account and
|
||||||
to reset your password.
|
we'll send you a link to reset your password.
|
||||||
</Text>
|
</Text>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -170,7 +184,7 @@ export function ForgotPasswordPage() {
|
|||||||
<form onSubmit={handleSubmit(onSubmit)}>
|
<form onSubmit={handleSubmit(onSubmit)}>
|
||||||
<Stack gap="md">
|
<Stack gap="md">
|
||||||
<TextInput
|
<TextInput
|
||||||
label="Email address"
|
label="Email or phone"
|
||||||
placeholder="you@example.com"
|
placeholder="you@example.com"
|
||||||
size="md"
|
size="md"
|
||||||
leftSection={<IconMail size={18} />}
|
leftSection={<IconMail size={18} />}
|
||||||
|
|||||||
Reference in New Issue
Block a user