Improve emprestimos UX with skeleton loading and optimistic devolver

- Replace spinner with skeleton table rows during loading
- Apply optimistic closing for devolver dialog (instant feedback)
- Use toast.promise for background mutation with loading state
- Remove unnecessary isSubmitting state from devolver button
- Maintain table layout during filter changes (no layout shift)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
rever-tecnologia 2025-12-05 10:24:53 -03:00
parent b7e7f99f99
commit 0054b93d3c

View file

@ -343,27 +343,31 @@ export function EmprestimosPageClient() {
const handleDevolver = useCallback(async () => { const handleDevolver = useCallback(async () => {
if (!selectedEmprestimoId || !convexUserId) return if (!selectedEmprestimoId || !convexUserId) return
setIsSubmitting(true) // Fechamento otimista - fecha dialog imediatamente
try { const emprestimoId = selectedEmprestimoId
const result = await devolverEmprestimo({ const observacoes = formObservacoes
id: selectedEmprestimoId as Id<"emprestimos">, setIsDevolverDialogOpen(false)
setSelectedEmprestimoId(null)
setFormObservacoes("")
// Executa mutacao em background com toast de loading
toast.promise(
devolverEmprestimo({
id: emprestimoId as Id<"emprestimos">,
updatedBy: convexUserId as Id<"users">, updatedBy: convexUserId as Id<"users">,
observacoes: formObservacoes || undefined, observacoes: observacoes || undefined,
}) }),
if (result.multaCalculada) { {
toast.success(`Empréstimo devolvido com multa de R$ ${result.multaCalculada.toFixed(2)}.`) loading: "Registrando devolucao...",
} else { success: (result) => {
toast.success("Empréstimo devolvido com sucesso.") if (result.multaCalculada) {
return `Emprestimo devolvido com multa de R$ ${result.multaCalculada.toFixed(2)}.`
}
return "Emprestimo devolvido com sucesso."
},
error: "Falha ao registrar devolucao.",
} }
setIsDevolverDialogOpen(false) )
setSelectedEmprestimoId(null)
setFormObservacoes("")
} catch (error) {
console.error("[emprestimos] Falha ao devolver", error)
toast.error("Falha ao registrar devolução.")
} finally {
setIsSubmitting(false)
}
}, [selectedEmprestimoId, convexUserId, formObservacoes, devolverEmprestimo]) }, [selectedEmprestimoId, convexUserId, formObservacoes, devolverEmprestimo])
const openDevolverDialog = useCallback((id: string) => { const openDevolverDialog = useCallback((id: string) => {
@ -823,18 +827,9 @@ export function EmprestimosPageClient() {
<Button variant="outline" onClick={() => setIsDevolverDialogOpen(false)}> <Button variant="outline" onClick={() => setIsDevolverDialogOpen(false)}>
Cancelar Cancelar
</Button> </Button>
<Button onClick={handleDevolver} disabled={isSubmitting}> <Button onClick={handleDevolver}>
{isSubmitting ? ( <IconCircleCheck className="size-4" />
<> Confirmar devolucao
<Spinner className="size-4" />
Registrando...
</>
) : (
<>
<IconCircleCheck className="size-4" />
Confirmar devolução
</>
)}
</Button> </Button>
</DialogFooter> </DialogFooter>
</DialogContent> </DialogContent>