feat: enhance visit scheduling and closing flow

This commit is contained in:
Esdras Renan 2025-11-18 17:42:38 -03:00
parent a7f9191e1d
commit 6473e8d40f
5 changed files with 577 additions and 243 deletions

View file

@ -32,6 +32,12 @@ const DEFAULT_PHONE_NUMBER = "(11) 4173-5368"
const DEFAULT_COMPANY_NAME = "Rever Tecnologia"
const sanitizeTemplate = (html: string) => stripLeadingEmptyParagraphs(sanitizeEditorHtml(html.trim()))
const htmlToPlainText = (value: string) =>
value
.replace(/<[^>]+>/g, " ")
.replace(/&nbsp;/gi, " ")
.replace(/\s+/g, " ")
.trim()
export type AdjustWorkSummaryResult = {
ticketId: Id<"tickets">
@ -205,6 +211,9 @@ export function CloseTicketDialog({
const [selectedTemplateId, setSelectedTemplateId] = useState<string | null>(null)
const [message, setMessage] = useState<string>("")
const [messageWarning, setMessageWarning] = useState(false)
const messagePlainText = useMemo(() => htmlToPlainText(message ?? ""), [message])
const hasMessage = messagePlainText.length > 0
const [isSubmitting, setIsSubmitting] = useState(false)
const [shouldAdjustTime, setShouldAdjustTime] = useState<boolean>(false)
const [internalHours, setInternalHours] = useState<string>("0")
@ -228,6 +237,12 @@ export function CloseTicketDialog({
const draftStorageKey = useMemo(() => `${DRAFT_STORAGE_PREFIX}${ticketId}`, [ticketId])
useEffect(() => {
if (messageWarning && hasMessage) {
setMessageWarning(false)
}
}, [hasMessage, messageWarning])
const digitsOnlyReference = linkedReference.replace(/[^0-9]/g, "").trim()
const normalizedReference = useMemo(() => {
@ -540,7 +555,14 @@ export function CloseTicketDialog({
setCurrentStep(index)
}
const goToNextStep = () => setCurrentStep((prev) => Math.min(prev + 1, WIZARD_STEPS.length - 1))
const goToNextStep = useCallback(() => {
if (currentStep === 0 && !hasMessage) {
setMessageWarning(true)
toast.error("Escreva uma mensagem de encerramento antes de continuar.")
return
}
setCurrentStep((prev) => Math.min(prev + 1, WIZARD_STEPS.length - 1))
}, [currentStep, hasMessage])
const goToPreviousStep = () => setCurrentStep((prev) => Math.max(prev - 1, 0))
const isLastStep = currentStep === WIZARD_STEPS.length - 1
@ -930,16 +952,27 @@ export function CloseTicketDialog({
</Button>
</div>
</div>
<div className="space-y-2">
<div
className={cn(
"space-y-2 rounded-2xl border px-4 py-3 transition",
messageWarning ? "border-amber-500 bg-amber-50/70 shadow-[0_0_0_1px_rgba(251,191,36,0.4)]" : "border-transparent bg-transparent"
)}
>
<p className="text-sm font-medium text-neutral-800">Mensagem de encerramento</p>
<RichTextEditor
value={message}
onChange={setMessage}
minHeight={220}
placeholder="Escreva uma mensagem final para o cliente..."
placeholder="Descreva o encerramento para o cliente..."
/>
<p className="text-xs text-neutral-500">
Você pode editar o conteúdo antes de enviar. Deixe em branco para encerrar sem comentário adicional. O comentário será público e ficará registrado no histórico do ticket.
<p
className={cn(
"text-xs",
messageWarning ? "font-semibold text-amber-700" : "text-neutral-500"
)}
>
Este texto é enviado ao cliente e é obrigatório para encerrar o ticket.
{messageWarning ? " Digite uma mensagem para prosseguir." : ""}
</p>
</div>
</div>