@hed-hog/ticket 0.0.285

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 (134) hide show
  1. package/README.md +480 -0
  2. package/dist/dto/assign-ticket-owner.dto.d.ts +4 -0
  3. package/dist/dto/assign-ticket-owner.dto.d.ts.map +1 -0
  4. package/dist/dto/assign-ticket-owner.dto.js +7 -0
  5. package/dist/dto/assign-ticket-owner.dto.js.map +1 -0
  6. package/dist/dto/create-ticket-channel-account.dto.d.ts +10 -0
  7. package/dist/dto/create-ticket-channel-account.dto.d.ts.map +1 -0
  8. package/dist/dto/create-ticket-channel-account.dto.js +7 -0
  9. package/dist/dto/create-ticket-channel-account.dto.js.map +1 -0
  10. package/dist/dto/create-ticket-channel.dto.d.ts +7 -0
  11. package/dist/dto/create-ticket-channel.dto.d.ts.map +1 -0
  12. package/dist/dto/create-ticket-channel.dto.js +7 -0
  13. package/dist/dto/create-ticket-channel.dto.js.map +1 -0
  14. package/dist/dto/create-ticket-internal-note.dto.d.ts +4 -0
  15. package/dist/dto/create-ticket-internal-note.dto.d.ts.map +1 -0
  16. package/dist/dto/create-ticket-internal-note.dto.js +7 -0
  17. package/dist/dto/create-ticket-internal-note.dto.js.map +1 -0
  18. package/dist/dto/create-ticket-reply.dto.d.ts +5 -0
  19. package/dist/dto/create-ticket-reply.dto.d.ts.map +1 -0
  20. package/dist/dto/create-ticket-reply.dto.js +7 -0
  21. package/dist/dto/create-ticket-reply.dto.js.map +1 -0
  22. package/dist/dto/update-ticket-channel-account.dto.d.ts +8 -0
  23. package/dist/dto/update-ticket-channel-account.dto.d.ts.map +1 -0
  24. package/dist/dto/update-ticket-channel-account.dto.js +7 -0
  25. package/dist/dto/update-ticket-channel-account.dto.js.map +1 -0
  26. package/dist/dto/update-ticket-channel.dto.d.ts +5 -0
  27. package/dist/dto/update-ticket-channel.dto.d.ts.map +1 -0
  28. package/dist/dto/update-ticket-channel.dto.js +7 -0
  29. package/dist/dto/update-ticket-channel.dto.js.map +1 -0
  30. package/dist/dto/update-ticket-priority.dto.d.ts +4 -0
  31. package/dist/dto/update-ticket-priority.dto.d.ts.map +1 -0
  32. package/dist/dto/update-ticket-priority.dto.js +7 -0
  33. package/dist/dto/update-ticket-priority.dto.js.map +1 -0
  34. package/dist/dto/update-ticket-settings.dto.d.ts +13 -0
  35. package/dist/dto/update-ticket-settings.dto.d.ts.map +1 -0
  36. package/dist/dto/update-ticket-settings.dto.js +7 -0
  37. package/dist/dto/update-ticket-settings.dto.js.map +1 -0
  38. package/dist/dto/update-ticket-status.dto.d.ts +4 -0
  39. package/dist/dto/update-ticket-status.dto.d.ts.map +1 -0
  40. package/dist/dto/update-ticket-status.dto.js +7 -0
  41. package/dist/dto/update-ticket-status.dto.js.map +1 -0
  42. package/dist/index.d.ts +19 -0
  43. package/dist/index.d.ts.map +1 -0
  44. package/dist/index.js +35 -0
  45. package/dist/index.js.map +1 -0
  46. package/dist/ticket-ai-review.controller.d.ts +9 -0
  47. package/dist/ticket-ai-review.controller.d.ts.map +1 -0
  48. package/dist/ticket-ai-review.controller.js +36 -0
  49. package/dist/ticket-ai-review.controller.js.map +1 -0
  50. package/dist/ticket-channel-accounts.controller.d.ts +24 -0
  51. package/dist/ticket-channel-accounts.controller.d.ts.map +1 -0
  52. package/dist/ticket-channel-accounts.controller.js +72 -0
  53. package/dist/ticket-channel-accounts.controller.js.map +1 -0
  54. package/dist/ticket-channels.controller.d.ts +21 -0
  55. package/dist/ticket-channels.controller.d.ts.map +1 -0
  56. package/dist/ticket-channels.controller.js +72 -0
  57. package/dist/ticket-channels.controller.js.map +1 -0
  58. package/dist/ticket-data.controller.d.ts +24 -0
  59. package/dist/ticket-data.controller.d.ts.map +1 -0
  60. package/dist/ticket-data.controller.js +81 -0
  61. package/dist/ticket-data.controller.js.map +1 -0
  62. package/dist/ticket-items.controller.d.ts +35 -0
  63. package/dist/ticket-items.controller.d.ts.map +1 -0
  64. package/dist/ticket-items.controller.js +100 -0
  65. package/dist/ticket-items.controller.js.map +1 -0
  66. package/dist/ticket-settings.controller.d.ts +11 -0
  67. package/dist/ticket-settings.controller.d.ts.map +1 -0
  68. package/dist/ticket-settings.controller.js +50 -0
  69. package/dist/ticket-settings.controller.js.map +1 -0
  70. package/dist/ticket.module.d.ts +3 -0
  71. package/dist/ticket.module.d.ts.map +1 -0
  72. package/dist/ticket.module.js +45 -0
  73. package/dist/ticket.module.js.map +1 -0
  74. package/dist/ticket.service.d.ts +88 -0
  75. package/dist/ticket.service.d.ts.map +1 -0
  76. package/dist/ticket.service.js +83 -0
  77. package/dist/ticket.service.js.map +1 -0
  78. package/hedhog/data/menu.yaml +164 -0
  79. package/hedhog/data/role.yaml +23 -0
  80. package/hedhog/data/route.yaml +225 -0
  81. package/hedhog/data/setting_group.yaml +574 -0
  82. package/hedhog/frontend/app/[id]/page.tsx.ejs +360 -0
  83. package/hedhog/frontend/app/_components/ai-draft-editor-dialog.tsx.ejs +67 -0
  84. package/hedhog/frontend/app/_components/ticket-badges.tsx.ejs +65 -0
  85. package/hedhog/frontend/app/_components/ticket-context-card.tsx.ejs +80 -0
  86. package/hedhog/frontend/app/_components/ticket-timeline.tsx.ejs +59 -0
  87. package/hedhog/frontend/app/_lib/mock-data.ts.ejs +474 -0
  88. package/hedhog/frontend/app/_lib/types.ts.ejs +134 -0
  89. package/hedhog/frontend/app/ai-review/page.tsx.ejs +205 -0
  90. package/hedhog/frontend/app/channel-accounts/page.tsx.ejs +476 -0
  91. package/hedhog/frontend/app/channels/page.tsx.ejs +406 -0
  92. package/hedhog/frontend/app/dashboard/page.tsx.ejs +178 -0
  93. package/hedhog/frontend/app/inbox/page.tsx.ejs +500 -0
  94. package/hedhog/frontend/app/page.tsx.ejs +5 -0
  95. package/hedhog/frontend/app/reports/page.tsx.ejs +151 -0
  96. package/hedhog/frontend/app/roles/page.tsx.ejs +110 -0
  97. package/hedhog/frontend/app/settings/page.tsx.ejs +484 -0
  98. package/hedhog/frontend/messages/en.json +412 -0
  99. package/hedhog/frontend/messages/pt.json +412 -0
  100. package/hedhog/table/channel.yaml +23 -0
  101. package/hedhog/table/channel_account.yaml +34 -0
  102. package/hedhog/table/ticket.yaml +73 -0
  103. package/hedhog/table/ticket_ai_draft.yaml +51 -0
  104. package/hedhog/table/ticket_attachment.yaml +40 -0
  105. package/hedhog/table/ticket_category.yaml +22 -0
  106. package/hedhog/table/ticket_context.yaml +64 -0
  107. package/hedhog/table/ticket_message.yaml +49 -0
  108. package/hedhog/table/ticket_message_source.yaml +50 -0
  109. package/hedhog/table/ticket_metadata.yaml +21 -0
  110. package/hedhog/table/ticket_participant.yaml +25 -0
  111. package/hedhog/table/ticket_source.yaml +43 -0
  112. package/hedhog/table/ticket_tag.yaml +22 -0
  113. package/package.json +40 -0
  114. package/src/dto/assign-ticket-owner.dto.ts +3 -0
  115. package/src/dto/create-ticket-channel-account.dto.ts +9 -0
  116. package/src/dto/create-ticket-channel.dto.ts +6 -0
  117. package/src/dto/create-ticket-internal-note.dto.ts +3 -0
  118. package/src/dto/create-ticket-reply.dto.ts +4 -0
  119. package/src/dto/update-ticket-channel-account.dto.ts +7 -0
  120. package/src/dto/update-ticket-channel.dto.ts +4 -0
  121. package/src/dto/update-ticket-priority.dto.ts +3 -0
  122. package/src/dto/update-ticket-settings.dto.ts +12 -0
  123. package/src/dto/update-ticket-status.dto.ts +3 -0
  124. package/src/index.ts +19 -0
  125. package/src/language/en.json +8 -0
  126. package/src/language/pt.json +8 -0
  127. package/src/ticket-ai-review.controller.ts +14 -0
  128. package/src/ticket-channel-accounts.controller.ts +34 -0
  129. package/src/ticket-channels.controller.ts +31 -0
  130. package/src/ticket-data.controller.ts +39 -0
  131. package/src/ticket-items.controller.ts +56 -0
  132. package/src/ticket-settings.controller.ts +20 -0
  133. package/src/ticket.module.ts +32 -0
  134. package/src/ticket.service.ts +102 -0
