@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,277 +1,121 @@
1
1
  import { v } from 'convex/values';
2
2
  import { query, mutation } from './_generated/server';
3
- import { paginationOptsValidator } from 'convex/server';
4
3
  export const getUserProfile = query({
5
4
  args: { auth0Id: v.string() },
6
5
  handler: async (ctx, args) => {
7
- const profile = await ctx.db
6
+ return await ctx.db
8
7
  .query('user_profiles')
9
8
  .withIndex('by_auth0Id', (q) => q.eq('auth0Id', args.auth0Id))
10
9
  .first();
11
- return profile;
12
10
  },
13
11
  });
14
12
  export const getCurrentUserProfile = query({
15
- args: { auth0Id: v.string() },
13
+ args: {
14
+ auth0Id: v.string(),
15
+ userName: v.optional(v.string()),
16
+ userEmail: v.optional(v.string()),
17
+ userRole: v.optional(v.string()),
18
+ userIsActive: v.optional(v.boolean()),
19
+ },
16
20
  handler: async (ctx, args) => {
17
- const realProfile = await ctx.db
21
+ const settings = await ctx.db
18
22
  .query('user_profiles')
19
23
  .withIndex('by_auth0Id', (q) => q.eq('auth0Id', args.auth0Id))
20
24
  .first();
21
- if (!realProfile) {
25
+ if (!settings) {
22
26
  return null;
23
27
  }
24
- if (realProfile.isActive === false) {
28
+ if (args.userIsActive === false) {
25
29
  return {
26
- ...realProfile,
30
+ ...settings,
31
+ name: args.userName,
32
+ email: args.userEmail,
27
33
  role: null,
28
34
  isDisabled: true,
29
35
  isImpersonating: false,
30
36
  };
31
37
  }
32
- const realRole = realProfile.roleId ? await ctx.db.get(realProfile.roleId) : null;
33
- const isAdmin = realRole?.name === 'admin';
34
- if (isAdmin && realProfile.impersonatingUserId) {
35
- const impersonatedProfile = await ctx.db.get(realProfile.impersonatingUserId);
36
- if (impersonatedProfile) {
37
- const impersonatedRole = impersonatedProfile.roleId
38
- ? await ctx.db.get(impersonatedProfile.roleId)
39
- : null;
38
+ const isAdmin = args.userRole === 'admin';
39
+ if (isAdmin && settings.impersonatingUserId) {
40
+ const impersonatedSettings = await ctx.db
41
+ .query('user_profiles')
42
+ .withIndex('by_auth0Id', (q) => q.eq('auth0Id', settings.impersonatingUserId))
43
+ .first();
44
+ if (impersonatedSettings) {
40
45
  return {
41
- ...impersonatedProfile,
42
- role: impersonatedRole?.name,
46
+ ...impersonatedSettings,
47
+ role: undefined,
43
48
  isImpersonating: true,
44
- realAdminId: realProfile._id,
45
- realAdminName: realProfile.name || realProfile.email,
46
- realAdminEmail: realProfile.email,
49
+ realAdminId: settings._id,
50
+ realAdminName: args.userName,
51
+ realAdminEmail: args.userEmail,
47
52
  isDisabled: false,
48
53
  };
49
54
  }
50
55
  }
51
56
  return {
52
- ...realProfile,
53
- role: realRole?.name,
57
+ ...settings,
58
+ name: args.userName,
59
+ email: args.userEmail,
60
+ role: args.userRole,
54
61
  isImpersonating: false,
55
62
  isDisabled: false,
56
63
  };
57
64
  },
58
65
  });
59
- function isPlaceholderAuth0Id(auth0Id) {
60
- return auth0Id.startsWith('placeholder_') ||
61
- auth0Id.startsWith('manual_') ||
62
- !auth0Id.includes('|');
63
- }
64
66
  export const upsertUserProfile = mutation({
65
67
  args: {
66
68
  auth0Id: v.string(),
67
- email: v.string(),
68
- name: v.optional(v.string()),
69
- roleName: v.optional(v.string()),
70
- clinicId: v.optional(v.id('clinics')),
69
+ clinicId: v.optional(v.string()),
71
70
  supplierId: v.optional(v.id('suppliers')),
72
71
  },
73
72
  handler: async (ctx, args) => {
74
- let existing = await ctx.db
73
+ const existing = await ctx.db
75
74
  .query('user_profiles')
76
75
  .withIndex('by_auth0Id', (q) => q.eq('auth0Id', args.auth0Id))
77
76
  .first();
78
- let shouldUpdateAuth0Id = false;
79
- if (!existing) {
80
- const existingByEmail = await ctx.db
81
- .query('user_profiles')
82
- .withIndex('by_email', (q) => q.eq('email', args.email))
83
- .first();
84
- if (existingByEmail && isPlaceholderAuth0Id(existingByEmail.auth0Id)) {
85
- existing = existingByEmail;
86
- shouldUpdateAuth0Id = true;
87
- console.log(`🔄 Found pre-created user with email ${args.email}, updating auth0Id from placeholder to real Auth0 ID`);
88
- }
89
- }
90
- let roleId = existing?.roleId;
91
- if (args.roleName || !roleId) {
92
- const roleName = args.roleName || 'user';
93
- let role = await ctx.db
94
- .query('roles')
95
- .withIndex('by_name', (q) => q.eq('name', roleName))
96
- .first();
97
- if (!role) {
98
- const newRoleId = await ctx.db.insert('roles', {
99
- name: roleName,
100
- description: roleName === 'admin' ? 'Administrator with full access' :
101
- roleName === 'user' ? 'Standard user with limited access' :
102
- roleName === 'supplier' ? 'Supplier with access to assigned tickets' :
103
- `${roleName} role`,
104
- createdAt: Date.now(),
105
- });
106
- role = await ctx.db.get(newRoleId);
107
- }
108
- if (role) {
109
- roleId = role._id;
110
- }
111
- }
112
77
  if (existing) {
113
- const updateData = {
114
- email: args.email,
115
- name: args.name,
116
- ...(args.clinicId && { clinicId: args.clinicId }),
117
- ...(args.supplierId && { supplierId: args.supplierId }),
118
- };
119
- if (shouldUpdateAuth0Id) {
120
- updateData.auth0Id = args.auth0Id;
121
- console.log(`✅ Updated auth0Id for user ${args.email}`);
122
- }
123
- if (roleId) {
124
- updateData.roleId = roleId;
78
+ const updateData = {};
79
+ if (args.clinicId !== undefined)
80
+ updateData.clinicId = args.clinicId;
81
+ if (args.supplierId !== undefined)
82
+ updateData.supplierId = args.supplierId;
83
+ if (Object.keys(updateData).length > 0) {
84
+ await ctx.db.patch(existing._id, updateData);
125
85
  }
126
- await ctx.db.patch(existing._id, updateData);
127
86
  return existing._id;
128
87
  }
129
88
  else {
130
- const newProfile = {
89
+ const profileId = await ctx.db.insert('user_profiles', {
131
90
  auth0Id: args.auth0Id,
132
- email: args.email,
133
- name: args.name,
134
91
  ...(args.clinicId && { clinicId: args.clinicId }),
135
92
  ...(args.supplierId && { supplierId: args.supplierId }),
136
- };
137
- if (roleId) {
138
- newProfile.roleId = roleId;
139
- }
140
- const profileId = await ctx.db.insert('user_profiles', newProfile);
93
+ });
141
94
  return profileId;
142
95
  }
143
96
  },
144
97
  });
145
- export const updateUserRole = mutation({
146
- args: {
147
- userId: v.id('user_profiles'),
148
- roleName: v.string(),
149
- clinicId: v.optional(v.id('clinics')),
150
- supplierId: v.optional(v.id('suppliers')),
151
- },
152
- handler: async (ctx, args) => {
153
- const newRole = await ctx.db
154
- .query('roles')
155
- .withIndex('by_name', (q) => q.eq('name', args.roleName))
156
- .first();
157
- if (!newRole) {
158
- throw new Error(`Role ${args.roleName} not found`);
159
- }
160
- await ctx.db.patch(args.userId, {
161
- roleId: newRole._id,
162
- ...(args.clinicId !== undefined && { clinicId: args.clinicId }),
163
- ...(args.supplierId !== undefined && { supplierId: args.supplierId }),
164
- });
165
- return args.userId;
166
- },
167
- });
168
98
  export const updateUserSupplier = mutation({
169
99
  args: {
170
- userId: v.id('user_profiles'),
100
+ userId: v.string(),
171
101
  supplierId: v.id('suppliers'),
172
102
  },
173
103
  handler: async (ctx, args) => {
174
- await ctx.db.patch(args.userId, {
175
- supplierId: args.supplierId,
176
- });
177
- return args.userId;
104
+ const profile = await ctx.db
105
+ .query('user_profiles')
106
+ .withIndex('by_auth0Id', (q) => q.eq('auth0Id', args.userId))
107
+ .first();
108
+ if (!profile)
109
+ throw new Error('User settings not found');
110
+ await ctx.db.patch(profile._id, { supplierId: args.supplierId });
111
+ return profile._id;
178
112
  },
179
113
  });
180
114
  export const listUsers = query({
181
- args: {
182
- limit: v.optional(v.number()),
183
- },
115
+ args: { limit: v.optional(v.number()) },
184
116
  handler: async (ctx, args) => {
185
117
  const maxResults = args.limit || 500;
186
- const users = await ctx.db.query('user_profiles').order('desc').take(maxResults);
187
- const usersWithRoles = await Promise.all(users.map(async (user) => {
188
- const role = user.roleId ? await ctx.db.get(user.roleId) : null;
189
- return {
190
- ...user,
191
- role: role?.name || user.role,
192
- };
193
- }));
194
- return usersWithRoles;
195
- },
196
- });
197
- export const listUsersPaginated = query({
198
- args: {
199
- paginationOpts: paginationOptsValidator,
200
- roleId: v.optional(v.id('roles')),
201
- isActive: v.optional(v.boolean()),
202
- searchTerm: v.optional(v.string()),
203
- },
204
- handler: async (ctx, args) => {
205
- let baseQuery;
206
- if (args.roleId) {
207
- baseQuery = ctx.db
208
- .query('user_profiles')
209
- .withIndex('by_roleId', (q) => q.eq('roleId', args.roleId));
210
- }
211
- else if (args.isActive !== undefined) {
212
- baseQuery = ctx.db
213
- .query('user_profiles')
214
- .withIndex('by_isActive', (q) => q.eq('isActive', args.isActive));
215
- }
216
- else {
217
- baseQuery = ctx.db.query('user_profiles');
218
- }
219
- let filteredQuery = baseQuery.order('desc');
220
- if (args.isActive !== undefined && args.roleId) {
221
- filteredQuery = filteredQuery.filter((q) => q.eq(q.field('isActive'), args.isActive));
222
- }
223
- const result = await filteredQuery.paginate(args.paginationOpts);
224
- let filteredPage = result.page;
225
- if (args.searchTerm) {
226
- const search = args.searchTerm.toLowerCase();
227
- filteredPage = filteredPage.filter((user) => user.name?.toLowerCase().includes(search) ||
228
- user.email?.toLowerCase().includes(search));
229
- }
230
- const roleIds = [...new Set(filteredPage.map((u) => u.roleId).filter(Boolean))];
231
- const roles = await Promise.all(roleIds.map(id => ctx.db.get(id)));
232
- const roleMap = new Map(roles.filter(Boolean).map((r) => [r._id.toString(), r.name]));
233
- const minimalPage = filteredPage.map((user) => ({
234
- _id: user._id,
235
- auth0Id: user.auth0Id,
236
- email: user.email,
237
- name: user.name,
238
- roleId: user.roleId,
239
- role: roleMap.get(user.roleId?.toString()) || user.role || 'user',
240
- isActive: user.isActive,
241
- clinicId: user.clinicId,
242
- supplierId: user.supplierId,
243
- createdAt: user.createdAt || user._creationTime,
244
- }));
245
- return {
246
- page: minimalPage,
247
- isDone: result.isDone,
248
- continueCursor: result.continueCursor,
249
- };
250
- },
251
- });
252
- export const getUsersCount = query({
253
- args: {
254
- roleId: v.optional(v.id('roles')),
255
- isActive: v.optional(v.boolean()),
256
- },
257
- handler: async (ctx, args) => {
258
- let query;
259
- if (args.roleId) {
260
- query = ctx.db.query('user_profiles')
261
- .withIndex('by_roleId', (q) => q.eq('roleId', args.roleId));
262
- }
263
- else if (args.isActive !== undefined) {
264
- query = ctx.db.query('user_profiles')
265
- .withIndex('by_isActive', (q) => q.eq('isActive', args.isActive));
266
- }
267
- else {
268
- query = ctx.db.query('user_profiles');
269
- }
270
- if (args.isActive !== undefined && args.roleId) {
271
- query = query.filter((q) => q.eq(q.field('isActive'), args.isActive));
272
- }
273
- const users = await query.take(1000);
274
- return { total: users.length };
118
+ return await ctx.db.query('user_profiles').order('desc').take(maxResults);
275
119
  },
276
120
  });
277
121
  export const savePrimoUPToken = mutation({
@@ -313,9 +157,8 @@ export const getPrimoUPToken = query({
313
157
  .query('primoup_tokens')
314
158
  .withIndex('by_userId_active', (q) => q.eq('userId', args.auth0Id).eq('isActive', true))
315
159
  .first();
316
- if (!activeToken) {
160
+ if (!activeToken)
317
161
  return null;
318
- }
319
162
  if (activeToken.expiresAt && activeToken.expiresAt < Date.now()) {
320
163
  return {
321
164
  token: null,
@@ -362,43 +205,11 @@ export const getPrimoUPAccessLogs = query({
362
205
  },
363
206
  handler: async (ctx, args) => {
364
207
  const targetUserId = args.isAdmin && args.userId ? args.userId : args.auth0Id;
365
- const logs = await ctx.db
208
+ return await ctx.db
366
209
  .query('primoup_access_logs')
367
210
  .withIndex('by_userId_timestamp', (q) => q.eq('userId', targetUserId))
368
211
  .order('desc')
369
212
  .take(args.limit || 50);
370
- return logs;
371
- },
372
- });
373
- export const updateUserRoleByEmail = mutation({
374
- args: {
375
- email: v.string(),
376
- roleName: v.string(),
377
- },
378
- handler: async (ctx, args) => {
379
- const user = await ctx.db
380
- .query('user_profiles')
381
- .filter((q) => q.eq(q.field('email'), args.email))
382
- .first();
383
- if (!user) {
384
- throw new Error(`User with email ${args.email} not found`);
385
- }
386
- const role = await ctx.db
387
- .query('roles')
388
- .withIndex('by_name', (q) => q.eq('name', args.roleName))
389
- .first();
390
- if (!role) {
391
- throw new Error(`Role ${args.roleName} not found`);
392
- }
393
- await ctx.db.patch(user._id, {
394
- roleId: role._id,
395
- });
396
- return {
397
- success: true,
398
- userId: user._id,
399
- email: user.email,
400
- newRole: args.roleName,
401
- };
402
213
  },
403
214
  });
404
215
  export const saveUserClinics = mutation({
@@ -411,9 +222,8 @@ export const saveUserClinics = mutation({
411
222
  .query('user_profiles')
412
223
  .withIndex('by_auth0Id', (q) => q.eq('auth0Id', args.auth0Id))
413
224
  .first();
414
- if (!profile) {
415
- throw new Error('User profile not found');
416
- }
225
+ if (!profile)
226
+ throw new Error('User settings not found');
417
227
  const optimizedClinics = args.primoupClinics.map((clinic) => ({
418
228
  id: clinic.id,
419
229
  name: clinic.name,
@@ -437,33 +247,16 @@ export const updateSelectedClinic = mutation({
437
247
  .query('user_profiles')
438
248
  .withIndex('by_auth0Id', (q) => q.eq('auth0Id', args.auth0Id))
439
249
  .first();
440
- if (!profile) {
441
- throw new Error('User profile not found');
442
- }
250
+ if (!profile)
251
+ throw new Error('User settings not found');
443
252
  if (profile.primoupClinics) {
444
253
  const hasClinic = profile.primoupClinics.some((clinic) => clinic.id === args.clinicId);
445
- if (!hasClinic) {
254
+ if (!hasClinic)
446
255
  throw new Error('Clinic not found in user clinics');
447
- }
448
- }
449
- const clinic = await ctx.db
450
- .query('clinics')
451
- .withIndex('by_primoupId', (q) => q.eq('primoupId', args.clinicId.toString()))
452
- .first();
453
- if (!clinic) {
454
- console.warn(`⚠️ Clinic NOT FOUND in Convex with primoupId: ${args.clinicId}`);
455
- const newCounter = (profile.clinicChangeCounter || 0) + 1;
456
- await ctx.db.patch(profile._id, {
457
- selectedClinicId: args.clinicId,
458
- clinicId: undefined,
459
- clinicChangeCounter: newCounter,
460
- });
461
- return profile._id;
462
256
  }
463
257
  const newCounter = (profile.clinicChangeCounter || 0) + 1;
464
258
  await ctx.db.patch(profile._id, {
465
259
  selectedClinicId: args.clinicId,
466
- clinicId: clinic._id,
467
260
  clinicChangeCounter: newCounter,
468
261
  });
469
262
  return profile._id;
@@ -472,38 +265,28 @@ export const updateSelectedClinic = mutation({
472
265
  export const startImpersonation = mutation({
473
266
  args: {
474
267
  auth0Id: v.string(),
475
- targetUserId: v.id('user_profiles'),
268
+ targetUserAuth0Id: v.string(),
476
269
  },
477
270
  handler: async (ctx, args) => {
478
271
  const currentUser = await ctx.db
479
272
  .query('user_profiles')
480
273
  .withIndex('by_auth0Id', (q) => q.eq('auth0Id', args.auth0Id))
481
274
  .first();
482
- if (!currentUser) {
483
- throw new Error('User profile not found');
484
- }
485
- const currentRole = currentUser.roleId ? await ctx.db.get(currentUser.roleId) : null;
486
- if (!currentRole || currentRole.name !== 'admin') {
487
- throw new Error('Solo gli amministratori possono impersonare altri utenti');
488
- }
489
- const targetUser = await ctx.db.get(args.targetUserId);
490
- if (!targetUser) {
491
- throw new Error('Utente target non trovato');
492
- }
275
+ if (!currentUser)
276
+ throw new Error('User settings not found');
277
+ const targetUser = await ctx.db
278
+ .query('user_profiles')
279
+ .withIndex('by_auth0Id', (q) => q.eq('auth0Id', args.targetUserAuth0Id))
280
+ .first();
281
+ if (!targetUser)
282
+ throw new Error('Target user settings not found');
493
283
  if (targetUser._id === currentUser._id) {
494
284
  throw new Error('Non puoi impersonare te stesso');
495
285
  }
496
286
  await ctx.db.patch(currentUser._id, {
497
- impersonatingUserId: args.targetUserId,
287
+ impersonatingUserId: args.targetUserAuth0Id,
498
288
  });
499
- return {
500
- success: true,
501
- impersonatedUser: {
502
- id: targetUser._id,
503
- name: targetUser.name,
504
- email: targetUser.email,
505
- },
506
- };
289
+ return { success: true };
507
290
  },
508
291
  });
509
292
  export const stopImpersonation = mutation({
@@ -513,103 +296,14 @@ export const stopImpersonation = mutation({
513
296
  .query('user_profiles')
514
297
  .withIndex('by_auth0Id', (q) => q.eq('auth0Id', args.auth0Id))
515
298
  .first();
516
- if (!currentUser) {
517
- throw new Error('User profile not found');
518
- }
519
- const currentRole = currentUser.roleId ? await ctx.db.get(currentUser.roleId) : null;
520
- if (!currentRole || currentRole.name !== 'admin') {
521
- throw new Error('Solo gli amministratori possono terminare l\'impersonazione');
522
- }
299
+ if (!currentUser)
300
+ throw new Error('User settings not found');
523
301
  await ctx.db.patch(currentUser._id, {
524
302
  impersonatingUserId: undefined,
525
303
  });
526
304
  return { success: true };
527
305
  },
528
306
  });
529
- export const updateUserProfile = mutation({
530
- args: {
531
- userId: v.id('user_profiles'),
532
- name: v.optional(v.string()),
533
- email: v.optional(v.string()),
534
- roleName: v.optional(v.string()),
535
- clinicId: v.optional(v.id('clinics')),
536
- supplierId: v.optional(v.id('suppliers')),
537
- },
538
- handler: async (ctx, args) => {
539
- const targetUser = await ctx.db.get(args.userId);
540
- if (!targetUser) {
541
- throw new Error('Target user not found');
542
- }
543
- const updateData = {};
544
- if (args.name !== undefined) {
545
- updateData.name = args.name;
546
- }
547
- if (args.email !== undefined) {
548
- const existingUser = await ctx.db
549
- .query('user_profiles')
550
- .withIndex('by_email', (q) => q.eq('email', args.email))
551
- .first();
552
- if (existingUser && existingUser._id !== args.userId) {
553
- throw new Error('Email già in uso da un altro utente');
554
- }
555
- updateData.email = args.email;
556
- }
557
- if (args.roleName !== undefined) {
558
- const newRole = await ctx.db
559
- .query('roles')
560
- .withIndex('by_name', (q) => q.eq('name', args.roleName))
561
- .first();
562
- if (!newRole) {
563
- throw new Error(`Ruolo ${args.roleName} non trovato`);
564
- }
565
- updateData.roleId = newRole._id;
566
- }
567
- if (args.clinicId !== undefined) {
568
- updateData.clinicId = args.clinicId;
569
- }
570
- if (args.supplierId !== undefined) {
571
- updateData.supplierId = args.supplierId;
572
- }
573
- if (Object.keys(updateData).length > 0) {
574
- await ctx.db.patch(args.userId, updateData);
575
- }
576
- return args.userId;
577
- },
578
- });
579
- export const disableUser = mutation({
580
- args: {
581
- userId: v.id('user_profiles'),
582
- callerUserId: v.optional(v.id('user_profiles')),
583
- },
584
- handler: async (ctx, args) => {
585
- if (args.callerUserId && args.userId === args.callerUserId) {
586
- throw new Error('Non puoi disabilitare te stesso');
587
- }
588
- const targetUser = await ctx.db.get(args.userId);
589
- if (!targetUser) {
590
- throw new Error('Utente non trovato');
591
- }
592
- await ctx.db.patch(args.userId, {
593
- isActive: false,
594
- });
595
- return { success: true, userId: args.userId };
596
- },
597
- });
598
- export const enableUser = mutation({
599
- args: {
600
- userId: v.id('user_profiles'),
601
- },
602
- handler: async (ctx, args) => {
603
- const targetUser = await ctx.db.get(args.userId);
604
- if (!targetUser) {
605
- throw new Error('Utente non trovato');
606
- }
607
- await ctx.db.patch(args.userId, {
608
- isActive: true,
609
- });
610
- return { success: true, userId: args.userId };
611
- },
612
- });
613
307
  export const getRealAdminProfile = query({
614
308
  args: { auth0Id: v.string() },
615
309
  handler: async (ctx, args) => {
@@ -617,15 +311,10 @@ export const getRealAdminProfile = query({
617
311
  .query('user_profiles')
618
312
  .withIndex('by_auth0Id', (q) => q.eq('auth0Id', args.auth0Id))
619
313
  .first();
620
- if (!profile) {
314
+ if (!profile)
621
315
  return null;
622
- }
623
- const role = profile.roleId ? await ctx.db.get(profile.roleId) : null;
624
316
  return {
625
317
  _id: profile._id,
626
- name: profile.name,
627
- email: profile.email,
628
- role: role?.name,
629
318
  isImpersonating: !!profile.impersonatingUserId,
630
319
  impersonatingUserId: profile.impersonatingUserId,
631
320
  };