@simple-auth-kit/cli 1.3.2 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (75) hide show
  1. package/package.json +1 -1
  2. package/registry/admin-apps/nextjs/shared/.husky/commit-msg +1 -0
  3. package/registry/admin-apps/nextjs/shared/.husky/pre-commit +1 -0
  4. package/registry/admin-apps/nextjs/shared/.lintstagedrc.json +4 -0
  5. package/registry/admin-apps/nextjs/shared/.prettierrc.json +3 -0
  6. package/registry/admin-apps/nextjs/shared/commitlint.config.js +5 -0
  7. package/registry/admin-apps/nextjs/shared/eslint.config.js +28 -0
  8. package/registry/admin-apps/nextjs/variants/base/package.json +11 -2
  9. package/registry/admin-apps/nextjs/variants/base/src/app/(console)/audit-log/page.tsx +72 -16
  10. package/registry/admin-apps/nextjs/variants/base/src/app/(console)/customers/[id]/edit/page.tsx +107 -26
  11. package/registry/admin-apps/nextjs/variants/base/src/app/(console)/customers/[id]/page.tsx +131 -29
  12. package/registry/admin-apps/nextjs/variants/base/src/app/(console)/languages/[id]/edit/page.tsx +111 -25
  13. package/registry/admin-apps/nextjs/variants/base/src/app/(console)/languages/[id]/page.tsx +97 -22
  14. package/registry/admin-apps/nextjs/variants/base/src/app/(console)/permissions/[id]/edit/page.tsx +129 -46
  15. package/registry/admin-apps/nextjs/variants/base/src/app/(console)/permissions/[id]/page.tsx +64 -14
  16. package/registry/admin-apps/nextjs/variants/base/src/app/(console)/roles/[id]/page.tsx +91 -22
  17. package/registry/admin-apps/nextjs/variants/base/src/app/(console)/users/[id]/edit/page.tsx +94 -23
  18. package/registry/admin-apps/nextjs/variants/workspaces/package.json +11 -2
  19. package/registry/admin-apps/nextjs/variants/workspaces/src/app/(console)/account/page.tsx +179 -41
  20. package/registry/admin-apps/react/shared/.husky/commit-msg +1 -0
  21. package/registry/admin-apps/react/shared/.husky/pre-commit +1 -0
  22. package/registry/admin-apps/react/shared/.lintstagedrc.json +4 -0
  23. package/registry/admin-apps/react/shared/.prettierrc.json +3 -0
  24. package/registry/admin-apps/react/shared/commitlint.config.js +3 -0
  25. package/registry/admin-apps/react/shared/eslint.config.js +38 -0
  26. package/registry/admin-apps/react/variants/base/package.json +15 -2
  27. package/registry/admin-apps/react/variants/base/src/pages/CountryDetailPage.tsx +76 -19
  28. package/registry/admin-apps/react/variants/base/src/pages/CustomerDetailPage.tsx +110 -26
  29. package/registry/admin-apps/react/variants/base/src/pages/EditCountryPage.tsx +115 -29
  30. package/registry/admin-apps/react/variants/base/src/pages/EditCustomerPage.tsx +123 -31
  31. package/registry/admin-apps/react/variants/base/src/pages/EditLanguagePage.tsx +100 -24
  32. package/registry/admin-apps/react/variants/base/src/pages/EditRolePage.tsx +99 -26
  33. package/registry/admin-apps/react/variants/base/src/pages/EditUserPage.tsx +126 -31
  34. package/registry/admin-apps/react/variants/base/src/pages/LanguageDetailPage.tsx +75 -19
  35. package/registry/admin-apps/react/variants/base/src/pages/PermissionDetailPage.tsx +58 -13
  36. package/registry/admin-apps/react/variants/base/src/pages/PermissionsPage.tsx +132 -29
  37. package/registry/admin-apps/react/variants/base/src/pages/RoleDetailPage.tsx +70 -17
  38. package/registry/admin-apps/react/variants/base/src/pages/RolesPage.tsx +277 -59
  39. package/registry/admin-apps/react/variants/workspaces/package.json +15 -2
  40. package/registry/combos/express-drizzle/eslint.config.js +18 -0
  41. package/registry/combos/express-drizzle/package.json +5 -1
  42. package/registry/combos/express-drizzle/shared/src/request-context.ts +3 -0
  43. package/registry/combos/express-prisma/eslint.config.js +18 -0
  44. package/registry/combos/express-prisma/package.json +5 -1
  45. package/registry/combos/express-prisma/shared/src/request-context.ts +3 -0
  46. package/registry/combos/nestjs-drizzle/eslint.config.js +18 -0
  47. package/registry/combos/nestjs-drizzle/package.json +5 -1
  48. package/registry/combos/nestjs-drizzle/shared/src/auth.controller.ts +138 -33
  49. package/registry/combos/nestjs-drizzle/shared/src/route-tiers.ts +71 -18
  50. package/registry/combos/nestjs-prisma/eslint.config.js +18 -0
  51. package/registry/combos/nestjs-prisma/package.json +5 -1
  52. package/registry/combos/nestjs-prisma/shared/src/auth.controller.ts +148 -35
  53. package/registry/combos/nestjs-prisma/shared/src/route-tiers.ts +72 -18
  54. package/registry/mobile-apps/bare-rn/shared/.husky/commit-msg +1 -0
  55. package/registry/mobile-apps/bare-rn/shared/.husky/pre-commit +1 -0
  56. package/registry/mobile-apps/bare-rn/shared/.lintstagedrc.json +4 -0
  57. package/registry/mobile-apps/bare-rn/shared/.prettierrc.json +5 -0
  58. package/registry/mobile-apps/bare-rn/shared/commitlint.config.js +3 -0
  59. package/registry/mobile-apps/bare-rn/shared/eslint.config.js +19 -0
  60. package/registry/mobile-apps/bare-rn/variants/base/package.json +17 -12
  61. package/registry/mobile-apps/bare-rn/variants/workspaces/package.json +17 -12
  62. package/registry/mobile-apps/expo/shared/.husky/commit-msg +1 -0
  63. package/registry/mobile-apps/expo/shared/.husky/pre-commit +1 -0
  64. package/registry/mobile-apps/expo/shared/.lintstagedrc.json +4 -0
  65. package/registry/mobile-apps/expo/shared/.prettierrc.json +5 -0
  66. package/registry/mobile-apps/expo/shared/commitlint.config.js +3 -0
  67. package/registry/mobile-apps/expo/shared/eslint.config.js +9 -0
  68. package/registry/mobile-apps/expo/shared/src/screens/SessionsScreen.tsx +6 -17
  69. package/registry/mobile-apps/expo/shared/src/store/sessionsStore.ts +35 -0
  70. package/registry/mobile-apps/expo/variants/base/package.json +12 -3
  71. package/registry/mobile-apps/expo/variants/workspaces/package.json +12 -3
  72. package/registry/mobile-apps/expo/variants/workspaces/src/screens/WorkspaceSelectScreen.tsx +1 -1
  73. package/registry.json +13 -36
  74. package/registry/mobile-apps/bare-rn/shared/.eslintrc.js +0 -4
  75. package/registry/mobile-apps/bare-rn/shared/.prettierrc.js +0 -5
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@simple-auth-kit/cli",
3
- "version": "1.3.2",
3
+ "version": "1.4.0",
4
4
  "license": "MIT",
