Admin search now matches against per-card keyword lists so typing "client portal", "smtp", "tier ladder" lands on the System Settings card (which hosts those flags). The same keyword list extends the topbar global search (NAV_CATALOG) so any setting key resolves from the cmd-K input — settings results sort to the bottom of the dropdown beneath entity hits. User management: - Third action button (Power/PowerOff) enables/disables sign-in from the desktop list; mobile card dropdown gains the same item. Backed by the existing userProfiles.isActive flag — withAuth already refuses disabled sessions with 403. - UserForm collects first + last name (canonical) alongside displayName, with admin email-change behind a confirmation modal. On confirm we send the OLD address an automated "your admin changed your sign-in email" notice (new template at admin-email-change.ts) and rewrite the Better Auth user row. - Phone field swaps the bare tel input for the shared PhoneInput (country combobox + AsYouType formatting + E.164 storage). - "Manage permissions" link points to /admin/roles?focusUser=… as a stepping stone for the future fine-tuned-permissions UI. Role names normalize through a new ROLE_LABELS + formatRole() helper in constants.ts. Replaces the ad-hoc humanizeRole in sidebar and the prettifyRoleName in role-list; user-list and user-card now render "Sales Agent" instead of "sales_agent". Custom roles pass through unchanged. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
42 lines
1.6 KiB
TypeScript
42 lines
1.6 KiB
TypeScript
import { z } from 'zod';
|
|
|
|
export const createUserSchema = z.object({
|
|
email: z.string().email(),
|
|
name: z.string().min(1).max(200),
|
|
password: z.string().min(12),
|
|
displayName: z.string().min(1).max(200),
|
|
firstName: z.string().min(1).max(200).nullable().optional(),
|
|
lastName: z.string().min(1).max(200).nullable().optional(),
|
|
phone: z.string().optional(),
|
|
roleId: z.string().uuid(),
|
|
residentialAccess: z.boolean().optional().default(false),
|
|
});
|
|
|
|
export type CreateUserInput = z.infer<typeof createUserSchema>;
|
|
|
|
export const updateUserSchema = z.object({
|
|
displayName: z.string().min(1).max(200).optional(),
|
|
firstName: z.string().min(1).max(200).nullable().optional(),
|
|
lastName: z.string().min(1).max(200).nullable().optional(),
|
|
fullName: z.string().min(1).max(400).optional(),
|
|
/** Admin-initiated email change. When changed, the original address
|
|
* receives an automated heads-up email (see notifyEmailChange). */
|
|
email: z.string().email().optional(),
|
|
/** Set true alongside `email` to send the "your admin changed your
|
|
* sign-in email" notification to the prior address. UI sets this when
|
|
* the admin confirms the warning dialog. */
|
|
notifyEmailChange: z.boolean().optional(),
|
|
phone: z.string().nullable().optional(),
|
|
isActive: z.boolean().optional(),
|
|
roleId: z.string().uuid().optional(),
|
|
residentialAccess: z.boolean().optional(),
|
|
});
|
|
|
|
export type UpdateUserInput = z.infer<typeof updateUserSchema>;
|
|
|
|
export const resetPasswordSchema = z.object({
|
|
newPassword: z.string().min(12),
|
|
});
|
|
|
|
export type ResetPasswordInput = z.infer<typeof resetPasswordSchema>;
|