feat: implement user role status toggle and reset password functionality

- Added toggle functionality for user roles (activate/deactivate) in roles and users pages.
- Introduced a reset password page that validates and updates user passwords via a reset link.
- Enhanced user detail page with edit functionality for user information (display name, email, mobile number).
- Implemented sending reset link feature for users, with appropriate error handling and success notifications.
- Updated API endpoints for user management to support new functionalities.
- Improved UI components for better user experience during status updates and password changes.
This commit is contained in:
Dhananjaya99
2026-10-15 10:54:28 +05:30
parent 5ec3edc0c6
commit 61330f3927
26 changed files with 817 additions and 141 deletions
@@ -28,6 +28,10 @@ import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@
import { toast } from "@/components/ui/toast"
const PAGE_SIZE_OPTIONS = [5, 10, 20, 25]
// Mirrors Branch.DefaultCode (backend) — the deployment's seeded branch, which
// BranchService blocks deactivating or deleting (every branch-scoped entity needs
// at least one branch to exist).
const DEFAULT_BRANCH_CODE = "BR-000"
// Mobile has no page-size selector — tapping "Show more" just grows the page size and
// re-fetches from page 1, so previously loaded cards stay put and more append below.
const MOBILE_PAGE_SIZE_STEP = 10
@@ -329,12 +333,16 @@ export function BranchMasterPage() {
size="icon-sm"
className={cn(
item.status === "Active"
? "text-destructive hover:bg-destructive/10"
? "text-destructive hover:bg-destructive/10 disabled:pointer-events-auto disabled:cursor-not-allowed"
: "text-success hover:bg-success/10"
)}
aria-label={item.status === "Active" ? `Deactivate ${item.name}` : `Activate ${item.name}`}
title={item.status === "Active" ? `Deactivate ${item.name}` : `Activate ${item.name}`}
disabled={actionPendingId === item.branchId}
title={
item.status === "Active" && item.code === DEFAULT_BRANCH_CODE
? "The default branch cannot be deactivated"
: item.status === "Active" ? `Deactivate ${item.name}` : `Activate ${item.name}`
}
disabled={actionPendingId === item.branchId || (item.status === "Active" && item.code === DEFAULT_BRANCH_CODE)}
onClick={() => toggleStatus(item)}
>
{item.status === "Active" ? <XCircle className="size-4" /> : <CheckCircle2 className="size-4" />}
@@ -345,10 +353,10 @@ export function BranchMasterPage() {
<Button
variant="ghost"
size="icon-sm"
className="text-destructive hover:bg-destructive/10"
className="text-destructive hover:bg-destructive/10 disabled:pointer-events-auto disabled:cursor-not-allowed"
aria-label={`Delete ${item.name}`}
title={`Delete ${item.name}`}
disabled={deletingId === item.branchId}
title={item.code === DEFAULT_BRANCH_CODE ? "The default branch cannot be deleted" : `Delete ${item.name}`}
disabled={deletingId === item.branchId || item.code === DEFAULT_BRANCH_CODE}
/>
}
>
@@ -433,12 +441,16 @@ export function BranchMasterPage() {
size="icon-sm"
className={cn(
item.status === "Active"
? "text-destructive hover:bg-destructive/10"
? "text-destructive hover:bg-destructive/10 disabled:pointer-events-auto disabled:cursor-not-allowed"
: "text-success hover:bg-success/10"
)}
aria-label={item.status === "Active" ? `Deactivate ${item.name}` : `Activate ${item.name}`}
title={item.status === "Active" ? `Deactivate ${item.name}` : `Activate ${item.name}`}
disabled={actionPendingId === item.branchId}
title={
item.status === "Active" && item.code === DEFAULT_BRANCH_CODE
? "The default branch cannot be deactivated"
: item.status === "Active" ? `Deactivate ${item.name}` : `Activate ${item.name}`
}
disabled={actionPendingId === item.branchId || (item.status === "Active" && item.code === DEFAULT_BRANCH_CODE)}
onClick={() => toggleStatus(item)}
>
{item.status === "Active" ? <XCircle className="size-4" /> : <CheckCircle2 className="size-4" />}
@@ -449,10 +461,10 @@ export function BranchMasterPage() {
<Button
variant="ghost"
size="icon-sm"
className="text-destructive hover:bg-destructive/10"
className="text-destructive hover:bg-destructive/10 disabled:pointer-events-auto disabled:cursor-not-allowed"
aria-label={`Delete ${item.name}`}
title={`Delete ${item.name}`}
disabled={deletingId === item.branchId}
title={item.code === DEFAULT_BRANCH_CODE ? "The default branch cannot be deleted" : `Delete ${item.name}`}
disabled={deletingId === item.branchId || item.code === DEFAULT_BRANCH_CODE}
/>
}
>