refactor: update routing paths in app.vue, enhance AnnualBudget component layout, and streamline dashboard and budget pages for improved user experience
This commit is contained in:
parent
09d8794d72
commit
864a81065c
23 changed files with 3211 additions and 1978 deletions
|
|
@ -172,15 +172,16 @@
|
|||
<p class="content-paragraph mb-3 leading-relaxed text-left">
|
||||
Any person who:
|
||||
</p>
|
||||
<ul class="content-list my-2 pl-6 list-disc">
|
||||
<li>Shares our values and purpose</li>
|
||||
<li>
|
||||
Contributes labour to the cooperative (by doing actual work,
|
||||
not just investing money)
|
||||
</li>
|
||||
<li>Commits to collective decision-making</li>
|
||||
<li>Participates in governance responsibilities</li>
|
||||
</ul>
|
||||
<UFormField label="Member Requirements" class="form-group-large">
|
||||
<UTextarea
|
||||
v-model="formData.memberRequirements"
|
||||
:rows="4"
|
||||
placeholder="Enter member requirements"
|
||||
size="xl"
|
||||
class="large-field"
|
||||
@input="debouncedAutoSave"
|
||||
@change="autoSave" />
|
||||
</UFormField>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
|
|
@ -413,43 +414,102 @@
|
|||
class="subsection-title text-xl font-semibold text-neutral-700 dark:text-neutral-200 border-b border-neutral-200 dark:border-neutral-600 pb-1 mb-3">
|
||||
Paying Ourselves
|
||||
</h3>
|
||||
<ul class="content-list my-2 pl-6 list-disc">
|
||||
<li class="flex items-baseline gap-2 flex-wrap">
|
||||
Base rate: $<UInput
|
||||
v-model="formData.baseRate"
|
||||
type="number"
|
||||
placeholder="25"
|
||||
class="inline-field number-field"
|
||||
@change="autoSave" />/hour for all members
|
||||
</li>
|
||||
<li class="flex items-baseline gap-2 flex-wrap">
|
||||
Or: Equal monthly draw of $<UInput
|
||||
v-model="formData.monthlyDraw"
|
||||
type="number"
|
||||
placeholder="2000"
|
||||
class="inline-field number-field"
|
||||
@change="autoSave" />
|
||||
per member
|
||||
</li>
|
||||
<li class="flex items-baseline gap-2 flex-wrap">
|
||||
Paid on the
|
||||
<USelect
|
||||
v-model="formData.paymentDay"
|
||||
:items="dayOptions"
|
||||
placeholder="15"
|
||||
class="inline-field"
|
||||
@change="autoSave" />
|
||||
of each month
|
||||
</li>
|
||||
<li class="flex items-baseline gap-2 flex-wrap">
|
||||
Surplus (profit) distributed equally every
|
||||
<UInput
|
||||
v-model="formData.surplusFrequency"
|
||||
placeholder="quarter"
|
||||
class="inline-field"
|
||||
@change="autoSave" />
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<!-- Pay Policy Selection -->
|
||||
<UFormField label="Pay Policy" class="form-group-large mb-4">
|
||||
<USelect
|
||||
v-model="formData.payPolicy"
|
||||
:items="payPolicyOptions"
|
||||
placeholder="Select pay policy"
|
||||
size="xl"
|
||||
class="w-full"
|
||||
@change="autoSave" />
|
||||
</UFormField>
|
||||
|
||||
<!-- Equal Pay Policy -->
|
||||
<div v-if="formData.payPolicy === 'equal-pay'" class="space-y-3">
|
||||
<p class="content-paragraph">All members receive equal compensation regardless of role or hours worked.</p>
|
||||
<ul class="content-list my-2 pl-6 list-disc">
|
||||
<li class="flex items-baseline gap-2 flex-wrap">
|
||||
Base rate: $<UInput
|
||||
v-model="formData.baseRate"
|
||||
type="number"
|
||||
placeholder="25"
|
||||
class="inline-field number-field"
|
||||
@change="autoSave" />/hour for all members
|
||||
</li>
|
||||
<li class="flex items-baseline gap-2 flex-wrap">
|
||||
Or: Equal monthly draw of $<UInput
|
||||
v-model="formData.monthlyDraw"
|
||||
type="number"
|
||||
placeholder="2000"
|
||||
class="inline-field number-field"
|
||||
@change="autoSave" />
|
||||
per member
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<!-- Hours-Weighted Policy -->
|
||||
<div v-if="formData.payPolicy === 'hours-weighted'" class="space-y-3">
|
||||
<p class="content-paragraph">Compensation is proportional to hours worked by each member.</p>
|
||||
<ul class="content-list my-2 pl-6 list-disc">
|
||||
<li class="flex items-baseline gap-2 flex-wrap">
|
||||
Hourly rate: $<UInput
|
||||
v-model="formData.hourlyRate"
|
||||
type="number"
|
||||
placeholder="25"
|
||||
class="inline-field number-field"
|
||||
@change="autoSave" />/hour
|
||||
</li>
|
||||
<li>Members track their hours and are paid accordingly</li>
|
||||
<li>Minimum hours commitment may apply</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<!-- Needs-Weighted Policy -->
|
||||
<div v-if="formData.payPolicy === 'needs-weighted'" class="space-y-3">
|
||||
<p class="content-paragraph">Compensation is allocated based on each member's individual financial needs.</p>
|
||||
<ul class="content-list my-2 pl-6 list-disc">
|
||||
<li>Members declare their minimum monthly needs</li>
|
||||
<li>Available payroll is distributed proportionally to cover needs</li>
|
||||
<li>Regular needs assessment and adjustment process</li>
|
||||
<li class="flex items-baseline gap-2 flex-wrap">
|
||||
Minimum guaranteed amount: $<UInput
|
||||
v-model="formData.minGuaranteedPay"
|
||||
type="number"
|
||||
placeholder="1000"
|
||||
class="inline-field number-field"
|
||||
@change="autoSave" />/month
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<!-- Common payment details -->
|
||||
<div class="mt-4 space-y-2">
|
||||
<p class="content-paragraph font-semibold">Payment Schedule:</p>
|
||||
<ul class="content-list my-2 pl-6 list-disc">
|
||||
<li class="flex items-baseline gap-2 flex-wrap">
|
||||
Paid on the
|
||||
<USelect
|
||||
v-model="formData.paymentDay"
|
||||
:items="dayOptions"
|
||||
placeholder="15th"
|
||||
arrow
|
||||
class="inline-field"
|
||||
@change="autoSave" />
|
||||
of each month
|
||||
</li>
|
||||
<li class="flex items-baseline gap-2 flex-wrap">
|
||||
Surplus (profit) distributed equally every
|
||||
<UInput
|
||||
v-model="formData.surplusFrequency"
|
||||
placeholder="quarter"
|
||||
class="inline-field"
|
||||
@change="autoSave" />
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||
|
|
@ -522,15 +582,16 @@
|
|||
@change="autoSave" />
|
||||
months. Current roles include:
|
||||
</p>
|
||||
<ul class="content-list">
|
||||
<li>
|
||||
Financial coordinator (handles bookkeeping, not financial
|
||||
decisions)
|
||||
</li>
|
||||
<li>Meeting facilitator</li>
|
||||
<li>External communications</li>
|
||||
<li>Others</li>
|
||||
</ul>
|
||||
<UFormField label="Rotating Roles" class="form-group-large">
|
||||
<UTextarea
|
||||
v-model="formData.rotatingRoles"
|
||||
:rows="4"
|
||||
placeholder="List rotating operational roles"
|
||||
size="xl"
|
||||
class="large-field"
|
||||
@input="debouncedAutoSave"
|
||||
@change="autoSave" />
|
||||
</UFormField>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
|
|
@ -541,11 +602,16 @@
|
|||
<p class="content-paragraph mb-3 leading-relaxed text-left">
|
||||
All members participate in:
|
||||
</p>
|
||||
<ul class="content-list my-2 pl-6 list-disc">
|
||||
<li>Governance and decision-making</li>
|
||||
<li>Strategic planning</li>
|
||||
<li>Mutual support and care</li>
|
||||
</ul>
|
||||
<UFormField label="Shared Responsibilities" class="form-group-large">
|
||||
<UTextarea
|
||||
v-model="formData.sharedResponsibilities"
|
||||
:rows="3"
|
||||
placeholder="List shared responsibilities for all members"
|
||||
size="xl"
|
||||
class="large-field"
|
||||
@input="debouncedAutoSave"
|
||||
@change="autoSave" />
|
||||
</UFormField>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -690,47 +756,6 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Section 10: Agreement Review -->
|
||||
<div class="section-card">
|
||||
<h2
|
||||
class="section-title text-2xl font-extrabold text-neutral-900 dark:text-neutral-100 mb-4">
|
||||
10. Agreement Review
|
||||
</h2>
|
||||
|
||||
<div class="space-y-4">
|
||||
<p class="content-paragraph mb-3 leading-relaxed text-left">
|
||||
By using this agreement, we commit to these principles and to
|
||||
showing up for each other.
|
||||
</p>
|
||||
|
||||
<div
|
||||
class="bg-neutral-50 dark:bg-neutral-900 p-4 rounded-md border-l-4 border-emerald-300">
|
||||
<p
|
||||
class="content-paragraph mb-3 leading-relaxed text-left flex items-baseline gap-2 flex-wrap">
|
||||
This agreement was last updated on
|
||||
<UInput
|
||||
v-model="formData.lastUpdated"
|
||||
type="date"
|
||||
class="inline-field"
|
||||
@change="autoSave" />. We commit to reviewing it on
|
||||
<UInput
|
||||
v-model="formData.nextReview"
|
||||
type="date"
|
||||
class="inline-field"
|
||||
@change="autoSave" />
|
||||
or sooner if circumstances require.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="signature-space mt-8 p-8 border border-dashed border-neutral-300 rounded-md bg-neutral-50 dark:bg-neutral-950">
|
||||
<p
|
||||
class="content-paragraph mb-3 leading-relaxed text-center text-neutral-600 italic">
|
||||
[Space for member signatures when printed]
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -768,13 +793,36 @@ const monthOptions = [
|
|||
"December",
|
||||
];
|
||||
|
||||
const dayOptions = Array.from({ length: 31 }, (_, i) => (i + 1).toString());
|
||||
const dayOptions = Array.from({ length: 31 }, (_, i) => ({
|
||||
value: i + 1,
|
||||
label: `${i + 1}${getOrdinalSuffix(i + 1)}`
|
||||
}));
|
||||
|
||||
// Helper function to get ordinal suffix (1st, 2nd, 3rd, etc.)
|
||||
function getOrdinalSuffix(num) {
|
||||
if (num >= 11 && num <= 13) {
|
||||
return 'th';
|
||||
}
|
||||
switch (num % 10) {
|
||||
case 1: return 'st';
|
||||
case 2: return 'nd';
|
||||
case 3: return 'rd';
|
||||
default: return 'th';
|
||||
}
|
||||
}
|
||||
|
||||
const payPolicyOptions = [
|
||||
{ value: 'equal-pay', label: 'Equal Pay - All members receive equal compensation' },
|
||||
{ value: 'hours-weighted', label: 'Hours-Weighted - Pay proportional to hours worked' },
|
||||
{ value: 'needs-weighted', label: 'Needs-Weighted - Pay proportional to individual needs' }
|
||||
];
|
||||
|
||||
const formData = ref({
|
||||
cooperativeName: "",
|
||||
dateEstablished: "",
|
||||
purpose: "",
|
||||
coreValues: "",
|
||||
memberRequirements: "Shares our values and purpose\nContributes labour to the cooperative (by doing actual work, not just investing money)\nCommits to collective decision-making\nParticipates in governance responsibilities",
|
||||
members: [{ name: "", email: "", joinDate: "", role: "" }],
|
||||
trialPeriodMonths: 3,
|
||||
buyInAmount: "",
|
||||
|
|
@ -787,20 +835,24 @@ const formData = ref({
|
|||
majorDebtThreshold: 5000,
|
||||
meetingFrequency: "weekly",
|
||||
emergencyNoticeHours: 24,
|
||||
// Pay policy settings
|
||||
payPolicy: "equal-pay",
|
||||
baseRate: 25,
|
||||
monthlyDraw: "",
|
||||
hourlyRate: 25,
|
||||
minGuaranteedPay: 1000,
|
||||
paymentDay: 15,
|
||||
surplusFrequency: "quarter",
|
||||
targetHours: 40,
|
||||
roleRotationMonths: 6,
|
||||
rotatingRoles: "Financial coordinator (handles bookkeeping, not financial decisions)\nMeeting facilitator\nExternal communications\nOthers",
|
||||
sharedResponsibilities: "Governance and decision-making\nStrategic planning\nMutual support and care",
|
||||
reviewFrequency: "year",
|
||||
assetDonationTarget: "",
|
||||
legalStructure: "",
|
||||
registeredLocation: "",
|
||||
fiscalYearEndMonth: "December",
|
||||
fiscalYearEndDay: 31,
|
||||
lastUpdated: new Date().toISOString().split("T")[0],
|
||||
nextReview: "",
|
||||
});
|
||||
|
||||
// Load saved data immediately (before watchers)
|
||||
|
|
@ -1017,28 +1069,12 @@ const handlePrint = () => {
|
|||
|
||||
// Export data for the ExportOptions component
|
||||
const exportData = computed(() => ({
|
||||
// Pass the complete formData object - this is what the export functions use
|
||||
formData: formData.value,
|
||||
// Also provide direct access to key fields for backward compatibility
|
||||
cooperativeName: formData.value.cooperativeName || "Worker Cooperative",
|
||||
dateEstablished: formData.value.dateEstablished,
|
||||
purpose: formData.value.purpose,
|
||||
coreValues: formData.value.coreValues,
|
||||
members: formData.value.members,
|
||||
trialPeriodMonths: formData.value.trialPeriodMonths,
|
||||
policies: {
|
||||
buyInAmount: formData.value.buyInAmount,
|
||||
noticeDays: formData.value.noticeDays,
|
||||
surplusPayoutDays: formData.value.surplusPayoutDays,
|
||||
buyInReturnDays: formData.value.buyInReturnDays,
|
||||
dayToDayLimit: formData.value.dayToDayLimit,
|
||||
regularDecisionMin: formData.value.regularDecisionMin,
|
||||
regularDecisionMax: formData.value.regularDecisionMax,
|
||||
majorDebtThreshold: formData.value.majorDebtThreshold,
|
||||
meetingFrequency: formData.value.meetingFrequency,
|
||||
emergencyNoticeHours: formData.value.emergencyNoticeHours,
|
||||
baseRate: formData.value.baseRate,
|
||||
},
|
||||
exportedAt: new Date().toISOString(),
|
||||
section: "membership-agreement",
|
||||
exportedAt: new Date().toISOString(),
|
||||
}));
|
||||
</script>
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue