KPI's na lista de beneficiários
This commit is contained in:
@@ -23,6 +23,7 @@ vite.config.js.timestamp-*
|
|||||||
vite.config.ts.timestamp-*
|
vite.config.ts.timestamp-*
|
||||||
# SQLite
|
# SQLite
|
||||||
*.db
|
*.db
|
||||||
|
*.db.*
|
||||||
|
|
||||||
# Persistent local data / uploads
|
# Persistent local data / uploads
|
||||||
/data/
|
/data/
|
||||||
|
|||||||
Binary file not shown.
@@ -1,20 +1,20 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { page } from '$app/state';
|
import { page } from "$app/state";
|
||||||
import { enhance } from '$app/forms';
|
import { enhance } from "$app/forms";
|
||||||
|
|
||||||
let { data, form } = $props();
|
let { data, form } = $props();
|
||||||
|
|
||||||
let syncing = $state(false);
|
let syncing = $state(false);
|
||||||
|
|
||||||
let sortBy = $state<'number' | 'name' | 'householdSize'>('number');
|
let sortBy = $state<"number" | "name" | "householdSize">("number");
|
||||||
let sortOrder = $state<'asc' | 'desc'>('asc');
|
let sortOrder = $state<"asc" | "desc">("asc");
|
||||||
|
|
||||||
function toggleSort(field: 'number' | 'name' | 'householdSize') {
|
function toggleSort(field: "number" | "name" | "householdSize") {
|
||||||
if (sortBy === field) {
|
if (sortBy === field) {
|
||||||
sortOrder = sortOrder === 'asc' ? 'desc' : 'asc';
|
sortOrder = sortOrder === "asc" ? "desc" : "asc";
|
||||||
} else {
|
} else {
|
||||||
sortBy = field;
|
sortBy = field;
|
||||||
sortOrder = 'asc';
|
sortOrder = "asc";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -27,20 +27,19 @@
|
|||||||
if (valA === null || valA === undefined) return 1;
|
if (valA === null || valA === undefined) return 1;
|
||||||
if (valB === null || valB === undefined) return -1;
|
if (valB === null || valB === undefined) return -1;
|
||||||
|
|
||||||
if (typeof valA === 'string' && typeof valB === 'string') {
|
if (typeof valA === "string" && typeof valB === "string") {
|
||||||
return sortOrder === 'asc'
|
return sortOrder === "asc"
|
||||||
? valA.localeCompare(valB, 'pt-PT')
|
? valA.localeCompare(valB, "pt-PT")
|
||||||
: valB.localeCompare(valA, 'pt-PT');
|
: valB.localeCompare(valA, "pt-PT");
|
||||||
} else {
|
} else {
|
||||||
return sortOrder === 'asc'
|
return sortOrder === "asc"
|
||||||
? (valA as number) - (valB as number)
|
? (valA as number) - (valB as number)
|
||||||
: (valB as number) - (valA as number);
|
: (valB as number) - (valA as number);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
const successMessage = $derived(page.url.searchParams.get('success'));
|
const successMessage = $derived(page.url.searchParams.get("success"));
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<svelte:head>
|
<svelte:head>
|
||||||
@@ -49,9 +48,21 @@
|
|||||||
|
|
||||||
<div class="container py-4">
|
<div class="container py-4">
|
||||||
{#if successMessage}
|
{#if successMessage}
|
||||||
<div class="alert alert-success border-0 shadow-sm rounded-3 d-flex align-items-center gap-2 mb-4" role="alert">
|
<div
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="currentColor" class="bi bi-check-circle-fill text-success" viewBox="0 0 16 16">
|
class="alert alert-success border-0 shadow-sm rounded-3 d-flex align-items-center gap-2 mb-4"
|
||||||
<path d="M16 8A8 8 0 1 1 0 8a8 8 0 0 1 16 0m-3.97-3.03a.75.75 0 0 0-1.08.022L7.477 9.417 5.384 7.323a.75.75 0 0 0-1.06 1.06L6.97 11.03a.75.75 0 0 0 1.079-.02l3.992-4.99a.75.75 0 0 0-.01-1.05z"/>
|
role="alert"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
width="20"
|
||||||
|
height="20"
|
||||||
|
fill="currentColor"
|
||||||
|
class="bi bi-check-circle-fill text-success"
|
||||||
|
viewBox="0 0 16 16"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M16 8A8 8 0 1 1 0 8a8 8 0 0 1 16 0m-3.97-3.03a.75.75 0 0 0-1.08.022L7.477 9.417 5.384 7.323a.75.75 0 0 0-1.06 1.06L6.97 11.03a.75.75 0 0 0 1.079-.02l3.992-4.99a.75.75 0 0 0-.01-1.05z"
|
||||||
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
<div>
|
<div>
|
||||||
{successMessage}
|
{successMessage}
|
||||||
@@ -60,9 +71,21 @@
|
|||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
{#if form?.success}
|
{#if form?.success}
|
||||||
<div class="alert alert-success border-0 shadow-sm rounded-3 d-flex align-items-center gap-2 mb-4" role="alert">
|
<div
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="currentColor" class="bi bi-check-circle-fill text-success" viewBox="0 0 16 16">
|
class="alert alert-success border-0 shadow-sm rounded-3 d-flex align-items-center gap-2 mb-4"
|
||||||
<path d="M16 8A8 8 0 1 1 0 8a8 8 0 0 1 16 0m-3.97-3.03a.75.75 0 0 0-1.08.022L7.477 9.417 5.384 7.323a.75.75 0 0 0-1.06 1.06L6.97 11.03a.75.75 0 0 0 1.079-.02l3.992-4.99a.75.75 0 0 0-.01-1.05z"/>
|
role="alert"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
width="20"
|
||||||
|
height="20"
|
||||||
|
fill="currentColor"
|
||||||
|
class="bi bi-check-circle-fill text-success"
|
||||||
|
viewBox="0 0 16 16"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M16 8A8 8 0 1 1 0 8a8 8 0 0 1 16 0m-3.97-3.03a.75.75 0 0 0-1.08.022L7.477 9.417 5.384 7.323a.75.75 0 0 0-1.06 1.06L6.97 11.03a.75.75 0 0 0 1.079-.02l3.992-4.99a.75.75 0 0 0-.01-1.05z"
|
||||||
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
<div>
|
<div>
|
||||||
Sincronização concluída com sucesso! {form.count} beneficiários atualizados/importados.
|
Sincronização concluída com sucesso! {form.count} beneficiários atualizados/importados.
|
||||||
@@ -71,9 +94,21 @@
|
|||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
{#if form?.error}
|
{#if form?.error}
|
||||||
<div class="alert alert-danger border-0 shadow-sm rounded-3 d-flex align-items-center gap-2 mb-4" role="alert">
|
<div
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="currentColor" class="bi bi-exclamation-triangle-fill text-danger" viewBox="0 0 16 16">
|
class="alert alert-danger border-0 shadow-sm rounded-3 d-flex align-items-center gap-2 mb-4"
|
||||||
<path d="M8.982 1.566a1.13 1.13 0 0 0-1.96 0L.165 13.233c-.457.778.091 1.767.98 1.767h13.713c.889 0 1.438-.99.98-1.767L8.982 1.566zM8 5c.535 0 .954.462.9.995l-.35 3.507a.552.552 0 0 1-1.1 0L7.1 5.995A.905.905 0 0 1 8 5zm.002 6a1 1 0 1 1 0 2 1 1 0 0 1 0-2z"/>
|
role="alert"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
width="20"
|
||||||
|
height="20"
|
||||||
|
fill="currentColor"
|
||||||
|
class="bi bi-exclamation-triangle-fill text-danger"
|
||||||
|
viewBox="0 0 16 16"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M8.982 1.566a1.13 1.13 0 0 0-1.96 0L.165 13.233c-.457.778.091 1.767.98 1.767h13.713c.889 0 1.438-.99.98-1.767L8.982 1.566zM8 5c.535 0 .954.462.9.995l-.35 3.507a.552.552 0 0 1-1.1 0L7.1 5.995A.905.905 0 0 1 8 5zm.002 6a1 1 0 1 1 0 2 1 1 0 0 1 0-2z"
|
||||||
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
<div>
|
<div>
|
||||||
{form.error}
|
{form.error}
|
||||||
@@ -81,32 +116,78 @@
|
|||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
<div class="d-flex flex-column flex-md-row justify-content-between align-items-start align-items-md-center gap-3 mb-4">
|
<div
|
||||||
|
class="d-flex flex-column flex-md-row justify-content-between align-items-start align-items-md-center gap-3 mb-4"
|
||||||
|
>
|
||||||
<div>
|
<div>
|
||||||
<h2 class="fw-bold text-dark mb-1">Beneficiários</h2>
|
<h2 class="fw-bold text-dark mb-1">Beneficiários</h2>
|
||||||
<p class="text-muted mb-0">Gerir a listagem de beneficiários e agregados familiares</p>
|
<p class="text-muted mb-0">
|
||||||
|
Gerir a listagem de beneficiários e agregados familiares
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="d-flex gap-2">
|
<div class="d-flex gap-2">
|
||||||
{#if data.user?.role === 'admin'}
|
{#if data.user?.role === "admin"}
|
||||||
<form method="POST" action="?/sync" use:enhance={() => {
|
<form
|
||||||
syncing = true;
|
method="POST"
|
||||||
return async ({ update }) => {
|
action="?/sync"
|
||||||
await update();
|
use:enhance={() => {
|
||||||
syncing = false;
|
syncing = true;
|
||||||
};
|
return async ({ update }) => {
|
||||||
}} onsubmit={(e) => { if (!confirm('Tem a certeza que deseja sincronizar os beneficiários com o Odoo?')) e.preventDefault(); }}>
|
await update();
|
||||||
<button type="submit" class="btn btn-outline-sync btn-lg d-flex align-items-center gap-2 rounded-3 shadow-sm" disabled={syncing}>
|
syncing = false;
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="currentColor" class="bi bi-arrow-repeat {syncing ? 'spin' : ''}" viewBox="0 0 16 16">
|
};
|
||||||
<path d="M11.534 7h3.932a.25.25 0 0 1 .192.41l-1.966 2.36a.25.25 0 0 1-.384 0l-1.966-2.36a.25.25 0 0 1 .192-.41zm-11 2h3.932a.25.25 0 0 0 .192-.41L2.692 6.23a.25.25 0 0 0-.384 0L.342 8.59A.25.25 0 0 0 .534 9z"/>
|
}}
|
||||||
<path fill-rule="evenodd" d="M8 3c-1.552 0-2.94.707-3.857 1.818a.5.5 0 1 1-.771-.636A6.002 6.002 0 0 1 13.917 7H12.9A5.002 5.002 0 0 0 8 3zM3.1 9a5.002 5.002 0 0 0 8.757 2.182.5.5 0 1 1 .771.636A6.002 6.002 0 0 1 2.083 9H3.1z"/>
|
onsubmit={(e) => {
|
||||||
|
if (
|
||||||
|
!confirm(
|
||||||
|
"Tem a certeza que deseja sincronizar os beneficiários com o Odoo?",
|
||||||
|
)
|
||||||
|
)
|
||||||
|
e.preventDefault();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
type="submit"
|
||||||
|
class="btn btn-outline-sync btn-lg d-flex align-items-center gap-2 rounded-3 shadow-sm"
|
||||||
|
disabled={syncing}
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
width="20"
|
||||||
|
height="20"
|
||||||
|
fill="currentColor"
|
||||||
|
class="bi bi-arrow-repeat {syncing ? 'spin' : ''}"
|
||||||
|
viewBox="0 0 16 16"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M11.534 7h3.932a.25.25 0 0 1 .192.41l-1.966 2.36a.25.25 0 0 1-.384 0l-1.966-2.36a.25.25 0 0 1 .192-.41zm-11 2h3.932a.25.25 0 0 0 .192-.41L2.692 6.23a.25.25 0 0 0-.384 0L.342 8.59A.25.25 0 0 0 .534 9z"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
fill-rule="evenodd"
|
||||||
|
d="M8 3c-1.552 0-2.94.707-3.857 1.818a.5.5 0 1 1-.771-.636A6.002 6.002 0 0 1 13.917 7H12.9A5.002 5.002 0 0 0 8 3zM3.1 9a5.002 5.002 0 0 0 8.757 2.182.5.5 0 1 1 .771.636A6.002 6.002 0 0 1 2.083 9H3.1z"
|
||||||
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
{syncing ? 'A sincronizar...' : 'Sincronizar Odoo'}
|
{syncing ? "A sincronizar..." : "Sincronizar Odoo"}
|
||||||
</button>
|
</button>
|
||||||
</form>
|
</form>
|
||||||
{/if}
|
{/if}
|
||||||
<a href="/admin/beneficiarios/novo" class="btn btn-success btn-lg d-flex align-items-center gap-2 rounded-3 shadow-sm border-0" style="background-color: var(--refood-primary, #FCB515);">
|
<a
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="currentColor" class="bi bi-plus-lg" viewBox="0 0 16 16">
|
href="/admin/beneficiarios/novo"
|
||||||
<path fill-rule="evenodd" d="M8 2a.5.5 0 0 1 .5.5v5h5a.5.5 0 0 1 0 1h-5v5a.5.5 0 0 1-1 0v-5h-5a.5.5 0 0 1 0-1h5v-5A.5.5 0 0 1 8 2"/>
|
class="btn btn-success btn-lg d-flex align-items-center gap-2 rounded-3 shadow-sm border-0"
|
||||||
|
style="background-color: var(--refood-primary, #FCB515);"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
width="20"
|
||||||
|
height="20"
|
||||||
|
fill="currentColor"
|
||||||
|
class="bi bi-plus-lg"
|
||||||
|
viewBox="0 0 16 16"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
fill-rule="evenodd"
|
||||||
|
d="M8 2a.5.5 0 0 1 .5.5v5h5a.5.5 0 0 1 0 1h-5v5a.5.5 0 0 1-1 0v-5h-5a.5.5 0 0 1 0-1h5v-5A.5.5 0 0 1 8 2"
|
||||||
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
Novo Beneficiário
|
Novo Beneficiário
|
||||||
</a>
|
</a>
|
||||||
@@ -116,33 +197,84 @@
|
|||||||
<!-- Indicadores/Estatísticas -->
|
<!-- Indicadores/Estatísticas -->
|
||||||
<div class="row g-3 mb-4">
|
<div class="row g-3 mb-4">
|
||||||
<div class="col-12 col-sm-6">
|
<div class="col-12 col-sm-6">
|
||||||
<div class="card border-0 shadow-sm rounded-4 p-3 bg-white h-100 d-flex flex-row align-items-center gap-3">
|
<div
|
||||||
<div class="stats-icon rounded-3 p-3 d-flex align-items-center justify-content-center" style="background-color: rgba(44, 86, 46, 0.1); color: #2c562e; width: 60px; height: 60px; flex-shrink: 0;">
|
class="card border-0 shadow-sm rounded-4 p-3 bg-white h-100 d-flex flex-row align-items-center gap-3"
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" width="28" height="28" fill="currentColor" class="bi bi-house-door-fill" viewBox="0 0 16 16">
|
>
|
||||||
<path d="M6.5 14.5v-3.507c0-.31.25-.56.56-.56h2c.31 0 .56.25.56.56v3.507c0 .31-.25.56-.56.56H7.06a.56.56 0 0 1-.56-.56"/>
|
<div
|
||||||
<path d="M13 2.5V6l-2-2V2.5a.5.5 0 0 1 .5-.5h1a.5.5 0 0 1 .5.5z"/>
|
class="stats-icon rounded-3 p-3 d-flex align-items-center justify-content-center"
|
||||||
<path d="M8 .757 1.01 6.855a.5.5 0 0 0-.01.768l.66.583a.5.5 0 0 0 .702-.055L8 2.501l5.64 5.65a.5.5 0 0 0 .702.054l.66-.583a.5.5 0 0 0-.01-.767L8 .757z"/>
|
style="background-color: rgba(44, 86, 46, 0.1); color: #2c562e; width: 60px; height: 60px; flex-shrink: 0;"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
width="28"
|
||||||
|
height="28"
|
||||||
|
fill="currentColor"
|
||||||
|
class="bi bi-house-door-fill"
|
||||||
|
viewBox="0 0 16 16"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M6.5 14.5v-3.507c0-.31.25-.56.56-.56h2c.31 0 .56.25.56.56v3.507c0 .31-.25.56-.56.56H7.06a.56.56 0 0 1-.56-.56"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M13 2.5V6l-2-2V2.5a.5.5 0 0 1 .5-.5h1a.5.5 0 0 1 .5.5z"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M8 .757 1.01 6.855a.5.5 0 0 0-.01.768l.66.583a.5.5 0 0 0 .702-.055L8 2.501l5.64 5.65a.5.5 0 0 0 .702.054l.66-.583a.5.5 0 0 0-.01-.767L8 .757z"
|
||||||
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<span class="text-secondary small fw-semibold d-block text-uppercase" style="letter-spacing: 0.05em; font-size: 0.75rem;">Famílias</span>
|
<span
|
||||||
<span class="fs-2 fw-bold text-dark lh-1">{data.totalFamilies}</span>
|
class="text-secondary small fw-semibold d-block text-uppercase"
|
||||||
<span class="text-muted small d-block mt-1" style="font-size: 0.75rem;">Número de famílias (IsParent=true)</span>
|
style="letter-spacing: 0.05em; font-size: 0.75rem;"
|
||||||
|
>Famílias</span
|
||||||
|
>
|
||||||
|
<span class="fs-2 fw-bold text-dark lh-1"
|
||||||
|
>{data.totalFamilies}</span
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
class="text-muted small d-block mt-1"
|
||||||
|
style="font-size: 0.75rem;">Número de famílias</span
|
||||||
|
>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="col-12 col-sm-6">
|
<div class="col-12 col-sm-6">
|
||||||
<div class="card border-0 shadow-sm rounded-4 p-3 bg-white h-100 d-flex flex-row align-items-center gap-3">
|
<div
|
||||||
<div class="stats-icon rounded-3 p-3 d-flex align-items-center justify-content-center" style="background-color: rgba(252, 181, 21, 0.15); color: #b78104; width: 60px; height: 60px; flex-shrink: 0;">
|
class="card border-0 shadow-sm rounded-4 p-3 bg-white h-100 d-flex flex-row align-items-center gap-3"
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" width="28" height="28" fill="currentColor" class="bi bi-people-fill" viewBox="0 0 16 16">
|
>
|
||||||
<path d="M7 14s-1 0-1-1 1-4 5-4 5 3 5 4-1 1-1 1zm4-6a3 3 0 1 0 0-6 3 3 0 0 0 0 6m-5.784 6A2.24 2.24 0 0 1 5 13c0-1.355.68-2.75 1.936-3.72A6.3 6.3 0 0 0 5 9c-4 0-5 3-5 4s1 1 1 1zM4.5 8a2.5 2.5 0 1 0 0-5 2.5 2.5 0 0 0 0 5"/>
|
<div
|
||||||
|
class="stats-icon rounded-3 p-3 d-flex align-items-center justify-content-center"
|
||||||
|
style="background-color: rgba(252, 181, 21, 0.15); color: #b78104; width: 60px; height: 60px; flex-shrink: 0;"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
width="28"
|
||||||
|
height="28"
|
||||||
|
fill="currentColor"
|
||||||
|
class="bi bi-people-fill"
|
||||||
|
viewBox="0 0 16 16"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M7 14s-1 0-1-1 1-4 5-4 5 3 5 4-1 1-1 1zm4-6a3 3 0 1 0 0-6 3 3 0 0 0 0 6m-5.784 6A2.24 2.24 0 0 1 5 13c0-1.355.68-2.75 1.936-3.72A6.3 6.3 0 0 0 5 9c-4 0-5 3-5 4s1 1 1 1zM4.5 8a2.5 2.5 0 1 0 0-5 2.5 2.5 0 0 0 0 5"
|
||||||
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<span class="text-secondary small fw-semibold d-block text-uppercase" style="letter-spacing: 0.05em; font-size: 0.75rem;">Total de Beneficiários</span>
|
<span
|
||||||
<span class="fs-2 fw-bold text-dark lh-1">{data.totalBeneficiaries}</span>
|
class="text-secondary small fw-semibold d-block text-uppercase"
|
||||||
<span class="text-muted small d-block mt-1" style="font-size: 0.75rem;">Todos os registos na base de dados</span>
|
style="letter-spacing: 0.05em; font-size: 0.75rem;"
|
||||||
|
>Total de Beneficiários</span
|
||||||
|
>
|
||||||
|
<span class="fs-2 fw-bold text-dark lh-1"
|
||||||
|
>{data.totalBeneficiaries}</span
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
class="text-muted small d-block mt-1"
|
||||||
|
style="font-size: 0.75rem;"
|
||||||
|
>Todos os registos na base de dados</span
|
||||||
|
>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -151,7 +283,11 @@
|
|||||||
<div class="card border-0 shadow-sm rounded-4 p-3 mb-4 bg-white">
|
<div class="card border-0 shadow-sm rounded-4 p-3 mb-4 bg-white">
|
||||||
<form method="GET" class="row g-3 align-items-end">
|
<form method="GET" class="row g-3 align-items-end">
|
||||||
<div class="col-md-6 col-lg-7">
|
<div class="col-md-6 col-lg-7">
|
||||||
<label for="search" class="form-label fw-semibold text-secondary small">Pesquisar</label>
|
<label
|
||||||
|
for="search"
|
||||||
|
class="form-label fw-semibold text-secondary small"
|
||||||
|
>Pesquisar</label
|
||||||
|
>
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
name="search"
|
name="search"
|
||||||
@@ -163,8 +299,17 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="col-md-3 col-lg-3">
|
<div class="col-md-3 col-lg-3">
|
||||||
<label for="status" class="form-label fw-semibold text-secondary small">Estado</label>
|
<label
|
||||||
<select name="status" id="status" value={data.status} class="form-select rounded-3 border-2">
|
for="status"
|
||||||
|
class="form-label fw-semibold text-secondary small"
|
||||||
|
>Estado</label
|
||||||
|
>
|
||||||
|
<select
|
||||||
|
name="status"
|
||||||
|
id="status"
|
||||||
|
value={data.status}
|
||||||
|
class="form-select rounded-3 border-2"
|
||||||
|
>
|
||||||
<option value="todos">Todos</option>
|
<option value="todos">Todos</option>
|
||||||
<option value="ativo">Ativo</option>
|
<option value="ativo">Ativo</option>
|
||||||
<option value="inativo">Inativo</option>
|
<option value="inativo">Inativo</option>
|
||||||
@@ -172,7 +317,11 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="col-md-3 col-lg-2 d-grid">
|
<div class="col-md-3 col-lg-2 d-grid">
|
||||||
<button type="submit" class="btn btn-primary rounded-3 fw-semibold border-0 py-2" style="background-color: #2c562e;">
|
<button
|
||||||
|
type="submit"
|
||||||
|
class="btn btn-primary rounded-3 fw-semibold border-0 py-2"
|
||||||
|
style="background-color: #2c562e;"
|
||||||
|
>
|
||||||
Filtrar
|
Filtrar
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -180,50 +329,88 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="card border-0 shadow-sm rounded-4 overflow-hidden bg-white">
|
<div class="card border-0 shadow-sm rounded-4 overflow-hidden bg-white">
|
||||||
<div class="card-header border-0 bg-light py-3 px-4 d-flex justify-content-between align-items-center flex-wrap gap-2">
|
<div
|
||||||
|
class="card-header border-0 bg-light py-3 px-4 d-flex justify-content-between align-items-center flex-wrap gap-2"
|
||||||
|
>
|
||||||
<h5 class="fw-bold text-dark mb-0">Lista de Beneficiários</h5>
|
<h5 class="fw-bold text-dark mb-0">Lista de Beneficiários</h5>
|
||||||
</div>
|
</div>
|
||||||
<div class="table-responsive">
|
<div class="table-responsive">
|
||||||
<table class="table table-hover align-middle mb-0">
|
<table class="table table-hover align-middle mb-0">
|
||||||
<thead class="table-light text-secondary fw-semibold">
|
<thead class="table-light text-secondary fw-semibold">
|
||||||
<tr>
|
<tr>
|
||||||
<th class="px-4 py-3 sortable-header" style="width: 120px;" onclick={() => toggleSort('number')}>
|
<th
|
||||||
<div class="d-flex align-items-center gap-1 select-none">
|
class="px-4 py-3 sortable-header"
|
||||||
|
style="width: 120px;"
|
||||||
|
onclick={() => toggleSort("number")}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="d-flex align-items-center gap-1 select-none"
|
||||||
|
>
|
||||||
Número
|
Número
|
||||||
{#if sortBy === 'number'}
|
{#if sortBy === "number"}
|
||||||
<span class="sort-arrow">{sortOrder === 'asc' ? '▲' : '▼'}</span>
|
<span class="sort-arrow"
|
||||||
|
>{sortOrder === "asc" ? "▲" : "▼"}</span
|
||||||
|
>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
</th>
|
</th>
|
||||||
<th class="py-3 sortable-header" onclick={() => toggleSort('name')}>
|
<th
|
||||||
<div class="d-flex align-items-center gap-1 select-none">
|
class="py-3 sortable-header"
|
||||||
|
onclick={() => toggleSort("name")}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="d-flex align-items-center gap-1 select-none"
|
||||||
|
>
|
||||||
Nome
|
Nome
|
||||||
{#if sortBy === 'name'}
|
{#if sortBy === "name"}
|
||||||
<span class="sort-arrow">{sortOrder === 'asc' ? '▲' : '▼'}</span>
|
<span class="sort-arrow"
|
||||||
|
>{sortOrder === "asc" ? "▲" : "▼"}</span
|
||||||
|
>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
</th>
|
</th>
|
||||||
<th class="py-3">Contacto</th>
|
<th class="py-3">Contacto</th>
|
||||||
<th class="py-3 text-center sortable-header" style="width: 120px;" onclick={() => toggleSort('householdSize')}>
|
<th
|
||||||
<div class="d-flex align-items-center justify-content-center gap-1 select-none">
|
class="py-3 text-center sortable-header"
|
||||||
|
style="width: 120px;"
|
||||||
|
onclick={() => toggleSort("householdSize")}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="d-flex align-items-center justify-content-center gap-1 select-none"
|
||||||
|
>
|
||||||
Agregado
|
Agregado
|
||||||
{#if sortBy === 'householdSize'}
|
{#if sortBy === "householdSize"}
|
||||||
<span class="sort-arrow">{sortOrder === 'asc' ? '▲' : '▼'}</span>
|
<span class="sort-arrow"
|
||||||
|
>{sortOrder === "asc" ? "▲" : "▼"}</span
|
||||||
|
>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
</th>
|
</th>
|
||||||
<th class="py-3" style="width: 120px;">Estado</th>
|
<th class="py-3" style="width: 120px;">Estado</th>
|
||||||
<th class="px-4 py-3 text-end" style="width: 120px;">Ações</th>
|
<th class="px-4 py-3 text-end" style="width: 120px;"
|
||||||
|
>Ações</th
|
||||||
|
>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{#if sortedBeneficiaries.length === 0}
|
{#if sortedBeneficiaries.length === 0}
|
||||||
<tr>
|
<tr>
|
||||||
<td colspan="6" class="text-center py-5 text-muted">
|
<td colspan="6" class="text-center py-5 text-muted">
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" width="40" height="40" fill="currentColor" class="bi bi-people mb-2 text-black-50" viewBox="0 0 16 16">
|
<svg
|
||||||
<path d="M15 14s1 0 1-1-1-4-5-4-5 3-5 4 1 1 1 1zm-7.978-1L7 12.996c.001-.264.167-1.03.76-1.72C8.312 10.629 9.282 10 11 10c1.717 0 2.687.63 3.24 1.276.593.69.758 1.457.76 1.72l-.008.002-.014.002zM11 7a2 2 0 1 0 0-4 2 2 0 0 0 0 4m3-2a3 3 0 1 1-6 0 3 3 0 0 1 6 0M6.936 9.28a6 6 0 0 0-1.23-.247A7 7 0 0 0 5 9c-4 0-5 3-5 4q0 1 2 1h4.216A2.24 2.24 0 0 1 5 13c0-1.01.377-2.042 1.09-2.904.243-.294.526-.569.846-.816M4.92 8a2 2 0 1 0 0-4 2 2 0 0 0 0 4m3-2a3 3 0 1 1-6 0 3 3 0 0 1 6 0"/>
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
width="40"
|
||||||
|
height="40"
|
||||||
|
fill="currentColor"
|
||||||
|
class="bi bi-people mb-2 text-black-50"
|
||||||
|
viewBox="0 0 16 16"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M15 14s1 0 1-1-1-4-5-4-5 3-5 4 1 1 1 1zm-7.978-1L7 12.996c.001-.264.167-1.03.76-1.72C8.312 10.629 9.282 10 11 10c1.717 0 2.687.63 3.24 1.276.593.69.758 1.457.76 1.72l-.008.002-.014.002zM11 7a2 2 0 1 0 0-4 2 2 0 0 0 0 4m3-2a3 3 0 1 1-6 0 3 3 0 0 1 6 0M6.936 9.28a6 6 0 0 0-1.23-.247A7 7 0 0 0 5 9c-4 0-5 3-5 4q0 1 2 1h4.216A2.24 2.24 0 0 1 5 13c0-1.01.377-2.042 1.09-2.904.243-.294.526-.569.846-.816M4.92 8a2 2 0 1 0 0-4 2 2 0 0 0 0 4m3-2a3 3 0 1 1-6 0 3 3 0 0 1 6 0"
|
||||||
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
<p class="mb-0">Nenhum beneficiário encontrado.</p>
|
<p class="mb-0">
|
||||||
|
Nenhum beneficiário encontrado.
|
||||||
|
</p>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
{:else}
|
{:else}
|
||||||
@@ -242,16 +429,36 @@
|
|||||||
{beneficiary.householdSize}
|
{beneficiary.householdSize}
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
{#if beneficiary.status === 'ativo'}
|
{#if beneficiary.status === "ativo"}
|
||||||
<span class="badge bg-success-subtle text-success px-2.5 py-1.5 rounded-pill border border-success-subtle text-uppercase fw-semibold" style="font-size: 0.7rem;">Ativo</span>
|
<span
|
||||||
|
class="badge bg-success-subtle text-success px-2.5 py-1.5 rounded-pill border border-success-subtle text-uppercase fw-semibold"
|
||||||
|
style="font-size: 0.7rem;"
|
||||||
|
>Ativo</span
|
||||||
|
>
|
||||||
{:else}
|
{:else}
|
||||||
<span class="badge bg-danger-subtle text-danger px-2.5 py-1.5 rounded-pill border border-danger-subtle text-uppercase fw-semibold" style="font-size: 0.7rem;">Inativo</span>
|
<span
|
||||||
|
class="badge bg-danger-subtle text-danger px-2.5 py-1.5 rounded-pill border border-danger-subtle text-uppercase fw-semibold"
|
||||||
|
style="font-size: 0.7rem;"
|
||||||
|
>Inativo</span
|
||||||
|
>
|
||||||
{/if}
|
{/if}
|
||||||
</td>
|
</td>
|
||||||
<td class="px-4 text-end">
|
<td class="px-4 text-end">
|
||||||
<a href="/admin/beneficiarios/{beneficiary.id}" class="btn btn-sm btn-outline-secondary rounded-2 px-2.5 py-1 d-inline-flex align-items-center gap-1.5">
|
<a
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" fill="currentColor" class="bi bi-pencil" viewBox="0 0 16 16">
|
href="/admin/beneficiarios/{beneficiary.id}"
|
||||||
<path d="M12.146.146a.5.5 0 0 1 .708 0l3 3a.5.5 0 0 1 0 .708l-10 10a.5.5 0 0 1-.168.11l-5 2a.5.5 0 0 1-.65-.65l2-5a.5.5 0 0 1 .11-.168zM11.207 2.5 13.5 4.793 14.793 3.5 12.5 1.207zm1.586 3L10.5 3.207 4 9.707V10h.5a.5.5 0 0 1 .5.5v.5h.5a.5.5 0 0 1 .5.5v.5h.293zm-9.761 5.175-.106.106-1.528 3.821 3.821-1.528.106-.106A.5.5 0 0 1 5 12.5V12h-.5a.5.5 0 0 1-.5-.5V11h-.5a.5.5 0 0 1-.468-.325"/>
|
class="btn btn-sm btn-outline-secondary rounded-2 px-2.5 py-1 d-inline-flex align-items-center gap-1.5"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
width="14"
|
||||||
|
height="14"
|
||||||
|
fill="currentColor"
|
||||||
|
class="bi bi-pencil"
|
||||||
|
viewBox="0 0 16 16"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M12.146.146a.5.5 0 0 1 .708 0l3 3a.5.5 0 0 1 0 .708l-10 10a.5.5 0 0 1-.168.11l-5 2a.5.5 0 0 1-.65-.65l2-5a.5.5 0 0 1 .11-.168zM11.207 2.5 13.5 4.793 14.793 3.5 12.5 1.207zm1.586 3L10.5 3.207 4 9.707V10h.5a.5.5 0 0 1 .5.5v.5h.5a.5.5 0 0 1 .5.5v.5h.293zm-9.761 5.175-.106.106-1.528 3.821 3.821-1.528.106-.106A.5.5 0 0 1 5 12.5V12h-.5a.5.5 0 0 1-.5-.5V11h-.5a.5.5 0 0 1-.468-.325"
|
||||||
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
Editar
|
Editar
|
||||||
</a>
|
</a>
|
||||||
|
|||||||
Reference in New Issue
Block a user