diff --git a/app/(app)/settings/page.tsx b/app/(app)/settings/page.tsx index d8fd9ce..901896b 100644 --- a/app/(app)/settings/page.tsx +++ b/app/(app)/settings/page.tsx @@ -238,6 +238,8 @@ function AreasSettings() { const [areaName, setAreaName] = useState(""); const [zoneName, setZoneName] = useState(""); const [zoneAreaId, setZoneAreaId] = useState(""); + const [editArea, setEditArea] = useState(null); + const [editAreaName, setEditAreaName] = useState(""); const { data: areas, isLoading, refetch } = useQuery({ queryKey: ["areas"], @@ -256,26 +258,31 @@ function AreasSettings() { mutationFn: async () => { await api.post("/api/v1/areas", { name: areaName }); }, - onSuccess: () => { - toast.success("Area added"); - setAreaName(""); - setShowAddArea(false); - refetch(); - }, + onSuccess: () => { toast.success("Area added"); setAreaName(""); setShowAddArea(false); refetch(); }, onError: () => toast.error("Failed to add area"), }); + const updateAreaMutation = useMutation({ + mutationFn: async () => { + await api.patch(`/api/v1/areas/${editArea!.id}`, { name: editAreaName }); + }, + onSuccess: () => { toast.success("Area updated"); setEditArea(null); refetch(); }, + onError: () => toast.error("Failed to update area"), + }); + + const deleteAreaMutation = useMutation({ + mutationFn: async (id: string) => { + await api.delete(`/api/v1/areas/${id}`); + }, + onSuccess: () => { toast.success("Area archived"); refetch(); }, + onError: (e: any) => toast.error(e.response?.data?.message ?? "Failed to archive area"), + }); + const addZoneMutation = useMutation({ mutationFn: async () => { await api.post("/api/v1/zones", { name: zoneName, areaId: zoneAreaId }); }, - onSuccess: () => { - toast.success("Zone added"); - setZoneName(""); - setZoneAreaId(""); - setShowAddZone(false); - refetch(); - }, + onSuccess: () => { toast.success("Zone added"); setZoneName(""); setZoneAreaId(""); setShowAddZone(false); refetch(); }, onError: () => toast.error("Failed to add zone"), }); @@ -287,21 +294,14 @@ function AreasSettings() { Areas & Zones
- - + +
- - - - + {isLoading ? ( @@ -309,6 +309,7 @@ function AreasSettings() { + )) ) : areaList.length === 0 ? ( @@ -318,9 +319,13 @@ function AreasSettings() { + )) @@ -330,20 +335,24 @@ function AreasSettings() { + {/* Edit Area Modal */} + setEditArea(null)} title="Edit Area"> +
{ e.preventDefault(); updateAreaMutation.mutate(); }} className="space-y-4"> + setEditAreaName(e.target.value)} /> +
+ + +
+ +
+ {/* Add Area Modal */} setShowAddArea(false)} title="Add Area">
{ e.preventDefault(); addAreaMutation.mutate(); }} className="space-y-4"> - setAreaName(e.target.value)} - placeholder="e.g. North Sector" - /> + setAreaName(e.target.value)} placeholder="e.g. North Sector" />
- +
@@ -353,33 +362,16 @@ function AreasSettings() { { e.preventDefault(); addZoneMutation.mutate(); }} className="space-y-4">
- setZoneAreaId(e.target.value)}> - {areaList.map((a) => ( - - ))} + {areaList.map(a => )}
- setZoneName(e.target.value)} - placeholder="e.g. Zone 1" - /> + setZoneName(e.target.value)} placeholder="e.g. Zone 1" />
- +
@@ -636,6 +628,8 @@ const ROLES = ["ADMIN", "STAFF", "COLLECTOR", "TECHNICIAN"]; function UsersSettings() { const qc = useQueryClient(); const [showAdd, setShowAdd] = useState(false); + const [resetPwUser, setResetPwUser] = useState(null); + const [newPassword, setNewPassword] = useState(""); const [form, setForm] = useState({ firstName: "", lastName: "", email: "", password: "", phone: "", role: "STAFF" }); const { data, isLoading, refetch } = useQuery({ @@ -671,6 +665,14 @@ function UsersSettings() { onError: (e: any) => toast.error(e.response?.data?.message ?? "Failed"), }); + const resetPassword = useMutation({ + mutationFn: async () => { + await api.patch(`/api/v1/users/${resetPwUser!.id}/password`, { newPassword }); + }, + onSuccess: () => { toast.success("Password reset!"); setResetPwUser(null); setNewPassword(""); }, + onError: (e: any) => toast.error(e.response?.data?.message ?? "Failed to reset password"), + }); + const users = data ?? []; return ( @@ -693,17 +695,29 @@ function UsersSettings() { ) : users.length === 0 ? ( ) : users.map(u => { - const role = u.roleAssignments?.[0]?.role ?? "—"; + const roles = u.roleAssignments?.map(r => r.role) ?? []; + const primaryRole = roles[0] ?? "—"; return ( - + ); @@ -713,6 +727,21 @@ function UsersSettings() { + {/* Reset Password Modal */} + setResetPwUser(null)} title={`Reset Password — ${resetPwUser ? `${resetPwUser.firstName} ${resetPwUser.lastName}` : ""}`}> +
+

Enter a new password for this user. They will need to use this to log in.

+ setNewPassword(e.target.value)} hint="Minimum 8 characters" /> +
+ + +
+
+
+ setShowAdd(false)} title="Add New User">
Area NameZonesArea NameZonesActions
{a.name} - {a.zones?.length - ? a.zones.map((z) => z.name).join(", ") - : No zones} + {a.zones?.length ? a.zones.map(z => z.name).join(", ") : No zones} + +
+ + +
{u.firstName} {u.lastName}
{u.phone ?? ""}
{u.email}{role} +
+ {roles.length > 0 ? roles.map(r => ( + {r} + )) : } +
+
{u.isActive ? "Active" : "Inactive"} - +
+ + +