first-deploy #72

Merged
kilder merged 12 commits from first-deploy into master 2026-01-13 17:54:12 +00:00
37 changed files with 6814 additions and 905 deletions
Showing only changes of commit 4551adf64f - Show all commits

View File

@@ -1,8 +1,10 @@
name: Build Docker images
name: Build and Deploy Docker images
on:
push:
branches: ["master"]
branches: ['master']
pull_request:
branches: ['master']
jobs:
build-and-push-dockerfile-image:
@@ -12,25 +14,22 @@ jobs:
- name: Checkout repository
uses: actions/checkout@v3
- name: Setup Bun
uses: oven-sh/setup-bun@v2
- name: Log in to Docker Hub
# Only login if we are actually going to push
if: github.event_name == 'push'
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKERHUB_USERNAME }} # Make sure to add the secrets in your repository in -> Settings -> Secrets (Actions) -> New repository secret
password: ${{ secrets.DOCKERHUB_TOKEN }} # Make sure to add the secrets in your repository in -> Settings -> Secrets (Actions) -> New repository secret
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Build and push Docker image
uses: docker/build-push-action@v4
with:
context: .
file: ./apps/web/Dockerfile
push: true
# Make sure to replace with your own namespace and repository
tags: |
killercf/sgc:latest
# Only push on 'push' event (merge to master), not on 'pull_request'
push: ${{ github.event_name == 'push' }}
tags: killercf/sgc:latest
platforms: linux/amd64
build-args: |
PUBLIC_CONVEX_URL=${{ secrets.PUBLIC_CONVEX_URL }}

View File

