feat: aggiungi pulsante svuota piano settimanale
- Sposta .btn-clear da ShoppingList.vue (scoped) a style.css (globale) - Aggiunge hasMeals, clearAll e btn-clear in MealPlanner.vue - Aggiunge 4 test di integrazione per il nuovo pulsante Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -22,6 +22,8 @@
|
||||
Genera lista della spesa
|
||||
</button>
|
||||
|
||||
<button v-if="hasMeals" class="btn-clear" @click="clearAll">Svuota piano</button>
|
||||
|
||||
<div class="btn-share-row">
|
||||
<button class="btn-share" @click="openShare">
|
||||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
@@ -99,7 +101,7 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { reactive, watch, ref, onUnmounted, nextTick } from 'vue'
|
||||
import { reactive, watch, ref, computed, onUnmounted, nextTick } from 'vue'
|
||||
import MealCard from '../components/MealCard.vue'
|
||||
import { save, load } from '../utils/storage.js'
|
||||
import QRCode from 'qrcode'
|
||||
@@ -137,6 +139,14 @@ function removeItem(day, slot, idx) {
|
||||
meals[day][slot].splice(idx, 1)
|
||||
}
|
||||
|
||||
const hasMeals = computed(() =>
|
||||
days.some(d => ['colazione', 'pranzo', 'cena'].some(s => meals[d.id][s].length > 0))
|
||||
)
|
||||
|
||||
function clearAll() {
|
||||
if (confirm('Svuotare tutto il piano settimanale?')) Object.assign(meals, defaultMeals())
|
||||
}
|
||||
|
||||
function generateShopping() {
|
||||
const allItems = days.flatMap(d =>
|
||||
['colazione', 'pranzo', 'cena'].flatMap(slot => meals[d.id][slot])
|
||||
|
||||
@@ -144,21 +144,6 @@ function clearAll() {
|
||||
background: var(--color-border);
|
||||
}
|
||||
|
||||
/* bottone distruttivo in ghost style — meno aggressivo del solid rosso */
|
||||
.btn-clear {
|
||||
width: 100%;
|
||||
background: transparent;
|
||||
color: var(--color-danger);
|
||||
border: 1.5px solid var(--color-danger);
|
||||
margin-top: 16px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.btn-clear:active {
|
||||
background: var(--color-danger-muted);
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.empty-state {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
@@ -78,6 +78,21 @@ button {
|
||||
|
||||
button:active { opacity: 0.75; }
|
||||
|
||||
/* bottone distruttivo in ghost style — meno aggressivo del solid rosso */
|
||||
.btn-clear {
|
||||
width: 100%;
|
||||
background: transparent;
|
||||
color: var(--color-danger);
|
||||
border: 1.5px solid var(--color-danger);
|
||||
margin-top: 16px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.btn-clear:active {
|
||||
background: var(--color-danger-muted);
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
input[type="text"],
|
||||
input[type="number"] {
|
||||
font-size: 1rem;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { describe, it, expect } from 'vitest'
|
||||
import { describe, it, expect, vi } from 'vitest'
|
||||
import { mount } from '@vue/test-utils'
|
||||
import { nextTick } from 'vue'
|
||||
import MealPlanner from '../../src/pages/MealPlanner.vue'
|
||||
@@ -150,3 +150,41 @@ describe('MealPlanner — genera lista della spesa', () => {
|
||||
expect(load('shopping', [])).toHaveLength(0)
|
||||
})
|
||||
})
|
||||
|
||||
describe('MealPlanner — svuota piano', () => {
|
||||
it('non mostra il pulsante se il piano è vuoto', () => {
|
||||
const w = mountPlanner()
|
||||
expect(w.find('.btn-clear').exists()).toBe(false)
|
||||
})
|
||||
|
||||
it('mostra il pulsante se c\'è almeno un pasto', () => {
|
||||
seedMeals({ lunedi: { colazione: ['caffè'], pranzo: [], cena: [] } })
|
||||
const w = mountPlanner()
|
||||
expect(w.find('.btn-clear').exists()).toBe(true)
|
||||
})
|
||||
|
||||
it('svuota il piano dopo conferma', async () => {
|
||||
vi.spyOn(window, 'confirm').mockReturnValue(true)
|
||||
seedMeals({ lunedi: { colazione: ['caffè'], pranzo: ['pasta'], cena: [] } })
|
||||
const w = mountPlanner()
|
||||
|
||||
await w.find('.btn-clear').trigger('click')
|
||||
await nextTick()
|
||||
|
||||
const saved = load('meals', {})
|
||||
expect(saved.lunedi.colazione).toHaveLength(0)
|
||||
expect(saved.lunedi.pranzo).toHaveLength(0)
|
||||
expect(w.find('.btn-clear').exists()).toBe(false)
|
||||
})
|
||||
|
||||
it('non svuota se l\'utente annulla', async () => {
|
||||
vi.spyOn(window, 'confirm').mockReturnValue(false)
|
||||
seedMeals({ lunedi: { colazione: ['caffè'], pranzo: [], cena: [] } })
|
||||
const w = mountPlanner()
|
||||
|
||||
await w.find('.btn-clear').trigger('click')
|
||||
await nextTick()
|
||||
|
||||
expect(load('meals', {}).lunedi.colazione).toHaveLength(1)
|
||||
})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user