@primocaredentgroup/elettromedicali 0.1.0 → 0.1.1

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 (150) hide show
  1. package/dist/client/index.d.ts +0 -2
  2. package/dist/client/index.d.ts.map +1 -1
  3. package/dist/client/index.js +2 -28
  4. package/dist/client/index.js.map +1 -1
  5. package/dist/component/_generated/api.d.ts +4 -4
  6. package/dist/component/_generated/api.d.ts.map +1 -1
  7. package/dist/component/_generated/component.d.ts +165 -218
  8. package/dist/component/_generated/component.d.ts.map +1 -1
  9. package/dist/component/contracts.d.ts +9 -9
  10. package/dist/component/contracts.d.ts.map +1 -1
  11. package/dist/component/contracts.js +7 -13
  12. package/dist/component/contracts.js.map +1 -1
  13. package/dist/component/crons.d.ts.map +1 -1
  14. package/dist/component/crons.js +1 -2
  15. package/dist/component/crons.js.map +1 -1
  16. package/dist/component/dashboardStats.d.ts +8 -3
  17. package/dist/component/dashboardStats.d.ts.map +1 -1
  18. package/dist/component/dashboardStats.js +24 -39
  19. package/dist/component/dashboardStats.js.map +1 -1
  20. package/dist/component/dashboardStatsCache.d.ts +5 -11
  21. package/dist/component/dashboardStatsCache.d.ts.map +1 -1
  22. package/dist/component/dashboardStatsCache.js +12 -53
  23. package/dist/component/dashboardStatsCache.js.map +1 -1
  24. package/dist/component/deviceCategories.d.ts +22 -15
  25. package/dist/component/deviceCategories.d.ts.map +1 -1
  26. package/dist/component/deviceCategories.js +10 -4
  27. package/dist/component/deviceCategories.js.map +1 -1
  28. package/dist/component/deviceQuestions.d.ts +36 -27
  29. package/dist/component/deviceQuestions.d.ts.map +1 -1
  30. package/dist/component/deviceQuestions.js +22 -5
  31. package/dist/component/deviceQuestions.js.map +1 -1
  32. package/dist/component/deviceRepairHistory.d.ts +3 -3
  33. package/dist/component/deviceRepairHistory.js +1 -1
  34. package/dist/component/deviceRepairHistory.js.map +1 -1
  35. package/dist/component/deviceStatus.d.ts +8 -57
  36. package/dist/component/deviceStatus.d.ts.map +1 -1
  37. package/dist/component/deviceStatus.js +32 -30
  38. package/dist/component/deviceStatus.js.map +1 -1
  39. package/dist/component/devices.d.ts +39 -22
  40. package/dist/component/devices.d.ts.map +1 -1
  41. package/dist/component/devices.js +85 -96
  42. package/dist/component/devices.js.map +1 -1
  43. package/dist/component/emailHelpers.d.ts +10 -3
  44. package/dist/component/emailHelpers.d.ts.map +1 -1
  45. package/dist/component/emailHelpers.js +9 -20
  46. package/dist/component/emailHelpers.js.map +1 -1
  47. package/dist/component/emails.d.ts +5 -5
  48. package/dist/component/emails.js +2 -2
  49. package/dist/component/emails.js.map +1 -1
  50. package/dist/component/http.d.ts.map +1 -1
  51. package/dist/component/http.js +3 -108
  52. package/dist/component/http.js.map +1 -1
  53. package/dist/component/migrationHelpers.d.ts +29 -0
  54. package/dist/component/migrationHelpers.d.ts.map +1 -0
  55. package/dist/component/migrationHelpers.js +84 -0
  56. package/dist/component/migrationHelpers.js.map +1 -0
  57. package/dist/component/roles.d.ts +1 -0
  58. package/dist/component/roles.d.ts.map +1 -1
  59. package/dist/component/roles.js +5 -6
  60. package/dist/component/roles.js.map +1 -1
  61. package/dist/component/schema.d.ts +69 -150
  62. package/dist/component/schema.d.ts.map +1 -1
  63. package/dist/component/schema.js +35 -88
  64. package/dist/component/schema.js.map +1 -1
  65. package/dist/component/slaMonitoring.d.ts +16 -30
  66. package/dist/component/slaMonitoring.d.ts.map +1 -1
  67. package/dist/component/slaMonitoring.js +48 -99
  68. package/dist/component/slaMonitoring.js.map +1 -1
  69. package/dist/component/spareParts.d.ts +11 -48
  70. package/dist/component/spareParts.d.ts.map +1 -1
  71. package/dist/component/spareParts.js +41 -11
  72. package/dist/component/spareParts.js.map +1 -1
  73. package/dist/component/suppliers.d.ts +38 -19
  74. package/dist/component/suppliers.d.ts.map +1 -1
  75. package/dist/component/suppliers.js +63 -44
  76. package/dist/component/suppliers.js.map +1 -1
  77. package/dist/component/ticketComments.d.ts +18 -12
  78. package/dist/component/ticketComments.d.ts.map +1 -1
  79. package/dist/component/ticketComments.js +28 -59
  80. package/dist/component/ticketComments.js.map +1 -1
  81. package/dist/component/ticketDeviceData.d.ts +63 -0
  82. package/dist/component/ticketDeviceData.d.ts.map +1 -0
  83. package/dist/component/ticketDeviceData.js +103 -0
  84. package/dist/component/ticketDeviceData.js.map +1 -0
  85. package/dist/component/ticketExport.d.ts +22 -40
  86. package/dist/component/ticketExport.d.ts.map +1 -1
  87. package/dist/component/ticketExport.js +43 -109
  88. package/dist/component/ticketExport.js.map +1 -1
  89. package/dist/component/ticketHistory.d.ts +4 -4
  90. package/dist/component/ticketHistory.d.ts.map +1 -1
  91. package/dist/component/ticketHistory.js +6 -9
  92. package/dist/component/ticketHistory.js.map +1 -1
  93. package/dist/component/ticketMacros.d.ts +19 -18
  94. package/dist/component/ticketMacros.d.ts.map +1 -1
  95. package/dist/component/ticketMacros.js +24 -30
  96. package/dist/component/ticketMacros.js.map +1 -1
  97. package/dist/component/ticketStatuses.d.ts +1 -0
  98. package/dist/component/ticketStatuses.d.ts.map +1 -1
  99. package/dist/component/ticketStatuses.js +5 -6
  100. package/dist/component/ticketStatuses.js.map +1 -1
  101. package/dist/component/ticketTriggers.d.ts +36 -16
  102. package/dist/component/ticketTriggers.d.ts.map +1 -1
  103. package/dist/component/ticketTriggers.js +115 -153
  104. package/dist/component/ticketTriggers.js.map +1 -1
  105. package/dist/component/userProfiles.d.ts +25 -120
  106. package/dist/component/userProfiles.d.ts.map +1 -1
  107. package/dist/component/userProfiles.js +73 -384
  108. package/dist/component/userProfiles.js.map +1 -1
  109. package/dist/test.d.ts +69 -150
  110. package/dist/test.d.ts.map +1 -1
  111. package/package.json +12 -3
  112. package/src/client/index.ts +2 -30
  113. package/src/component/_generated/api.ts +4 -4
  114. package/src/component/_generated/component.ts +228 -350
  115. package/src/component/contracts.ts +7 -14
  116. package/src/component/crons.ts +2 -7
  117. package/src/component/dashboardStats.ts +24 -41
  118. package/src/component/dashboardStatsCache.ts +12 -61
  119. package/src/component/deviceCategories.ts +12 -4
  120. package/src/component/deviceQuestions.ts +28 -5
  121. package/src/component/deviceRepairHistory.ts +1 -1
  122. package/src/component/deviceStatus.ts +43 -45
  123. package/src/component/devices.ts +87 -106
  124. package/src/component/emailHelpers.ts +9 -19
  125. package/src/component/emails.ts +2 -2
  126. package/src/component/http.ts +3 -108
  127. package/src/component/migrationHelpers.ts +96 -0
  128. package/src/component/roles.ts +5 -6
  129. package/src/component/schema.ts +35 -93
  130. package/src/component/slaMonitoring.ts +52 -107
  131. package/src/component/spareParts.ts +46 -12
  132. package/src/component/suppliers.ts +71 -48
  133. package/src/component/ticketComments.ts +28 -71
  134. package/src/component/ticketDeviceData.ts +113 -0
  135. package/src/component/ticketExport.ts +52 -137
  136. package/src/component/ticketHistory.ts +6 -9
  137. package/src/component/ticketMacros.ts +25 -37
  138. package/src/component/ticketStatuses.ts +5 -6
  139. package/src/component/ticketTriggers.ts +121 -217
  140. package/src/component/userProfiles.ts +67 -451
  141. package/dist/component/clinics.d.ts +0 -103
  142. package/dist/component/clinics.d.ts.map +0 -1
  143. package/dist/component/clinics.js +0 -126
  144. package/dist/component/clinics.js.map +0 -1
  145. package/dist/component/maintenanceTasks.d.ts +0 -733
  146. package/dist/component/maintenanceTasks.d.ts.map +0 -1
  147. package/dist/component/maintenanceTasks.js +0 -937
  148. package/dist/component/maintenanceTasks.js.map +0 -1
  149. package/src/component/clinics.ts +0 -136
  150. package/src/component/maintenanceTasks.ts +0 -1003