@@ -13,7 +13,6 @@
Package,
AlertTriangle,
ArrowLeftRight,
Download,
CheckCircle,
ArrowDown,
ArrowUp,
@@ -21,6 +20,7 @@
FileText,
FileSpreadsheet
} from 'lucide-svelte';
import { SvelteDate } from 'svelte/reactivity';
const statsQuery = useQuery(api.almoxarifado.obterEstatisticas, {});
const materiaisQuery = useQuery(api.almoxarifado.listarMateriais, {});
@@ -31,7 +31,7 @@
let tipoRelatorioGerando = $state<string | null>(null);
// Agrupar materiais por categoria
const materiaisPorCategoria = $derived(() => {
const materiaisPorCategoria = $derived.by(() => {
if (!materiaisQuery.data) return {};
const agrupado: Record<string, number> = {};
materiaisQuery.data.forEach((m) => {
@@ -41,10 +41,10 @@
});
// Movimentações do mês
const movimentacoesMes = $derived(() => {
const movimentacoesMes = $derived.by(() => {
if (!movimentacoesQuery.data) return { entrada: 0, saida: 0, ajuste: 0 };
const agora = Date.now();
const inicioMes = new Date(agora);
const inicioMes = new SvelteDate(agora);
inicioMes.setDate(1);
inicioMes.setHours(0, 0, 0, 0);
@@ -124,7 +124,10 @@
if (ctx) {
ctx.drawImage(logoImg, 0, 0);
const blob = await new Promise<Blob>((resolve, reject) => {
canvas.toBlob((b) => (b ? resolve(b) : reject(new Error('Falha ao converter'))), 'image/png');
canvas.toBlob(
(b) => (b ? resolve(b) : reject(new Error('Falha ao converter'))),
'image/png'
);
});
return await blob.arrayBuffer();
}
@@ -257,7 +260,10 @@
yPos += 15;
const dados = materiaisPorCategoria;
const dadosArray = Object.entries(dados).map(([categoria, quantidade]) => [categoria, String(quantidade)]);
const dadosArray = Object.entries(dados).map(([categoria, quantidade]) => [
categoria,
String(quantidade)
]);
if (dadosArray.length === 0) {
doc.text('Nenhum dado disponível', 14, yPos);
@@ -532,7 +538,12 @@
{ header: 'Estoque Mínimo', key: 'estoqueMinimo', width: 18 }
];
await adicionarTituloExcel(worksheet, 'RELATÓRIO DE MATERIAIS COM ESTOQUE BAIXO', 4, workbook);
await adicionarTituloExcel(
worksheet,
'RELATÓRIO DE MATERIAIS COM ESTOQUE BAIXO',
4,
workbook
);
const headerRow = worksheet.getRow(2);
headerRow.values = ['Código', 'Material', 'Estoque Atual', 'Estoque Mínimo'];
@@ -751,9 +762,7 @@
<div class="breadcrumbs mb-6 text-sm">
<ul>
<li>
<a href={resolve('/almoxarifado')} class="text-primary hover:underline"
>Almoxarifado</a
>
<a href={resolve('/almoxarifado')} class="text-primary hover:underline">Almoxarifado</a>
</li>
<li>Relatórios</li>
</ul>
@@ -762,14 +771,18 @@
<!-- Cabeçalho -->
<div class="mb-8">
<div class="flex items-center gap-4">
<div class="rounded-2xl bg-gradient-to-br from-primary/20 via-primary/10 to-primary/5 p-4 shadow-lg border border-primary/20">
<BarChart3 class="h-10 w-10 text-primary" strokeWidth={2.5} />
<div
class="from-primary/20 via-primary/10 to-primary/5 border-primary/20 rounded-2xl border bg-linear-to-br p-4 shadow-lg"
>
<BarChart3 class="text-primary h-10 w-10" strokeWidth={2.5} />
</div>
<div class="flex-1">
<h1 class="text-4xl font-bold tracking-tight bg-gradient-to-r from-primary to-primary/70 bg-clip-text text-transparent">
<h1
class="from-primary to-primary/70 bg-linear-to-r bg-clip-text text-4xl font-bold tracking-tight text-transparent"
>
Relatórios
</h1>
<p class="text-base-content/70 text-lg mt-1">Estatísticas e relatórios do almoxarifado</p>
<p class="text-base-content/70 mt-1 text-lg">Estatísticas e relatórios do almoxarifado</p>
</div>
</div>
</div>
@@ -777,68 +790,84 @@
<!-- Estatísticas Gerais -->
{#if statsQuery.data}
<div class="mb-10">
<div class="mb-6 flex items-center gap-3 border-b-2 border-primary/20 pb-4">
<div class="rounded-lg bg-primary/10 p-2.5">
<BarChart3 class="h-5 w-5 text-primary" strokeWidth={2.5} />
<div class="border-primary/20 mb-6 flex items-center gap-3 border-b-2 pb-4">
<div class="bg-primary/10 rounded-lg p-2.5">
<BarChart3 class="text-primary h-5 w-5" strokeWidth={2.5} />
</div>
<h2 class="text-xl font-bold text-base-content">Estatísticas Gerais</h2>
<h2 class="text-base-content text-xl font-bold">Estatísticas Gerais</h2>
</div>
<div class="grid grid-cols-1 gap-6 md:grid-cols-2 lg:grid-cols-4">
<div class="card bg-gradient-to-br from-primary/10 via-primary/5 to-base-100 border border-primary/20 shadow-xl hover:shadow-2xl transition-all duration-300 hover:scale-105">
<div
class="card from-primary/10 via-primary/5 to-base-100 border-primary/20 border bg-linear-to-br shadow-xl transition-all duration-300 hover:scale-105 hover:shadow-2xl"
>
<div class="card-body">
<div class="flex items-center justify-between">
<div class="flex-1">
<div class="text-sm font-medium text-base-content/60 mb-1">Total de Materiais</div>
<div class="text-3xl font-bold text-primary mb-1">{statsQuery.data.totalMateriais}</div>
<div class="text-xs text-base-content/50">Cadastrados no sistema</div>
<div class="text-base-content/60 mb-1 text-sm font-medium">Total de Materiais</div>
<div class="text-primary mb-1 text-3xl font-bold">
{statsQuery.data.totalMateriais}
</div>
<div class="rounded-xl bg-primary/20 p-3">
<Package class="h-8 w-8 text-primary" strokeWidth={2.5} />
<div class="text-base-content/50 text-xs">Cadastrados no sistema</div>
</div>
<div class="bg-primary/20 rounded-xl p-3">
<Package class="text-primary h-8 w-8" strokeWidth={2.5} />
</div>
</div>
</div>
</div>
<div class="card bg-gradient-to-br from-success/10 via-success/5 to-base-100 border border-success/20 shadow-xl hover:shadow-2xl transition-all duration-300 hover:scale-105">
<div
class="card from-success/10 via-success/5 to-base-100 border-success/20 border bg-linear-to-br shadow-xl transition-all duration-300 hover:scale-105 hover:shadow-2xl"
>
<div class="card-body">
<div class="flex items-center justify-between">
<div class="flex-1">
<div class="text-sm font-medium text-base-content/60 mb-1">Materiais Ativos</div>
<div class="text-3xl font-bold text-success mb-1">{statsQuery.data.totalMateriaisAtivos}</div>
<div class="text-xs text-base-content/50">Em estoque</div>
<div class="text-base-content/60 mb-1 text-sm font-medium">Materiais Ativos</div>
<div class="text-success mb-1 text-3xl font-bold">
{statsQuery.data.totalMateriaisAtivos}
</div>
<div class="rounded-xl bg-success/20 p-3">
<CheckCircle class="h-8 w-8 text-success" strokeWidth={2.5} />
<div class="text-base-content/50 text-xs">Em estoque</div>
</div>
<div class="bg-success/20 rounded-xl p-3">
<CheckCircle class="text-success h-8 w-8" strokeWidth={2.5} />
</div>
</div>
</div>
</div>
<div class="card bg-gradient-to-br from-warning/10 via-warning/5 to-base-100 border border-warning/20 shadow-xl hover:shadow-2xl transition-all duration-300 hover:scale-105">
<div
class="card from-warning/10 via-warning/5 to-base-100 border-warning/20 border bg-linear-to-br shadow-xl transition-all duration-300 hover:scale-105 hover:shadow-2xl"
>
<div class="card-body">
<div class="flex items-center justify-between">
<div class="flex-1">
<div class="text-sm font-medium text-base-content/60 mb-1">Alertas Ativos</div>
<div class="text-3xl font-bold text-warning mb-1">{statsQuery.data.totalAlertasAtivos}</div>
<div class="text-xs text-base-content/50">Estoque baixo</div>
<div class="text-base-content/60 mb-1 text-sm font-medium">Alertas Ativos</div>
<div class="text-warning mb-1 text-3xl font-bold">
{statsQuery.data.totalAlertasAtivos}
</div>
<div class="rounded-xl bg-warning/20 p-3">
<AlertTriangle class="h-8 w-8 text-warning" strokeWidth={2.5} />
<div class="text-base-content/50 text-xs">Estoque baixo</div>
</div>
<div class="bg-warning/20 rounded-xl p-3">
<AlertTriangle class="text-warning h-8 w-8" strokeWidth={2.5} />
</div>
</div>
</div>
</div>
<div class="card bg-gradient-to-br from-info/10 via-info/5 to-base-100 border border-info/20 shadow-xl hover:shadow-2xl transition-all duration-300 hover:scale-105">
<div
class="card from-info/10 via-info/5 to-base-100 border-info/20 border bg-linear-to-br shadow-xl transition-all duration-300 hover:scale-105 hover:shadow-2xl"
>
<div class="card-body">
<div class="flex items-center justify-between">
<div class="flex-1">
<div class="text-sm font-medium text-base-content/60 mb-1">Movimentações</div>
<div class="text-3xl font-bold text-info mb-1">{statsQuery.data.movimentacoesMes}</div>
<div class="text-xs text-base-content/50">Este mês</div>
<div class="text-base-content/60 mb-1 text-sm font-medium">Movimentações</div>
<div class="text-info mb-1 text-3xl font-bold">
{statsQuery.data.movimentacoesMes}
</div>
<div class="rounded-xl bg-info/20 p-3">
<ArrowLeftRight class="h-8 w-8 text-info" strokeWidth={2.5} />
<div class="text-base-content/50 text-xs">Este mês</div>
</div>
<div class="bg-info/20 rounded-xl p-3">
<ArrowLeftRight class="text-info h-8 w-8" strokeWidth={2.5} />
</div>
</div>
</div>
@@ -849,26 +878,26 @@
<!-- Relatórios Disponíveis -->
<div class="mb-8">
<div class="mb-6 flex items-center gap-3 border-b-2 border-info/20 pb-4">
<div class="rounded-lg bg-info/10 p-2.5">
<FileText class="h-5 w-5 text-info" strokeWidth={2.5} />
<div class="border-info/20 mb-6 flex items-center gap-3 border-b-2 pb-4">
<div class="bg-info/10 rounded-lg p-2.5">
<FileText class="text-info h-5 w-5" strokeWidth={2.5} />
</div>
<h2 class="text-xl font-bold text-base-content">Relatórios Disponíveis</h2>
<h2 class="text-base-content text-xl font-bold">Relatórios Disponíveis</h2>
</div>
<div class="grid grid-cols-1 gap-6 md:grid-cols-2">
<!-- Relatório de Materiais por Categoria -->
<div class="card bg-base-100 border border-base-300 shadow-2xl">
<div class="card bg-base-100 border-base-300 border shadow-2xl">
<div class="card-body p-6">
<div class="flex items-center justify-between mb-6 border-b-2 border-base-300 pb-4">
<div class="border-base-300 mb-6 flex items-center justify-between border-b-2 pb-4">
<div class="flex items-center gap-3">
<div class="rounded-lg bg-primary/10 p-2">
<Package class="h-5 w-5 text-primary" strokeWidth={2.5} />
<div class="bg-primary/10 rounded-lg p-2">
<Package class="text-primary h-5 w-5" strokeWidth={2.5} />
</div>
<h2 class="text-lg font-bold text-base-content">Materiais por Categoria</h2>
<h2 class="text-base-content text-lg font-bold">Materiais por Categoria</h2>
</div>
<div class="flex gap-2">
<button
class="btn btn-sm btn-primary shadow-md hover:shadow-lg transition-all"
class="btn btn-sm btn-primary shadow-md transition-all hover:shadow-lg"
onclick={gerarPDFMateriaisCategoria}
disabled={gerandoRelatorio}
title="Gerar PDF"
@@ -881,7 +910,7 @@
PDF
</button>
<button
class="btn btn-sm btn-success shadow-md hover:shadow-lg transition-all"
class="btn btn-sm btn-success shadow-md transition-all hover:shadow-lg"
onclick={gerarExcelMateriaisCategoria}
disabled={gerandoRelatorio}
title="Gerar Excel"
@@ -897,26 +926,30 @@
</div>
{#if materiaisQuery.data && Object.keys(materiaisPorCategoria).length > 0}
<div class="space-y-3">
{#each Object.entries(materiaisPorCategoria) as [categoria, quantidade]}
<div class="flex items-center justify-between p-2 rounded-lg hover:bg-base-200/50 transition-colors">
<span class="font-semibold text-base-content">{categoria}</span>
{#each Object.entries(materiaisPorCategoria) as [categoria, quantidade] (categoria)}
<div
class="hover:bg-base-200/50 flex items-center justify-between rounded-lg p-2 transition-colors"
>
<span class="text-base-content font-semibold">{categoria}</span>
<div class="flex items-center gap-3">
<div class="w-40">
<div class="h-3 bg-base-300 rounded-full overflow-hidden shadow-inner">
<div class="bg-base-300 h-3 overflow-hidden rounded-full shadow-inner">
<div
class="h-full bg-gradient-to-r from-primary to-primary/70 transition-all rounded-full"
class="from-primary to-primary/70 h-full rounded-full bg-linear-to-r transition-all"
style="width: {(quantidade / (materiaisQuery.data?.length || 1)) * 100}%"
></div>
</div>
</div>
<span class="text-base font-bold text-primary w-12 text-right">{quantidade}</span>
<span class="text-primary w-12 text-right text-base font-bold"
>{quantidade}</span
>
</div>
</div>
{/each}
</div>
{:else}
<div class="alert alert-info border-info/30 bg-info/10">
<Package class="h-5 w-5 text-info" />
<Package class="text-info h-5 w-5" />
<span class="font-medium">Nenhum dado disponível</span>
</div>
{/if}
@@ -924,18 +957,18 @@
</div>
<!-- Movimentações do Mês -->
<div class="card bg-base-100 border border-base-300 shadow-2xl">
<div class="card bg-base-100 border-base-300 border shadow-2xl">
<div class="card-body p-6">
<div class="flex items-center justify-between mb-6 border-b-2 border-base-300 pb-4">
<div class="border-base-300 mb-6 flex items-center justify-between border-b-2 pb-4">
<div class="flex items-center gap-3">
<div class="rounded-lg bg-info/10 p-2">
<ArrowLeftRight class="h-5 w-5 text-info" strokeWidth={2.5} />
<div class="bg-info/10 rounded-lg p-2">
<ArrowLeftRight class="text-info h-5 w-5" strokeWidth={2.5} />
</div>
<h2 class="text-lg font-bold text-base-content">Movimentações do Mês</h2>
<h2 class="text-base-content text-lg font-bold">Movimentações do Mês</h2>
</div>
<div class="flex gap-2">
<button
class="btn btn-sm btn-primary shadow-md hover:shadow-lg transition-all"
class="btn btn-sm btn-primary shadow-md transition-all hover:shadow-lg"
onclick={gerarPDFMovimentacoesMes}
disabled={gerandoRelatorio}
title="Gerar PDF"
@@ -948,7 +981,7 @@
PDF
</button>
<button
class="btn btn-sm btn-success shadow-md hover:shadow-lg transition-all"
class="btn btn-sm btn-success shadow-md transition-all hover:shadow-lg"
onclick={gerarExcelMovimentacoesMes}
disabled={gerandoRelatorio}
title="Gerar Excel"
@@ -963,50 +996,56 @@
</div>
</div>
<div class="space-y-4">
<div class="flex items-center justify-between p-3 rounded-lg bg-success/10 border border-success/20 hover:bg-success/15 transition-colors">
<div
class="bg-success/10 border-success/20 hover:bg-success/15 flex items-center justify-between rounded-lg border p-3 transition-colors"
>
<div class="flex items-center gap-3">
<div class="rounded-lg bg-success/20 p-2">
<ArrowDown class="h-5 w-5 text-success" strokeWidth={2.5} />
<div class="bg-success/20 rounded-lg p-2">
<ArrowDown class="text-success h-5 w-5" strokeWidth={2.5} />
</div>
<span class="font-semibold text-base-content">Entradas</span>
<span class="text-base-content font-semibold">Entradas</span>
</div>
<span class="text-2xl font-bold text-success">{movimentacoesMes.entrada}</span>
<span class="text-success text-2xl font-bold">{movimentacoesMes.entrada}</span>
</div>
<div class="flex items-center justify-between p-3 rounded-lg bg-error/10 border border-error/20 hover:bg-error/15 transition-colors">
<div
class="bg-error/10 border-error/20 hover:bg-error/15 flex items-center justify-between rounded-lg border p-3 transition-colors"
>
<div class="flex items-center gap-3">
<div class="rounded-lg bg-error/20 p-2">
<ArrowUp class="h-5 w-5 text-error" strokeWidth={2.5} />
<div class="bg-error/20 rounded-lg p-2">
<ArrowUp class="text-error h-5 w-5" strokeWidth={2.5} />
</div>
<span class="font-semibold text-base-content">Saídas</span>
<span class="text-base-content font-semibold">Saídas</span>
</div>
<span class="text-2xl font-bold text-error">{movimentacoesMes.saida}</span>
<span class="text-error text-2xl font-bold">{movimentacoesMes.saida}</span>
</div>
<div class="flex items-center justify-between p-3 rounded-lg bg-warning/10 border border-warning/20 hover:bg-warning/15 transition-colors">
<div
class="bg-warning/10 border-warning/20 hover:bg-warning/15 flex items-center justify-between rounded-lg border p-3 transition-colors"
>
<div class="flex items-center gap-3">
<div class="rounded-lg bg-warning/20 p-2">
<Settings class="h-5 w-5 text-warning" strokeWidth={2.5} />
<div class="bg-warning/20 rounded-lg p-2">
<Settings class="text-warning h-5 w-5" strokeWidth={2.5} />
</div>
<span class="font-semibold text-base-content">Ajustes</span>
<span class="text-base-content font-semibold">Ajustes</span>
</div>
<span class="text-2xl font-bold text-warning">{movimentacoesMes.ajuste}</span>
<span class="text-warning text-2xl font-bold">{movimentacoesMes.ajuste}</span>
</div>
</div>
</div>
</div>
<!-- Materiais com Estoque Baixo -->
<div class="card bg-base-100 border border-base-300 shadow-2xl">
<div class="card bg-base-100 border-base-300 border shadow-2xl">
<div class="card-body p-6">
<div class="flex items-center justify-between mb-6 border-b-2 border-base-300 pb-4">
<div class="border-base-300 mb-6 flex items-center justify-between border-b-2 pb-4">
<div class="flex items-center gap-3">
<div class="rounded-lg bg-warning/10 p-2">
<AlertTriangle class="h-5 w-5 text-warning" strokeWidth={2.5} />
<div class="bg-warning/10 rounded-lg p-2">
<AlertTriangle class="text-warning h-5 w-5" strokeWidth={2.5} />
</div>
<h2 class="text-lg font-bold text-base-content">Materiais com Estoque Baixo</h2>
<h2 class="text-base-content text-lg font-bold">Materiais com Estoque Baixo</h2>
</div>
<div class="flex gap-2">
<button
class="btn btn-sm btn-primary shadow-md hover:shadow-lg transition-all"
class="btn btn-sm btn-primary shadow-md transition-all hover:shadow-lg"
onclick={gerarPDFEstoqueBaixo}
disabled={gerandoRelatorio}
title="Gerar PDF"
@@ -1019,7 +1058,7 @@
PDF
</button>
<button
class="btn btn-sm btn-success shadow-md hover:shadow-lg transition-all"
class="btn btn-sm btn-success shadow-md transition-all hover:shadow-lg"
onclick={gerarExcelEstoqueBaixo}
disabled={gerandoRelatorio}
title="Gerar Excel"
@@ -1034,26 +1073,30 @@
</div>
</div>
{#if materiaisQuery.data}
{@const estoqueBaixo = materiaisQuery.data.filter(m => m.estoqueAtual <= m.estoqueMinimo)}
{@const estoqueBaixo = materiaisQuery.data.filter(
(m) => m.estoqueAtual <= m.estoqueMinimo
)}
{#if estoqueBaixo.length > 0}
<div class="overflow-x-auto rounded-lg border border-base-300">
<table class="table table-zebra table-sm">
<div class="border-base-300 overflow-x-auto rounded-lg border">
<table class="table-zebra table-sm table">
<thead>
<tr class="bg-base-200">
<th class="font-bold text-base-content">Material</th>
<th class="font-bold text-base-content">Atual</th>
<th class="font-bold text-base-content">Mínimo</th>
<th class="text-base-content font-bold">Material</th>
<th class="text-base-content font-bold">Atual</th>
<th class="text-base-content font-bold">Mínimo</th>
</tr>
</thead>
<tbody>
{#each estoqueBaixo.slice(0, 10) as material}
{#each estoqueBaixo.slice(0, 10) as material (material._id)}
<tr class="hover:bg-base-200/50 transition-colors">
<td>
<div class="font-medium">{material.nome}</div>
<div class="text-xs text-base-content/60 font-mono">{material.codigo}</div>
<div class="text-base-content/60 font-mono text-xs">
{material.codigo}
</div>
</td>
<td>
<span class="font-bold text-error">{material.estoqueAtual}</span>
<span class="text-error font-bold">{material.estoqueAtual}</span>
</td>
<td>
<span class="font-medium">{material.estoqueMinimo}</span>
@@ -1064,13 +1107,13 @@
</table>
</div>
{#if estoqueBaixo.length > 10}
<p class="text-sm text-base-content/70 mt-4 text-center font-medium">
<p class="text-base-content/70 mt-4 text-center text-sm font-medium">
E mais <span class="text-primary font-bold">{estoqueBaixo.length - 10}</span> materiais...
</p>
{/if}
{:else}
<div class="alert alert-success border-success/30 bg-success/10">
<CheckCircle class="h-6 w-6 text-success" />
<CheckCircle class="text-success h-6 w-6" />
<span class="font-medium">Todos os materiais estão com estoque adequado!</span>
</div>
{/if}
@@ -1079,18 +1122,18 @@
</div>
<!-- Alertas Recentes -->
<div class="card bg-base-100 border border-base-300 shadow-2xl">
<div class="card bg-base-100 border-base-300 border shadow-2xl">
<div class="card-body p-6">
<div class="flex items-center justify-between mb-6 border-b-2 border-base-300 pb-4">
<div class="border-base-300 mb-6 flex items-center justify-between border-b-2 pb-4">
<div class="flex items-center gap-3">
<div class="rounded-lg bg-warning/10 p-2">
<AlertTriangle class="h-5 w-5 text-warning" strokeWidth={2.5} />
<div class="bg-warning/10 rounded-lg p-2">
<AlertTriangle class="text-warning h-5 w-5" strokeWidth={2.5} />
</div>
<h2 class="text-lg font-bold text-base-content">Alertas Recentes</h2>
<h2 class="text-base-content text-lg font-bold">Alertas Recentes</h2>
</div>
<div class="flex gap-2">
<button
class="btn btn-sm btn-primary shadow-md hover:shadow-lg transition-all"
class="btn btn-sm btn-primary shadow-md transition-all hover:shadow-lg"
onclick={gerarPDFAlertas}
disabled={gerandoRelatorio}
title="Gerar PDF"
@@ -1103,7 +1146,7 @@
PDF
</button>
<button
class="btn btn-sm btn-success shadow-md hover:shadow-lg transition-all"
class="btn btn-sm btn-success shadow-md transition-all hover:shadow-lg"
onclick={gerarExcelAlertas}
disabled={gerandoRelatorio}
title="Gerar Excel"
@@ -1119,17 +1162,22 @@
</div>
{#if alertasQuery.data && alertasQuery.data.length > 0}
<div class="space-y-3">
{#each alertasQuery.data.slice(0, 5) as alerta}
<div class="flex items-center justify-between p-3 bg-warning/10 rounded-lg border border-warning/20 hover:bg-warning/15 transition-colors">
{#each alertasQuery.data.slice(0, 5) as alerta (alerta._id)}
<div
class="bg-warning/10 border-warning/20 hover:bg-warning/15 flex items-center justify-between rounded-lg border p-3 transition-colors"
>
<div class="flex-1">
<div class="font-semibold text-sm text-base-content">
<div class="text-base-content text-sm font-semibold">
{#if materiaisQuery.data}
{@const material = materiaisQuery.data.find(m => m._id === alerta.materialId)}
{@const material = materiaisQuery.data.find(
(m) => m._id === alerta.materialId
)}
{material?.nome || 'Carregando...'}
{/if}
</div>
<div class="text-xs text-base-content/60 mt-1 font-mono">
Estoque: <span class="font-bold text-error">{alerta.quantidadeAtual}</span> / Mínimo: <span class="font-bold">{alerta.quantidadeMinima}</span>
<div class="text-base-content/60 mt-1 font-mono text-xs">
Estoque: <span class="text-error font-bold">{alerta.quantidadeAtual}</span> /
Mínimo: <span class="font-bold">{alerta.quantidadeMinima}</span>
</div>
</div>
<span class="badge badge-warning badge-lg ml-3">
@@ -1144,12 +1192,12 @@
</div>
{:else}
<div class="alert alert-success border-success/30 bg-success/10">
<CheckCircle class="h-6 w-6 text-success" />
<CheckCircle class="text-success h-6 w-6" />
<span class="font-medium">Nenhum alerta ativo</span>
</div>
{/if}
</div>
</div>
</div>
</div>
</main>