@devlider001/washlab-backend 1.0.4 → 1.0.6

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 (78) hide show
  1. package/convex/_generated/api.d.ts +2 -0
  2. package/convex/admin.d.ts +1 -1
  3. package/convex/audit.d.ts +39 -0
  4. package/convex/customers.d.ts +12 -5
  5. package/convex/lib/auth.d.ts +24 -1
  6. package/convex/notifications.d.ts +170 -0
  7. package/convex/schema.d.ts +53 -2
  8. package/dist/convex/admin.d.ts +377 -0
  9. package/dist/convex/admin.d.ts.map +1 -0
  10. package/dist/convex/admin.js +959 -0
  11. package/dist/convex/admin.js.map +1 -0
  12. package/dist/convex/analytics.d.ts +87 -0
  13. package/dist/convex/analytics.d.ts.map +1 -0
  14. package/dist/convex/analytics.js +361 -0
  15. package/dist/convex/analytics.js.map +1 -0
  16. package/dist/convex/attendants.d.ts +140 -0
  17. package/dist/convex/attendants.d.ts.map +1 -0
  18. package/dist/convex/attendants.js +337 -0
  19. package/dist/convex/attendants.js.map +1 -0
  20. package/dist/convex/audit.d.ts +158 -0
  21. package/dist/convex/audit.d.ts.map +1 -0
  22. package/dist/convex/audit.js +184 -0
  23. package/dist/convex/audit.js.map +1 -0
  24. package/dist/convex/clerk.d.ts +53 -0
  25. package/dist/convex/clerk.d.ts.map +1 -0
  26. package/dist/convex/clerk.js +316 -0
  27. package/dist/convex/clerk.js.map +1 -0
  28. package/dist/convex/customers.d.ts +224 -0
  29. package/dist/convex/customers.d.ts.map +1 -0
  30. package/dist/convex/customers.js +504 -0
  31. package/dist/convex/customers.js.map +1 -0
  32. package/dist/convex/http.d.ts +3 -0
  33. package/dist/convex/http.d.ts.map +1 -0
  34. package/dist/convex/http.js +115 -0
  35. package/dist/convex/http.js.map +1 -0
  36. package/dist/convex/lib/audit.d.ts +36 -0
  37. package/dist/convex/lib/audit.d.ts.map +1 -0
  38. package/dist/convex/lib/audit.js +59 -0
  39. package/dist/convex/lib/audit.js.map +1 -0
  40. package/dist/convex/lib/auth.d.ts +96 -0
  41. package/dist/convex/lib/auth.d.ts.map +1 -0
  42. package/dist/convex/lib/auth.js +94 -0
  43. package/dist/convex/lib/auth.js.map +1 -0
  44. package/dist/convex/lib/utils.d.ts +38 -0
  45. package/dist/convex/lib/utils.d.ts.map +1 -0
  46. package/dist/convex/lib/utils.js +71 -0
  47. package/dist/convex/lib/utils.js.map +1 -0
  48. package/dist/convex/loyalty.d.ts +82 -0
  49. package/dist/convex/loyalty.d.ts.map +1 -0
  50. package/dist/convex/loyalty.js +286 -0
  51. package/dist/convex/loyalty.js.map +1 -0
  52. package/dist/convex/orders.d.ts +326 -0
  53. package/dist/convex/orders.d.ts.map +1 -0
  54. package/dist/convex/orders.js +570 -0
  55. package/dist/convex/orders.js.map +1 -0
  56. package/dist/convex/payments.d.ts +134 -0
  57. package/dist/convex/payments.d.ts.map +1 -0
  58. package/dist/convex/payments.js +360 -0
  59. package/dist/convex/payments.js.map +1 -0
  60. package/dist/convex/resources.d.ts +119 -0
  61. package/dist/convex/resources.d.ts.map +1 -0
  62. package/dist/convex/resources.js +283 -0
  63. package/dist/convex/resources.js.map +1 -0
  64. package/dist/convex/schema.d.ts +450 -0
  65. package/dist/convex/schema.d.ts.map +1 -0
  66. package/dist/convex/schema.js +347 -0
  67. package/dist/convex/schema.js.map +1 -0
  68. package/dist/convex/vouchers.d.ts +187 -0
  69. package/dist/convex/vouchers.d.ts.map +1 -0
  70. package/dist/convex/vouchers.js +464 -0
  71. package/dist/convex/vouchers.js.map +1 -0
  72. package/dist/src/index.d.ts +9 -0
  73. package/dist/src/index.d.ts.map +1 -0
  74. package/dist/src/index.js +9 -0
  75. package/dist/src/index.js.map +1 -0
  76. package/package.json +5 -3
  77. package/convex/_generated/api.js +0 -23
  78. package/convex/_generated/server.js +0 -93
