All files / src/components/list BudgetBar.vue

100% Statements 18/18
100% Branches 14/14
100% Functions 5/5
100% Lines 16/16

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83  13x       1x     2x       2x                             2x         2x 2x   5x                   6x         6x 6x     7x 7x 6x   1x       7x                                        
<template>
  <div v-if="budget" class="bg-ctp-surface0/60 rounded-2xl p-3 mb-3">
    <!-- Header row: toggle + total -->
    <button
      type="button"
      @click="expanded = !expanded"
      class="w-full flex items-center justify-between gap-2 text-left"
    >
      <div class="flex items-center gap-2">
        <svg class="w-4 h-4 text-ctp-teal shrink-0" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
          <path stroke-linecap="round" stroke-linejoin="round" d="M12 8c-1.657 0-3 .895-3 2s1.343 2 3 2 3 .895 3 2-1.343 2-3 2m0-8c1.11 0 2.08.402 2.599 1M12 8V7m0 1v8m0 0v1m0-1c-1.11 0-2.08-.402-2.599-1M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
        </svg>
        <span class="text-sm font-semibold text-ctp-teal">€ {{ budget.total.toFixed(2) }}</span>
        <span class="text-xs text-ctp-overlay0">Budget (offen)</span>
      </div>
      <svg
        class="w-4 h-4 text-ctp-overlay0 transition-transform duration-200"
        :class="expanded ? 'rotate-180' : ''"
        fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"
      >
        <path stroke-linecap="round" stroke-linejoin="round" d="M19 9l-7 7-7-7" />
      </svg>
    </button>
 
    <!-- Breakdown rows -->
    <Transition name="budget-expand">
      <div v-if="expanded && Object.keys(budget.byCategory).length > 0" class="mt-2 space-y-1">
        <div
          v-for="(amount, cat) in budget.byCategory"
          :key="cat"
          class="flex justify-between items-center text-xs text-ctp-subtext0 px-1"
        >
          <span class="truncate">{{ cat }}</span>
          <span class="tabular-nums shrink-0 ml-2">€ {{ amount.toFixed(2) }}</span>
        </div>
      </div>
    </Transition>
  </div>
</template>
 
<script setup lang="ts">
import { ref, watch } from 'vue'
import type { BudgetSummary } from '../../types'
import { budgetService } from '../../services/budget'
 
const props = defineProps<{
  listId: string
  itemsVersion: number
}>()
 
const budget = ref<BudgetSummary | null>(null)
const expanded = ref(false)
 
async function load() {
  try {
    budget.value = await budgetService.get(props.listId)
    if (budget.value.total === 0) budget.value = null
  } catch {
    budget.value = null
  }
}
 
watch(() => props.itemsVersion, load, { immediate: true })
</script>
 
<style scoped>
.budget-expand-enter-active,
.budget-expand-leave-active {
  transition: all 0.2s ease;
  overflow: hidden;
}
.budget-expand-enter-from,
.budget-expand-leave-to {
  opacity: 0;
  max-height: 0;
}
.budget-expand-enter-to,
.budget-expand-leave-from {
  opacity: 1;
  max-height: 200px;
}
</style>