170 lines
5 KiB
Vue
170 lines
5 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">
|
|
<!-- Currency Selection -->
|
|
<UFormField label="Currency" class="w-1/2">
|
|
<USelect
|
|
v-model="selectedCurrency"
|
|
:items="currencySelectOptions"
|
|
placeholder="Select currency"
|
|
size="xl"
|
|
class="w-full"
|
|
@update:model-value="updateCurrency">
|
|
<template #leading>
|
|
<span class="text-lg">{{
|
|
getCurrencySymbol(selectedCurrency)
|
|
}}</span>
|
|
</template>
|
|
</USelect>
|
|
</UFormField>
|
|
|
|
<UFormField label="Hourly Rate" class="w-1/2">
|
|
<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)
|
|
}}</span>
|
|
</template>
|
|
</UInput>
|
|
</UFormField>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { currencyOptions, 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 = ref(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",
|
|
},
|
|
];
|
|
|
|
// Currency options for USelect (simplified format)
|
|
const currencySelectOptions = computed(() =>
|
|
currencyOptions.map((currency) => ({
|
|
label: `${currency.name} (${currency.code})`,
|
|
value: currency.code,
|
|
}))
|
|
);
|
|
|
|
// Already initialized above with store values
|
|
|
|
// Removed uniqueRoles computed - no longer needed with simplified policies
|
|
|
|
function updateCurrency(value: string) {
|
|
selectedCurrency.value = value;
|
|
coop.setCurrency(value);
|
|
emit("save-status", "saved");
|
|
}
|
|
|
|
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>
|