5
5
  "description": "simple-auth-kit add <combo> — copies registry source (backend combos, admin consoles, mobile apps) into a consumer repo, shadcn-CLI-style. Nothing is ever installed as a runtime dependency of the consumer.",
6
6
  "bin": {
@@ -0,0 +1 @@
1
+ npx --no -- commitlint --edit "$1"
@@ -0,0 +1 @@
1
+ npx lint-staged
@@ -0,0 +1,4 @@
1
+ {
2
+ "*.{ts,tsx,js,jsx}": "eslint --fix",
3
+ "*.{ts,tsx,js,jsx,json,md,css,scss}": "prettier --write"
4
+ }
@@ -0,0 +1,3 @@
1
+ {
2
+ "trailingComma": "all"
3
+ }
@@ -0,0 +1,5 @@
1
+ const config = {
2
+ extends: ["@commitlint/config-conventional"],
3
+ };
4
+
5
+ export default config;
@@ -0,0 +1,28 @@
1
+ import nextCoreWebVitals from "eslint-config-next/core-web-vitals";
2
+
3
+ const config = [
4
+ {
5
+ // src/components/ui/** is shadcn-generated (components.json), not hand-authored — same
6
+ // "vendored, don't lint" treatment this repo already gives it for Biome (the surviving
7
+ // biome-ignore-all comment on multi-selector.tsx).
8
+ ignores: [
9
+ ".next/**",
10
+ "node_modules/**",
11
+ "out/**",
12
+ "dist/**",
13
+ "src/components/ui/**",
14
+ ],
15
+ },
16
+ ...nextCoreWebVitals,
17
+ {
18
+ rules: {
19
+ // TanStack Table's useReactTable() is on React Compiler's own documented list of
20
+ // incompatible APIs (it returns functions that can't be safely memoized) — the compiler
21
+ // already handles this correctly by skipping memoization for it; there's no code change
22
+ // that "fixes" a structural library incompatibility.
23
+ "react-hooks/incompatible-library": "off",
24
+ },
25
+ },
26
+ ];
27
+
28
+ export default config;
@@ -8,7 +8,9 @@
8
8
  "dev": "next dev -p 3000",
9
9
  "build": "next build",
10
10
  "start": "next start -p 3000",
11
- "typecheck": "tsc --noEmit"
11
+ "typecheck": "tsc --noEmit",
12
+ "lint": "eslint .",
13
+ "prepare": "husky"
12
14
  },
