app/components/WizardPoliciesStep.vue

141 lines
4.1 KiB
Vue

<template>
<div class="max-w-4xl mx-auto space-y-6">
<!-- Section Header -->
<div class="mb-8">
<h3 class="text-2xl font-black text-black dark:text-white mb-2">
How will you share money?
</h3>
<p class="text-neutral-600 dark:text-neutral-200">
This is the foundation of your co-op's finances. Choose a pay approach
and set your hourly rate.
</p>
</div>
<!-- Pay Policy Selection -->
<div
class="p-6 border-2 border-black dark:border-netural-400 bg-white dark:bg-neutral-950 shadow-md">
<h4 class="font-bold mb-2">Step 1: Choose your pay approach</h4>
<p class="text-sm text-neutral-600 dark:text-neutral-200 mb-4">
How should available money be shared among members?
</p>
<URadioGroup
v-model="selectedPolicy"
:items="policyOptions"
@update:model-value="updatePolicy"
variant="list"
size="xl"
class="flex flex-col gap-2 w-full" />
</div>
<!-- Hourly Wage Input -->
<div
class="p-6 border-2 border-black dark:border-neutral-950 bg-white dark:bg-neutral-950 shadow-md">
<h4 class="font-bold mb-2">Step 2: Set your base wage</h4>
<p class="text-sm text-neutral-600 dark:text-neutral-200 mb-4">
This hourly rate applies to all paid work in your co-op
</p>
<div class="flex gap-4 items-start">
<UFormField label="Hourly Rate" class="w-full">
<UInput
v-model="wageText"
type="text"
placeholder="0.00"
size="xl"
class="text-2xl font-bold w-full"
@update:model-value="validateAndSaveWage">
<template #leading>
<span class="text-neutral-500 text-xl">{{
getCurrencySymbol(selectedCurrency.value)
}}</span>
</template>
</UInput>
</UFormField>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { getCurrencySymbol } from "~/utils/currency";
const emit = defineEmits<{
"save-status": [status: "saving" | "saved" | "error"];
}>();
// Store
const coop = useCoopBuilder();
const store = useCoopBuilderStore();
// Initialize from store
const selectedPolicy = ref(coop.policy.value?.relationship || "equal-pay");
const roleBands = ref(coop.policy.value?.roleBands || {});
const wageText = ref(String(store.equalHourlyWage || ""));
const selectedCurrency = computed(() => coop.currency.value || "EUR");
function parseNumberInput(val: unknown): number {
if (typeof val === "number") return val;
if (typeof val === "string") {
const cleaned = val.replace(/,/g, ".").replace(/[^0-9.\-]/g, "");
const parsed = parseFloat(cleaned);
return Number.isFinite(parsed) ? parsed : 0;
}
return 0;
}
// Simplified pay policy options
const policyOptions = [
{
value: "equal-pay",
label: "Equal pay - Everyone gets the same amount",
},
{
value: "hours-weighted",
label: "Hours-based - Pay proportional to hours worked",
},
{
value: "needs-weighted",
label: "Needs-based - Pay proportional to individual needs",
},
];
// Already initialized above with store values
// Removed uniqueRoles computed - no longer needed with simplified policies
function updatePolicy(value: string) {
coop.setPolicy(value as "equal-pay" | "needs-weighted" | "hours-weighted");
// Trigger payroll reallocation after policy change
const allocatedMembers = coop.allocatePayroll();
allocatedMembers.forEach((m) => {
coop.upsertMember(m);
});
emit("save-status", "saved");
}
// Removed updateRoleBands - no longer needed with simplified policies
// Text input for wage with validation (initialized above)
function validateAndSaveWage(value: string) {
const cleanValue = value.replace(/[^\d.]/g, "");
const numValue = parseFloat(cleanValue);
wageText.value = cleanValue;
if (!isNaN(numValue) && numValue >= 0) {
coop.setEqualWage(numValue);
// Trigger payroll reallocation after wage change
const allocatedMembers = coop.allocatePayroll();
allocatedMembers.forEach((m) => {
coop.upsertMember(m);
});
emit("save-status", "saved");
}
}
</script>