Okay, I've made some changes to integrate the Valerie UI components into the Account, Group Detail, and List Detail pages. This is part of the ongoing effort to standardize the UI and make the code easier to maintain.
Here's a breakdown of the changes: 1. **`AccountPage.vue`**: * I replaced the main heading with `VHeading`. * I updated the loading spinner to `VSpinner`. * I converted the error alert to `VAlert` with an action button. * I refactored the Profile, Password, and Notifications sections to use `VCard` for their structure. * The form elements within these cards (name, email, passwords) now use `VFormField` and `VInput`. * Action buttons like "Save Changes" and "Change Password" are now `VButton` with an integrated `VSpinner` for loading states. * The notification preferences list uses `VList` and `VListItem`, with each preference toggle converted to `VToggleSwitch`. 2. **`GroupDetailPage.vue`**: * I updated the page-level loading spinner, error alert, and main heading to `VSpinner`, `VAlert`, and `VHeading`. * I refactored the "Group Members", "Invite Members", "Chores", and "Expenses" sections from custom "neo-card" styling to use `VCard`. * Headers within these cards use `VHeading` and action buttons use `VButton` (I kept Material Icons where `VIcon` wasn't a direct replacement). * Lists of members, chores, and expenses now use `VList` and `VListItem`. * Buttons within list items (e.g., "Remove member") are `VButton` with `VSpinner`. * Role indicators and frequency/split type "chips" are now `VBadge` components, and I updated the helper functions to return VBadge-compatible variants. * The "Invite Members" form elements (input for code, copy button) use `VFormField`, `VInput`, and `VButton`. * I simplified empty states within card bodies using `VIcon` and text. 3. **`ListDetailPage.vue`**: This complex page required several steps to refactor: * **Page-Level & Header:** I updated the loading state to `VSpinner`, the error alert to `VAlert`, and the main title to `VHeading`. Header action buttons are `VButton` with icons, and the list status is `VBadge`. * **Modals:** I converted all five custom modals (OCR, Confirmation, Edit Item, Settle Share, Cost Summary shell) to use `VModal`. Internal forms and actions within these modals now use `VFormField`, `VInput`, `VButton`, `VSpinner`, `VList`, `VListItem`, and `VAlert` as appropriate. I removed the `onClickOutside` logic. * **Main Items List:** The loading state uses `VCard` with `VSpinner`, and the empty state uses `VCard variant="empty-state"`. The list itself is now a `VCard` containing a `VList`. Each item is a `VListItem` with internal content refactored to use `VCheckbox`, `VInput` (for price), and `VButton` with `VIcon` for actions. * **Add Item Form:** I re-structured this below the items list, using `VFormField`, `VInput`, and `VButton` with `VIcon`. * **Expenses Section:** The main card uses `VCard` with `VHeading` and `VButton` in the header. Loading/error/empty states use `VSpinner`, `VAlert`, `VIcon`. The expenses list is `VList`, with each expense item as a `VListItem`. Statuses are `VBadge`. This refactoring significantly increases the usage of the Valerie UI component library across these key application pages. This should help create a more consistent experience for you and make development smoother. Next, I'll focus on the Chores-related pages.
This commit is contained in:
parent
272e5abe41
commit
813ed911f1
@ -1,116 +1,84 @@
|
||||
<template>
|
||||
<main class="container page-padding">
|
||||
<h1 class="mb-3">Account Settings</h1>
|
||||
<VHeading level="1" text="Account Settings" class="mb-3" />
|
||||
|
||||
<div v-if="loading" class="text-center">
|
||||
<div class="spinner-dots" role="status"><span /><span /><span /></div>
|
||||
<p>Loading profile...</p>
|
||||
<VSpinner label="Loading profile..." />
|
||||
</div>
|
||||
|
||||
<div v-else-if="error" class="alert alert-error mb-3" role="alert">
|
||||
<div class="alert-content">
|
||||
<svg class="icon" aria-hidden="true">
|
||||
<use xlink:href="#icon-alert-triangle" />
|
||||
</svg>
|
||||
{{ error }}
|
||||
</div>
|
||||
<button type="button" class="btn btn-sm btn-danger" @click="fetchProfile">Retry</button>
|
||||
</div>
|
||||
<VAlert v-else-if="error" type="error" :message="error" class="mb-3">
|
||||
<template #actions>
|
||||
<VButton variant="danger" size="sm" @click="fetchProfile">Retry</VButton>
|
||||
</template>
|
||||
</VAlert>
|
||||
|
||||
<form v-else @submit.prevent="onSubmitProfile">
|
||||
<!-- Profile Section -->
|
||||
<div class="card mb-3">
|
||||
<div class="card-header">
|
||||
<h3>Profile Information</h3>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<VCard class="mb-3">
|
||||
<template #header><VHeading level="3">Profile Information</VHeading></template>
|
||||
<div class="flex flex-wrap" style="gap: 1rem;">
|
||||
<div class="form-group flex-grow">
|
||||
<label for="profileName" class="form-label">Name</label>
|
||||
<input type="text" id="profileName" v-model="profile.name" class="form-input" required />
|
||||
</div>
|
||||
<div class="form-group flex-grow">
|
||||
<label for="profileEmail" class="form-label">Email</label>
|
||||
<input type="email" id="profileEmail" v-model="profile.email" class="form-input" required readonly />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-footer">
|
||||
<button type="submit" class="btn btn-primary" :disabled="saving">
|
||||
<span v-if="saving" class="spinner-dots-sm" role="status"><span /><span /><span /></span>
|
||||
Save Changes
|
||||
</button>
|
||||
</div>
|
||||
<VFormField label="Name" class="flex-grow">
|
||||
<VInput id="profileName" v-model="profile.name" required />
|
||||
</VFormField>
|
||||
<VFormField label="Email" class="flex-grow">
|
||||
<VInput type="email" id="profileEmail" v-model="profile.email" required readonly />
|
||||
</VFormField>
|
||||
</div>
|
||||
<template #footer>
|
||||
<VButton type="submit" variant="primary" :disabled="saving">
|
||||
<VSpinner v-if="saving" size="sm" /> Save Changes
|
||||
</VButton>
|
||||
</template>
|
||||
</VCard>
|
||||
</form>
|
||||
|
||||
<!-- Password Section -->
|
||||
<form @submit.prevent="onChangePassword">
|
||||
<div class="card mb-3">
|
||||
<div class="card-header">
|
||||
<h3>Change Password</h3>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<VCard class="mb-3">
|
||||
<template #header><VHeading level="3">Change Password</VHeading></template>
|
||||
<div class="flex flex-wrap" style="gap: 1rem;">
|
||||
<div class="form-group flex-grow">
|
||||
<label for="currentPassword" class="form-label">Current Password</label>
|
||||
<input type="password" id="currentPassword" v-model="password.current" class="form-input" required />
|
||||
</div>
|
||||
<div class="form-group flex-grow">
|
||||
<label for="newPassword" class="form-label">New Password</label>
|
||||
<input type="password" id="newPassword" v-model="password.newPassword" class="form-input" required />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-footer">
|
||||
<button type="submit" class="btn btn-primary" :disabled="changingPassword">
|
||||
<span v-if="changingPassword" class="spinner-dots-sm" role="status"><span /><span /><span /></span>
|
||||
Change Password
|
||||
</button>
|
||||
</div>
|
||||
<VFormField label="Current Password" class="flex-grow">
|
||||
<VInput type="password" id="currentPassword" v-model="password.current" required />
|
||||
</VFormField>
|
||||
<VFormField label="New Password" class="flex-grow">
|
||||
<VInput type="password" id="newPassword" v-model="password.newPassword" required />
|
||||
</VFormField>
|
||||
</div>
|
||||
<template #footer>
|
||||
<VButton type="submit" variant="primary" :disabled="changingPassword">
|
||||
<VSpinner v-if="changingPassword" size="sm" /> Change Password
|
||||
</VButton>
|
||||
</template>
|
||||
</VCard>
|
||||
</form>
|
||||
|
||||
<!-- Notifications Section -->
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h3>Notification Preferences</h3>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<ul class="item-list preference-list">
|
||||
<li class="preference-item">
|
||||
<VCard>
|
||||
<template #header><VHeading level="3">Notification Preferences</VHeading></template>
|
||||
<VList class="preference-list">
|
||||
<VListItem class="preference-item">
|
||||
<div class="preference-label">
|
||||
<span>Email Notifications</span>
|
||||
<small>Receive email notifications for important updates</small>
|
||||
</div>
|
||||
<label class="switch-container">
|
||||
<input type="checkbox" v-model="preferences.emailNotifications" @change="onPreferenceChange" />
|
||||
<span class="switch" aria-hidden="true"></span>
|
||||
</label>
|
||||
</li>
|
||||
<li class="preference-item">
|
||||
<VToggleSwitch v-model="preferences.emailNotifications" @change="onPreferenceChange" label="Email Notifications" id="emailNotificationsToggle" />
|
||||
</VListItem>
|
||||
<VListItem class="preference-item">
|
||||
<div class="preference-label">
|
||||
<span>List Updates</span>
|
||||
<small>Get notified when lists are updated</small>
|
||||
</div>
|
||||
<label class="switch-container">
|
||||
<input type="checkbox" v-model="preferences.listUpdates" @change="onPreferenceChange" />
|
||||
<span class="switch" aria-hidden="true"></span>
|
||||
</label>
|
||||
</li>
|
||||
<li class="preference-item">
|
||||
<VToggleSwitch v-model="preferences.listUpdates" @change="onPreferenceChange" label="List Updates" id="listUpdatesToggle"/>
|
||||
</VListItem>
|
||||
<VListItem class="preference-item">
|
||||
<div class="preference-label">
|
||||
<span>Group Activities</span>
|
||||
<small>Receive notifications for group activities</small>
|
||||
</div>
|
||||
<label class="switch-container">
|
||||
<input type="checkbox" v-model="preferences.groupActivities" @change="onPreferenceChange" />
|
||||
<span class="switch" aria-hidden="true"></span>
|
||||
</label>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<VToggleSwitch v-model="preferences.groupActivities" @change="onPreferenceChange" label="Group Activities" id="groupActivitiesToggle"/>
|
||||
</VListItem>
|
||||
</VList>
|
||||
</VCard>
|
||||
</main>
|
||||
</template>
|
||||
|
||||
@ -118,6 +86,16 @@
|
||||
import { ref, onMounted } from 'vue';
|
||||
import { apiClient, API_ENDPOINTS } from '@/config/api'; // Assuming path
|
||||
import { useNotificationStore } from '@/stores/notifications';
|
||||
import VHeading from '@/components/valerie/VHeading.vue';
|
||||
import VSpinner from '@/components/valerie/VSpinner.vue';
|
||||
import VAlert from '@/components/valerie/VAlert.vue';
|
||||
import VCard from '@/components/valerie/VCard.vue';
|
||||
import VFormField from '@/components/valerie/VFormField.vue';
|
||||
import VInput from '@/components/valerie/VInput.vue';
|
||||
import VButton from '@/components/valerie/VButton.vue';
|
||||
import VToggleSwitch from '@/components/valerie/VToggleSwitch.vue';
|
||||
import VList from '@/components/valerie/VList.vue';
|
||||
import VListItem from '@/components/valerie/VListItem.vue';
|
||||
|
||||
interface Profile {
|
||||
name: string;
|
||||
|
@ -1,82 +1,57 @@
|
||||
<template>
|
||||
<main class="container page-padding">
|
||||
<div v-if="loading" class="text-center">
|
||||
<div class="spinner-dots" role="status"><span /><span /><span /></div>
|
||||
<p>Loading group details...</p>
|
||||
</div>
|
||||
<div v-else-if="error" class="alert alert-error mb-3" role="alert">
|
||||
<div class="alert-content">
|
||||
<svg class="icon" aria-hidden="true">
|
||||
<use xlink:href="#icon-alert-triangle" />
|
||||
</svg>
|
||||
{{ error }}
|
||||
</div>
|
||||
<button type="button" class="btn btn-sm btn-danger" @click="fetchGroupDetails">Retry</button>
|
||||
<VSpinner label="Loading group details..." />
|
||||
</div>
|
||||
<VAlert v-else-if="error" type="error" :message="error" class="mb-3">
|
||||
<template #actions>
|
||||
<VButton variant="danger" size="sm" @click="fetchGroupDetails">Retry</VButton>
|
||||
</template>
|
||||
</VAlert>
|
||||
<div v-else-if="group">
|
||||
<h1 class="mb-3">{{ group.name }}</h1>
|
||||
<VHeading level="1" :text="group.name" class="mb-3" />
|
||||
|
||||
<div class="neo-grid">
|
||||
<!-- Group Members Section -->
|
||||
<div class="neo-card">
|
||||
<div class="neo-card-header">
|
||||
<h3>Group Members</h3>
|
||||
</div>
|
||||
<div class="neo-card-body">
|
||||
<div v-if="group.members && group.members.length > 0" class="neo-members-list">
|
||||
<div v-for="member in group.members" :key="member.id" class="neo-member-item">
|
||||
<VCard>
|
||||
<template #header><VHeading level="3">Group Members</VHeading></template>
|
||||
<VList v-if="group.members && group.members.length > 0">
|
||||
<VListItem v-for="member in group.members" :key="member.id" class="flex justify-between items-center">
|
||||
<div class="neo-member-info">
|
||||
<span class="neo-member-name">{{ member.email }}</span>
|
||||
<span class="neo-member-role" :class="member.role?.toLowerCase()">{{ member.role || 'Member' }}</span>
|
||||
<VBadge :text="member.role || 'Member'" :variant="member.role?.toLowerCase() === 'owner' ? 'primary' : 'secondary'" />
|
||||
</div>
|
||||
<button v-if="canRemoveMember(member)" class="btn btn-danger btn-sm" @click="removeMember(member.id)"
|
||||
:disabled="removingMember === member.id">
|
||||
<span v-if="removingMember === member.id" class="spinner-dots-sm"
|
||||
role="status"><span /><span /><span /></span>
|
||||
Remove
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else class="neo-empty-state">
|
||||
<svg class="icon icon-lg" aria-hidden="true">
|
||||
<use xlink:href="#icon-users" />
|
||||
</svg>
|
||||
<VButton v-if="canRemoveMember(member)" variant="danger" size="sm" @click="removeMember(member.id)" :disabled="removingMember === member.id">
|
||||
<VSpinner v-if="removingMember === member.id" size="sm"/> Remove
|
||||
</VButton>
|
||||
</VListItem>
|
||||
</VList>
|
||||
<div v-else class="text-center py-4">
|
||||
<VIcon name="users" size="lg" class="opacity-50 mb-2" />
|
||||
<p>No members found.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</VCard>
|
||||
|
||||
<!-- Invite Members Section -->
|
||||
<div class="neo-card">
|
||||
<div class="neo-card-header">
|
||||
<h3>Invite Members</h3>
|
||||
</div>
|
||||
<div class="neo-card-body">
|
||||
<button class="btn btn-primary w-full" @click="generateInviteCode" :disabled="generatingInvite">
|
||||
<span v-if="generatingInvite" class="spinner-dots-sm" role="status"><span /><span /><span /></span>
|
||||
{{ inviteCode ? 'Regenerate Invite Code' : 'Generate Invite Code' }}
|
||||
</button>
|
||||
<VCard>
|
||||
<template #header><VHeading level="3">Invite Members</VHeading></template>
|
||||
<VButton variant="primary" class="w-full" @click="generateInviteCode" :disabled="generatingInvite">
|
||||
<VSpinner v-if="generatingInvite" size="sm"/> {{ inviteCode ? 'Regenerate Invite Code' : 'Generate Invite Code' }}
|
||||
</VButton>
|
||||
<div v-if="inviteCode" class="neo-invite-code mt-3">
|
||||
<label for="inviteCodeInput" class="neo-label">Current Active Invite Code:</label>
|
||||
<div class="neo-input-group">
|
||||
<input id="inviteCodeInput" type="text" :value="inviteCode" class="neo-input" readonly />
|
||||
<button class="btn btn-neutral btn-icon-only" @click="copyInviteCodeHandler"
|
||||
aria-label="Copy invite code">
|
||||
<svg class="icon">
|
||||
<use xlink:href="#icon-clipboard"></use>
|
||||
</svg>
|
||||
</button>
|
||||
<VFormField label="Current Active Invite Code:" :label-sr-only="false">
|
||||
<div class="flex items-center gap-2">
|
||||
<VInput id="inviteCodeInput" :model-value="inviteCode" readonly class="flex-grow" />
|
||||
<VButton variant="neutral" :icon-only="true" iconLeft="clipboard" @click="copyInviteCodeHandler" aria-label="Copy invite code" />
|
||||
</div>
|
||||
<p v-if="copySuccess" class="neo-success-text">Invite code copied to clipboard!</p>
|
||||
</VFormField>
|
||||
<p v-if="copySuccess" class="text-sm text-green-600 mt-1">Invite code copied to clipboard!</p>
|
||||
</div>
|
||||
<div v-else class="neo-empty-state mt-3">
|
||||
<svg class="icon icon-lg" aria-hidden="true">
|
||||
<use xlink:href="#icon-link" />
|
||||
</svg>
|
||||
<div v-else class="text-center py-4 mt-3">
|
||||
<VIcon name="link" size="lg" class="opacity-50 mb-2" />
|
||||
<p>No active invite code. Click the button above to generate one.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</VCard>
|
||||
</div>
|
||||
|
||||
<!-- Lists Section -->
|
||||
@ -85,78 +60,61 @@
|
||||
</div>
|
||||
|
||||
<!-- Chores Section -->
|
||||
<div class="mt-4">
|
||||
<div class="neo-card">
|
||||
<div class="neo-card-header">
|
||||
<h3>Group Chores</h3>
|
||||
<router-link :to="`/groups/${groupId}/chores`" class="btn btn-primary">
|
||||
<span class="material-icons">cleaning_services</span>
|
||||
Manage Chores
|
||||
</router-link>
|
||||
<VCard class="mt-4">
|
||||
<template #header>
|
||||
<div class="flex justify-between items-center w-full">
|
||||
<VHeading level="3">Group Chores</VHeading>
|
||||
<VButton :to="`/groups/${groupId}/chores`" variant="primary">
|
||||
<span class="material-icons" style="margin-right: 0.25em;">cleaning_services</span> Manage Chores
|
||||
</VButton>
|
||||
</div>
|
||||
<div class="neo-card-body">
|
||||
<div v-if="upcomingChores.length > 0" class="neo-chores-list">
|
||||
<div v-for="chore in upcomingChores" :key="chore.id" class="neo-chore-item">
|
||||
</template>
|
||||
<VList v-if="upcomingChores.length > 0">
|
||||
<VListItem v-for="chore in upcomingChores" :key="chore.id" class="flex justify-between items-center">
|
||||
<div class="neo-chore-info">
|
||||
<span class="neo-chore-name">{{ chore.name }}</span>
|
||||
<span class="neo-chore-due">Due: {{ formatDate(chore.next_due_date) }}</span>
|
||||
</div>
|
||||
<span class="neo-chip" :class="getFrequencyColor(chore.frequency)">
|
||||
{{ formatFrequency(chore.frequency) }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else class="neo-empty-state">
|
||||
<svg class="icon icon-lg" aria-hidden="true">
|
||||
<use xlink:href="#icon-cleaning_services" />
|
||||
</svg>
|
||||
<VBadge :text="formatFrequency(chore.frequency)" :variant="getFrequencyBadgeVariant(chore.frequency)" />
|
||||
</VListItem>
|
||||
</VList>
|
||||
<div v-else class="text-center py-4">
|
||||
<VIcon name="cleaning_services" size="lg" class="opacity-50 mb-2" /> {/* Assuming cleaning_services is a valid VIcon name or will be added */}
|
||||
<p>No chores scheduled. Click "Manage Chores" to create some!</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</VCard>
|
||||
|
||||
<!-- Expenses Section -->
|
||||
<div class="mt-4">
|
||||
<div class="neo-card">
|
||||
<div class="neo-card-header">
|
||||
<h3>Group Expenses</h3>
|
||||
<router-link :to="`/groups/${groupId}/expenses`" class="btn btn-primary">
|
||||
<span class="material-icons">payments</span>
|
||||
Manage Expenses
|
||||
</router-link>
|
||||
<VCard class="mt-4">
|
||||
<template #header>
|
||||
<div class="flex justify-between items-center w-full">
|
||||
<VHeading level="3">Group Expenses</VHeading>
|
||||
<VButton :to="`/groups/${groupId}/expenses`" variant="primary">
|
||||
<span class="material-icons" style="margin-right: 0.25em;">payments</span> Manage Expenses
|
||||
</VButton>
|
||||
</div>
|
||||
<div class="neo-card-body">
|
||||
<div v-if="recentExpenses.length > 0" class="neo-expenses-list">
|
||||
<div v-for="expense in recentExpenses" :key="expense.id" class="neo-expense-item">
|
||||
</template>
|
||||
<VList v-if="recentExpenses.length > 0">
|
||||
<VListItem v-for="expense in recentExpenses" :key="expense.id" class="flex justify-between items-center">
|
||||
<div class="neo-expense-info">
|
||||
<span class="neo-expense-name">{{ expense.description }}</span>
|
||||
<span class="neo-expense-date">{{ formatDate(expense.expense_date) }}</span>
|
||||
</div>
|
||||
<div class="neo-expense-details">
|
||||
<span class="neo-expense-amount">{{ expense.currency }} {{ formatAmount(expense.total_amount)
|
||||
}}</span>
|
||||
<span class="neo-chip" :class="getSplitTypeColor(expense.split_type)">
|
||||
{{ formatSplitType(expense.split_type) }}
|
||||
</span>
|
||||
<span class="neo-expense-amount">{{ expense.currency }} {{ formatAmount(expense.total_amount) }}</span>
|
||||
<VBadge :text="formatSplitType(expense.split_type)" :variant="getSplitTypeBadgeVariant(expense.split_type)" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else class="neo-empty-state">
|
||||
<svg class="icon icon-lg" aria-hidden="true">
|
||||
<use xlink:href="#icon-payments" />
|
||||
</svg>
|
||||
</VListItem>
|
||||
</VList>
|
||||
<div v-else class="text-center py-4">
|
||||
<VIcon name="payments" size="lg" class="opacity-50 mb-2" /> {/* Assuming payments is a valid VIcon name or will be added */}
|
||||
<p>No expenses recorded. Click "Manage Expenses" to add some!</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</VCard>
|
||||
|
||||
</div>
|
||||
|
||||
<div v-else class="alert alert-info" role="status">
|
||||
<div class="alert-content">Group not found or an error occurred.</div>
|
||||
</div>
|
||||
<VAlert v-else type="info" message="Group not found or an error occurred." />
|
||||
</main>
|
||||
</template>
|
||||
|
||||
@ -171,6 +129,17 @@ import { choreService } from '../services/choreService'
|
||||
import type { Chore, ChoreFrequency } from '../types/chore'
|
||||
import { format } from 'date-fns'
|
||||
import type { Expense } from '@/types/expense'
|
||||
import VHeading from '@/components/valerie/VHeading.vue';
|
||||
import VSpinner from '@/components/valerie/VSpinner.vue';
|
||||
import VAlert from '@/components/valerie/VAlert.vue';
|
||||
import VCard from '@/components/valerie/VCard.vue';
|
||||
import VList from '@/components/valerie/VList.vue';
|
||||
import VListItem from '@/components/valerie/VListItem.vue';
|
||||
import VButton from '@/components/valerie/VButton.vue';
|
||||
import VBadge from '@/components/valerie/VBadge.vue';
|
||||
import VInput from '@/components/valerie/VInput.vue';
|
||||
import VFormField from '@/components/valerie/VFormField.vue';
|
||||
import VIcon from '@/components/valerie/VIcon.vue';
|
||||
|
||||
interface Group {
|
||||
id: string | number;
|
||||
@ -355,16 +324,16 @@ const formatFrequency = (frequency: ChoreFrequency) => {
|
||||
return options[frequency] || frequency
|
||||
}
|
||||
|
||||
const getFrequencyColor = (frequency: ChoreFrequency) => {
|
||||
const colors: Record<ChoreFrequency, string> = {
|
||||
one_time: 'grey',
|
||||
daily: 'blue',
|
||||
weekly: 'green',
|
||||
monthly: 'purple',
|
||||
custom: 'orange'
|
||||
}
|
||||
return colors[frequency]
|
||||
}
|
||||
const getFrequencyBadgeVariant = (frequency: ChoreFrequency): string => {
|
||||
const colorMap: Record<ChoreFrequency, string> = {
|
||||
one_time: 'neutral',
|
||||
daily: 'info',
|
||||
weekly: 'success',
|
||||
monthly: 'accent', // Using accent for purple as an example
|
||||
custom: 'warning'
|
||||
};
|
||||
return colorMap[frequency] || 'secondary';
|
||||
};
|
||||
|
||||
// Add new methods for expenses
|
||||
const loadRecentExpenses = async () => {
|
||||
@ -387,16 +356,16 @@ const formatSplitType = (type: string) => {
|
||||
).join(' ')
|
||||
}
|
||||
|
||||
const getSplitTypeColor = (type: string) => {
|
||||
const colors: Record<string, string> = {
|
||||
equal: 'blue',
|
||||
exact_amounts: 'green',
|
||||
percentage: 'purple',
|
||||
shares: 'orange',
|
||||
item_based: 'teal'
|
||||
}
|
||||
return colors[type] || 'grey'
|
||||
}
|
||||
const getSplitTypeBadgeVariant = (type: string): string => {
|
||||
const colorMap: Record<string, string> = {
|
||||
equal: 'info',
|
||||
exact_amounts: 'success',
|
||||
percentage: 'accent', // Using accent for purple
|
||||
shares: 'warning',
|
||||
item_based: 'secondary', // Using secondary for teal as an example
|
||||
};
|
||||
return colorMap[type] || 'neutral';
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
fetchGroupDetails();
|
||||
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user