13
15
  "dependencies": {
14
16
  "@casl/ability": "^7.0.1",
@@ -48,11 +50,18 @@
48
50
  "zod": "^4.2.1"
49
51
  },
50
52
  "devDependencies": {
53
+ "@commitlint/cli": "^21.2.2",
54
+ "@commitlint/config-conventional": "^21.2.2",
51
55
  "@tailwindcss/postcss": "^4.3.3",
52
56
  "@types/node": "^26.2.0",
53
57
  "@types/react": "^19.2.9",
54
58
  "@types/react-dom": "^19.2.4",
59
+ "eslint": "^9.39.5",
60
+ "eslint-config-next": "^16.3.5",
61
+ "husky": "^9.1.7",
62
+ "lint-staged": "^17.5.1",
63
+ "prettier": "^3.9.6",
55
64
  "tailwindcss": "^4.3.3",
56
- "typescript": "^7.0.2"
65
+ "typescript": "^6.0.3"
57
66
  }
58
67
  }
@@ -1,7 +1,7 @@
1
1
  "use client";
2
2
 
3
3
  import { useAbility } from "@casl/react";
4
- import { useCallback, useEffect, useState } from "react";
4
+ import { startTransition, useCallback, useEffect, useState } from "react";
5
5
  import type { AuditLogEntry, PageMeta } from "@simple-auth-kit/auth-client";
6
6
  import { Breadcrumb } from "@/components/breadcrumb";
7
7
  import { PermissionRequired } from "@/components/permission-required";
@@ -11,7 +11,14 @@ import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
11
11
  import { DateTimePicker } from "@/components/ui/datetime-picker";
12
12
  import { Input } from "@/components/ui/input";
13
13
  import { Label } from "@/components/ui/label";
14
- import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table";
14
+ import {
15
+ Table,
16
+ TableBody,
17
+ TableCell,
18
+ TableHead,
19
+ TableHeader,
20
+ TableRow,
21
+ } from "@/components/ui/table";
15
22
  import { PERMISSIONS, hasPermission, type AppAbility } from "@/lib/ability";
16
23
  import { authClient } from "@/lib/auth-client";
17
24
  import { errorMessage } from "@/lib/error";
