b913a2bf90
Refs gitea:Adriano/AI-OS#310 Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
96 lines
3.3 KiB
Markdown
96 lines
3.3 KiB
Markdown
### Task 9: Toggle "Mostra tag" — endpoint cookie e cablaggio
|
|
|
|
**Files:**
|
|
- Create: `src/pages/api/admin/showtags.ts`
|
|
- Modify: `src/components/Header.astro` (script del pulsante)
|
|
|
|
**Interfaces:**
|
|
- Consumes: `locals.user` dal middleware (rotta sotto `/api/admin`, quindi login garantito).
|
|
- Produces: `POST /api/admin/showtags` con body `{ on: boolean }`; imposta/rimuove il cookie `showtags`; `403` se il ruolo non è `superuser`/`admin`.
|
|
|
|
- [ ] **Step 1: Crea l'endpoint**
|
|
|
|
Crea `src/pages/api/admin/showtags.ts`:
|
|
|
|
```typescript
|
|
import type { APIRoute } from 'astro';
|
|
export const prerender = false;
|
|
|
|
const json = (status: number, body: object) =>
|
|
new Response(JSON.stringify(body), { status, headers: { 'Content-Type': 'application/json' } });
|
|
|
|
export const POST: APIRoute = async ({ request, cookies, locals }) => {
|
|
const role = locals.user!.role;
|
|
if (role !== 'superuser' && role !== 'admin') return json(403, { error: 'Permessi insufficienti' });
|
|
let data: { on?: unknown };
|
|
try { data = await request.json(); } catch { return json(400, { error: 'Dati non validi.' }); }
|
|
if (data.on) {
|
|
cookies.set('showtags', '1', { httpOnly: true, sameSite: 'lax', path: '/', secure: import.meta.env.PROD });
|
|
} else {
|
|
cookies.delete('showtags', { path: '/' });
|
|
}
|
|
return json(200, { on: Boolean(data.on) });
|
|
};
|
|
```
|
|
|
|
- [ ] **Step 2: Cabla il pulsante nell'header**
|
|
|
|
In `src/components/Header.astro`, dentro il blocco `<script>` esistente (dopo il codice del burger), aggiungi:
|
|
|
|
```javascript
|
|
const tagsBtn = document.getElementById('toggle-tags');
|
|
if (tagsBtn) {
|
|
// Lo stato attuale è riflesso server-side; il testo lo deriviamo dal cookie.
|
|
const on = document.cookie.split('; ').some((c) => c === 'showtags=1');
|
|
tagsBtn.textContent = on ? 'Nascondi tag' : 'Mostra tag';
|
|
tagsBtn.addEventListener('click', async () => {
|
|
const res = await fetch('/api/admin/showtags', {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({ on: !on }),
|
|
});
|
|
if (res.ok) location.reload();
|
|
else alert('Operazione non riuscita.');
|
|
});
|
|
}
|
|
```
|
|
|
|
Nota: il cookie `showtags` è `httpOnly`, quindi `document.cookie` non lo espone. Per riflettere lo stato senza reload, l'header riceve già `showTags` come prop: passa lo stato al pulsante via attributo. Correzione da applicare in questo step — nel markup del Task 8 il pulsante diventa:
|
|
|
|
```astro
|
|
<button type="button" class="umenu__tags" id="toggle-tags" data-on={Astro.props.showTags ? '1' : '0'}>{Astro.props.showTags ? 'Nascondi tag' : 'Mostra tag'}</button>
|
|
```
|
|
|
|
e lo script usa `data-on`:
|
|
|
|
```javascript
|
|
const tagsBtn = document.getElementById('toggle-tags');
|
|
if (tagsBtn) {
|
|
const on = tagsBtn.dataset.on === '1';
|
|
tagsBtn.addEventListener('click', async () => {
|
|
const res = await fetch('/api/admin/showtags', {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({ on: !on }),
|
|
});
|
|
if (res.ok) location.reload();
|
|
else alert('Operazione non riuscita.');
|
|
});
|
|
}
|
|
```
|
|
|
|
- [ ] **Step 3: Verifica build**
|
|
|
|
Run: `npm run build`
|
|
Expected: build OK.
|
|
|
|
- [ ] **Step 4: Commit**
|
|
|
|
```bash
|
|
git add src/pages/api/admin/showtags.ts src/components/Header.astro
|
|
git commit -m "feat(showtags): endpoint cookie + toggle nel menu utente"
|
|
```
|
|
|
|
---
|
|
|