Implement company provisioning codes and session tweaks
This commit is contained in:
parent
0fb9bf59b2
commit
2cba553efa
28 changed files with 1407 additions and 534 deletions
|
|
@ -424,11 +424,61 @@ export const getById = query({
|
|||
const visibleComments = canViewInternalComments
|
||||
? comments
|
||||
: comments.filter((comment) => comment.visibility !== "INTERNAL");
|
||||
const timeline = await ctx.db
|
||||
const visibleCommentKeys = new Set(
|
||||
visibleComments.map((comment) => `${comment.createdAt}:${comment.authorId}`)
|
||||
)
|
||||
const visibleCommentTimestamps = new Set(visibleComments.map((comment) => comment.createdAt))
|
||||
|
||||
let timelineRecords = await ctx.db
|
||||
.query("ticketEvents")
|
||||
.withIndex("by_ticket", (q) => q.eq("ticketId", id))
|
||||
.collect();
|
||||
|
||||
if (!(role === "ADMIN" || role === "AGENT")) {
|
||||
timelineRecords = timelineRecords.filter((event) => {
|
||||
const payload = (event.payload ?? {}) as Record<string, unknown>
|
||||
switch (event.type) {
|
||||
case "CREATED":
|
||||
return true
|
||||
case "QUEUE_CHANGED":
|
||||
return true
|
||||
case "ASSIGNEE_CHANGED":
|
||||
return true
|
||||
case "CATEGORY_CHANGED":
|
||||
return true
|
||||
case "COMMENT_ADDED": {
|
||||
const authorIdRaw = (payload as { authorId?: string }).authorId
|
||||
if (typeof authorIdRaw === "string" && authorIdRaw.trim().length > 0) {
|
||||
const key = `${event.createdAt}:${authorIdRaw}`
|
||||
if (visibleCommentKeys.has(key)) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return visibleCommentTimestamps.has(event.createdAt)
|
||||
}
|
||||
case "STATUS_CHANGED": {
|
||||
const toLabelRaw = (payload as { toLabel?: string }).toLabel
|
||||
const toRaw = (payload as { to?: string }).to
|
||||
const normalized = (typeof toLabelRaw === "string" && toLabelRaw.trim().length > 0
|
||||
? toLabelRaw.trim()
|
||||
: typeof toRaw === "string"
|
||||
? toRaw.trim()
|
||||
: "").toUpperCase()
|
||||
if (!normalized) return false
|
||||
return (
|
||||
normalized === "RESOLVED" ||
|
||||
normalized === "RESOLVIDO" ||
|
||||
normalized === "CLOSED" ||
|
||||
normalized === "FINALIZADO" ||
|
||||
normalized === "FINALIZED"
|
||||
)
|
||||
}
|
||||
default:
|
||||
return false
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const customFieldsRecord = mapCustomFieldsToRecord(
|
||||
(t.customFields as NormalizedCustomField[] | undefined) ?? undefined
|
||||
);
|
||||
|
|
@ -529,7 +579,7 @@ export const getById = query({
|
|||
},
|
||||
description: undefined,
|
||||
customFields: customFieldsRecord,
|
||||
timeline: timeline.map((ev) => {
|
||||
timeline: timelineRecords.map((ev) => {
|
||||
let payload = ev.payload;
|
||||
if (ev.type === "QUEUE_CHANGED" && payload && typeof payload === "object" && "queueName" in payload) {
|
||||
const normalized = renameQueueString((payload as { queueName?: string }).queueName ?? null);
|
||||
|
|
@ -712,14 +762,19 @@ export const addComment = mutation({
|
|||
|
||||
const normalizedRole = (author.role ?? "AGENT").toUpperCase()
|
||||
|
||||
const requestedVisibility = (args.visibility ?? "").toUpperCase()
|
||||
if (requestedVisibility !== "PUBLIC" && requestedVisibility !== "INTERNAL") {
|
||||
throw new ConvexError("Visibilidade inválida")
|
||||
}
|
||||
|
||||
if (normalizedRole === "MANAGER") {
|
||||
await ensureManagerTicketAccess(ctx, author, ticketDoc)
|
||||
if (args.visibility !== "PUBLIC") {
|
||||
if (requestedVisibility !== "PUBLIC") {
|
||||
throw new ConvexError("Gestores só podem registrar comentários públicos")
|
||||
}
|
||||
}
|
||||
const canUseInternalComments = normalizedRole === "ADMIN" || normalizedRole === "AGENT"
|
||||
if (args.visibility === "INTERNAL" && !canUseInternalComments) {
|
||||
if (requestedVisibility === "INTERNAL" && !canUseInternalComments) {
|
||||
throw new ConvexError("Apenas administradores e agentes podem registrar comentários internos")
|
||||
}
|
||||
|
||||
|
|
@ -731,13 +786,24 @@ export const addComment = mutation({
|
|||
await requireTicketStaff(ctx, args.authorId, ticketDoc)
|
||||
}
|
||||
|
||||
const attachments = args.attachments ?? []
|
||||
if (attachments.length > 5) {
|
||||
throw new ConvexError("É permitido anexar no máximo 5 arquivos por comentário")
|
||||
}
|
||||
const maxAttachmentSize = 5 * 1024 * 1024
|
||||
for (const attachment of attachments) {
|
||||
if (typeof attachment.size === "number" && attachment.size > maxAttachmentSize) {
|
||||
throw new ConvexError("Cada anexo pode ter até 5MB")
|
||||
}
|
||||
}
|
||||
|
||||
const now = Date.now();
|
||||
const id = await ctx.db.insert("ticketComments", {
|
||||
ticketId: args.ticketId,
|
||||
authorId: args.authorId,
|
||||
visibility: args.visibility,
|
||||
visibility: requestedVisibility,
|
||||
body: args.body,
|
||||
attachments: args.attachments ?? [],
|
||||
attachments,
|
||||
createdAt: now,
|
||||
updatedAt: now,
|
||||
});
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue