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: "/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
|
||||
{
|
||||
element: (
|
||||
@@ -79,14 +83,6 @@ export const router = createBrowserRouter([
|
||||
),
|
||||
path: "/otp-verify",
|
||||
},
|
||||
{
|
||||
element: (
|
||||
<ProtectedRoute>
|
||||
<ForgotPasswordPage />
|
||||
</ProtectedRoute>
|
||||
),
|
||||
path: "/forgot-password",
|
||||
},
|
||||
// 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,
|
||||
// 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 { useApiMutation } from '@ema-platform/api';
|
||||
import { notify, useErrorHandler } from '@ema-platform/ui';
|
||||
import { isValidPhoneNumber, parsePhoneNumberFromString } from 'libphonenumber-js';
|
||||
import { AuthShell } from '../components/AuthShell';
|
||||
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({
|
||||
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>;
|
||||
@@ -156,8 +170,8 @@ export function ForgotPasswordPage() {
|
||||
Forgot your password?
|
||||
</Title>
|
||||
<Text c="dimmed" mt={6}>
|
||||
Enter the email linked to your account and we'll send you a link
|
||||
to reset your password.
|
||||
Enter the email or phone number linked to your account and
|
||||
we'll send you a link to reset your password.
|
||||
</Text>
|
||||
</div>
|
||||
|
||||
@@ -170,7 +184,7 @@ export function ForgotPasswordPage() {
|
||||
<form onSubmit={handleSubmit(onSubmit)}>
|
||||
<Stack gap="md">
|
||||
<TextInput
|
||||
label="Email address"
|
||||
label="Email or phone"
|
||||
placeholder="you@example.com"
|
||||
size="md"
|
||||
leftSection={<IconMail size={18} />}
|
||||
|
||||
Reference in New Issue
Block a user