@@ -0,0 +1,184 @@
1
+ import { query } from "./_generated/server";
2
+ import { v } from "convex/values";
3
+ import { getCurrentAdmin } from "./lib/auth";
4
+ /**
5
+ * Audit Functions
6
+ *
7
+ * Handles querying audit logs for compliance and accountability.
8
+ * Only admins can access audit logs.
9
+ */
10
+ /**
11
+ * Get audit logs by entity
12
+ */
13
+ export const getByEntity = query({
14
+ args: {
15
+ entityType: v.string(),
16
+ entityId: v.optional(v.string()),
17
+ limit: v.optional(v.number()),
18
+ },
19
+ handler: async (ctx, args) => {
20
+ await getCurrentAdmin(ctx);
21
+ const limit = args.limit ?? 100;
22
+ let logs;
23
+ if (args.entityId) {
24
+ logs = await ctx.db
25
+ .query("auditLogs")
26
+ .withIndex("by_entity", (q) => q.eq("entityType", args.entityType).eq("entityId", args.entityId))
27
+ .order("desc")
28
+ .take(limit);
29
+ }
30
+ else {
31
+ logs = await ctx.db
32
+ .query("auditLogs")
33
+ .filter((q) => q.eq(q.field("entityType"), args.entityType))
34
+ .order("desc")
35
+ .take(limit);
36
+ }
37
+ return logs;
38
+ },
39
+ });
40
+ /**
41
+ * Get audit logs by actor
42
+ */
43
+ export const getByActor = query({
44
+ args: {
45
+ actorId: v.string(),
46
+ actorType: v.optional(v.union(v.literal("customer"), v.literal("attendant"), v.literal("admin"))),
47
+ limit: v.optional(v.number()),
48
+ },
49
+ handler: async (ctx, args) => {
50
+ await getCurrentAdmin(ctx);
51
+ const limit = args.limit ?? 100;
52
+ let logs;
53
+ if (args.actorType) {
54
+ logs = await ctx.db
55
+ .query("auditLogs")
56
+ .withIndex("by_actor", (q) => q.eq("actorId", args.actorId).eq("actorType", args.actorType))
57
+ .order("desc")
58
+ .take(limit);
59
+ }
60
+ else {
61
+ logs = await ctx.db
62
+ .query("auditLogs")
63
+ .filter((q) => q.eq(q.field("actorId"), args.actorId))
64
+ .order("desc")
65
+ .take(limit);
66
+ }
67
+ return logs;
68
+ },
69
+ });
70
+ /**
71
+ * Get audit logs by branch
72
+ */
73
+ export const getByBranch = query({
74
+ args: {
75
+ branchId: v.id("branches"),
76
+ limit: v.optional(v.number()),
77
+ },
78
+ handler: async (ctx, args) => {
79
+ await getCurrentAdmin(ctx);
80
+ const limit = args.limit ?? 100;
81
+ const logs = await ctx.db
82
+ .query("auditLogs")
83
+ .withIndex("by_branch", (q) => q.eq("branchId", args.branchId))
84
+ .order("desc")
85
+ .take(limit);
86
+ return logs;
87
+ },
88
+ });
89
+ /**
90
+ * Get audit logs by action
91
+ */
92
+ export const getByAction = query({
93
+ args: {
94
+ action: v.string(),
95
+ limit: v.optional(v.number()),
96
+ },
97
+ handler: async (ctx, args) => {
98
+ await getCurrentAdmin(ctx);
99
+ const limit = args.limit ?? 100;
100
+ const logs = await ctx.db
101
+ .query("auditLogs")
102
+ .withIndex("by_action", (q) => q.eq("action", args.action))
103
+ .order("desc")
104
+ .take(limit);
105
+ return logs;
106
+ },
107
+ });
108
+ /**
109
+ * Get audit logs by time range
110
+ */
111
+ export const getByTimeRange = query({
112
+ args: {
113
+ startTimestamp: v.number(),
114
+ endTimestamp: v.number(),
115
+ limit: v.optional(v.number()),
116
+ },
117
+ handler: async (ctx, args) => {
118
+ await getCurrentAdmin(ctx);
119
+ const limit = args.limit ?? 100;
120
+ const logs = await ctx.db
121
+ .query("auditLogs")
122
+ .withIndex("by_timestamp")
123
+ .filter((q) => q.and(q.gte(q.field("timestamp"), args.startTimestamp), q.lte(q.field("timestamp"), args.endTimestamp)))
124
+ .order("desc")
125
+ .take(limit);
126
+ return logs;
127
+ },
128
+ });
129
+ /**
130
+ * Get all audit logs with filters - Paginated
131
+ * Supports usePaginatedQuery for infinite scroll
132
+ */
133
+ export const getAll = query({
134
+ args: {
135
+ entityType: v.optional(v.string()),
136
+ actorType: v.optional(v.union(v.literal("customer"), v.literal("attendant"), v.literal("admin"))),
137
+ action: v.optional(v.string()),
138
+ startTimestamp: v.optional(v.number()),
139
+ endTimestamp: v.optional(v.number()),
140
+ cursor: v.optional(v.string()),
141
+ numItems: v.optional(v.number()),
142
+ },
143
+ handler: async (ctx, args) => {
144
+ await getCurrentAdmin(ctx);
145
+ const numItems = args.numItems ?? 50;
146
+ // Build query with filters
147
+ const result = await ctx.db
148
+ .query("auditLogs")
149
+ .filter((q) => {
150
+ const conditions = [];
151
+ if (args.entityType) {
152
+ conditions.push(q.eq(q.field("entityType"), args.entityType));
153
+ }
154
+ if (args.actorType) {
155
+ conditions.push(q.eq(q.field("actorType"), args.actorType));
156
+ }
157
+ if (args.action) {
158
+ conditions.push(q.eq(q.field("action"), args.action));
159
+ }
160
+ if (args.startTimestamp) {
161
+ conditions.push(q.gte(q.field("timestamp"), args.startTimestamp));
162
+ }
163
+ if (args.endTimestamp) {
164
+ conditions.push(q.lte(q.field("timestamp"), args.endTimestamp));
165
+ }
166
+ // If no filters, return all (always true condition)
167
+ if (conditions.length === 0) {
168
+ return q.eq(q.field("_id"), q.field("_id"));
169
+ }
170
+ return q.and(...conditions);
171
+ })
172
+ .order("desc")
173
+ .paginate({
174
+ cursor: args.cursor ?? null,
175
+ numItems,
176
+ });
177
+ return {
178
+ page: result.page,
179
+ isDone: result.isDone,
180
+ continueCursor: result.continueCursor,
181
+ };
182
+ },
183
+ });
184
+ //# sourceMappingURL=audit.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audit.js","sourceRoot":"","sources":["../../convex/audit.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,53 @@
1
+ /**
2
+ * Internal Clerk Webhook Mutations
3
+ *
4
+ * These mutations are called from the webhook handler to sync Clerk user data
5
+ * with our database. They are internal (not exposed to clients) for security.
6
+ */
7
+ /**
8
+ * Sync user created event from Clerk
9
+ */
10
+ export declare const syncUserCreated: import("convex/server").RegisteredMutation<"internal", {
11
+ phoneNumber?: string | undefined;
12
+ email?: string | undefined;
13
+ userType?: "admin" | "customer" | "attendant" | undefined;
14
+ name: string;
15
+ clerkUserId: string;
16
+ emailVerified: boolean;
17
+ }, Promise<import("convex/values").GenericId<"admins"> | import("convex/values").GenericId<"users"> | import("convex/values").GenericId<"attendants"> | null>>;
18
+ /**
19
+ * Sync user updated event from Clerk
20
+ */
21
+ export declare const syncUserUpdated: import("convex/server").RegisteredMutation<"internal", {
22
+ phoneNumber?: string | undefined;
23
+ email?: string | undefined;
24
+ userType?: "admin" | "customer" | "attendant" | undefined;
25
+ name: string;
26
+ clerkUserId: string;
27
+ emailVerified: boolean;
28
+ }, Promise<{
29
+ type: string;
30
+ id: import("convex/values").GenericId<"admins">;
31
+ } | {
32
+ type: string;
33
+ id: import("convex/values").GenericId<"users">;
34
+ } | {
35
+ type: string;
36
+ id: import("convex/values").GenericId<"attendants">;
37
+ } | null>>;
38
+ /**
39
+ * Sync user deleted event from Clerk
40
+ */
41
+ export declare const syncUserDeleted: import("convex/server").RegisteredMutation<"internal", {
42
+ clerkUserId: string;
43
+ }, Promise<{
44
+ type: string;
45
+ id: import("convex/values").GenericId<"users">;
46
+ } | {
47
+ type: string;
48
+ id: import("convex/values").GenericId<"attendants">;
49
+ } | {
50
+ type: string;
51
+ id: import("convex/values").GenericId<"admins">;
52
+ } | null>>;
53
+ //# sourceMappingURL=clerk.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"clerk.d.ts","sourceRoot":"","sources":["../../convex/clerk.ts"],"names":[],"mappings":"AAKA;;;;;GAKG;AAEH;;GAEG;AACH,eAAO,MAAM,eAAe;;;;;;;8JA6J1B,CAAC;AAEH;;GAEG;AACH,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;UAgH1B,CAAC;AAEH;;GAEG;AACH,eAAO,MAAM,eAAe;;;;;;;;;;;UA0D1B,CAAC"}
@@ -0,0 +1,316 @@
1
+ import { internalMutation } from "./_generated/server";
2
+ import { v } from "convex/values";
3
+ import { getCurrentTimestamp } from "./lib/utils";
4
+ /**
5
+ * Internal Clerk Webhook Mutations
6
+ *
7
+ * These mutations are called from the webhook handler to sync Clerk user data
8
+ * with our database. They are internal (not exposed to clients) for security.
9
+ */
10
+ /**
11
+ * Sync user created event from Clerk
12
+ */
13
+ export const syncUserCreated = internalMutation({
14
+ args: {
15
+ clerkUserId: v.string(),
16
+ email: v.optional(v.string()),
17
+ phoneNumber: v.optional(v.string()),
18
+ name: v.string(),
19
+ emailVerified: v.boolean(),
20
+ userType: v.optional(v.union(v.literal("customer"), v.literal("attendant"), v.literal("admin"))),
21
+ },
22
+ handler: async (ctx, args) => {
23
+ const { clerkUserId, email, phoneNumber, name, emailVerified, userType } = args;
24
+ const now = getCurrentTimestamp();
25
+ // Determine which table to create the user in based on userType
26
+ // Default to customer if not specified
27
+ const type = userType || "customer";
28
+ if (type === "customer") {
29
+ // Check if customer already exists
30
+ const existing = await ctx.db
31
+ .query("users")
32
+ .withIndex("by_clerk_user", (q) => q.eq("clerkUserId", clerkUserId))
33
+ .first();
34
+ if (existing) {
35
+ // Update existing customer (reactivate if deleted)
36
+ await ctx.db.patch(existing._id, {
37
+ clerkUserId,
38
+ email,
39
+ phoneNumber: phoneNumber || existing.phoneNumber,
40
+ name,
41
+ isRegistered: true,
42
+ isVerified: emailVerified,
43
+ isDeleted: false,
44
+ lastLoginAt: now,
45
+ });
46
+ return existing._id;
47
+ }
48
+ // Create new customer
49
+ // If phone number is not provided (e.g., Ghana not supported in Clerk),
50
+ // use a placeholder that can be updated later
51
+ // Format: "pending-{clerkUserId}" or use email as fallback
52
+ const finalPhoneNumber = phoneNumber ||
53
+ (email ? `pending-${email.replace(/[^a-zA-Z0-9]/g, "")}` : `pending-${clerkUserId}`);
54
+ const userId = await ctx.db.insert("users", {
55
+ clerkUserId,
56
+ phoneNumber: finalPhoneNumber,
57
+ email,
58
+ name,
59
+ isRegistered: true,
60
+ isVerified: emailVerified,
61
+ status: "active",
62
+ createdAt: now,
63
+ lastLoginAt: now,
64
+ isDeleted: false,
65
+ });
66
+ return userId;
67
+ }
68
+ else if (type === "attendant") {
69
+ // Check if attendant already exists
70
+ const existing = await ctx.db
71
+ .query("attendants")
72
+ .withIndex("by_clerk_user", (q) => q.eq("clerkUserId", clerkUserId))
73
+ .first();
74
+ if (existing) {
75
+ // Update existing attendant
76
+ await ctx.db.patch(existing._id, {
77
+ clerkUserId,
78
+ email: email || existing.email,
79
+ phoneNumber: phoneNumber || existing.phoneNumber,
80
+ name,
81
+ isDeleted: false,
82
+ lastLoginAt: now,
83
+ });
84
+ return existing._id;
85
+ }
86
+ // Note: Attendants should be created by admin first with branch assignment
87
+ // This webhook will only update existing attendants or create placeholder
88
+ // For new attendants, admin.createAttendant should be used
89
+ if (!email) {
90
+ throw new Error("Email is required for attendant");
91
+ }
92
+ // Check if there's an existing attendant record waiting for Clerk account
93
+ const existingByEmail = await ctx.db
94
+ .query("attendants")
95
+ .withIndex("by_email", (q) => q.eq("email", email))
96
+ .first();
97
+ if (existingByEmail) {
98
+ // Link Clerk account to existing attendant
99
+ await ctx.db.patch(existingByEmail._id, {
100
+ clerkUserId,
101
+ phoneNumber: phoneNumber || existingByEmail.phoneNumber,
102
+ name: name || existingByEmail.name,
103
+ lastLoginAt: now,
104
+ });
105
+ return existingByEmail._id;
106
+ }
107
+ // If no existing record, we can't create attendant without branch
108
+ // Log this case - admin should create attendant first
109
+ console.warn(`Attendant created in Clerk but no attendant record exists: ${email}`);
110
+ return null;
111
+ }
112
+ else if (type === "admin") {
113
+ // Check if admin already exists
114
+ const existing = await ctx.db
115
+ .query("admins")
116
+ .withIndex("by_clerk_user", (q) => q.eq("clerkUserId", clerkUserId))
117
+ .first();
118
+ if (existing) {
119
+ // Update existing admin
120
+ await ctx.db.patch(existing._id, {
121
+ clerkUserId,
122
+ email: email || existing.email,
123
+ name,
124
+ isDeleted: false,
125
+ lastLoginAt: now,
126
+ });
127
+ return existing._id;
128
+ }
129
+ // Note: Admins should be created by super admin first
130
+ // This webhook will only update existing admins
131
+ if (!email) {
132
+ throw new Error("Email is required for admin");
133
+ }
134
+ // Check if there's an existing admin record waiting for Clerk account
135
+ const existingByEmail = await ctx.db
136
+ .query("admins")
137
+ .withIndex("by_email", (q) => q.eq("email", email))
138
+ .first();
139
+ if (existingByEmail) {
140
+ // Link Clerk account to existing admin
141
+ await ctx.db.patch(existingByEmail._id, {
142
+ clerkUserId,
143
+ name: name || existingByEmail.name,
144
+ lastLoginAt: now,
145
+ });
146
+ return existingByEmail._id;
147
+ }
148
+ // If no existing record, we can't create admin without role
149
+ // Log this case - super admin should create admin first
150
+ console.warn(`Admin created in Clerk but no admin record exists: ${email}`);
151
+ return null;
152
+ }
153
+ throw new Error(`Unknown user type: ${type}`);
154
+ },
155
+ });
156
+ /**
157
+ * Sync user updated event from Clerk
158
+ */
159
+ export const syncUserUpdated = internalMutation({
160
+ args: {
161
+ clerkUserId: v.string(),
162
+ email: v.optional(v.string()),
163
+ phoneNumber: v.optional(v.string()),
164
+ name: v.string(),
165
+ emailVerified: v.boolean(),
166
+ userType: v.optional(v.union(v.literal("customer"), v.literal("attendant"), v.literal("admin"))),
167
+ },
168
+ handler: async (ctx, args) => {
169
+ const { clerkUserId, email, phoneNumber, name, emailVerified, userType } = args;
170
+ const now = getCurrentTimestamp();
171
+ // Try to find user in any table
172
+ const customer = await ctx.db
173
+ .query("users")
174
+ .withIndex("by_clerk_user", (q) => q.eq("clerkUserId", clerkUserId))
175
+ .first();
176
+ const attendant = await ctx.db
177
+ .query("attendants")
178
+ .withIndex("by_clerk_user", (q) => q.eq("clerkUserId", clerkUserId))
179
+ .first();
180
+ const admin = await ctx.db
181
+ .query("admins")
182
+ .withIndex("by_clerk_user", (q) => q.eq("clerkUserId", clerkUserId))
183
+ .first();
184
+ // Handle userType change - move user between tables if needed
185
+ if (userType === "admin" && customer && !customer.isDeleted && !admin) {
186
+ // User was a customer, now should be an admin
187
+ // Create admin record
188
+ if (!email) {
189
+ console.warn(`Cannot create admin without email: ${clerkUserId}`);
190
+ return null;
191
+ }
192
+ // Check if admin already exists by email
193
+ const existingAdminByEmail = await ctx.db
194
+ .query("admins")
195
+ .withIndex("by_email", (q) => q.eq("email", email))
196
+ .first();
197
+ if (existingAdminByEmail) {
198
+ // Link Clerk account to existing admin
199
+ await ctx.db.patch(existingAdminByEmail._id, {
200
+ clerkUserId,
201
+ name: name || existingAdminByEmail.name,
202
+ lastLoginAt: now,
203
+ });
204
+ // Mark customer as deleted
205
+ await ctx.db.patch(customer._id, {
206
+ isDeleted: true,
207
+ });
208
+ return { type: "admin", id: existingAdminByEmail._id };
209
+ }
210
+ // Create new admin record (default role is "admin", super_admin must be set manually)
211
+ const adminId = await ctx.db.insert("admins", {
212
+ clerkUserId,
213
+ email,
214
+ name,
215
+ role: "admin",
216
+ createdAt: now,
217
+ lastLoginAt: now,
218
+ isDeleted: false,
219
+ });
220
+ // Mark customer as deleted
221
+ await ctx.db.patch(customer._id, {
222
+ isDeleted: true,
223
+ });
224
+ return { type: "admin", id: adminId };
225
+ }
226
+ // Update existing records
227
+ if (customer && !customer.isDeleted) {
228
+ await ctx.db.patch(customer._id, {
229
+ email,
230
+ phoneNumber: phoneNumber || customer.phoneNumber,
231
+ name,
232
+ isVerified: emailVerified,
233
+ lastLoginAt: now,
234
+ });
235
+ return { type: "customer", id: customer._id };
236
+ }
237
+ if (attendant && !attendant.isDeleted) {
238
+ await ctx.db.patch(attendant._id, {
239
+ email: email || attendant.email,
240
+ phoneNumber: phoneNumber || attendant.phoneNumber,
241
+ name,
242
+ lastLoginAt: now,
243
+ });
244
+ return { type: "attendant", id: attendant._id };
245
+ }
246
+ if (admin && !admin.isDeleted) {
247
+ await ctx.db.patch(admin._id, {
248
+ email: email || admin.email,
249
+ name,
250
+ lastLoginAt: now,
251
+ });
252
+ return { type: "admin", id: admin._id };
253
+ }
254
+ // User not found - might be a new user, but we can't determine type
255
+ console.warn(`User updated in Clerk but not found in database: ${clerkUserId}`);
256
+ return null;
257
+ },
258
+ });
259
+ /**
260
+ * Sync user deleted event from Clerk
261
+ */
262
+ export const syncUserDeleted = internalMutation({
263
+ args: {
264
+ clerkUserId: v.string(),
265
+ },
266
+ handler: async (ctx, args) => {
267
+ const { clerkUserId } = args;
268
+ // Soft delete user in any table they might be in
269
+ // Check all tables in parallel
270
+ const [customer, attendant, admin] = await Promise.all([
271
+ ctx.db
272
+ .query("users")
273
+ .withIndex("by_clerk_user", (q) => q.eq("clerkUserId", clerkUserId))
274
+ .first(),
275
+ ctx.db
276
+ .query("attendants")
277
+ .withIndex("by_clerk_user", (q) => q.eq("clerkUserId", clerkUserId))
278
+ .first(),
279
+ ctx.db
280
+ .query("admins")
281
+ .withIndex("by_clerk_user", (q) => q.eq("clerkUserId", clerkUserId))
282
+ .first(),
283
+ ]);
284
+ // Soft delete customer (clerkUserId is optional, so we can clear it)
285
+ if (customer && !customer.isDeleted) {
286
+ await ctx.db.patch(customer._id, {
287
+ isDeleted: true,
288
+ clerkUserId: undefined, // Clear Clerk ID since it's optional
289
+ });
290
+ return { type: "customer", id: customer._id };
291
+ }
292
+ // Soft delete attendant (clerkUserId is required, so we keep it but mark as deleted)
293
+ if (attendant && !attendant.isDeleted) {
294
+ await ctx.db.patch(attendant._id, {
295
+ isDeleted: true,
296
+ isActive: false,
297
+ // Note: clerkUserId is required, so we can't clear it
298
+ // The record will remain but be marked as deleted
299
+ });
300
+ return { type: "attendant", id: attendant._id };
301
+ }
302
+ // Soft delete admin (clerkUserId is required, so we keep it but mark as deleted)
303
+ if (admin && !admin.isDeleted) {
304
+ await ctx.db.patch(admin._id, {
305
+ isDeleted: true,
306
+ // Note: clerkUserId is required, so we can't clear it
307
+ // The record will remain but be marked as deleted
308
+ });
309
+ return { type: "admin", id: admin._id };
310
+ }
311
+ // User not found - might have already been deleted
312
+ console.warn(`User deleted in Clerk but not found in database: ${clerkUserId}`);
313
+ return null;
314
+ },
315
+ });
316
+ //# sourceMappingURL=clerk.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"clerk.js","sourceRoot":"","sources":["../../convex/clerk.ts"],"names":[],"mappings":"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"}