@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.
- package/dist/client/index.d.ts +0 -2
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +2 -28
- package/dist/client/index.js.map +1 -1
- package/dist/component/_generated/api.d.ts +4 -4
- package/dist/component/_generated/api.d.ts.map +1 -1
- package/dist/component/_generated/component.d.ts +165 -218
- package/dist/component/_generated/component.d.ts.map +1 -1
- package/dist/component/contracts.d.ts +9 -9
- package/dist/component/contracts.d.ts.map +1 -1
- package/dist/component/contracts.js +7 -13
- package/dist/component/contracts.js.map +1 -1
- package/dist/component/crons.d.ts.map +1 -1
- package/dist/component/crons.js +1 -2
- package/dist/component/crons.js.map +1 -1
- package/dist/component/dashboardStats.d.ts +8 -3
- package/dist/component/dashboardStats.d.ts.map +1 -1
- package/dist/component/dashboardStats.js +24 -39
- package/dist/component/dashboardStats.js.map +1 -1
- package/dist/component/dashboardStatsCache.d.ts +5 -11
- package/dist/component/dashboardStatsCache.d.ts.map +1 -1
- package/dist/component/dashboardStatsCache.js +12 -53
- package/dist/component/dashboardStatsCache.js.map +1 -1
- package/dist/component/deviceCategories.d.ts +22 -15
- package/dist/component/deviceCategories.d.ts.map +1 -1
- package/dist/component/deviceCategories.js +10 -4
- package/dist/component/deviceCategories.js.map +1 -1
- package/dist/component/deviceQuestions.d.ts +36 -27
- package/dist/component/deviceQuestions.d.ts.map +1 -1
- package/dist/component/deviceQuestions.js +22 -5
- package/dist/component/deviceQuestions.js.map +1 -1
- package/dist/component/deviceRepairHistory.d.ts +3 -3
- package/dist/component/deviceRepairHistory.js +1 -1
- package/dist/component/deviceRepairHistory.js.map +1 -1
- package/dist/component/deviceStatus.d.ts +8 -57
- package/dist/component/deviceStatus.d.ts.map +1 -1
- package/dist/component/deviceStatus.js +32 -30
- package/dist/component/deviceStatus.js.map +1 -1
- package/dist/component/devices.d.ts +39 -22
- package/dist/component/devices.d.ts.map +1 -1
- package/dist/component/devices.js +85 -96
- package/dist/component/devices.js.map +1 -1
- package/dist/component/emailHelpers.d.ts +10 -3
- package/dist/component/emailHelpers.d.ts.map +1 -1
- package/dist/component/emailHelpers.js +9 -20
- package/dist/component/emailHelpers.js.map +1 -1
- package/dist/component/emails.d.ts +5 -5
- package/dist/component/emails.js +2 -2
- package/dist/component/emails.js.map +1 -1
- package/dist/component/http.d.ts.map +1 -1
- package/dist/component/http.js +3 -108
- package/dist/component/http.js.map +1 -1
- package/dist/component/migrationHelpers.d.ts +29 -0
- package/dist/component/migrationHelpers.d.ts.map +1 -0
- package/dist/component/migrationHelpers.js +84 -0
- package/dist/component/migrationHelpers.js.map +1 -0
- package/dist/component/roles.d.ts +1 -0
- package/dist/component/roles.d.ts.map +1 -1
- package/dist/component/roles.js +5 -6
- package/dist/component/roles.js.map +1 -1
- package/dist/component/schema.d.ts +69 -150
- package/dist/component/schema.d.ts.map +1 -1
- package/dist/component/schema.js +35 -88
- package/dist/component/schema.js.map +1 -1
- package/dist/component/slaMonitoring.d.ts +16 -30
- package/dist/component/slaMonitoring.d.ts.map +1 -1
- package/dist/component/slaMonitoring.js +48 -99
- package/dist/component/slaMonitoring.js.map +1 -1
- package/dist/component/spareParts.d.ts +11 -48
- package/dist/component/spareParts.d.ts.map +1 -1
- package/dist/component/spareParts.js +41 -11
- package/dist/component/spareParts.js.map +1 -1
- package/dist/component/suppliers.d.ts +38 -19
- package/dist/component/suppliers.d.ts.map +1 -1
- package/dist/component/suppliers.js +63 -44
- package/dist/component/suppliers.js.map +1 -1
- package/dist/component/ticketComments.d.ts +18 -12
- package/dist/component/ticketComments.d.ts.map +1 -1
- package/dist/component/ticketComments.js +28 -59
- package/dist/component/ticketComments.js.map +1 -1
- package/dist/component/ticketDeviceData.d.ts +63 -0
- package/dist/component/ticketDeviceData.d.ts.map +1 -0
- package/dist/component/ticketDeviceData.js +103 -0
- package/dist/component/ticketDeviceData.js.map +1 -0
- package/dist/component/ticketExport.d.ts +22 -40
- package/dist/component/ticketExport.d.ts.map +1 -1
- package/dist/component/ticketExport.js +43 -109
- package/dist/component/ticketExport.js.map +1 -1
- package/dist/component/ticketHistory.d.ts +4 -4
- package/dist/component/ticketHistory.d.ts.map +1 -1
- package/dist/component/ticketHistory.js +6 -9
- package/dist/component/ticketHistory.js.map +1 -1
- package/dist/component/ticketMacros.d.ts +19 -18
- package/dist/component/ticketMacros.d.ts.map +1 -1
- package/dist/component/ticketMacros.js +24 -30
- package/dist/component/ticketMacros.js.map +1 -1
- package/dist/component/ticketStatuses.d.ts +1 -0
- package/dist/component/ticketStatuses.d.ts.map +1 -1
- package/dist/component/ticketStatuses.js +5 -6
- package/dist/component/ticketStatuses.js.map +1 -1
- package/dist/component/ticketTriggers.d.ts +36 -16
- package/dist/component/ticketTriggers.d.ts.map +1 -1
- package/dist/component/ticketTriggers.js +115 -153
- package/dist/component/ticketTriggers.js.map +1 -1
- package/dist/component/userProfiles.d.ts +25 -120
- package/dist/component/userProfiles.d.ts.map +1 -1
- package/dist/component/userProfiles.js +73 -384
- package/dist/component/userProfiles.js.map +1 -1
- package/dist/test.d.ts +69 -150
- package/dist/test.d.ts.map +1 -1
- package/package.json +12 -3
- package/src/client/index.ts +2 -30
- package/src/component/_generated/api.ts +4 -4
- package/src/component/_generated/component.ts +228 -350
- package/src/component/contracts.ts +7 -14
- package/src/component/crons.ts +2 -7
- package/src/component/dashboardStats.ts +24 -41
- package/src/component/dashboardStatsCache.ts +12 -61
- package/src/component/deviceCategories.ts +12 -4
- package/src/component/deviceQuestions.ts +28 -5
- package/src/component/deviceRepairHistory.ts +1 -1
- package/src/component/deviceStatus.ts +43 -45
- package/src/component/devices.ts +87 -106
- package/src/component/emailHelpers.ts +9 -19
- package/src/component/emails.ts +2 -2
- package/src/component/http.ts +3 -108
- package/src/component/migrationHelpers.ts +96 -0
- package/src/component/roles.ts +5 -6
- package/src/component/schema.ts +35 -93
- package/src/component/slaMonitoring.ts +52 -107
- package/src/component/spareParts.ts +46 -12
- package/src/component/suppliers.ts +71 -48
- package/src/component/ticketComments.ts +28 -71
- package/src/component/ticketDeviceData.ts +113 -0
- package/src/component/ticketExport.ts +52 -137
- package/src/component/ticketHistory.ts +6 -9
- package/src/component/ticketMacros.ts +25 -37
- package/src/component/ticketStatuses.ts +5 -6
- package/src/component/ticketTriggers.ts +121 -217
- package/src/component/userProfiles.ts +67 -451
- package/dist/component/clinics.d.ts +0 -103
- package/dist/component/clinics.d.ts.map +0 -1
- package/dist/component/clinics.js +0 -126
- package/dist/component/clinics.js.map +0 -1
- package/dist/component/maintenanceTasks.d.ts +0 -733
- package/dist/component/maintenanceTasks.d.ts.map +0 -1
- package/dist/component/maintenanceTasks.js +0 -937
- package/dist/component/maintenanceTasks.js.map +0 -1
- package/src/component/clinics.ts +0 -136
- package/src/component/maintenanceTasks.ts +0 -1003
|
@@ -3,183 +3,97 @@ import { query } from './_generated/server';
|
|
|
3
3
|
|
|
4
4
|
export const exportTickets = query({
|
|
5
5
|
args: {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
clinicIds: v.optional(v.array(v.id('clinics'))),
|
|
9
|
-
supplierIds: v.optional(v.array(v.id('suppliers'))),
|
|
10
|
-
createdByEmail: v.optional(v.string()),
|
|
11
|
-
ticketNumber: v.optional(v.string()),
|
|
12
|
-
dateFrom: v.optional(v.number()),
|
|
13
|
-
dateTo: v.optional(v.number()),
|
|
14
|
-
slaBreached: v.optional(v.boolean()),
|
|
15
|
-
isExternal: v.optional(v.boolean()),
|
|
16
|
-
needsAssignment: v.optional(v.boolean()),
|
|
17
|
-
hasDevice: v.optional(v.boolean()),
|
|
18
|
-
deviceCategory: v.optional(v.string()),
|
|
19
|
-
deviceBrand: v.optional(v.string()),
|
|
6
|
+
tickets: v.array(v.any()),
|
|
7
|
+
clinicDataMap: v.optional(v.any()),
|
|
20
8
|
},
|
|
21
9
|
handler: async (ctx, args) => {
|
|
22
|
-
|
|
10
|
+
const tickets = args.tickets;
|
|
23
11
|
|
|
24
|
-
|
|
25
|
-
tickets = tickets.filter(t => args.statuses!.includes(t.status));
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
if (args.priorities && args.priorities.length > 0) {
|
|
29
|
-
tickets = tickets.filter(t => t.priority && args.priorities!.includes(t.priority));
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
if (args.clinicIds && args.clinicIds.length > 0) {
|
|
33
|
-
tickets = tickets.filter(t => args.clinicIds!.includes(t.clinicId));
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
if (args.supplierIds && args.supplierIds.length > 0) {
|
|
37
|
-
tickets = tickets.filter(t => t.supplierId && args.supplierIds!.includes(t.supplierId));
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
if (args.createdByEmail) {
|
|
41
|
-
const emailLower = args.createdByEmail.toLowerCase();
|
|
42
|
-
tickets = tickets.filter(t =>
|
|
43
|
-
t.createdByEmail?.toLowerCase().includes(emailLower)
|
|
44
|
-
);
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
if (args.ticketNumber) {
|
|
48
|
-
const numLower = args.ticketNumber.toLowerCase();
|
|
49
|
-
tickets = tickets.filter(t =>
|
|
50
|
-
t.ticketNumber?.toLowerCase().includes(numLower)
|
|
51
|
-
);
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
if (args.dateFrom) {
|
|
55
|
-
tickets = tickets.filter(t => t.created_at >= args.dateFrom!);
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
if (args.dateTo) {
|
|
59
|
-
tickets = tickets.filter(t => t.created_at <= args.dateTo!);
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
if (args.slaBreached !== undefined) {
|
|
63
|
-
tickets = tickets.filter(t => t.slaBreached === args.slaBreached);
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
if (args.isExternal !== undefined) {
|
|
67
|
-
tickets = tickets.filter(t => t.isExternal === args.isExternal);
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
if (args.needsAssignment !== undefined) {
|
|
71
|
-
tickets = tickets.filter(t => t.needsAssignment === args.needsAssignment);
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
if (args.hasDevice !== undefined) {
|
|
75
|
-
if (args.hasDevice) {
|
|
76
|
-
tickets = tickets.filter(t => t.deviceId);
|
|
77
|
-
} else {
|
|
78
|
-
tickets = tickets.filter(t => !t.deviceId);
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
const clinicIds = [...new Set(tickets.map(t => t.clinicId))].slice(0, 300);
|
|
83
|
-
const supplierIds = [...new Set(tickets.filter(t => t.supplierId).map(t => t.supplierId!))].slice(0, 300);
|
|
84
|
-
const deviceIds = [...new Set(tickets.filter(t => t.deviceId).map(t => t.deviceId!))].slice(0, 500);
|
|
85
|
-
|
|
86
|
-
const clinicsMap = new Map();
|
|
87
|
-
for (const id of clinicIds) {
|
|
88
|
-
const clinic = await ctx.db.get(id);
|
|
89
|
-
if (clinic) clinicsMap.set(id, clinic);
|
|
90
|
-
}
|
|
12
|
+
const supplierIds = [...new Set(tickets.filter((t: any) => t.supplierId).map((t: any) => t.supplierId))].slice(0, 300);
|
|
91
13
|
|
|
92
14
|
const suppliersMap = new Map();
|
|
93
15
|
for (const id of supplierIds) {
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
16
|
+
try {
|
|
17
|
+
const supplier = await ctx.db.get(id);
|
|
18
|
+
if (supplier) suppliersMap.set(id, supplier);
|
|
19
|
+
} catch { /* skip invalid IDs */ }
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const ticketIds = tickets.map((t: any) => t._id?.toString() || t.ticketId);
|
|
23
|
+
const deviceDataEntries = await Promise.all(
|
|
24
|
+
ticketIds.map(async (tid: string) =>
|
|
25
|
+
ctx.db.query('ticket_device_data')
|
|
26
|
+
.withIndex('by_ticketId', q => q.eq('ticketId', tid))
|
|
27
|
+
.first()
|
|
28
|
+
)
|
|
29
|
+
);
|
|
30
|
+
const validDeviceData = deviceDataEntries.filter(Boolean);
|
|
31
|
+
const deviceDataMap = new Map(validDeviceData.map(d => [d!.ticketId, d!]));
|
|
32
|
+
|
|
33
|
+
const deviceIds = [...new Set(
|
|
34
|
+
validDeviceData.filter((d): d is NonNullable<typeof d> => d != null && !!d.deviceId).map(d => d.deviceId!)
|
|
35
|
+
)].slice(0, 500);
|
|
97
36
|
|
|
98
37
|
const devicesMap = new Map();
|
|
99
38
|
for (const id of deviceIds) {
|
|
100
39
|
const device = await ctx.db.get(id);
|
|
101
|
-
if (device) devicesMap.set(id, device);
|
|
40
|
+
if (device) devicesMap.set(id.toString(), device);
|
|
102
41
|
}
|
|
103
42
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
if (args.deviceCategory && device.category !== args.deviceCategory) {
|
|
111
|
-
return false;
|
|
112
|
-
}
|
|
113
|
-
if (args.deviceBrand && device.brand !== args.deviceBrand) {
|
|
114
|
-
return false;
|
|
115
|
-
}
|
|
116
|
-
return true;
|
|
117
|
-
});
|
|
43
|
+
const clinicsMap = new Map();
|
|
44
|
+
if (args.clinicDataMap && typeof args.clinicDataMap === 'object') {
|
|
45
|
+
for (const [id, data] of Object.entries(args.clinicDataMap)) {
|
|
46
|
+
clinicsMap.set(id, data);
|
|
47
|
+
}
|
|
118
48
|
}
|
|
119
49
|
|
|
120
50
|
const statuses = await ctx.db.query('ticket_statuses').collect();
|
|
121
51
|
const statusMap = new Map(statuses.map(s => [s.name, s.label]));
|
|
122
52
|
|
|
123
|
-
const enrichedTickets = tickets.map(t => {
|
|
53
|
+
const enrichedTickets = tickets.map((t: any) => {
|
|
124
54
|
const clinic = clinicsMap.get(t.clinicId);
|
|
125
55
|
const supplier = t.supplierId ? suppliersMap.get(t.supplierId) : null;
|
|
126
|
-
const
|
|
56
|
+
const dd = deviceDataMap.get(t._id?.toString() || t.ticketId);
|
|
57
|
+
const device = dd?.deviceId ? devicesMap.get(dd.deviceId.toString()) : null;
|
|
127
58
|
|
|
128
59
|
return {
|
|
129
|
-
_id: t._id,
|
|
60
|
+
_id: t._id || t.ticketId,
|
|
130
61
|
ticketNumber: t.ticketNumber || '-',
|
|
131
|
-
|
|
132
62
|
title: t.title || '-',
|
|
133
63
|
description: t.description,
|
|
134
64
|
status: t.status,
|
|
135
65
|
statusLabel: statusMap.get(t.status) || t.status,
|
|
136
66
|
priority: t.priority || '-',
|
|
137
|
-
|
|
138
67
|
createdByEmail: t.createdByEmail || '-',
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
updated_at: t.updated_at,
|
|
144
|
-
updatedAtFormatted: new Date(t.updated_at).toLocaleString('it-IT'),
|
|
145
|
-
|
|
68
|
+
created_at: t.created_at || t.lastActivityAt,
|
|
69
|
+
createdAtFormatted: t.created_at ? new Date(t.created_at).toLocaleString('it-IT') : '-',
|
|
70
|
+
updated_at: t.updated_at || t.lastActivityAt,
|
|
71
|
+
updatedAtFormatted: t.updated_at ? new Date(t.updated_at).toLocaleString('it-IT') : '-',
|
|
146
72
|
clinicId: t.clinicId,
|
|
147
|
-
clinicName: clinic?.name || '-',
|
|
148
|
-
clinicAddress: clinic?.address || '-',
|
|
149
|
-
clinicRegion: clinic?.region || '-',
|
|
150
|
-
|
|
73
|
+
clinicName: (clinic as any)?.name || '-',
|
|
74
|
+
clinicAddress: (clinic as any)?.address || '-',
|
|
75
|
+
clinicRegion: (clinic as any)?.region || '-',
|
|
151
76
|
supplierId: t.supplierId || null,
|
|
152
77
|
supplierName: supplier?.name || '-',
|
|
153
78
|
supplierEmail: supplier?.contact_email || '-',
|
|
154
|
-
|
|
155
|
-
deviceId: t.deviceId || null,
|
|
79
|
+
deviceId: dd?.deviceId || null,
|
|
156
80
|
deviceName: device?.name || '-',
|
|
157
81
|
deviceCategory: device?.category || '-',
|
|
158
82
|
deviceBrand: device?.brand || '-',
|
|
159
83
|
deviceModel: device?.model || '-',
|
|
160
84
|
deviceSerialNumber: device?.serial_number || '-',
|
|
161
|
-
|
|
162
85
|
slaDeadline: t.slaDeadline || null,
|
|
163
86
|
slaDeadlineFormatted: t.slaDeadline ? new Date(t.slaDeadline).toLocaleString('it-IT') : '-',
|
|
164
87
|
slaBreached: t.slaBreached || false,
|
|
165
|
-
|
|
166
|
-
isExternal: t.isExternal || false,
|
|
167
|
-
needsAssignment: t.needsAssignment || false,
|
|
168
|
-
|
|
88
|
+
isExternal: t.isExternalApi || false,
|
|
169
89
|
notes: t.notes || '-',
|
|
170
90
|
customFields: t.customFields || {},
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
externalTicketNumber: t.externalTicketNumber || '-',
|
|
174
|
-
importSource: t.importSource || '-',
|
|
175
|
-
|
|
176
|
-
photosCount: t.photos?.length || 0,
|
|
177
|
-
|
|
178
|
-
deviceQuestionAnswers: t.deviceQuestionAnswers || [],
|
|
91
|
+
photosCount: dd?.photoStorageIds?.length || 0,
|
|
92
|
+
deviceQuestionAnswers: dd?.deviceQuestionAnswers || [],
|
|
179
93
|
};
|
|
180
94
|
});
|
|
181
95
|
|
|
182
|
-
enrichedTickets.sort((a, b) => b.created_at - a.created_at);
|
|
96
|
+
enrichedTickets.sort((a: any, b: any) => (b.created_at || 0) - (a.created_at || 0));
|
|
183
97
|
|
|
184
98
|
return {
|
|
185
99
|
tickets: enrichedTickets,
|
|
@@ -189,13 +103,14 @@ export const exportTickets = query({
|
|
|
189
103
|
});
|
|
190
104
|
|
|
191
105
|
export const getFilterOptions = query({
|
|
192
|
-
args: {
|
|
193
|
-
|
|
106
|
+
args: {
|
|
107
|
+
clinics: v.optional(v.array(v.any())),
|
|
108
|
+
},
|
|
109
|
+
handler: async (ctx, args) => {
|
|
194
110
|
const statuses = await ctx.db.query('ticket_statuses').collect();
|
|
195
111
|
const statusOptions = statuses.map(s => ({ value: s.name, label: s.label }));
|
|
196
112
|
|
|
197
|
-
const
|
|
198
|
-
const clinicOptions = clinics.map(c => ({ value: c._id, label: c.name }));
|
|
113
|
+
const clinicOptions = args.clinics || [];
|
|
199
114
|
|
|
200
115
|
const suppliers = await ctx.db.query('suppliers').collect();
|
|
201
116
|
const supplierOptions = suppliers.map(s => ({ value: s._id, label: s.name }));
|
|
@@ -211,7 +126,7 @@ export const getFilterOptions = query({
|
|
|
211
126
|
{ value: 'medium', label: 'Media' },
|
|
212
127
|
{ value: 'high', label: 'Alta' },
|
|
213
128
|
],
|
|
214
|
-
clinics: clinicOptions
|
|
129
|
+
clinics: clinicOptions,
|
|
215
130
|
suppliers: supplierOptions.sort((a, b) => a.label.localeCompare(b.label)),
|
|
216
131
|
deviceCategories: categories.sort(),
|
|
217
132
|
deviceBrands: brands.sort(),
|
|
@@ -1,24 +1,22 @@
|
|
|
1
1
|
import { v } from 'convex/values';
|
|
2
2
|
import { query, mutation, internalMutation } from './_generated/server';
|
|
3
3
|
|
|
4
|
-
// Get ticket history (admin only)
|
|
5
4
|
export const getTicketHistory = query({
|
|
6
|
-
args: { ticketId: v.
|
|
5
|
+
args: { ticketId: v.string() },
|
|
7
6
|
handler: async (ctx, args) => {
|
|
8
7
|
const history = await ctx.db
|
|
9
8
|
.query('ticket_history')
|
|
10
|
-
.withIndex('
|
|
9
|
+
.withIndex('by_ticketId_timestamp', (q: any) => q.eq('ticketId', args.ticketId))
|
|
10
|
+
.order('desc')
|
|
11
11
|
.take(200);
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
return history.sort((a, b) => b.timestamp - a.timestamp);
|
|
13
|
+
return history;
|
|
15
14
|
},
|
|
16
15
|
});
|
|
17
16
|
|
|
18
|
-
// Add history entry (internal mutation - called by other functions)
|
|
19
17
|
export const addHistoryEntry = internalMutation({
|
|
20
18
|
args: {
|
|
21
|
-
ticketId: v.
|
|
19
|
+
ticketId: v.string(),
|
|
22
20
|
eventType: v.union(
|
|
23
21
|
v.literal('created'),
|
|
24
22
|
v.literal('status_change'),
|
|
@@ -53,10 +51,9 @@ export const addHistoryEntry = internalMutation({
|
|
|
53
51
|
},
|
|
54
52
|
});
|
|
55
53
|
|
|
56
|
-
// Public mutation to add history (for use from frontend/other mutations)
|
|
57
54
|
export const recordHistoryEvent = mutation({
|
|
58
55
|
args: {
|
|
59
|
-
ticketId: v.
|
|
56
|
+
ticketId: v.string(),
|
|
60
57
|
eventType: v.union(
|
|
61
58
|
v.literal('created'),
|
|
62
59
|
v.literal('status_change'),
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import { v } from 'convex/values';
|
|
2
2
|
import { query, mutation } from './_generated/server';
|
|
3
|
-
import type { Id } from './_generated/dataModel';
|
|
4
3
|
|
|
5
4
|
export const listMacros = query({
|
|
6
5
|
args: {
|
|
7
|
-
userProfileId: v.optional(v.
|
|
6
|
+
userProfileId: v.optional(v.string()),
|
|
8
7
|
},
|
|
9
8
|
handler: async (ctx, args) => {
|
|
10
9
|
const allMacros = await ctx.db.query('ticket_macros').collect();
|
|
@@ -13,25 +12,18 @@ export const listMacros = query({
|
|
|
13
12
|
m.isGlobal || (args.userProfileId && m.createdBy === args.userProfileId)
|
|
14
13
|
);
|
|
15
14
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
creatorEmail: creator?.email,
|
|
23
|
-
isOwner: args.userProfileId ? macro.createdBy === args.userProfileId : false,
|
|
24
|
-
};
|
|
25
|
-
})
|
|
26
|
-
);
|
|
27
|
-
|
|
28
|
-
return macrosWithCreator;
|
|
15
|
+
return filteredMacros.map((macro) => ({
|
|
16
|
+
...macro,
|
|
17
|
+
creatorName: macro.createdBy,
|
|
18
|
+
creatorEmail: undefined,
|
|
19
|
+
isOwner: args.userProfileId ? macro.createdBy === args.userProfileId : false,
|
|
20
|
+
}));
|
|
29
21
|
},
|
|
30
22
|
});
|
|
31
23
|
|
|
32
24
|
export const listActiveMacros = query({
|
|
33
25
|
args: {
|
|
34
|
-
userProfileId: v.optional(v.
|
|
26
|
+
userProfileId: v.optional(v.string()),
|
|
35
27
|
},
|
|
36
28
|
handler: async (ctx, args) => {
|
|
37
29
|
const allMacros = await ctx.db
|
|
@@ -53,7 +45,7 @@ export const listActiveMacros = query({
|
|
|
53
45
|
export const getMacro = query({
|
|
54
46
|
args: {
|
|
55
47
|
macroId: v.id('ticket_macros'),
|
|
56
|
-
userProfileId: v.optional(v.
|
|
48
|
+
userProfileId: v.optional(v.string()),
|
|
57
49
|
},
|
|
58
50
|
handler: async (ctx, args) => {
|
|
59
51
|
const macro = await ctx.db.get(args.macroId);
|
|
@@ -77,7 +69,7 @@ export const createMacro = mutation({
|
|
|
77
69
|
actions: v.object({
|
|
78
70
|
changeStatus: v.optional(v.string()),
|
|
79
71
|
assignSupplier: v.optional(v.id('suppliers')),
|
|
80
|
-
assignUser: v.optional(v.
|
|
72
|
+
assignUser: v.optional(v.string()),
|
|
81
73
|
setSlaHours: v.optional(v.number()),
|
|
82
74
|
applySlaRule: v.optional(v.boolean()),
|
|
83
75
|
addNote: v.optional(v.string()),
|
|
@@ -87,7 +79,7 @@ export const createMacro = mutation({
|
|
|
87
79
|
})),
|
|
88
80
|
setPriority: v.optional(v.string()),
|
|
89
81
|
}),
|
|
90
|
-
createdBy: v.
|
|
82
|
+
createdBy: v.string(),
|
|
91
83
|
},
|
|
92
84
|
handler: async (ctx, args) => {
|
|
93
85
|
const macroId = await ctx.db.insert('ticket_macros', {
|
|
@@ -115,7 +107,7 @@ export const updateMacro = mutation({
|
|
|
115
107
|
actions: v.optional(v.object({
|
|
116
108
|
changeStatus: v.optional(v.string()),
|
|
117
109
|
assignSupplier: v.optional(v.id('suppliers')),
|
|
118
|
-
assignUser: v.optional(v.
|
|
110
|
+
assignUser: v.optional(v.string()),
|
|
119
111
|
setSlaHours: v.optional(v.number()),
|
|
120
112
|
applySlaRule: v.optional(v.boolean()),
|
|
121
113
|
addNote: v.optional(v.string()),
|
|
@@ -181,7 +173,7 @@ export const duplicateMacro = mutation({
|
|
|
181
173
|
args: {
|
|
182
174
|
macroId: v.id('ticket_macros'),
|
|
183
175
|
newName: v.string(),
|
|
184
|
-
createdBy: v.
|
|
176
|
+
createdBy: v.string(),
|
|
185
177
|
},
|
|
186
178
|
handler: async (ctx, args) => {
|
|
187
179
|
const macro = await ctx.db.get(args.macroId);
|
|
@@ -207,8 +199,8 @@ export const duplicateMacro = mutation({
|
|
|
207
199
|
export const executeMacro = mutation({
|
|
208
200
|
args: {
|
|
209
201
|
macroId: v.id('ticket_macros'),
|
|
210
|
-
ticketId: v.
|
|
211
|
-
userProfileId: v.optional(v.
|
|
202
|
+
ticketId: v.string(),
|
|
203
|
+
userProfileId: v.optional(v.string()),
|
|
212
204
|
userAuth0Id: v.optional(v.string()),
|
|
213
205
|
userName: v.optional(v.string()),
|
|
214
206
|
userEmail: v.optional(v.string()),
|
|
@@ -227,13 +219,8 @@ export const executeMacro = mutation({
|
|
|
227
219
|
throw new Error('Non hai accesso a questa macro');
|
|
228
220
|
}
|
|
229
221
|
|
|
230
|
-
const ticket = await ctx.db.get(args.ticketId);
|
|
231
|
-
if (!ticket) {
|
|
232
|
-
throw new Error('Ticket non trovato');
|
|
233
|
-
}
|
|
234
|
-
|
|
235
222
|
const actions = macro.actions;
|
|
236
|
-
const updates: any = {
|
|
223
|
+
const updates: any = {};
|
|
237
224
|
const executedActions: string[] = [];
|
|
238
225
|
|
|
239
226
|
if (actions.changeStatus) {
|
|
@@ -247,16 +234,18 @@ export const executeMacro = mutation({
|
|
|
247
234
|
}
|
|
248
235
|
|
|
249
236
|
if (actions.assignUser) {
|
|
250
|
-
const
|
|
251
|
-
|
|
252
|
-
|
|
237
|
+
const userSettings = await ctx.db
|
|
238
|
+
.query('user_profiles')
|
|
239
|
+
.withIndex('by_auth0Id', (q: any) => q.eq('auth0Id', actions.assignUser))
|
|
240
|
+
.first();
|
|
241
|
+
if (userSettings?.supplierId) {
|
|
242
|
+
updates.supplierId = userSettings.supplierId;
|
|
253
243
|
}
|
|
254
244
|
executedActions.push('Utente assegnato');
|
|
255
245
|
}
|
|
256
246
|
|
|
257
247
|
if (actions.setSlaHours) {
|
|
258
|
-
updates.
|
|
259
|
-
updates.slaDueDate = Date.now() + (actions.setSlaHours * 60 * 60 * 1000);
|
|
248
|
+
updates.slaDeadline = Date.now() + (actions.setSlaHours * 60 * 60 * 1000);
|
|
260
249
|
executedActions.push(`SLA impostato a ${actions.setSlaHours} ore`);
|
|
261
250
|
}
|
|
262
251
|
|
|
@@ -265,11 +254,9 @@ export const executeMacro = mutation({
|
|
|
265
254
|
executedActions.push(`Priorità impostata a: ${actions.setPriority}`);
|
|
266
255
|
}
|
|
267
256
|
|
|
268
|
-
await ctx.db.patch(args.ticketId, updates);
|
|
269
|
-
|
|
270
257
|
if (actions.addNote) {
|
|
271
258
|
await ctx.db.insert('ticket_comments', {
|
|
272
|
-
|
|
259
|
+
ticketId: args.ticketId,
|
|
273
260
|
authorId: args.userAuth0Id || 'system',
|
|
274
261
|
authorName: args.userName || args.userEmail || 'Sistema',
|
|
275
262
|
authorEmail: args.userEmail || 'system@app',
|
|
@@ -286,6 +273,7 @@ export const executeMacro = mutation({
|
|
|
286
273
|
ticketId: args.ticketId,
|
|
287
274
|
macroName: macro.name,
|
|
288
275
|
executedActions,
|
|
276
|
+
ticketUpdates: updates,
|
|
289
277
|
};
|
|
290
278
|
},
|
|
291
279
|
});
|
|
@@ -74,15 +74,14 @@ export const updateTicketStatus = mutation({
|
|
|
74
74
|
});
|
|
75
75
|
|
|
76
76
|
export const deleteTicketStatus = mutation({
|
|
77
|
-
args: {
|
|
77
|
+
args: {
|
|
78
|
+
statusId: v.id('ticket_statuses'),
|
|
79
|
+
hasLinkedTickets: v.optional(v.boolean()),
|
|
80
|
+
},
|
|
78
81
|
handler: async (ctx, args) => {
|
|
79
82
|
const status = await ctx.db.get(args.statusId);
|
|
80
83
|
if (!status) throw new Error('Status not found');
|
|
81
|
-
|
|
82
|
-
.query('maintenance_tasks')
|
|
83
|
-
.withIndex('by_status', (q: any) => q.eq('status', status.name))
|
|
84
|
-
.first();
|
|
85
|
-
if (ticketsWithStatus) {
|
|
84
|
+
if (args.hasLinkedTickets) {
|
|
86
85
|
throw new Error('Cannot delete status: tickets are using it. Deactivate it instead.');
|
|
87
86
|
}
|
|
88
87
|
await ctx.db.delete(args.statusId);
|