@@ -1,319 +1,129 @@
1
1
  import { v } from 'convex/values';
2
2
  import { query, mutation } from './_generated/server';
3
- import { paginationOptsValidator } from 'convex/server';
4
3
 
5
4
  export const getUserProfile = query({
6
5
  args: { auth0Id: v.string() },
7
6
  handler: async (ctx, args) => {
8
- const profile = await ctx.db
7
+ return await ctx.db
9
8
  .query('user_profiles')
10
9
  .withIndex('by_auth0Id', (q) => q.eq('auth0Id', args.auth0Id))
11
10
  .first();
12
-
13
- return profile;
14
11
  },
15
12
  });
16
13
 
17
14
  export const getCurrentUserProfile = query({
18
- args: { auth0Id: v.string() },
15
+ args: {
16
+ auth0Id: v.string(),
17
+ userName: v.optional(v.string()),
18
+ userEmail: v.optional(v.string()),
19
+ userRole: v.optional(v.string()),
20
+ userIsActive: v.optional(v.boolean()),
21
+ },
19
22
  handler: async (ctx, args) => {
20
- const realProfile = await ctx.db
23
+ const settings = await ctx.db
21
24
  .query('user_profiles')
22
25
  .withIndex('by_auth0Id', (q) => q.eq('auth0Id', args.auth0Id))
23
26
  .first();
24
27
 
25
- if (!realProfile) {
28
+ if (!settings) {
26
29
  return null;
27
30
  }
28
31
 
29
- if (realProfile.isActive === false) {
32
+ if (args.userIsActive === false) {
30
33
  return {
31
- ...realProfile,
34
+ ...settings,
35
+ name: args.userName,
36
+ email: args.userEmail,
32
37
  role: null,
33
38
  isDisabled: true,
34
39
  isImpersonating: false,
35
40
  };
36
41
  }
37
42
 
38
- const realRole = realProfile.roleId ? await ctx.db.get(realProfile.roleId) : null;
39
- const isAdmin = realRole?.name === 'admin';
43
+ const isAdmin = args.userRole === 'admin';
40
44
 
41
- if (isAdmin && realProfile.impersonatingUserId) {
42
- const impersonatedProfile = await ctx.db.get(realProfile.impersonatingUserId);
43
-
44
- if (impersonatedProfile) {
45
- const impersonatedRole = impersonatedProfile.roleId
46
- ? await ctx.db.get(impersonatedProfile.roleId)
47
- : null;
45
+ if (isAdmin && settings.impersonatingUserId) {
46
+ const impersonatedSettings = await ctx.db
47
+ .query('user_profiles')
48
+ .withIndex('by_auth0Id', (q) => q.eq('auth0Id', settings.impersonatingUserId!))
49
+ .first();
48
50
 
51
+ if (impersonatedSettings) {
49
52
  return {
50
- ...impersonatedProfile,
51
- role: impersonatedRole?.name,
53
+ ...impersonatedSettings,
54
+ role: undefined,
52
55
  isImpersonating: true,
53
- realAdminId: realProfile._id,
54
- realAdminName: realProfile.name || realProfile.email,
55
- realAdminEmail: realProfile.email,
56
+ realAdminId: settings._id,
57
+ realAdminName: args.userName,
58
+ realAdminEmail: args.userEmail,
56
59
  isDisabled: false,
57
60
  };
58
61
  }
59
62
  }
60
63
 
61
64
  return {
62
- ...realProfile,
63
- role: realRole?.name,
65
+ ...settings,
66
+ name: args.userName,
67
+ email: args.userEmail,
68
+ role: args.userRole,
64
69
  isImpersonating: false,
65
70
  isDisabled: false,
66
71
  };
67
72
  },
68
73
  });
69
74
 
70
- function isPlaceholderAuth0Id(auth0Id: string): boolean {
71
- return auth0Id.startsWith('placeholder_') ||
72
- auth0Id.startsWith('manual_') ||
73
- !auth0Id.includes('|');
74
- }
75
-
76
75
  export const upsertUserProfile = mutation({
77
76
  args: {
78
77
  auth0Id: v.string(),
79
- email: v.string(),
80
- name: v.optional(v.string()),
81
- roleName: v.optional(v.string()),
82
- clinicId: v.optional(v.id('clinics')),
78
+ clinicId: v.optional(v.string()),
83
79
  supplierId: v.optional(v.id('suppliers')),
84
80
  },
85
81
  handler: async (ctx, args) => {
86
- let existing = await ctx.db
82
+ const existing = await ctx.db
87
83
  .query('user_profiles')
88
84
  .withIndex('by_auth0Id', (q) => q.eq('auth0Id', args.auth0Id))
89
85
  .first();
90
86
 
91
- let shouldUpdateAuth0Id = false;
92
- if (!existing) {
93
- const existingByEmail = await ctx.db
94
- .query('user_profiles')
95
- .withIndex('by_email', (q) => q.eq('email', args.email))
96
- .first();
97
-
98
- if (existingByEmail && isPlaceholderAuth0Id(existingByEmail.auth0Id)) {
99
- existing = existingByEmail;
100
- shouldUpdateAuth0Id = true;
101
- console.log(`🔄 Found pre-created user with email ${args.email}, updating auth0Id from placeholder to real Auth0 ID`);
102
- }
103
- }
104
-
105
- let roleId = existing?.roleId;
106
- if (args.roleName || !roleId) {
107
- const roleName = args.roleName || 'user';
108
- let role = await ctx.db
109
- .query('roles')
110
- .withIndex('by_name', (q) => q.eq('name', roleName))
111
- .first();
112
-
113
- if (!role) {
114
- const newRoleId = await ctx.db.insert('roles', {
115
- name: roleName,
116
- description: roleName === 'admin' ? 'Administrator with full access' :
117
- roleName === 'user' ? 'Standard user with limited access' :
118
- roleName === 'supplier' ? 'Supplier with access to assigned tickets' :
119
- `${roleName} role`,
120
- createdAt: Date.now(),
121
- });
122
- role = await ctx.db.get(newRoleId);
123
- }
124
-
125
- if (role) {
126
- roleId = role._id;
127
- }
128
- }
129
-
130
87
  if (existing) {
131
- const updateData: any = {
132
- email: args.email,
133
- name: args.name,
134
- ...(args.clinicId && { clinicId: args.clinicId }),
135
- ...(args.supplierId && { supplierId: args.supplierId }),
136
- };
137
-
138
- if (shouldUpdateAuth0Id) {
139
- updateData.auth0Id = args.auth0Id;
140
- console.log(`✅ Updated auth0Id for user ${args.email}`);
141
- }
142
-
143
- if (roleId) {
144
- updateData.roleId = roleId;
88
+ const updateData: any = {};
89
+ if (args.clinicId !== undefined) updateData.clinicId = args.clinicId;
90
+ if (args.supplierId !== undefined) updateData.supplierId = args.supplierId;
91
+ if (Object.keys(updateData).length > 0) {
92
+ await ctx.db.patch(existing._id, updateData);
145
93
  }
146
- await ctx.db.patch(existing._id, updateData);
147
94
  return existing._id;
148
95
  } else {
149
- const newProfile: any = {
96
+ const profileId = await ctx.db.insert('user_profiles', {
150
97
  auth0Id: args.auth0Id,
151
- email: args.email,
152
- name: args.name,
153
98
  ...(args.clinicId && { clinicId: args.clinicId }),
154
99
  ...(args.supplierId && { supplierId: args.supplierId }),
155
- };
156
- if (roleId) {
157
- newProfile.roleId = roleId;
158
- }
159
- const profileId = await ctx.db.insert('user_profiles', newProfile);
100
+ });
160
101
  return profileId;
161
102
  }
162
103
  },
163
104
  });
164
105
 
165
- export const updateUserRole = mutation({
166
- args: {
167
- userId: v.id('user_profiles'),
168
- roleName: v.string(),
169
- clinicId: v.optional(v.id('clinics')),
170
- supplierId: v.optional(v.id('suppliers')),
171
- },
172
- handler: async (ctx, args) => {
173
- const newRole = await ctx.db
174
- .query('roles')
175
- .withIndex('by_name', (q) => q.eq('name', args.roleName))
176
- .first();
177
-
178
- if (!newRole) {
179
- throw new Error(`Role ${args.roleName} not found`);
180
- }
181
-
182
- await ctx.db.patch(args.userId, {
183
- roleId: newRole._id,
184
- ...(args.clinicId !== undefined && { clinicId: args.clinicId }),
185
- ...(args.supplierId !== undefined && { supplierId: args.supplierId }),
186
- });
187
-
188
- return args.userId;
189
- },
190
- });
191
-
192
106
  export const updateUserSupplier = mutation({
193
107
  args: {
194
- userId: v.id('user_profiles'),
108
+ userId: v.string(),
195
109
  supplierId: v.id('suppliers'),
196
110
  },
197
111
  handler: async (ctx, args) => {
198
- await ctx.db.patch(args.userId, {
199
- supplierId: args.supplierId,
200
- });
201
-
202
- return args.userId;
112
+ const profile = await ctx.db
113
+ .query('user_profiles')
114
+ .withIndex('by_auth0Id', (q) => q.eq('auth0Id', args.userId))
115
+ .first();
116
+ if (!profile) throw new Error('User settings not found');
117
+ await ctx.db.patch(profile._id, { supplierId: args.supplierId });
118
+ return profile._id;
203
119
  },
204
120
  });
205
121
 
206
122
  export const listUsers = query({
207
- args: {
208
- limit: v.optional(v.number()),
209
- },
123
+ args: { limit: v.optional(v.number()) },
210
124
  handler: async (ctx, args) => {
211
125
  const maxResults = args.limit || 500;
212
- const users = await ctx.db.query('user_profiles').order('desc').take(maxResults);
213
-
214
- const usersWithRoles = await Promise.all(
215
- users.map(async (user) => {
216
- const role = user.roleId ? await ctx.db.get(user.roleId) : null;
217
- return {
218
- ...user,
219
- role: role?.name || user.role,
220
- };
221
- })
222
- );
223
-
224
- return usersWithRoles;
225
- },
226
- });
227
-
228
- export const listUsersPaginated = query({
229
- args: {
230
- paginationOpts: paginationOptsValidator,
231
- roleId: v.optional(v.id('roles')),
232
- isActive: v.optional(v.boolean()),
233
- searchTerm: v.optional(v.string()),
234
- },
235
- handler: async (ctx, args) => {
236
- let baseQuery;
237
-
238
- if (args.roleId) {
239
- baseQuery = ctx.db
240
- .query('user_profiles')
241
- .withIndex('by_roleId', (q: any) => q.eq('roleId', args.roleId));
242
- } else if (args.isActive !== undefined) {
243
- baseQuery = ctx.db
244
- .query('user_profiles')
245
- .withIndex('by_isActive', (q: any) => q.eq('isActive', args.isActive));
246
- } else {
247
- baseQuery = ctx.db.query('user_profiles');
248
- }
249
-
250
- let filteredQuery = baseQuery.order('desc');
251
-
252
- if (args.isActive !== undefined && args.roleId) {
253
- filteredQuery = filteredQuery.filter((q: any) => q.eq(q.field('isActive'), args.isActive));
254
- }
255
-
256
- const result = await filteredQuery.paginate(args.paginationOpts);
257
-
258
- let filteredPage = result.page;
259
-
260
- if (args.searchTerm) {
261
- const search = args.searchTerm.toLowerCase();
262
- filteredPage = filteredPage.filter((user: any) =>
263
- user.name?.toLowerCase().includes(search) ||
264
- user.email?.toLowerCase().includes(search)
265
- );
266
- }
267
-
268
- const roleIds = [...new Set(filteredPage.map((u: any) => u.roleId).filter(Boolean))];
269
- const roles = await Promise.all(roleIds.map(id => ctx.db.get(id)));
270
- const roleMap = new Map(roles.filter(Boolean).map((r: any) => [r._id.toString(), r.name]));
271
-
272
- const minimalPage = filteredPage.map((user: any) => ({
273
- _id: user._id,
274
- auth0Id: user.auth0Id,
275
- email: user.email,
276
- name: user.name,
277
- roleId: user.roleId,
278
- role: roleMap.get(user.roleId?.toString()) || user.role || 'user',
279
- isActive: user.isActive,
280
- clinicId: user.clinicId,
281
- supplierId: user.supplierId,
282
- createdAt: user.createdAt || user._creationTime,
283
- }));
284
-
285
- return {
286
- page: minimalPage,
287
- isDone: result.isDone,
288
- continueCursor: result.continueCursor,
289
- };
290
- },
291
- });
292
-
293
- export const getUsersCount = query({
294
- args: {
295
- roleId: v.optional(v.id('roles')),
296
- isActive: v.optional(v.boolean()),
297
- },
298
- handler: async (ctx, args) => {
299
- let query;
300
-
301
- if (args.roleId) {
302
- query = ctx.db.query('user_profiles')
303
- .withIndex('by_roleId', (q: any) => q.eq('roleId', args.roleId));
304
- } else if (args.isActive !== undefined) {
305
- query = ctx.db.query('user_profiles')
306
- .withIndex('by_isActive', (q: any) => q.eq('isActive', args.isActive));
307
- } else {
308
- query = ctx.db.query('user_profiles');
309
- }
310
-
311
- if (args.isActive !== undefined && args.roleId) {
312
- query = query.filter((q: any) => q.eq(q.field('isActive'), args.isActive));
313
- }
314
-
315
- const users = await query.take(1000);
316
- return { total: users.length };
126
+ return await ctx.db.query('user_profiles').order('desc').take(maxResults);
317
127
  },
318
128
  });
319
129
 
@@ -364,9 +174,7 @@ export const getPrimoUPToken = query({
364
174
  )
365
175
  .first();
366
176
 
367
- if (!activeToken) {
368
- return null;
369
- }
177
+ if (!activeToken) return null;
370
178
 
371
179
  if (activeToken.expiresAt && activeToken.expiresAt < Date.now()) {
372
180
  return {
@@ -404,7 +212,6 @@ export const logPrimoUPAccess = mutation({
404
212
  timestamp: Date.now(),
405
213
  metadata: args.metadata,
406
214
  });
407
-
408
215
  return { success: true };
409
216
  },
410
217
  });
@@ -418,51 +225,11 @@ export const getPrimoUPAccessLogs = query({
418
225
  },
419
226
  handler: async (ctx, args) => {
420
227
  const targetUserId = args.isAdmin && args.userId ? args.userId : args.auth0Id;
421
-
422
- const logs = await ctx.db
228
+ return await ctx.db
423
229
  .query('primoup_access_logs')
424
230
  .withIndex('by_userId_timestamp', (q) => q.eq('userId', targetUserId))
425
231
  .order('desc')
426
232
  .take(args.limit || 50);
427
-
428
- return logs;
429
- },
430
- });
431
-
432
- export const updateUserRoleByEmail = mutation({
433
- args: {
434
- email: v.string(),
435
- roleName: v.string(),
436
- },
437
- handler: async (ctx, args) => {
438
- const user = await ctx.db
439
- .query('user_profiles')
440
- .filter((q) => q.eq(q.field('email'), args.email))
441
- .first();
442
-
443
- if (!user) {
444
- throw new Error(`User with email ${args.email} not found`);
445
- }
446
-
447
- const role = await ctx.db
448
- .query('roles')
449
- .withIndex('by_name', (q) => q.eq('name', args.roleName))
450
- .first();
451
-
452
- if (!role) {
453
- throw new Error(`Role ${args.roleName} not found`);
454
- }
455
-
456
- await ctx.db.patch(user._id, {
457
- roleId: role._id,
458
- });
459
-
460
- return {
461
- success: true,
462
- userId: user._id,
463
- email: user.email,
464
- newRole: args.roleName,
465
- };
466
233
  },
467
234
  });
468
235
 
@@ -477,9 +244,7 @@ export const saveUserClinics = mutation({
477
244
  .withIndex('by_auth0Id', (q) => q.eq('auth0Id', args.auth0Id))
478
245
  .first();
479
246
 
480
- if (!profile) {
481
- throw new Error('User profile not found');
482
- }
247
+ if (!profile) throw new Error('User settings not found');
483
248
 
484
249
  const optimizedClinics = args.primoupClinics.map((clinic: any) => ({
485
250
  id: clinic.id,
@@ -509,41 +274,20 @@ export const updateSelectedClinic = mutation({
509
274
  .withIndex('by_auth0Id', (q) => q.eq('auth0Id', args.auth0Id))
510
275
  .first();
511
276
 
512
- if (!profile) {
513
- throw new Error('User profile not found');
514
- }
277
+ if (!profile) throw new Error('User settings not found');
515
278
 
516
279
  if (profile.primoupClinics) {
517
280
  const hasClinic = profile.primoupClinics.some((clinic: any) => clinic.id === args.clinicId);
518
- if (!hasClinic) {
519
- throw new Error('Clinic not found in user clinics');
520
- }
281
+ if (!hasClinic) throw new Error('Clinic not found in user clinics');
521
282
  }
522
283
 
523
- const clinic = await ctx.db
524
- .query('clinics')
525
- .withIndex('by_primoupId', (q) => q.eq('primoupId', args.clinicId.toString()))
526
- .first();
527
-
528
- if (!clinic) {
529
- console.warn(`⚠️ Clinic NOT FOUND in Convex with primoupId: ${args.clinicId}`);
530
- const newCounter = (profile.clinicChangeCounter || 0) + 1;
531
- await ctx.db.patch(profile._id, {
532
- selectedClinicId: args.clinicId,
533
- clinicId: undefined,
534
- clinicChangeCounter: newCounter,
535
- });
536
- return profile._id;
537
- }
538
-
539
284
  const newCounter = (profile.clinicChangeCounter || 0) + 1;
540
-
285
+
541
286
  await ctx.db.patch(profile._id, {
542
287
  selectedClinicId: args.clinicId,
543
- clinicId: clinic._id,
544
288
  clinicChangeCounter: newCounter,
545
289
  });
546
-
290
+
547
291
  return profile._id;
548
292
  },
549
293
  });
@@ -551,7 +295,7 @@ export const updateSelectedClinic = mutation({
551
295
  export const startImpersonation = mutation({
552
296
  args: {
553
297
  auth0Id: v.string(),
554
- targetUserId: v.id('user_profiles'),
298
+ targetUserAuth0Id: v.string(),
555
299
  },
556
300
  handler: async (ctx, args) => {
557
301
  const currentUser = await ctx.db
@@ -559,36 +303,24 @@ export const startImpersonation = mutation({
559
303
  .withIndex('by_auth0Id', (q) => q.eq('auth0Id', args.auth0Id))
560
304
  .first();
561
305
 
562
- if (!currentUser) {
563
- throw new Error('User profile not found');
564
- }
306
+ if (!currentUser) throw new Error('User settings not found');
565
307
 
566
- const currentRole = currentUser.roleId ? await ctx.db.get(currentUser.roleId) : null;
567
- if (!currentRole || currentRole.name !== 'admin') {
568
- throw new Error('Solo gli amministratori possono impersonare altri utenti');
569
- }
308
+ const targetUser = await ctx.db
309
+ .query('user_profiles')
310
+ .withIndex('by_auth0Id', (q) => q.eq('auth0Id', args.targetUserAuth0Id))
311
+ .first();
570
312
 
571
- const targetUser = await ctx.db.get(args.targetUserId);
572
- if (!targetUser) {
573
- throw new Error('Utente target non trovato');
574
- }
313
+ if (!targetUser) throw new Error('Target user settings not found');
575
314
 
576
315
  if (targetUser._id === currentUser._id) {
577
316
  throw new Error('Non puoi impersonare te stesso');
578
317
  }
579
318
 
580
319
  await ctx.db.patch(currentUser._id, {
581
- impersonatingUserId: args.targetUserId,
320
+ impersonatingUserId: args.targetUserAuth0Id,
582
321
  });
583
322
 
584
- return {
585
- success: true,
586
- impersonatedUser: {
587
- id: targetUser._id,
588
- name: targetUser.name,
589
- email: targetUser.email,
590
- },
591
- };
323
+ return { success: true };
592
324
  },
593
325
  });
594
326
 
@@ -600,14 +332,7 @@ export const stopImpersonation = mutation({
600
332
  .withIndex('by_auth0Id', (q) => q.eq('auth0Id', args.auth0Id))
601
333
  .first();
602
334
 
603
- if (!currentUser) {
604
- throw new Error('User profile not found');
605
- }
606
-
607
- const currentRole = currentUser.roleId ? await ctx.db.get(currentUser.roleId) : null;
608
- if (!currentRole || currentRole.name !== 'admin') {
609
- throw new Error('Solo gli amministratori possono terminare l\'impersonazione');
610
- }
335
+ if (!currentUser) throw new Error('User settings not found');
611
336
 
612
337
  await ctx.db.patch(currentUser._id, {
613
338
  impersonatingUserId: undefined,
@@ -617,108 +342,6 @@ export const stopImpersonation = mutation({
617
342
  },
618
343
  });
619
344
 
620
- export const updateUserProfile = mutation({
621
- args: {
622
- userId: v.id('user_profiles'),
623
- name: v.optional(v.string()),
624
- email: v.optional(v.string()),
625
- roleName: v.optional(v.string()),
626
- clinicId: v.optional(v.id('clinics')),
627
- supplierId: v.optional(v.id('suppliers')),
628
- },
629
- handler: async (ctx, args) => {
630
- const targetUser = await ctx.db.get(args.userId);
631
- if (!targetUser) {
632
- throw new Error('Target user not found');
633
- }
634
-
635
- const updateData: Record<string, any> = {};
636
-
637
- if (args.name !== undefined) {
638
- updateData.name = args.name;
639
- }
640
-
641
- if (args.email !== undefined) {
642
- const existingUser = await ctx.db
643
- .query('user_profiles')
644
- .withIndex('by_email', (q) => q.eq('email', args.email!))
645
- .first();
646
-
647
- if (existingUser && existingUser._id !== args.userId) {
648
- throw new Error('Email già in uso da un altro utente');
649
- }
650
- updateData.email = args.email;
651
- }
652
-
653
- if (args.roleName !== undefined) {
654
- const newRole = await ctx.db
655
- .query('roles')
656
- .withIndex('by_name', (q) => q.eq('name', args.roleName!))
657
- .first();
658
-
659
- if (!newRole) {
660
- throw new Error(`Ruolo ${args.roleName} non trovato`);
661
- }
662
- updateData.roleId = newRole._id;
663
- }
664
-
665
- if (args.clinicId !== undefined) {
666
- updateData.clinicId = args.clinicId;
667
- }
668
-
669
- if (args.supplierId !== undefined) {
670
- updateData.supplierId = args.supplierId;
671
- }
672
-
673
- if (Object.keys(updateData).length > 0) {
674
- await ctx.db.patch(args.userId, updateData);
675
- }
676
-
677
- return args.userId;
678
- },
679
- });
680
-
681
- export const disableUser = mutation({
682
- args: {
683
- userId: v.id('user_profiles'),
684
- callerUserId: v.optional(v.id('user_profiles')),
685
- },
686
- handler: async (ctx, args) => {
687
- if (args.callerUserId && args.userId === args.callerUserId) {
688
- throw new Error('Non puoi disabilitare te stesso');
689
- }
690
-
691
- const targetUser = await ctx.db.get(args.userId);
692
- if (!targetUser) {
693
- throw new Error('Utente non trovato');
694
- }
695
-
696
- await ctx.db.patch(args.userId, {
697
- isActive: false,
698
- });
699
-
700
- return { success: true, userId: args.userId };
701
- },
702
- });
703
-
704
- export const enableUser = mutation({
705
- args: {
706
- userId: v.id('user_profiles'),
707
- },
708
- handler: async (ctx, args) => {
709
- const targetUser = await ctx.db.get(args.userId);
710
- if (!targetUser) {
711
- throw new Error('Utente non trovato');
712
- }
713
-
714
- await ctx.db.patch(args.userId, {
715
- isActive: true,
716
- });
717
-
718
- return { success: true, userId: args.userId };
719
- },
720
- });
721
-
722
345
  export const getRealAdminProfile = query({
723
346
  args: { auth0Id: v.string() },
724
347
  handler: async (ctx, args) => {
@@ -727,17 +350,10 @@ export const getRealAdminProfile = query({
727
350
  .withIndex('by_auth0Id', (q) => q.eq('auth0Id', args.auth0Id))
728
351
  .first();
729
352
 
730
- if (!profile) {
731
- return null;
732
- }
353
+ if (!profile) return null;
733
354
 
734
- const role = profile.roleId ? await ctx.db.get(profile.roleId) : null;
735
-
736
355
  return {
737
356
  _id: profile._id,
738
- name: profile.name,
739
- email: profile.email,
740
- role: role?.name,
741
357
  isImpersonating: !!profile.impersonatingUserId,
742
358
  impersonatingUserId: profile.impersonatingUserId,
743
359
  };