Add first-login password setup flow
Accounts created by tenant/store onboarding (createtenantuser, createtenantlocation) have no password set. Previously the login form treated the backend's "please setup a password" response as a successful login instead of prompting for one. Now auth.ts recognizes it (PasswordSetupRequiredError) and LoginView routes to a create- password step, then signs in immediately with the new password. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -139,6 +139,22 @@ export interface LoginResult {
|
||||
email: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Thrown by `loginRequest` when the account exists but has never had a password
|
||||
* set (a freshly onboarded tenant admin or store login — see AppLogin's
|
||||
* "No password set" branch, `{ code: 409, status: true, details: { setup: true } }`).
|
||||
* Distinct from a plain login failure: the caller should route to a
|
||||
* create-password step, not show an error.
|
||||
*/
|
||||
export class PasswordSetupRequiredError extends Error {
|
||||
userid: number;
|
||||
constructor(userid: number, message = 'Please set up a password to continue.') {
|
||||
super(message);
|
||||
this.name = 'PasswordSetupRequiredError';
|
||||
this.userid = userid;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* POST the credentials to the Fiesta web-login endpoint. Resolves with the raw
|
||||
* user record on success; throws an Error with a user-facing message on invalid
|
||||
@@ -168,6 +184,15 @@ export async function loginRequest(email: string, password: string): Promise<Log
|
||||
| { code?: number; status?: boolean; message?: string; details?: unknown }
|
||||
| null;
|
||||
|
||||
// Account exists but has no password yet — server-side this fires before it
|
||||
// even looks at the password the caller sent, so it happens on any attempt
|
||||
// (including checkEmailRequest's password-less probe). `status: true` here,
|
||||
// so this must be checked before the generic status===false failure branch.
|
||||
const details = json?.details as { userid?: number; setup?: boolean } | undefined;
|
||||
if (json?.code === 409 && details?.setup === true && typeof details.userid === 'number') {
|
||||
throw new PasswordSetupRequiredError(details.userid, json.message);
|
||||
}
|
||||
|
||||
// Failure: HTTP error, or the Fiesta `status: false` envelope (e.g. wrong
|
||||
// email/password → { code: 409, message: "Invalid Email", status: false }).
|
||||
if (!res.ok || (json && json.status === false)) {
|
||||
|
||||
@@ -1015,6 +1015,15 @@ export async function updateUser(input: UpdateUserInput): Promise<Row> {
|
||||
return fiestaSend<Row>('users/update', 'PUT', input);
|
||||
}
|
||||
|
||||
/**
|
||||
* PUT /users/update — set (or reset) a user's login password. Same endpoint as
|
||||
* `updateUser`, called with only userid + password so every other column is
|
||||
* left untouched (the backend's Updates() skips zero-value fields).
|
||||
*/
|
||||
export async function setUserPassword(userid: number, password: string): Promise<Row> {
|
||||
return fiestaSend<Row>('users/update', 'PUT', { userid, password });
|
||||
}
|
||||
|
||||
export interface CreateTenantLocationPayload {
|
||||
locationname: string;
|
||||
email?: string;
|
||||
|
||||
@@ -54,6 +54,7 @@ import {
|
||||
getUserById,
|
||||
createUser,
|
||||
updateUser,
|
||||
setUserPassword,
|
||||
assignRiderToOrders,
|
||||
CreateUserInput,
|
||||
createTenantUser,
|
||||
@@ -892,6 +893,18 @@ export function useLogin() {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Set (or reset) a user's login password — used by the login flow's
|
||||
* create-password step (see PasswordSetupRequiredError in ./auth) for a
|
||||
* first-time tenant admin or store login.
|
||||
*/
|
||||
export function useSetPassword() {
|
||||
return useMutation({
|
||||
mutationFn: (input: { userid: number; password: string }) =>
|
||||
setUserPassword(input.userid, input.password),
|
||||
});
|
||||
}
|
||||
|
||||
export function useFiestaDeleteLocation() {
|
||||
const qc = useQueryClient();
|
||||
return useMutation({
|
||||
|
||||
Reference in New Issue
Block a user