feat: made catalog button better looking

This commit is contained in:
2026-06-18 01:17:44 +02:00 Unverified
parent 84e737849b
commit f9fd4ccb25
2 changed files with 127 additions and 104 deletions
+1 -1
View File
@@ -71,7 +71,7 @@ export const useAuth = () => {
const handleLoginSuccess = async (jwtToken: string) => { const handleLoginSuccess = async (jwtToken: string) => {
token.value = jwtToken token.value = jwtToken
tokenState.value = jwtToken tokenState.value = jwtToken
await syncUser({ redirectOnSuccess: true }) await syncUser()
window.location.reload(); window.location.reload();
} }
+126 -103
View File
@@ -12,7 +12,10 @@ const { createCategory, updateCategory, deleteCategory, createTeam, updateTeam,
const { getCategories } = useReports() const { getCategories } = useReports()
const { getTeams } = useOperator() const { getTeams } = useOperator()
const { data: categoriesRes, refresh: refreshCategories } = await useAsyncData('report-categories-admin-view', () => getCategories()) const {
data: categoriesRes,
refresh: refreshCategories
} = await useAsyncData('report-categories-admin-view', () => getCategories())
const { data: teamsRes, refresh: refreshTeams } = await useAsyncData('admin-teams', () => getTeams()) const { data: teamsRes, refresh: refreshTeams } = await useAsyncData('admin-teams', () => getTeams())
const { data: areasRes } = await useAsyncData('admin-team-areas', () => getAreas()) const { data: areasRes } = await useAsyncData('admin-team-areas', () => getAreas())
@@ -45,10 +48,10 @@ const categories = computed(() => categoriesRes.value?.categories || [])
const teams = computed(() => teamsRes.value?.teams || []) const teams = computed(() => teamsRes.value?.teams || [])
const areas = computed(() => areasRes.value?.areas || []) const areas = computed(() => areasRes.value?.areas || [])
const categoryDeleteMessage = computed(() => const categoryDeleteMessage = computed(() =>
categoryPendingDelete.value ? `Vuoi eliminare categoria "${categoryPendingDelete.value.name}"? Operazione irreversibile.` : '' categoryPendingDelete.value ? `Vuoi eliminare categoria "${categoryPendingDelete.value.name}"? Operazione irreversibile.` : ''
) )
const teamDeleteMessage = computed(() => const teamDeleteMessage = computed(() =>
teamPendingDelete.value ? `Vuoi eliminare team "${teamPendingDelete.value.name}"? Operazione irreversibile.` : '' teamPendingDelete.value ? `Vuoi eliminare team "${teamPendingDelete.value.name}"? Operazione irreversibile.` : ''
) )
const resetCategoryForm = () => { const resetCategoryForm = () => {
@@ -236,7 +239,7 @@ const handleDeleteTeam = async () => {
<form class="mb-4" @submit.prevent="submitCategory"> <form class="mb-4" @submit.prevent="submitCategory">
<div class="mb-3"> <div class="mb-3">
<label class="form-label">Nome categoria</label> <label class="form-label">Nome categoria</label>
<input v-model="categoryForm.name" type="text" class="form-control" required /> <input v-model="categoryForm.name" class="form-control" required type="text"/>
</div> </div>
<div class="mb-3"> <div class="mb-3">
<label class="form-label">Descrizione</label> <label class="form-label">Descrizione</label>
@@ -247,61 +250,65 @@ const handleDeleteTeam = async () => {
{{ editingCategoryId ? 'Salva categoria' : 'Crea categoria' }} {{ editingCategoryId ? 'Salva categoria' : 'Crea categoria' }}
</button> </button>
<button <button
v-if="editingCategoryId" v-if="editingCategoryId"
type="button" class="btn btn-outline-secondary ms-2"
class="btn btn-outline-secondary ms-2" type="button"
@click="resetCategoryForm" @click="resetCategoryForm"
> >
Annulla Annulla
</button> </button>
</form> </form>
<div class="table-responsive report-table-wrapper"> <div class="table-responsive report-table-wrapper">
<table class="table table-hover report-table mb-0"> <table class="table table-hover report-table mb-0 align-middle">
<thead> <thead>
<tr> <tr>
<th>ID</th> <th>ID</th>
<th>Nome</th> <th>Nome</th>
<th>Stato</th> <th>Stato</th>
<th class="text-end">Azioni</th> <th class="text-end">Azioni</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
<tr v-for="category in categories" :key="category.id"> <tr v-for="category in categories" :key="category.id">
<td class="report-table-id">#{{ category.id }}</td> <td class="report-table-id">#{{ category.id }}</td>
<td> <td>
<strong>{{ category.name }}</strong> <strong>{{ category.name }}</strong>
<div v-if="category.description" class="small text-muted mt-1">{{ category.description }}</div> <div v-if="category.description" class="small text-muted mt-1">{{ category.description }}</div>
</td> </td>
<td> <td>
<span class="badge" :class="category.active === false ? 'bg-secondary' : 'bg-success'"> <span class="badge" :class="category.active === false ? 'bg-secondary' : 'bg-success'">
{{ category.active === false ? 'Inattiva' : 'Attiva' }} {{ category.active === false ? 'Inattiva' : 'Attiva' }}
</span> </span>
</td> </td>
<td class="text-end"> <td class="text-end">
<button class="btn btn-sm btn-outline-primary me-2" @click="editCategory(category)"> <div class="d-flex justify-content-end gap-2">
Modifica <button class="btn btn-outline-primary btn-icon" title="Modifica" @click="editCategory(category)">
<Icon name="lucide:pencil" size="16"/>
</button> </button>
<button <button
class="btn btn-sm" :class="category.active === false ? 'btn-outline-success' : 'btn-outline-secondary'"
:class="category.active === false ? 'btn-outline-success' : 'btn-outline-secondary'" :title="category.active === false ? 'Attiva' : 'Disattiva'"
@click="toggleCategoryActive(category)" class="btn btn-icon"
@click="toggleCategoryActive(category)"
> >
{{ category.active === false ? 'Attiva' : 'Disattiva' }} <Icon :name="category.active === false ? 'lucide:check-circle' : 'lucide:ban'" size="16"/>
</button> </button>
<button <button
class="btn btn-sm btn-outline-danger ms-2" :disabled="deletingCategoryId === category.id"
:disabled="deletingCategoryId === category.id" class="btn btn-outline-danger btn-icon"
@click="askDeleteCategory(category)" title="Elimina"
@click="askDeleteCategory(category)"
> >
<span v-if="deletingCategoryId === category.id" class="spinner-border spinner-border-sm me-1"></span> <span v-if="deletingCategoryId === category.id" class="spinner-border spinner-icon"></span>
Elimina <Icon v-else name="lucide:trash-2" size="16"/>
</button> </button>
</td> </div>
</tr> </td>
<tr v-if="categories.length === 0"> </tr>
<td colspan="4" class="text-muted">Nessuna categoria configurata.</td> <tr v-if="categories.length === 0">
</tr> <td class="text-muted text-center py-4" colspan="4">Nessuna categoria configurata.</td>
</tr>
</tbody> </tbody>
</table> </table>
</div> </div>
@@ -324,7 +331,7 @@ const handleDeleteTeam = async () => {
<form class="row g-3 mb-4" @submit.prevent="submitTeam"> <form class="row g-3 mb-4" @submit.prevent="submitTeam">
<div class="col-12 col-md-6"> <div class="col-12 col-md-6">
<label class="form-label">Nome team</label> <label class="form-label">Nome team</label>
<input v-model="teamForm.name" type="text" class="form-control" required /> <input v-model="teamForm.name" class="form-control" required type="text"/>
</div> </div>
<div class="col-12 col-md-6"> <div class="col-12 col-md-6">
<label class="form-label">Categoria coperta</label> <label class="form-label">Categoria coperta</label>
@@ -346,18 +353,19 @@ const handleDeleteTeam = async () => {
</div> </div>
<div class="col-12 col-md-6"> <div class="col-12 col-md-6">
<label class="form-label">Descrizione</label> <label class="form-label">Descrizione</label>
<input v-model="teamForm.description" type="text" class="form-control" /> <input v-model="teamForm.description" class="form-control" type="text"/>
</div> </div>
<div class="col-12"> <div class="col-12">
<button type="submit" class="btn btn-primary" :disabled="isSavingTeam || !teamForm.name.trim() || !teamForm.team_category_id"> <button :disabled="isSavingTeam || !teamForm.name.trim() || !teamForm.team_category_id" class="btn btn-primary"
type="submit">
<span v-if="isSavingTeam" class="spinner-border spinner-border-sm me-2"></span> <span v-if="isSavingTeam" class="spinner-border spinner-border-sm me-2"></span>
{{ editingTeamId ? 'Salva team' : 'Crea team' }} {{ editingTeamId ? 'Salva team' : 'Crea team' }}
</button> </button>
<button <button
v-if="editingTeamId" v-if="editingTeamId"
type="button" class="btn btn-outline-secondary ms-2"
class="btn btn-outline-secondary ms-2" type="button"
@click="resetTeamForm" @click="resetTeamForm"
> >
Annulla Annulla
</button> </button>
@@ -365,55 +373,59 @@ const handleDeleteTeam = async () => {
</form> </form>
<div class="table-responsive report-table-wrapper"> <div class="table-responsive report-table-wrapper">
<table class="table table-hover report-table mb-0"> <table class="table table-hover report-table mb-0 align-middle">
<thead> <thead>
<tr> <tr>
<th>ID</th> <th>ID</th>
<th>Team</th> <th>Team</th>
<th>Categoria</th> <th>Categoria</th>
<th>Area</th> <th>Area</th>
<th>Stato</th> <th>Stato</th>
<th class="text-end">Azioni</th> <th class="text-end">Azioni</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
<tr v-for="team in teams" :key="team.id"> <tr v-for="team in teams" :key="team.id">
<td class="report-table-id">#{{ team.id }}</td> <td class="report-table-id">#{{ team.id }}</td>
<td> <td>
<strong>{{ team.name }}</strong> <strong>{{ team.name }}</strong>
<div v-if="team.description" class="small text-muted mt-1">{{ team.description }}</div> <div v-if="team.description" class="small text-muted mt-1">{{ team.description }}</div>
</td> </td>
<td>{{ team.category_name || '-' }}</td> <td>{{ team.category_name || '-' }}</td>
<td>{{ team.area_name || 'Tutte' }}</td> <td>{{ team.area_name || 'Tutte' }}</td>
<td> <td>
<span class="badge" :class="team.active === false ? 'bg-secondary' : 'bg-success'"> <span class="badge" :class="team.active === false ? 'bg-secondary' : 'bg-success'">
{{ team.active === false ? 'Inattivo' : 'Attivo' }} {{ team.active === false ? 'Inattivo' : 'Attivo' }}
</span> </span>
</td> </td>
<td class="text-end"> <td class="text-end">
<button class="btn btn-sm btn-outline-primary me-2" @click="editTeam(team)"> <div class="d-flex justify-content-end gap-2">
Modifica <button class="btn btn-outline-primary btn-icon" title="Modifica" @click="editTeam(team)">
<Icon name="lucide:pencil" size="16"/>
</button> </button>
<button <button
class="btn btn-sm" :class="team.active === false ? 'btn-outline-success' : 'btn-outline-secondary'"
:class="team.active === false ? 'btn-outline-success' : 'btn-outline-secondary'" :title="team.active === false ? 'Attiva' : 'Disattiva'"
@click="toggleTeamActive(team)" class="btn btn-icon"
@click="toggleTeamActive(team)"
> >
{{ team.active === false ? 'Attiva' : 'Disattiva' }} <Icon :name="team.active === false ? 'lucide:check-circle' : 'lucide:ban'" size="16"/>
</button> </button>
<button <button
class="btn btn-sm btn-outline-danger ms-2" :disabled="deletingTeamId === team.id"
:disabled="deletingTeamId === team.id" class="btn btn-outline-danger btn-icon"
@click="askDeleteTeam(team)" title="Elimina"
@click="askDeleteTeam(team)"
> >
<span v-if="deletingTeamId === team.id" class="spinner-border spinner-border-sm me-1"></span> <span v-if="deletingTeamId === team.id" class="spinner-border spinner-icon"></span>
Elimina <Icon v-else name="lucide:trash-2" size="16"/>
</button> </button>
</td> </div>
</tr> </td>
<tr v-if="teams.length === 0"> </tr>
<td colspan="6" class="text-muted">Nessun team configurato.</td> <tr v-if="teams.length === 0">
</tr> <td class="text-muted text-center py-4" colspan="6">Nessun team configurato.</td>
</tr>
</tbody> </tbody>
</table> </table>
</div> </div>
@@ -423,32 +435,43 @@ const handleDeleteTeam = async () => {
</div> </div>
<ConfirmModal <ConfirmModal
:open="categoryPendingDelete !== null" :message="categoryDeleteMessage"
title="Elimina categoria" :open="categoryPendingDelete !== null"
:message="categoryDeleteMessage" :pending="deletingCategoryId !== null"
confirm-label="Elimina categoria" confirm-class="btn-danger"
confirm-class="btn-danger" confirm-label="Elimina categoria"
:pending="deletingCategoryId !== null" title="Elimina categoria"
@cancel="closeDeleteCategoryModal" @cancel="closeDeleteCategoryModal"
@confirm="handleDeleteCategory" @confirm="handleDeleteCategory"
/> />
<ConfirmModal <ConfirmModal
:open="teamPendingDelete !== null" :message="teamDeleteMessage"
title="Elimina team" :open="teamPendingDelete !== null"
:message="teamDeleteMessage" :pending="deletingTeamId !== null"
confirm-label="Elimina team" confirm-class="btn-danger"
confirm-class="btn-danger" confirm-label="Elimina team"
:pending="deletingTeamId !== null" title="Elimina team"
@cancel="closeDeleteTeamModal" @cancel="closeDeleteTeamModal"
@confirm="handleDeleteTeam" @confirm="handleDeleteTeam"
/> />
</div> </div>
</template> </template>
<style> <style scoped>
.text-end .btn { .btn-icon {
margin: 0 !important; width: 32px;
width: 120px; height: 32px;
padding: 0;
display: inline-flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
}
.spinner-icon {
width: 14px;
height: 14px;
border-width: 2px;
} }
</style> </style>