Enforce assignee-required commenting for staff; UI disables commenting until responsible is set; poll machine session for live deactivation; desktop deactivation screen update
This commit is contained in:
parent
2a8fb4330c
commit
b468c6c9e7
2 changed files with 21 additions and 2 deletions
|
|
@ -778,6 +778,15 @@ export const addComment = mutation({
|
||||||
throw new ConvexError("Apenas administradores e agentes podem registrar comentários internos")
|
throw new ConvexError("Apenas administradores e agentes podem registrar comentários internos")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Regra: a equipe (ADMIN/AGENT/MANAGER) só pode comentar se o ticket tiver responsável.
|
||||||
|
// O solicitante (colaborador) pode comentar sempre.
|
||||||
|
const isRequester = String(ticketDoc.requesterId) === String(author._id)
|
||||||
|
const isStaff = normalizedRole === "ADMIN" || normalizedRole === "AGENT" || normalizedRole === "MANAGER"
|
||||||
|
const hasAssignee = Boolean(ticketDoc.assigneeId)
|
||||||
|
if (!isRequester && isStaff && !hasAssignee) {
|
||||||
|
throw new ConvexError("Somente é possível comentar quando o chamado possui um responsável.")
|
||||||
|
}
|
||||||
|
|
||||||
if (ticketDoc.requesterId === args.authorId) {
|
if (ticketDoc.requesterId === args.authorId) {
|
||||||
// O próprio solicitante pode comentar seu ticket.
|
// O próprio solicitante pode comentar seu ticket.
|
||||||
// Comentários internos já são bloqueados acima para quem não é STAFF.
|
// Comentários internos já são bloqueados acima para quem não é STAFF.
|
||||||
|
|
|
||||||
|
|
@ -36,6 +36,10 @@ export function TicketComments({ ticket }: TicketCommentsProps) {
|
||||||
const { convexUserId, isStaff, role } = useAuth()
|
const { convexUserId, isStaff, role } = useAuth()
|
||||||
const normalizedRole = role ?? null
|
const normalizedRole = role ?? null
|
||||||
const canSeeInternalComments = normalizedRole === "admin" || normalizedRole === "agent"
|
const canSeeInternalComments = normalizedRole === "admin" || normalizedRole === "agent"
|
||||||
|
const hasAssignee = Boolean(ticket.assignee)
|
||||||
|
const isRequester = convexUserId ? ticket.requester.id === convexUserId : false
|
||||||
|
const canStaffComment = hasAssignee
|
||||||
|
const canComment = isRequester || (isStaff && canStaffComment)
|
||||||
const addComment = useMutation(api.tickets.addComment)
|
const addComment = useMutation(api.tickets.addComment)
|
||||||
const removeAttachment = useMutation(api.tickets.removeCommentAttachment)
|
const removeAttachment = useMutation(api.tickets.removeCommentAttachment)
|
||||||
const updateComment = useMutation(api.tickets.updateComment)
|
const updateComment = useMutation(api.tickets.updateComment)
|
||||||
|
|
@ -360,12 +364,18 @@ export function TicketComments({ ticket }: TicketCommentsProps) {
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
)}
|
)}
|
||||||
|
{!canComment && (
|
||||||
|
<div className="rounded-xl border border-amber-200 bg-amber-50 px-3 py-2 text-sm text-amber-700">
|
||||||
|
Atribua um responsável ao chamado para que a equipe possa comentar.
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
<form onSubmit={handleSubmit} className="mt-4 space-y-3">
|
<form onSubmit={handleSubmit} className="mt-4 space-y-3">
|
||||||
<RichTextEditor value={body} onChange={setBody} placeholder="Escreva um comentário..." />
|
<RichTextEditor value={body} onChange={setBody} placeholder="Escreva um comentário..." className="rounded-2xl border border-slate-200" disabled={!canComment} />
|
||||||
<Dropzone
|
<Dropzone
|
||||||
onUploaded={(files) => setAttachmentsToSend((prev) => [...prev, ...files])}
|
onUploaded={(files) => setAttachmentsToSend((prev) => [...prev, ...files])}
|
||||||
currentFileCount={attachmentsToSend.length}
|
currentFileCount={attachmentsToSend.length}
|
||||||
currentTotalBytes={attachmentsToSendTotalBytes}
|
currentTotalBytes={attachmentsToSendTotalBytes}
|
||||||
|
disabled={!canComment}
|
||||||
/>
|
/>
|
||||||
{attachmentsToSend.length > 0 ? (
|
{attachmentsToSend.length > 0 ? (
|
||||||
<div className="grid max-w-xl grid-cols-[repeat(auto-fill,minmax(96px,1fr))] gap-3">
|
<div className="grid max-w-xl grid-cols-[repeat(auto-fill,minmax(96px,1fr))] gap-3">
|
||||||
|
|
@ -477,7 +487,7 @@ export function TicketComments({ ticket }: TicketCommentsProps) {
|
||||||
</Select>
|
</Select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<Button type="submit" size="sm" className={submitButtonClass}>
|
<Button type="submit" size="sm" className={submitButtonClass} disabled={!canComment}>
|
||||||
Enviar
|
Enviar
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue