app/pages/settings.vue

219 lines
6.9 KiB
Vue

<template>
<section class="py-8 space-y-6">
<div class="flex items-center justify-between">
<h2 class="text-2xl font-semibold">Policies & Privacy</h2>
</div>
<div class="grid grid-cols-1 lg:grid-cols-2 gap-6">
<UCard>
<template #header>
<h3 class="text-lg font-medium">Wage & Costs</h3>
</template>
<div class="space-y-4">
<div>
<label class="block text-sm font-medium mb-2"
>Equal Hourly Wage</label
>
<UInput
v-model="policies.hourlyWage"
type="number"
:ui="{ wrapper: 'relative' }">
<template #leading>
<span class="text-neutral-500"></span>
</template>
</UInput>
</div>
<div>
<label class="block text-sm font-medium mb-2"
>Payroll On-costs (%)</label
>
<UInput
v-model="policies.payrollOncost"
type="number"
:ui="{ wrapper: 'relative' }">
<template #trailing>
<span class="text-neutral-500">%</span>
</template>
</UInput>
</div>
</div>
</UCard>
<UCard>
<template #header>
<h3 class="text-lg font-medium">Cash Management</h3>
</template>
<div class="space-y-4">
<div>
<label class="block text-sm font-medium mb-2"
>Savings Target (months)</label
>
<UInput
v-model="policies.savingsTargetMonths"
type="number"
step="0.1" />
</div>
<div>
<label class="block text-sm font-medium mb-2"
>Minimum Cash Cushion</label
>
<UInput
v-model="policies.minCashCushion"
type="number"
:ui="{ wrapper: 'relative' }">
<template #leading>
<span class="text-neutral-500"></span>
</template>
</UInput>
</div>
</div>
</UCard>
<UCard>
<template #header>
<h3 class="text-lg font-medium">Deferred Pay Limits</h3>
</template>
<div class="space-y-4">
<div>
<label class="block text-sm font-medium mb-2"
>Cap (hours per quarter)</label
>
<UInput v-model="policies.deferredCapHours" type="number" />
</div>
<div>
<label class="block text-sm font-medium mb-2"
>Sunset (months)</label
>
<UInput v-model="policies.deferredSunsetMonths" type="number" />
</div>
</div>
</UCard>
<UCard>
<template #header>
<h3 class="text-lg font-medium">Distribution Order</h3>
</template>
<div class="space-y-4">
<p class="text-sm text-neutral-600">
Order of surplus distribution priorities.
</p>
<div class="space-y-2">
<div
v-for="(item, index) in distributionOrder"
:key="item"
class="flex items-center justify-between p-2 bg-neutral-50 rounded">
<span class="text-sm font-medium"
>{{ index + 1 }}. {{ item }}</span
>
<div class="flex gap-1">
<UButton
size="xs"
variant="ghost"
icon="i-heroicons-chevron-up" />
<UButton
size="xs"
variant="ghost"
icon="i-heroicons-chevron-down" />
</div>
</div>
</div>
</div>
</UCard>
</div>
<!-- Member Management Section -->
<UCard id="members">
<template #header>
<div class="flex items-center justify-between">
<h3 class="text-lg font-medium">Team Members</h3>
<div class="flex items-center gap-2">
<UBadge v-if="isSetupComplete" color="green" variant="subtle" size="xs">
Synchronized with Setup
</UBadge>
<UButton variant="ghost" size="xs" @click="goToSetup">
Edit in Setup
</UButton>
</div>
</div>
</template>
<div class="space-y-4">
<div v-if="members.length === 0" class="text-center py-8 text-neutral-500">
<p class="mb-4">No team members found.</p>
<UButton @click="goToSetup" variant="outline">
Add Members in Setup
</UButton>
</div>
<div v-else class="space-y-3">
<div
v-for="member in members"
:key="member.id"
class="p-4 border border-neutral-200 rounded-lg bg-neutral-50">
<div class="flex items-center justify-between">
<div>
<h4 class="font-medium">{{ member.displayName || member.name }}</h4>
<div class="text-sm text-neutral-600 space-y-1">
<div v-if="member.role">Role: {{ member.role }}</div>
<div>Monthly Target: {{ $format.currency(member.monthlyPayPlanned || 0) }}</div>
<div v-if="member.minMonthlyNeeds">Min Needs: {{ $format.currency(member.minMonthlyNeeds) }}</div>
</div>
</div>
<div class="text-right text-sm text-neutral-600">
<div>{{ Math.round((member.hoursPerMonth || member.hoursPerWeek * 4.33)) }} hrs/month</div>
</div>
</div>
</div>
</div>
</div>
</UCard>
<div class="flex justify-end">
<UButton color="primary"> Save Policies </UButton>
</div>
</section>
</template>
<script setup lang="ts">
// Store sync and setup state
const { initSync, getMembers, unifiedMembers } = useStoreSync();
const { isSetupComplete, goToSetup } = useSetupState();
const coopStore = useCoopBuilderStore();
const { $format } = useNuxtApp();
// Initialize synchronization on mount
onMounted(async () => {
await initSync();
});
// Get reactive synchronized member data
const members = unifiedMembers;
// Get synchronized policy data from setup
const policies = computed({
get: () => ({
hourlyWage: coopStore.equalHourlyWage,
payrollOncost: coopStore.payrollOncostPct,
savingsTargetMonths: coopStore.savingsTargetMonths,
minCashCushion: coopStore.minCashCushion,
deferredCapHours: 240, // These fields might not be in coop store yet
deferredSunsetMonths: 12,
}),
set: (newPolicies) => {
// Update the CoopBuilder store when policies change
coopStore.setEqualWage(newPolicies.hourlyWage);
coopStore.setOncostPct(newPolicies.payrollOncost);
coopStore.savingsTargetMonths = newPolicies.savingsTargetMonths;
coopStore.minCashCushion = newPolicies.minCashCushion;
}
});
const distributionOrder = ref([
"Deferred",
"Savings",
"Hardship",
"Training",
"Patronage",
"Retained",
]);
</script>