@@ -0,0 +1,474 @@
1
+ import {
2
+ Channel,
3
+ ChannelAccount,
4
+ PersonLite,
5
+ TicketContext,
6
+ TicketDraft,
7
+ TicketItem,
8
+ TicketMessage,
9
+ TicketRolePermission,
10
+ } from './types';
11
+
12
+ export const ticketPeople: PersonLite[] = [
13
+ {
14
+ id: 101,
15
+ name: 'Camila Moraes',
16
+ email: 'camila.moraes@hcode.com.br',
17
+ roleLabel: 'Ticket Operator',
18
+ },
19
+ {
20
+ id: 102,
21
+ name: 'Bruno Araujo',
22
+ email: 'bruno.araujo@hcode.com.br',
23
+ roleLabel: 'Ticket Admin',
24
+ },
25
+ {
26
+ id: 103,
27
+ name: 'Gabriel Nunes',
28
+ email: 'gabriel.nunes@hcode.com.br',
29
+ roleLabel: 'Ticket Analyst',
30
+ },
31
+ {
32
+ id: 201,
33
+ name: 'Aline Souza',
34
+ email: 'aline.souza@gmail.com',
35
+ roleLabel: 'Requester',
36
+ },
37
+ {
38
+ id: 202,
39
+ name: 'Fernando Lima',
40
+ email: 'fernando.lima@outlook.com',
41
+ roleLabel: 'Requester',
42
+ },
43
+ {
44
+ id: 203,
45
+ name: 'Patricia Vieira',
46
+ email: 'patricia.vieira@hcode.com.br',
47
+ roleLabel: 'Requester',
48
+ },
49
+ ];
50
+
51
+ export const ticketChannels: Channel[] = [
52
+ {
53
+ id: 1,
54
+ code: 'portal',
55
+ name: 'Hcode Class',
56
+ kind: 'portal',
57
+ status: 'active',
58
+ },
59
+ {
60
+ id: 2,
61
+ code: 'marketplace',
62
+ name: 'Udemy',
63
+ kind: 'marketplace',
64
+ status: 'active',
65
+ },
66
+ { id: 3, code: 'social', name: 'YouTube', kind: 'social', status: 'active' },
67
+ { id: 4, code: 'form', name: 'Site Contact', kind: 'form', status: 'active' },
68
+ { id: 5, code: 'email', name: 'Email', kind: 'email', status: 'active' },
69
+ {
70
+ id: 6,
71
+ code: 'whatsapp',
72
+ name: 'WhatsApp Official',
73
+ kind: 'whatsapp',
74
+ status: 'active',
75
+ },
76
+ { id: 7, code: 'api', name: 'External API', kind: 'api', status: 'inactive' },
77
+ { id: 8, code: 'other', name: 'Other', kind: 'other', status: 'inactive' },
78
+ ];
79
+
80
+ export const ticketChannelAccounts: ChannelAccount[] = [
81
+ {
82
+ id: 11,
83
+ channelId: 1,
84
+ code: 'hcode_class',
85
+ name: 'Hcode Class Main',
86
+ externalIdentifier: 'tenant_hcode_class_prod',
87
+ status: 'active',
88
+ aiEnabled: true,
89
+ aiModel: 'gpt-5.3-mini',
90
+ },
91
+ {
92
+ id: 12,
93
+ channelId: 2,
94
+ code: 'udemy_hcode',
95
+ name: 'Udemy Hcode',
96
+ externalIdentifier: 'udemy_org_hcode',
97
+ status: 'active',
98
+ aiEnabled: true,
99
+ aiModel: 'gpt-5.3-mini',
100
+ },
101
+ {
102
+ id: 13,
103
+ channelId: 3,
104
+ code: 'youtube_hcode',
105
+ name: 'YouTube Hcode',
106
+ externalIdentifier: 'UCvA9_fhcoDeMain',
107
+ status: 'active',
108
+ aiEnabled: false,
109
+ aiModel: 'disabled',
110
+ },
111
+ {
112
+ id: 14,
113
+ channelId: 4,
114
+ code: 'site_contact',
115
+ name: 'Site Contact Form',
116
+ externalIdentifier: 'form_fale_conosco_prod',
117
+ status: 'active',
118
+ aiEnabled: true,
119
+ aiModel: 'gpt-5.3-mini',
120
+ },
121
+ {
122
+ id: 15,
123
+ channelId: 5,
124
+ code: 'suporte_hcode_com_br',
125
+ name: 'support@hcode.com.br',
126
+ externalIdentifier: 'mailbox_support_prod',
127
+ status: 'active',
128
+ aiEnabled: true,
129
+ aiModel: 'gpt-5.3-mini',
130
+ },
131
+ {
132
+ id: 16,
133
+ channelId: 6,
134
+ code: 'whatsapp_hcode',
135
+ name: 'WhatsApp +55 11 99999-9999',
136
+ externalIdentifier: 'wa_business_5511999999999',
137
+ status: 'active',
138
+ aiEnabled: true,
139
+ aiModel: 'gpt-5.3-mini',
140
+ },
141
+ ];
142
+
143
+ export const ticketItems: TicketItem[] = [
144
+ {
145
+ id: 5001,
146
+ code: 'TCK-2026-00421',
147
+ subject: 'Erro ao gerar refresh token na aula JWT com Refresh Token',
148
+ status: 'open',
149
+ priority: 'urgent',
150
+ aiReviewMode: 'required',
151
+ requesterId: 201,
152
+ ownerId: 101,
153
+ channelId: 2,
154
+ channelAccountId: 12,
155
+ tags: ['nestjs', 'jwt', 'autenticacao'],
156
+ categories: ['duvida_tecnica'],
157
+ lastActivity: '2026-03-17T15:08:00Z',
158
+ },
159
+ {
160
+ id: 5002,
161
+ code: 'TCK-2026-00422',
162
+ subject: 'Nao recebi certificado no curso SQL Completo',
163
+ status: 'waiting_customer',
164
+ priority: 'normal',
165
+ aiReviewMode: 'optional',
166
+ requesterId: 202,
167
+ ownerId: 101,
168
+ channelId: 1,
169
+ channelAccountId: 11,
170
+ tags: ['sql', 'certificado'],
171
+ categories: ['certificacao'],
172
+ lastActivity: '2026-03-17T13:22:00Z',
173
+ },
174
+ {
175
+ id: 5003,
176
+ code: 'TCK-2026-00423',
177
+ subject: 'Duvida sobre INNER JOIN e LEFT JOIN na pratica',
178
+ status: 'pending',
179
+ priority: 'high',
180
+ aiReviewMode: 'optional',
181
+ requesterId: 203,
182
+ ownerId: 102,
183
+ channelId: 5,
184
+ channelAccountId: 15,
185
+ tags: ['sql', 'join'],
186
+ categories: ['conteudo_aula'],
187
+ lastActivity: '2026-03-17T14:41:00Z',
188
+ },
189
+ {
190
+ id: 5004,
191
+ code: 'TCK-2026-00424',
192
+ subject: 'Link quebrado na aula 10 do curso de PHP no YouTube',
193
+ status: 'resolved',
194
+ priority: 'low',
195
+ aiReviewMode: 'disabled',
196
+ requesterId: 202,
197
+ ownerId: 101,
198
+ channelId: 3,
199
+ channelAccountId: 13,
200
+ tags: ['youtube', 'php'],
201
+ categories: ['conteudo_aula'],
202
+ lastActivity: '2026-03-16T21:18:00Z',
203
+ },
204
+ {
205
+ id: 5005,
206
+ code: 'TCK-2026-00425',
207
+ subject: 'Solicitacao de segunda via de boleto via WhatsApp',
208
+ status: 'open',
209
+ priority: 'high',
210
+ aiReviewMode: 'required',
211
+ requesterId: 203,
212
+ ownerId: 101,
213
+ channelId: 6,
214
+ channelAccountId: 16,
215
+ tags: ['financeiro', 'boleto'],
216
+ categories: ['financeiro'],
217
+ lastActivity: '2026-03-17T15:12:00Z',
218
+ },
219
+ ];
220
+
221
+ export const ticketContexts: TicketContext[] = [
222
+ {
223
+ ticketId: 5001,
224
+ contextType: 'course_lesson',
225
+ sourceLabel: 'Udemy',
226
+ externalUrl:
227
+ 'https://www.udemy.com/course/nestjs/learn/lecture/refresh-token',
228
+ courseName: 'NestJS',
229
+ sectionName: 'Autenticacao',
230
+ lessonName: 'JWT com Refresh Token',
231
+ },
232
+ {
233
+ ticketId: 5002,
234
+ contextType: 'course_lesson',
235
+ sourceLabel: 'Hcode Class',
236
+ externalUrl:
237
+ 'https://class.hcode.com.br/course/sql-completo/section/certificacao',
238
+ courseName: 'SQL Completo',
239
+ sectionName: 'Provas e Certificacao',
240
+ lessonName: 'Emissao de Certificado',
241
+ },
242
+ {
243
+ ticketId: 5003,
244
+ contextType: 'course_lesson',
245
+ sourceLabel: 'Email',
246
+ courseName: 'SQL Completo',
247
+ sectionName: 'Consultas Avancadas',
248
+ lessonName: 'INNER JOIN e LEFT JOIN',
249
+ },
250
+ {
251
+ ticketId: 5004,
252
+ contextType: 'video',
253
+ sourceLabel: 'YouTube',
254
+ externalUrl: 'https://www.youtube.com/watch?v=php-aula10',
255
+ videoName: 'Curso de PHP - Aula 10',
256
+ },
257
+ {
258
+ ticketId: 5005,
259
+ contextType: 'whatsapp_chat',
260
+ sourceLabel: 'WhatsApp Official',
261
+ pageName: 'Atendimento Financeiro',
262
+ },
263
+ ];
264
+
265
+ export const ticketMessages: TicketMessage[] = [
266
+ {
267
+ id: 9001,
268
+ ticketId: 5001,
269
+ authorName: 'Aline Souza',
270
+ authorRole: 'requester',
271
+ direction: 'inbound',
272
+ audience: 'public',
273
+ body: 'Oi, no modulo de JWT com Refresh Token eu segui tudo igual e ainda recebo 401 no refresh. Pode me ajudar?',
274
+ createdAt: '2026-03-17T14:35:00Z',
275
+ },
276
+ {
277
+ id: 9002,
278
+ ticketId: 5001,
279
+ authorName: 'Camila Moraes',
280
+ authorRole: 'agent',
281
+ direction: 'outbound',
282
+ audience: 'public',
283
+ body: 'Claro! Você pode confirmar se a coluna refresh_token_hash foi criada e se o token antigo está sendo invalidado no login?',
284
+ createdAt: '2026-03-17T14:49:00Z',
285
+ },
286
+ {
287
+ id: 9003,
288
+ ticketId: 5001,
289
+ authorName: 'Aline Souza',
290
+ authorRole: 'requester',
291
+ direction: 'inbound',
292
+ audience: 'public',
293
+ body: 'A coluna existe sim. Descobri que estou assinando o refresh com secret diferente do access sem querer. Isso pode ser?',
294
+ createdAt: '2026-03-17T15:01:00Z',
295
+ },
296
+ {
297
+ id: 9004,
298
+ ticketId: 5001,
299
+ authorName: 'Ticket AI',
300
+ authorRole: 'system',
301
+ direction: 'system',
302
+ audience: 'internal',
303
+ body: 'Draft suggestion generated with model gpt-5.3-mini and queued for human review.',
304
+ createdAt: '2026-03-17T15:03:00Z',
305
+ },
306
+ {
307
+ id: 9101,
308
+ ticketId: 5005,
309
+ authorName: 'Patricia Vieira',
310
+ authorRole: 'requester',
311
+ direction: 'inbound',
312
+ audience: 'public',
313
+ body: 'Boa tarde, preciso da segunda via do boleto de renovacao anual.',
314
+ createdAt: '2026-03-17T15:10:00Z',
315
+ },
316
+ ];
317
+
318
+ export const ticketDrafts: TicketDraft[] = [
319
+ {
320
+ id: 3001,
321
+ ticketId: 5001,
322
+ ticketCode: 'TCK-2026-00421',
323
+ channel: 'Udemy',
324
+ context: 'NestJS > Autenticacao > JWT com Refresh Token',
325
+ modelName: 'gpt-5.3-mini',
326
+ status: 'pending_review',
327
+ originalSnippet:
328
+ 'Descobri que estou assinando o refresh com secret diferente do access sem querer. Isso pode ser?',
329
+ suggestion:
330
+ 'Sim, isso causa exatamente esse erro. No NestJS voce pode usar secrets diferentes para access e refresh, mas precisa validar cada token com a strategy correta e garantir que o refresh token tenha expiracao e secret consistentes no sign e no verify.',
331
+ },
332
+ {
333
+ id: 3002,
334
+ ticketId: 5005,
335
+ ticketCode: 'TCK-2026-00425',
336
+ channel: 'WhatsApp Official',
337
+ context: 'Financeiro > Renovacao',
338
+ modelName: 'gpt-5.3-mini',
339
+ status: 'pending_review',
340
+ originalSnippet: 'Preciso da segunda via do boleto de renovacao anual.',
341
+ suggestion:
342
+ 'Perfeito! Posso gerar a segunda via para voce agora. Me confirme por favor o e-mail cadastrado para envio do boleto atualizado.',
343
+ },
344
+ {
345
+ id: 3003,
346
+ ticketId: 5003,
347
+ ticketCode: 'TCK-2026-00423',
348
+ channel: 'Email',
349
+ context: 'SQL Completo > Consultas Avancadas',
350
+ modelName: 'gpt-5.3-mini',
351
+ status: 'approved',
352
+ originalSnippet:
353
+ 'Nao entendi quando usar LEFT JOIN no lugar de INNER JOIN.',
354
+ suggestion:
355
+ 'Use INNER JOIN quando so quer registros com correspondencia nas duas tabelas. Use LEFT JOIN quando quer todos os registros da tabela da esquerda, mesmo sem correspondencia na direita.',
356
+ reviewerName: 'Bruno Araujo',
357
+ },
358
+ ];
359
+
360
+ export const ticketRolePermissions: TicketRolePermission[] = [
361
+ {
362
+ permission: 'View all tickets',
363
+ ticketAdmin: true,
364
+ ticketOperator: true,
365
+ ticketAnalyst: true,
366
+ },
367
+ {
368
+ permission: 'Reply tickets',
369
+ ticketAdmin: true,
370
+ ticketOperator: true,
371
+ ticketAnalyst: false,
372
+ },
373
+ {
374
+ permission: 'Create internal notes',
375
+ ticketAdmin: true,
376
+ ticketOperator: true,
377
+ ticketAnalyst: false,
378
+ },
379
+ {
380
+ permission: 'Approve or reject AI drafts',
381
+ ticketAdmin: true,
382
+ ticketOperator: true,
383
+ ticketAnalyst: false,
384
+ },
385
+ {
386
+ permission: 'Change module settings',
387
+ ticketAdmin: true,
388
+ ticketOperator: false,
389
+ ticketAnalyst: false,
390
+ },
391
+ {
392
+ permission: 'Manage channels and accounts',
393
+ ticketAdmin: true,
394
+ ticketOperator: false,
395
+ ticketAnalyst: false,
396
+ },
397
+ {
398
+ permission: 'Assign operators',
399
+ ticketAdmin: true,
400
+ ticketOperator: true,
401
+ ticketAnalyst: false,
402
+ },
403
+ {
404
+ permission: 'Access reports',
405
+ ticketAdmin: true,
406
+ ticketOperator: false,
407
+ ticketAnalyst: true,
408
+ },
409
+ ];
410
+
411
+ export const dashboardSummary = {
412
+ totalOpen: 132,
413
+ pending: 47,
414
+ waitingCustomer: 28,
415
+ resolvedToday: 19,
416
+ urgent: 11,
417
+ aiPendingReview: 7,
418
+ };
419
+
420
+ export const ticketsByChannel = [
421
+ { label: 'Hcode Class', value: 46, color: 'bg-sky-500' },
422
+ { label: 'Udemy', value: 39, color: 'bg-orange-500' },
423
+ { label: 'YouTube', value: 12, color: 'bg-red-500' },
424
+ { label: 'Email', value: 18, color: 'bg-emerald-500' },
425
+ { label: 'WhatsApp', value: 14, color: 'bg-lime-500' },
426
+ { label: 'Site Contact', value: 9, color: 'bg-indigo-500' },
427
+ ];
428
+
429
+ export const ticketsByCourse = [
430
+ { label: 'NestJS', value: 34 },
431
+ { label: 'SQL Completo', value: 27 },
432
+ { label: 'React', value: 18 },
433
+ { label: 'PHP', value: 14 },
434
+ { label: 'Node.js', value: 11 },
435
+ ];
436
+
437
+ export const latestActivity = [
438
+ {
439
+ time: '15:12',
440
+ label: 'Patricia abriu ticket via WhatsApp sobre segunda via de boleto.',
441
+ },
442
+ {
443
+ time: '15:03',
444
+ label: 'IA sugeriu resposta para TCK-2026-00421 aguardando aprovacao.',
445
+ },
446
+ {
447
+ time: '14:49',
448
+ label: 'Camila respondeu duvida de JWT no ticket TCK-2026-00421.',
449
+ },
450
+ {
451
+ time: '14:31',
452
+ label: 'Novo ticket do canal Email associado ao curso SQL Completo.',
453
+ },
454
+ ];
455
+
456
+ export function getPersonById(id: number) {
457
+ return ticketPeople.find((item) => item.id === id);
458
+ }
459
+
460
+ export function getChannelById(id: number) {
461
+ return ticketChannels.find((item) => item.id === id);
462
+ }
463
+
464
+ export function getChannelAccountById(id: number) {
465
+ return ticketChannelAccounts.find((item) => item.id === id);
466
+ }
467
+
468
+ export function getTicketContextByTicketId(ticketId: number) {
469
+ return ticketContexts.find((item) => item.ticketId === ticketId);
470
+ }
471
+
472
+ export function getTicketMessages(ticketId: number) {
473
+ return ticketMessages.filter((item) => item.ticketId === ticketId);
474
+ }
@@ -0,0 +1,134 @@
1
+ export type TicketStatus =
2
+ | 'open'
3
+ | 'pending'
4
+ | 'waiting_customer'
5
+ | 'resolved'
6
+ | 'closed'
7
+ | 'spam';
8
+
9
+ export type TicketPriority = 'low' | 'normal' | 'high' | 'urgent';
10
+
11
+ export type TicketAiReviewMode = 'disabled' | 'optional' | 'required';
12
+
13
+ export type TicketChannelKind =
14
+ | 'portal'
15
+ | 'marketplace'
16
+ | 'social'
17
+ | 'form'
18
+ | 'email'
19
+ | 'whatsapp'
20
+ | 'api'
21
+ | 'other';
22
+
23
+ export type TicketDirection = 'inbound' | 'outbound' | 'internal' | 'system';
24
+
25
+ export type TicketAudience = 'public' | 'internal';
26
+
27
+ export type DraftStatus =
28
+ | 'draft'
29
+ | 'pending_review'
30
+ | 'approved'
31
+ | 'rejected'
32
+ | 'sent';
33
+
34
+ export type DeliveryStatus =
35
+ | 'pending'
36
+ | 'sent'
37
+ | 'delivered'
38
+ | 'failed'
39
+ | 'received'
40
+ | 'read';
41
+
42
+ export type PersonLite = {
43
+ id: number;
44
+ name: string;
45
+ email: string;
46
+ roleLabel: string;
47
+ };
48
+
49
+ export type Channel = {
50
+ id: number;
51
+ code: string;
52
+ name: string;
53
+ kind: TicketChannelKind;
54
+ status: 'active' | 'inactive';
55
+ };
56
+
57
+ export type ChannelAccount = {
58
+ id: number;
59
+ channelId: number;
60
+ code: string;
61
+ name: string;
62
+ externalIdentifier: string;
63
+ status: 'active' | 'inactive';
64
+ aiEnabled: boolean;
65
+ aiModel: string;
66
+ };
67
+
68
+ export type TicketContext = {
69
+ ticketId: number;
70
+ contextType:
71
+ | 'course_lesson'
72
+ | 'course'
73
+ | 'video'
74
+ | 'page'
75
+ | 'email_thread'
76
+ | 'whatsapp_chat'
77
+ | 'contact_form'
78
+ | 'other';
79
+ sourceLabel: string;
80
+ externalUrl?: string;
81
+ courseName?: string;
82
+ sectionName?: string;
83
+ lessonName?: string;
84
+ videoName?: string;
85
+ pageName?: string;
86
+ };
87
+
88
+ export type TicketItem = {
89
+ id: number;
90
+ code: string;
91
+ subject: string;
92
+ status: TicketStatus;
93
+ priority: TicketPriority;
94
+ aiReviewMode: TicketAiReviewMode;
95
+ requesterId: number;
96
+ ownerId: number;
97
+ channelId: number;
98
+ channelAccountId: number;
99
+ tags: string[];
100
+ categories: string[];
101
+ lastActivity: string;
102
+ };
103
+
104
+ export type TicketMessage = {
105
+ id: number;
106
+ ticketId: number;
107
+ authorName: string;
108
+ authorRole: 'requester' | 'agent' | 'system';
109
+ direction: TicketDirection;
110
+ audience: TicketAudience;
111
+ body: string;
112
+ createdAt: string;
113
+ attachments?: Array<{ name: string; kind: 'file' | 'image' | 'link' }>;
114
+ };
115
+
116
+ export type TicketDraft = {
117
+ id: number;
118
+ ticketId: number;
119
+ ticketCode: string;
120
+ channel: string;
121
+ context: string;
122
+ modelName: string;
123
+ status: DraftStatus;
124
+ originalSnippet: string;
125
+ suggestion: string;
126
+ reviewerName?: string;
127
+ };
128
+
129
+ export type TicketRolePermission = {
130
+ permission: string;
131
+ ticketAdmin: boolean;
132
+ ticketOperator: boolean;
133
+ ticketAnalyst: boolean;
134
+ };