@@ -55,11 +62,17 @@ export default function AuditLogPage() {
55
62
 
56
63
  useEffect(() => {
57
64
  if (!canRead) return;
58
- void load(1);
65
+ startTransition(() => void load(1));
59
66
  // eslint-disable-next-line react-hooks/exhaustive-deps
60
67
  }, [canRead]);
61
68
 
62
- if (!canRead) return <PermissionRequired permission={PERMISSIONS.auditLogRead} what="The audit log" />;
69
+ if (!canRead)
70
+ return (
71
+ <PermissionRequired
72
+ permission={PERMISSIONS.auditLogRead}
73
+ what="The audit log"
74
+ />
75
+ );
63
76
 
64
77
  return (
65
78
  <div className="flex flex-col">
@@ -80,19 +93,39 @@ export default function AuditLogPage() {
80
93
  >
81
94
  <div className="flex flex-col gap-1.5">
82
95
  <Label htmlFor="filterUserId">User ID</Label>
83
- <Input id="filterUserId" value={userId} onChange={(e) => setUserId(e.target.value)} placeholder="uuid" />
96
+ <Input
97
+ id="filterUserId"
98
+ value={userId}
99
+ onChange={(e) => setUserId(e.target.value)}
100
+ placeholder="uuid"
101
+ />
84
102
  </div>
85
103
  <div className="flex flex-col gap-1.5">
86
104
  <Label htmlFor="filterAction">Action</Label>
87
- <Input id="filterAction" value={action} onChange={(e) => setAction(e.target.value)} placeholder="role_assigned" />
105
+ <Input
106
+ id="filterAction"
107
+ value={action}
108
+ onChange={(e) => setAction(e.target.value)}
109
+ placeholder="role_assigned"
110
+ />
88
111
  </div>
89
112
  <div className="flex flex-col gap-1.5">
90
113
  <Label>Since</Label>
91
- <DateTimePicker value={since} onChange={setSince} granularity="minute" placeholder="Since" />
114
+ <DateTimePicker
115
+ value={since}
116
+ onChange={setSince}
117
+ granularity="minute"
118
+ placeholder="Since"
119
+ />
92
120
  </div>
93
121
  <div className="flex flex-col gap-1.5">
94
122
  <Label>Until</Label>
95
- <DateTimePicker value={until} onChange={setUntil} granularity="minute" placeholder="Until" />
123
+ <DateTimePicker
124
+ value={until}
125
+ onChange={setUntil}
126
+ granularity="minute"
127
+ placeholder="Until"
128
+ />
96
129
  </div>
97
130
  <div className="col-span-2 flex items-end gap-2 sm:col-span-4">
98
131
  <Button type="submit" disabled={loading}>
@@ -136,18 +169,30 @@ export default function AuditLogPage() {
136
169
  </TableCell>
137
170
  <TableCell>
138
171
  <div className="text-sm">{entry.name}</div>
139
- <div className="font-mono text-xs text-muted-foreground">{entry.action}</div>
172
+ <div className="font-mono text-xs text-muted-foreground">
173
+ {entry.action}
174
+ </div>
140
175
  </TableCell>
141
- <TableCell className="font-mono text-xs">{entry.userId ?? "—"}</TableCell>
142
- <TableCell className="max-w-xs truncate font-mono text-xs text-muted-foreground" title={JSON.stringify(entry.info)}>
176
+ <TableCell className="font-mono text-xs">
177
+ {entry.userId ?? "—"}
178
+ </TableCell>
179
+ <TableCell
180
+ className="max-w-xs truncate font-mono text-xs text-muted-foreground"
181
+ title={JSON.stringify(entry.info)}
182
+ >
143
183
  {JSON.stringify(entry.info)}
144
184
  </TableCell>
145
- <TableCell className="max-w-3xs truncate text-xs text-muted-foreground">{entry.remarks ?? "—"}</TableCell>
185
+ <TableCell className="max-w-3xs truncate text-xs text-muted-foreground">
186
+ {entry.remarks ?? "—"}
187
+ </TableCell>
146
188
  </TableRow>
147
189
  ))}
148
190
  {entries.length === 0 && !loading && (
149
191
  <TableRow>
150
- <TableCell colSpan={5} className="text-center text-sm text-muted-foreground">
192
+ <TableCell
193
+ colSpan={5}
194
+ className="text-center text-sm text-muted-foreground"
195
+ >
151
196
  No entries match these filters.
152
197
  </TableCell>
153
198
  </TableRow>
@@ -158,16 +203,27 @@ export default function AuditLogPage() {
158
203
  {meta && meta.total > 0 && (
159
204
  <div className="flex items-center justify-between">
160
205
  <p className="text-sm text-muted-foreground">
161
- Showing {(meta.page - 1) * meta.limit + 1}–{Math.min(meta.page * meta.limit, meta.total)} of {meta.total}
206
+ Showing {(meta.page - 1) * meta.limit + 1}–
207
+ {Math.min(meta.page * meta.limit, meta.total)} of {meta.total}
162
208
  </p>
163
209
  <div className="flex items-center gap-2">
164
- <Button variant="outline" size="sm" disabled={!meta.hasPreviousPage || loading} onClick={() => load(meta.page - 1)}>
210
+ <Button
211
+ variant="outline"
212
+ size="sm"
213
+ disabled={!meta.hasPreviousPage || loading}
214
+ onClick={() => load(meta.page - 1)}
215
+ >
165
216
  Previous
166
217
  </Button>
167
218
  <span className="text-sm text-muted-foreground">
168
219
  Page {meta.page} of {meta.pageCount}
169
220
  </span>
170
- <Button variant="outline" size="sm" disabled={!meta.hasNextPage || loading} onClick={() => load(meta.page + 1)}>
221
+ <Button
222
+ variant="outline"
223
+ size="sm"
224
+ disabled={!meta.hasNextPage || loading}
225
+ onClick={() => load(meta.page + 1)}
226
+ >
171
227
  Next
172
228
  </Button>
173
229
  </div>
@@ -3,9 +3,13 @@
3
3
  import { zodResolver } from "@hookform/resolvers/zod";
4
4
  import { useAbility } from "@casl/react";
5
5
  import { useParams, useRouter } from "next/navigation";
6
- import { useCallback, useEffect, useState } from "react";
6
+ import { startTransition, useCallback, useEffect, useState } from "react";
7
7
  import { useForm } from "react-hook-form";
8
- import { AuthApiError, type CustomerSummary, type UpdateCustomerInput } from "@simple-auth-kit/auth-client";
8
+ import {
9
+ AuthApiError,
10
+ type CustomerSummary,
11
+ type UpdateCustomerInput,
12
+ } from "@simple-auth-kit/auth-client";
9
13
  import { format } from "date-fns";
10
14
  import { toast } from "sonner";
11
15
  import { Breadcrumb } from "@/components/breadcrumb";
@@ -13,18 +17,37 @@ import { FormErrorAlert } from "@/components/form-error-alert";
13
17
  import { PermissionRequired } from "@/components/permission-required";
14
18
  import { PhotoUpload } from "@/components/photo-upload";
15
19
  import { Button } from "@/components/ui/button";
16
- import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from "@/components/ui/card";
20
+ import {
21
+ Card,
22
+ CardContent,
23
+ CardDescription,
24
+ CardFooter,
25
+ CardHeader,
26
+ CardTitle,
27
+ } from "@/components/ui/card";
17
28
  import { Checkbox } from "@/components/ui/checkbox";
18
29
  import { Combobox } from "@/components/ui/combobox";
19
30
  import { DatePicker } from "@/components/ui/date-picker";
20
- import { Form, FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage } from "@/components/ui/form";
31
+ import {
32
+ Form,
33
+ FormControl,
34
+ FormDescription,
35
+ FormField,
36
+ FormItem,
37
+ FormLabel,
38
+ FormMessage,
39
+ } from "@/components/ui/form";
21
40
  import { Heading } from "@/components/ui/heading";
22
41
  import { Input } from "@/components/ui/input";
23
42
  import { Separator } from "@/components/ui/separator";
24
43
  import { PERMISSIONS, hasPermission, type AppAbility } from "@/lib/ability";
25
44
  import { authClient } from "@/lib/auth-client";
26
45
  import { errorMessage, errorMessages } from "@/lib/error";
27
- import { GENDER_OPTIONS, editCustomerSchema, type EditCustomerFormValues } from "../../customer-schema";
46
+ import {
47
+ GENDER_OPTIONS,
48
+ editCustomerSchema,
49
+ type EditCustomerFormValues,
50
+ } from "../../customer-schema";
28
51
 
29
52
  function apiErrorMessage(err: unknown, fallback: string): string {
30
53
  return err instanceof AuthApiError ? err.message : fallback;
@@ -88,10 +111,16 @@ export default function EditCustomerPage() {
88
111
 
89
112
  useEffect(() => {
90
113
  if (!canManage) return;
91
- void load();
114
+ startTransition(() => void load());
92
115
  }, [canManage, load]);
93
116
 
94
- if (!canManage) return <PermissionRequired permission={PERMISSIONS.customersManage} what="Editing a customer" />;
117
+ if (!canManage)
118
+ return (
119
+ <PermissionRequired
120
+ permission={PERMISSIONS.customersManage}
121
+ what="Editing a customer"
122
+ />
123
+ );
95
124
 
96
125
  async function onSubmit(values: EditCustomerFormValues) {
97
126
  if (!customer) return;
@@ -105,7 +134,9 @@ export default function EditCustomerPage() {
105
134
  phone: values.phone || null,
106
135
  dob: values.dob ? format(values.dob, "yyyy-MM-dd") : null,
107
136
  gender: values.gender || null,
108
- joinedDate: values.joinedDate ? format(values.joinedDate, "yyyy-MM-dd") : undefined,
137
+ joinedDate: values.joinedDate
138
+ ? format(values.joinedDate, "yyyy-MM-dd")
139
+ : undefined,
109
140
  photo: values.photo || null,
110
141
  isActive: values.isActive,
111
142
  };
@@ -135,7 +166,9 @@ export default function EditCustomerPage() {
135
166
  </div>
136
167
  <Separator />
137
168
 
138
- {loading && !customer && <p className="text-sm text-muted-foreground">Loading…</p>}
169
+ {loading && !customer && (
170
+ <p className="text-sm text-muted-foreground">Loading…</p>
171
+ )}
139
172
 
140
173
  {customer && (
141
174
  <Card>
@@ -143,16 +176,25 @@ export default function EditCustomerPage() {
143
176
  <CardContent>
144
177
  <FormErrorAlert messages={formError} />
145
178
  <Form {...form}>
146
- <form onSubmit={form.handleSubmit(onSubmit)} className="space-y-8 w-full">
179
+ <form
180
+ onSubmit={form.handleSubmit(onSubmit)}
181
+ className="space-y-8 w-full"
182
+ >
147
183
  <Card className="w-full">
148
184
  <CardHeader className="border-b bg-muted/50">
149
- <CardTitle className="text-2xl">Customer Information</CardTitle>
150
- <CardDescription className="text-base">Update customer&apos;s basic information</CardDescription>
185
+ <CardTitle className="text-2xl">
186
+ Customer Information
187
+ </CardTitle>
188
+ <CardDescription className="text-base">
189
+ Update customer&apos;s basic information
190
+ </CardDescription>
151
191
  </CardHeader>
152
192
  <CardContent className="pt-6">
153
193
  <div className="space-y-6">
154
194
  <div className="space-y-4">
155
- <h3 className="text-sm font-semibold text-muted-foreground uppercase tracking-wide">Personal Information</h3>
195
+ <h3 className="text-sm font-semibold text-muted-foreground uppercase tracking-wide">
196
+ Personal Information
197
+ </h3>
156
198
  <div className="grid grid-cols-1 md:grid-cols-2 gap-6">
157
199
  <FormField
158
200
  control={form.control}
@@ -199,7 +241,9 @@ export default function EditCustomerPage() {
199
241
  <FormItem>
200
242
  <FormLabel>
201
243
  Username &nbsp;
202
- <span className="text-xs text-destructive dark:text-destructive-foreground">(Must be unique)</span>
244
+ <span className="text-xs text-destructive dark:text-destructive-foreground">
245
+ (Must be unique)
246
+ </span>
203
247
  </FormLabel>
204
248
  <FormControl>
205
249
  <Input
@@ -217,7 +261,9 @@ export default function EditCustomerPage() {
217
261
  </div>
218
262
 
219
263
  <div className="space-y-4">
220
- <h3 className="text-sm font-semibold text-muted-foreground uppercase tracking-wide">Contact Information</h3>
264
+ <h3 className="text-sm font-semibold text-muted-foreground uppercase tracking-wide">
265
+ Contact Information
266
+ </h3>
221
267
  <div className="grid grid-cols-1 md:grid-cols-2 gap-6">
222
268
  <FormField
223
269
  control={form.control}
@@ -226,7 +272,9 @@ export default function EditCustomerPage() {
226
272
  <FormItem>
227
273
  <FormLabel>
228
274
  Email &nbsp;
229
- <span className="text-xs text-destructive dark:text-destructive-foreground">(Must be unique)</span>
275
+ <span className="text-xs text-destructive dark:text-destructive-foreground">
276
+ (Must be unique)
277
+ </span>
230
278
  </FormLabel>
231
279
  <FormControl>
232
280
  <Input
@@ -248,7 +296,9 @@ export default function EditCustomerPage() {
248
296
  <FormItem>
249
297
  <FormLabel>
250
298
  Phone &nbsp;
251
- <span className="text-xs text-muted-foreground">(With country code)</span>
299
+ <span className="text-xs text-muted-foreground">
300
+ (With country code)
301
+ </span>
252
302
  </FormLabel>
253
303
  <FormControl>
254
304
  <Input
@@ -267,7 +317,9 @@ export default function EditCustomerPage() {
267
317
  </div>
268
318
 
269
319
  <div className="space-y-4">
270
- <h3 className="text-sm font-semibold text-muted-foreground uppercase tracking-wide">Additional Details</h3>
320
+ <h3 className="text-sm font-semibold text-muted-foreground uppercase tracking-wide">
321
+ Additional Details
322
+ </h3>
271
323
  <div className="grid grid-cols-1 md:grid-cols-2 gap-6">
272
324
  <FormField
273
325
  control={form.control}
@@ -313,7 +365,9 @@ export default function EditCustomerPage() {
313
365
  options={GENDER_OPTIONS}
314
366
  selected={field.value ?? ""}
315
367
  placeholder="Select Gender"
316
- onChange={(option) => field.onChange(option.value)}
368
+ onChange={(option) =>
369
+ field.onChange(option.value)
370
+ }
317
371
  showCreate={false}
318
372
  popoverClassName="min-w-[200px]"
319
373
  />
@@ -330,7 +384,10 @@ export default function EditCustomerPage() {
330
384
 
331
385
  <CardHeader className="border-b bg-muted/50 mt-6">
332
386
  <CardTitle className="text-2xl">Profile Photo</CardTitle>
333
- <CardDescription className="text-base">Upload customer&apos;s profile picture (Max size: 2MB, Formats: JPG, PNG)</CardDescription>
387
+ <CardDescription className="text-base">
388
+ Upload customer&apos;s profile picture (Max size: 2MB,
389
+ Formats: JPG, PNG)
390
+ </CardDescription>
334
391
  </CardHeader>
335
392
  <CardContent className="pt-6">
336
393
  <FormField
@@ -340,7 +397,12 @@ export default function EditCustomerPage() {
340
397
  <FormItem>
341
398
  <FormControl>
342
399
  <div>
343
- <PhotoUpload photo={field.value} fallback="?" onChange={field.onChange} disabled={saving} />
400
+ <PhotoUpload
401
+ photo={field.value}
402
+ fallback="?"
403
+ onChange={field.onChange}
404
+ disabled={saving}
405
+ />
344
406
  </div>
345
407
  </FormControl>
346
408
  <FormMessage />
@@ -356,11 +418,21 @@ export default function EditCustomerPage() {
356
418
  render={({ field }) => (
357
419
  <FormItem className="flex flex-row items-center space-x-3 space-y-0 rounded-lg border border-purple-500 bg-purple-50 dark:bg-purple-950/20 p-4">
358
420
  <FormControl>
359
- <Checkbox checked={field.value} onCheckedChange={(checked) => field.onChange(checked === true)} />
421
+ <Checkbox
422
+ checked={field.value}
423
+ onCheckedChange={(checked) =>
424
+ field.onChange(checked === true)
425
+ }
426
+ />
360
427
  </FormControl>
361
428
  <div className="space-y-1 leading-none">
362
- <FormLabel className="text-base font-medium">Active Status</FormLabel>
363
- <FormDescription className="text-sm">Customer will be active and available for selection</FormDescription>
429
+ <FormLabel className="text-base font-medium">
430
+ Active Status
431
+ </FormLabel>
432
+ <FormDescription className="text-sm">
433
+ Customer will be active and available for
434
+ selection
435
+ </FormDescription>
364
436
  </div>
365
437
  </FormItem>
366
438
  )}
@@ -368,10 +440,19 @@ export default function EditCustomerPage() {
368
440
  </div>
369
441
 
370
442
  <CardFooter className="flex justify-center gap-4 mt-8 pb-8">
371
- <Button type="button" variant="outline" onClick={() => router.push(`/customers/${id}`)} disabled={saving}>
443
+ <Button
444
+ type="button"
445
+ variant="outline"
446
+ onClick={() => router.push(`/customers/${id}`)}
447
+ disabled={saving}
448
+ >
372
449
  Cancel
373
450
  </Button>
374
- <Button disabled={saving} className="bg-purple-600 hover:bg-purple-700 dark:bg-purple-600 dark:hover:bg-purple-700 min-w-32" type="submit">
451
+ <Button
452
+ disabled={saving}
453
+ className="bg-purple-600 hover:bg-purple-700 dark:bg-purple-600 dark:hover:bg-purple-700 min-w-32"
454
+ type="submit"
455
+ >
375
456
  {saving ? "Updating..." : "Update Customer"}
376
457
  </Button>
377
458
  </CardFooter>