refactor: update membership agreement and conflict resolution framework templates to utilize centralized cooperative information, enhance decision framework handling, and improve overall layout for better user experience
This commit is contained in:
parent
f1889b3a70
commit
7b4fb6c2fd
5 changed files with 510 additions and 703 deletions
|
|
@ -16,7 +16,7 @@
|
|||
<div class="text-center mb-8">
|
||||
<h1
|
||||
class="text-3xl md:text-5xl font-bold uppercase m-0 py-4 border-t-2 border-b-2 text-black dark:text-white border-black dark:border-white"
|
||||
:data-org-name="formData.orgName || 'Organization'">
|
||||
:data-org-name="getOrgName()">
|
||||
CONFLICT RESOLUTION
|
||||
</h1>
|
||||
</div>
|
||||
|
|
@ -895,6 +895,9 @@
|
|||
<script setup>
|
||||
import { ref, watch, computed, onMounted } from "vue";
|
||||
|
||||
// Import centralized coop info
|
||||
const { coopInfo, updateCoopInfo, getOrgName } = useCoopInfo();
|
||||
|
||||
definePageMeta({
|
||||
layout: false,
|
||||
});
|
||||
|
|
@ -1429,6 +1432,27 @@ function debounce(func, wait) {
|
|||
};
|
||||
}
|
||||
|
||||
// Sync with centralized coop info
|
||||
watch(
|
||||
() => coopInfo.value,
|
||||
(newCoopInfo) => {
|
||||
if (newCoopInfo.cooperativeName) {
|
||||
formData.value.orgName = newCoopInfo.cooperativeName;
|
||||
}
|
||||
},
|
||||
{ deep: true, immediate: true }
|
||||
);
|
||||
|
||||
// Update centralized store when org name changes
|
||||
watch(
|
||||
() => formData.value.orgName,
|
||||
(newOrgName) => {
|
||||
if (newOrgName && newOrgName !== coopInfo.value.cooperativeName) {
|
||||
updateCoopInfo({ cooperativeName: newOrgName });
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// Watch for changes and auto-save
|
||||
watch(
|
||||
[
|
||||
|
|
@ -1450,7 +1474,7 @@ watch(
|
|||
// Export data for the ExportOptions component
|
||||
const exportData = computed(() => ({
|
||||
formData: formData.value,
|
||||
orgName: formData.value.orgName || "Organization",
|
||||
orgName: getOrgName(),
|
||||
orgType: formData.value.orgType,
|
||||
memberCount: formData.value.memberCount,
|
||||
sectionsEnabled: sectionsEnabled.value,
|
||||
|
|
|
|||
|
|
@ -15,9 +15,7 @@
|
|||
<div class="text-center mb-8">
|
||||
<h1
|
||||
class="text-3xl md:text-5xl font-bold uppercase text-neutral-900 dark:text-white m-0 py-4 border-t-2 border-b-2 border-neutral-900 dark:border-neutral-100"
|
||||
:data-coop-name="
|
||||
formData.cooperativeName || 'Worker Cooperative'
|
||||
">
|
||||
:data-coop-name="getDisplayName()">
|
||||
MEMBERSHIP AGREEMENT
|
||||
</h1>
|
||||
</div>
|
||||
|
|
@ -172,7 +170,7 @@
|
|||
<p class="content-paragraph mb-3 leading-relaxed text-left">
|
||||
Any person who:
|
||||
</p>
|
||||
<UFormField label="Member Requirements" class="form-group-large">
|
||||
<UFormField class="form-group-large">
|
||||
<UTextarea
|
||||
v-model="formData.memberRequirements"
|
||||
:rows="4"
|
||||
|
|
@ -193,7 +191,7 @@
|
|||
<p class="content-paragraph">
|
||||
New members join through a consent process, which means
|
||||
existing members must agree that adding this person won't harm
|
||||
the cooperative.
|
||||
{{ getDisplayName().toLowerCase() }}.
|
||||
</p>
|
||||
|
||||
<ol class="content-list numbered my-2 pl-6 list-decimal">
|
||||
|
|
@ -203,18 +201,17 @@
|
|||
v-model="formData.trialPeriodMonths"
|
||||
type="number"
|
||||
placeholder="3"
|
||||
class="inline-field number-field"
|
||||
class="inline-field number-field w-10"
|
||||
@change="autoSave" />
|
||||
months working together
|
||||
</li>
|
||||
<li>Values alignment conversation</li>
|
||||
<li>Consent decision by current members</li>
|
||||
<li class="flex items-baseline gap-2 flex-wrap">
|
||||
Optional - Equal buy-in contribution of $<UInput
|
||||
v-model="formData.buyInAmount"
|
||||
type="number"
|
||||
placeholder="1000"
|
||||
class="inline-field number-field"
|
||||
class="inline-field number-field w-10"
|
||||
@change="autoSave" />
|
||||
(can be paid over time or waived based on need)
|
||||
</li>
|
||||
|
|
@ -234,7 +231,7 @@
|
|||
v-model="formData.noticeDays"
|
||||
type="number"
|
||||
placeholder="30"
|
||||
class="inline-field number-field"
|
||||
class="inline-field number-field w-10"
|
||||
@change="autoSave" />
|
||||
days notice. The cooperative will:
|
||||
</p>
|
||||
|
|
@ -246,7 +243,7 @@
|
|||
v-model="formData.surplusPayoutDays"
|
||||
type="number"
|
||||
placeholder="30"
|
||||
class="inline-field number-field"
|
||||
class="inline-field number-field w-10"
|
||||
@change="autoSave" />
|
||||
days
|
||||
</li>
|
||||
|
|
@ -256,7 +253,7 @@
|
|||
v-model="formData.buyInReturnDays"
|
||||
type="number"
|
||||
placeholder="90"
|
||||
class="inline-field number-field"
|
||||
class="inline-field number-field w-10"
|
||||
@change="autoSave" />
|
||||
days
|
||||
</li>
|
||||
|
|
@ -276,16 +273,29 @@
|
|||
</h2>
|
||||
|
||||
<div class="space-y-4">
|
||||
<!-- Decision Framework Selection -->
|
||||
<div>
|
||||
<h3
|
||||
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">
|
||||
Consent-Based Decisions
|
||||
Primary Decision Framework
|
||||
</h3>
|
||||
<UFormField class="form-group-large mb-4">
|
||||
<USelect
|
||||
v-model="formData.decisionFramework"
|
||||
:items="decisionFrameworkOptions"
|
||||
placeholder="Select decision framework"
|
||||
size="xl"
|
||||
class="w-full"
|
||||
@change="autoSave" />
|
||||
</UFormField>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<p class="content-paragraph mb-3 leading-relaxed text-left">
|
||||
We use consent, not consensus. This means we move forward when
|
||||
no one has a principled objection that would harm the
|
||||
cooperative. An objection must explain how the proposal would
|
||||
contradict our values or threaten our sustainability.
|
||||
{{
|
||||
getFrameworkDetails(formData.decisionFramework)
|
||||
.practicalDescription
|
||||
}}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
|
|
@ -301,7 +311,7 @@
|
|||
v-model="formData.dayToDayLimit"
|
||||
type="number"
|
||||
placeholder="100"
|
||||
class="inline-field number-field"
|
||||
class="inline-field number-field w-10"
|
||||
@change="autoSave" />
|
||||
can be made by any member. Just tell others what you did at
|
||||
the next meeting.
|
||||
|
|
@ -319,13 +329,13 @@
|
|||
v-model="formData.regularDecisionMin"
|
||||
type="number"
|
||||
placeholder="100"
|
||||
class="inline-field number-field"
|
||||
class="inline-field number-field w-10"
|
||||
@change="autoSave" />
|
||||
and $<UInput
|
||||
v-model="formData.regularDecisionMax"
|
||||
type="number"
|
||||
placeholder="1000"
|
||||
class="inline-field number-field"
|
||||
class="inline-field number-field w-10"
|
||||
@change="autoSave" />
|
||||
need consent from members present at a meeting (minimum 2
|
||||
members).
|
||||
|
|
@ -349,11 +359,14 @@
|
|||
v-model="formData.majorDebtThreshold"
|
||||
type="number"
|
||||
placeholder="5000"
|
||||
class="inline-field number-field"
|
||||
class="inline-field number-field w-10"
|
||||
@change="autoSave" />
|
||||
</li>
|
||||
<li>Fundamental changes to our purpose or structure</li>
|
||||
<li>Dissolution of the cooperative</li>
|
||||
<li>
|
||||
Dissolution of
|
||||
{{ getDisplayName().toLowerCase() }}
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
|
|
@ -377,7 +390,7 @@
|
|||
v-model="formData.emergencyNoticeHours"
|
||||
type="number"
|
||||
placeholder="24"
|
||||
class="inline-field number-field"
|
||||
class="inline-field number-field w-10"
|
||||
@change="autoSave" />
|
||||
hours notice
|
||||
</li>
|
||||
|
|
@ -404,8 +417,9 @@
|
|||
Equal Ownership
|
||||
</h3>
|
||||
<p class="content-paragraph mb-3 leading-relaxed text-left">
|
||||
Each member owns an equal share of the cooperative, regardless
|
||||
of hours worked or tenure.
|
||||
Each member owns an equal share of
|
||||
{{ getDisplayName().toLowerCase() }},
|
||||
regardless of hours worked or tenure.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
|
|
@ -414,7 +428,7 @@
|
|||
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>
|
||||
|
||||
|
||||
<!-- Pay Policy Selection -->
|
||||
<UFormField label="Pay Policy" class="form-group-large mb-4">
|
||||
<USelect
|
||||
|
|
@ -427,15 +441,20 @@
|
|||
</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>
|
||||
<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"
|
||||
class="inline-field number-field w-10"
|
||||
@change="autoSave" />/hour for all members
|
||||
</li>
|
||||
<li class="flex items-baseline gap-2 flex-wrap">
|
||||
|
|
@ -443,7 +462,7 @@
|
|||
v-model="formData.monthlyDraw"
|
||||
type="number"
|
||||
placeholder="2000"
|
||||
class="inline-field number-field"
|
||||
class="inline-field number-field w-10"
|
||||
@change="autoSave" />
|
||||
per member
|
||||
</li>
|
||||
|
|
@ -451,15 +470,19 @@
|
|||
</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>
|
||||
<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"
|
||||
class="inline-field number-field w-10"
|
||||
@change="autoSave" />/hour
|
||||
</li>
|
||||
<li>Members track their hours and are paid accordingly</li>
|
||||
|
|
@ -468,18 +491,26 @@
|
|||
</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>
|
||||
<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>
|
||||
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"
|
||||
class="inline-field number-field w-10"
|
||||
@change="autoSave" />/month
|
||||
</li>
|
||||
</ul>
|
||||
|
|
@ -487,7 +518,9 @@
|
|||
|
||||
<!-- Common payment details -->
|
||||
<div class="mt-4 space-y-2">
|
||||
<p class="content-paragraph font-semibold">Payment Schedule:</p>
|
||||
<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
|
||||
|
|
@ -495,9 +528,9 @@
|
|||
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">
|
||||
|
|
@ -525,7 +558,7 @@
|
|||
v-model="formData.targetHours"
|
||||
type="number"
|
||||
placeholder="40"
|
||||
class="inline-field number-field"
|
||||
class="inline-field number-field w-10"
|
||||
@change="autoSave" />
|
||||
(flexible based on capacity)
|
||||
</li>
|
||||
|
|
@ -548,10 +581,7 @@
|
|||
All members can access all financial records anytime
|
||||
</li>
|
||||
<li>Monthly financial check-ins at meetings</li>
|
||||
<li>
|
||||
Quarterly reviews of our runway (how many months we can
|
||||
operate)
|
||||
</li>
|
||||
<li>Quarterly reviews of our runway</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -578,11 +608,11 @@
|
|||
v-model="formData.roleRotationMonths"
|
||||
type="number"
|
||||
placeholder="6"
|
||||
class="inline-field number-field"
|
||||
class="inline-field number-field w-10"
|
||||
@change="autoSave" />
|
||||
months. Current roles include:
|
||||
</p>
|
||||
<UFormField label="Rotating Roles" class="form-group-large">
|
||||
<UFormField class="form-group-large">
|
||||
<UTextarea
|
||||
v-model="formData.rotatingRoles"
|
||||
:rows="4"
|
||||
|
|
@ -602,7 +632,7 @@
|
|||
<p class="content-paragraph mb-3 leading-relaxed text-left">
|
||||
All members participate in:
|
||||
</p>
|
||||
<UFormField label="Shared Responsibilities" class="form-group-large">
|
||||
<UFormField class="form-group-large">
|
||||
<UTextarea
|
||||
v-model="formData.sharedResponsibilities"
|
||||
:rows="3"
|
||||
|
|
@ -669,8 +699,13 @@
|
|||
placeholder="year"
|
||||
class="inline-field"
|
||||
@change="autoSave" />
|
||||
and update it through our consent process. Small clarifications
|
||||
can happen anytime; structural changes need full member consent.
|
||||
and update it through our
|
||||
<span class="font-semibold">{{
|
||||
getFrameworkLabel(formData.decisionFramework)
|
||||
}}</span>
|
||||
process. Small clarifications can happen anytime; structural
|
||||
changes need
|
||||
{{ getStructuralChangeRequirement(formData.decisionFramework) }}.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
|
|
@ -683,7 +718,8 @@
|
|||
|
||||
<div class="space-y-4">
|
||||
<p class="content-paragraph mb-3 leading-relaxed text-left">
|
||||
If the cooperative dissolves:
|
||||
If
|
||||
{{ getDisplayName().toLowerCase() }} dissolves:
|
||||
</p>
|
||||
<ol class="content-list numbered my-2 pl-6 list-decimal">
|
||||
<li>Pay all debts and obligations</li>
|
||||
|
|
@ -700,21 +736,33 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Section 9: Legal Bits -->
|
||||
<!-- Section 9: Legal Registration (Optional) -->
|
||||
<div class="section-card">
|
||||
<h2
|
||||
class="section-title text-2xl font-extrabold text-neutral-900 dark:text-neutral-100 mb-4">
|
||||
9. Legal Bits
|
||||
</h2>
|
||||
<div class="flex items-center justify-between mb-4">
|
||||
<h2
|
||||
class="section-title text-2xl font-extrabold text-neutral-900 dark:text-neutral-100 mb-0">
|
||||
9. Legal Registration
|
||||
</h2>
|
||||
<div class="flex items-center gap-2">
|
||||
<label
|
||||
class="text-sm font-medium text-neutral-700 dark:text-neutral-300">
|
||||
Legally registered?
|
||||
</label>
|
||||
<USwitch
|
||||
v-model="formData.isLegallyRegistered"
|
||||
@change="autoSave" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="space-y-4">
|
||||
<div v-if="formData.isLegallyRegistered" class="space-y-4">
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||
<UFormField label="Legal Structure" class="form-group-block">
|
||||
<UInput
|
||||
v-model="formData.legalStructure"
|
||||
size="xl"
|
||||
class="w-full"
|
||||
placeholder="Cooperative corporation, LLC, partnership, etc." />
|
||||
placeholder="Cooperative corporation, LLC, partnership, etc."
|
||||
@change="autoSave" />
|
||||
</UFormField>
|
||||
|
||||
<UFormField label="Registered in" class="form-group-inline">
|
||||
|
|
@ -754,8 +802,16 @@
|
|||
but work to align our legal structure with our values.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-else class="text-neutral-600 dark:text-neutral-400 italic">
|
||||
<p class="content-paragraph">
|
||||
{{ getDisplayName() || "This cooperative" }} operates as
|
||||
an informal collective. If we decide to register legally in the
|
||||
future, we'll update this section with our legal structure
|
||||
details.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -771,6 +827,9 @@
|
|||
<script setup>
|
||||
import { ref, watch } from "vue";
|
||||
|
||||
// Import centralized coop info
|
||||
const { coopInfo, updateCoopInfo, getDisplayName } = useCoopInfo();
|
||||
|
||||
definePageMeta({
|
||||
layout: false,
|
||||
});
|
||||
|
|
@ -795,40 +854,194 @@ const monthOptions = [
|
|||
|
||||
const dayOptions = Array.from({ length: 31 }, (_, i) => ({
|
||||
value: i + 1,
|
||||
label: `${i + 1}${getOrdinalSuffix(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';
|
||||
return "th";
|
||||
}
|
||||
switch (num % 10) {
|
||||
case 1: return 'st';
|
||||
case 2: return 'nd';
|
||||
case 3: return 'rd';
|
||||
default: return 'th';
|
||||
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' }
|
||||
{
|
||||
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 decisionFrameworkOptions = [
|
||||
{
|
||||
value: "consent-based",
|
||||
label: "Consent-Based - No one objects strongly enough to block",
|
||||
},
|
||||
{
|
||||
value: "consensus",
|
||||
label: "Full Consensus - Everyone agrees to support",
|
||||
},
|
||||
{
|
||||
value: "consultative",
|
||||
label: "Consultative - Gather input, then designated person decides",
|
||||
},
|
||||
{
|
||||
value: "democratic-vote",
|
||||
label: "Democratic Vote - Majority decides",
|
||||
},
|
||||
{
|
||||
value: "advice-process",
|
||||
label: "Advice Process - Decision-maker seeks input, then decides",
|
||||
},
|
||||
{
|
||||
value: "delegation",
|
||||
label: "Delegation - Empower responsible party to decide",
|
||||
},
|
||||
{
|
||||
value: "defer-to-expert",
|
||||
label: "Defer to Expert - Trust the person who knows best",
|
||||
},
|
||||
{
|
||||
value: "facilitated-discussion",
|
||||
label: "Facilitated Discussion - Talk it through with structure",
|
||||
},
|
||||
];
|
||||
|
||||
// Helper function to get framework label
|
||||
function getFrameworkLabel(framework) {
|
||||
const labels = {
|
||||
"consent-based": "consent-based decision",
|
||||
consensus: "consensus",
|
||||
consultative: "consultative",
|
||||
"democratic-vote": "democratic voting",
|
||||
"advice-process": "advice",
|
||||
delegation: "delegation",
|
||||
"defer-to-expert": "expert-led",
|
||||
"facilitated-discussion": "facilitated discussion",
|
||||
};
|
||||
return labels[framework] || "decision-making";
|
||||
}
|
||||
|
||||
// Helper function to get structural change requirement text
|
||||
function getStructuralChangeRequirement(framework) {
|
||||
const requirements = {
|
||||
"consent-based": "no blocking objections from any member",
|
||||
consensus: "full consensus from all members",
|
||||
consultative: "consultation with all members before the decision",
|
||||
"democratic-vote": "a majority vote of all members",
|
||||
"advice-process": "advice from all members before the decision",
|
||||
delegation: "approval from the delegated authority",
|
||||
"defer-to-expert":
|
||||
"approval from the designated expert after member consultation",
|
||||
"facilitated-discussion": "a facilitated discussion with all members",
|
||||
};
|
||||
return (
|
||||
requirements[framework] || "approval through our chosen decision process"
|
||||
);
|
||||
}
|
||||
|
||||
// Helper function to get framework details
|
||||
function getFrameworkDetails(framework) {
|
||||
const details = {
|
||||
"consent-based": {
|
||||
tagline: "No one objects strongly enough to block",
|
||||
description:
|
||||
"Not everyone needs to love it, but no one sees it as harmful to our organization. Focus on addressing objections rather than optimizing preferences.",
|
||||
practicalDescription:
|
||||
"We use consent, not consensus. This means we move forward when no one has a principled objection that would harm our organization. An objection must explain how the proposal would contradict our values or threaten our sustainability.",
|
||||
},
|
||||
consensus: {
|
||||
tagline: "Everyone agrees to support the decision",
|
||||
description:
|
||||
"Take the time to get real alignment on high-stakes decisions. Everyone can live with it, even if it's not their favorite option.",
|
||||
practicalDescription:
|
||||
"For major decisions, we work together until everyone can support the outcome. This doesn't mean it's everyone's first choice, but that everyone understands and commits to the decision.",
|
||||
},
|
||||
consultative: {
|
||||
tagline: "Gather input, then designated person decides",
|
||||
description:
|
||||
"When no one has clear expertise but we need various perspectives, one person gathers input and makes the final call.",
|
||||
practicalDescription:
|
||||
"A designated decision owner seeks input from all stakeholders, researches options, and makes the decision with clear reasoning. They explain how input influenced the final decision.",
|
||||
},
|
||||
"democratic-vote": {
|
||||
tagline: "Majority decides, move forward together",
|
||||
description:
|
||||
"For larger groups or time-sensitive decisions, voting provides clear resolution while respecting everyone's input.",
|
||||
practicalDescription:
|
||||
"After discussion, we vote and move forward with the majority decision. We document minority concerns and revisit them if needed. Anonymous voting reduces peer pressure.",
|
||||
},
|
||||
"advice-process": {
|
||||
tagline: "Decision-maker seeks input, then decides",
|
||||
description:
|
||||
"Balances inclusion with efficiency. The decision owner genuinely considers input but isn't bound by it.",
|
||||
practicalDescription:
|
||||
"The person most affected or willing becomes the decision owner. They seek advice from those with expertise and those affected, then make the decision and explain their reasoning.",
|
||||
},
|
||||
delegation: {
|
||||
tagline: "Empower the responsible party to decide",
|
||||
description:
|
||||
"Trust those closest to the work to make decisions within clear scope and constraints.",
|
||||
practicalDescription:
|
||||
"We delegate decisions to the people most affected or with the most expertise. They have authority within defined boundaries and report back on outcomes.",
|
||||
},
|
||||
"defer-to-expert": {
|
||||
tagline: "Trust the person who knows this best",
|
||||
description:
|
||||
"When someone has clear expertise, let them lead while keeping everyone informed.",
|
||||
practicalDescription:
|
||||
"The expert proposes solutions with reasoning, answers clarifying questions, and makes the final call. They explain their thinking, not just the outcome.",
|
||||
},
|
||||
"facilitated-discussion": {
|
||||
tagline: "Talk it through with structure",
|
||||
description:
|
||||
"Use structured discussion to find clarity before choosing a specific decision method.",
|
||||
practicalDescription:
|
||||
"We clarify what we're deciding, share all relevant information, and each person shares their perspective with time limits. We identify alignment and differences, then choose the appropriate method.",
|
||||
},
|
||||
};
|
||||
|
||||
return (
|
||||
details[framework] || {
|
||||
tagline: "Select a framework to see details",
|
||||
description: "",
|
||||
practicalDescription:
|
||||
"Choose a decision-making framework above to see how it works in practice.",
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
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",
|
||||
memberRequirements:
|
||||
"Shares our values and purpose\nContributes labour to our organization (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: "",
|
||||
noticeDays: 30,
|
||||
surplusPayoutDays: 30,
|
||||
buyInReturnDays: 90,
|
||||
decisionFramework: "consent-based", // Default to consent-based
|
||||
dayToDayLimit: 100,
|
||||
regularDecisionMin: 100,
|
||||
regularDecisionMax: 1000,
|
||||
|
|
@ -845,10 +1058,13 @@ const formData = ref({
|
|||
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",
|
||||
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: "",
|
||||
isLegallyRegistered: false,
|
||||
legalStructure: "",
|
||||
registeredLocation: "",
|
||||
fiscalYearEndMonth: "December",
|
||||
|
|
@ -872,6 +1088,35 @@ const loadSavedData = () => {
|
|||
// Load data immediately
|
||||
loadSavedData();
|
||||
|
||||
// Sync with centralized coop info
|
||||
watch(
|
||||
() => coopInfo.value,
|
||||
(newCoopInfo) => {
|
||||
formData.value.cooperativeName = newCoopInfo.cooperativeName || formData.value.cooperativeName;
|
||||
formData.value.dateEstablished = newCoopInfo.dateEstablished || formData.value.dateEstablished;
|
||||
formData.value.purpose = newCoopInfo.purpose || formData.value.purpose;
|
||||
formData.value.coreValues = newCoopInfo.coreValues || formData.value.coreValues;
|
||||
},
|
||||
{ deep: true, immediate: true }
|
||||
);
|
||||
|
||||
// Update centralized store when key fields change
|
||||
watch(
|
||||
() => ({
|
||||
cooperativeName: formData.value.cooperativeName,
|
||||
dateEstablished: formData.value.dateEstablished,
|
||||
purpose: formData.value.purpose,
|
||||
coreValues: formData.value.coreValues,
|
||||
legalStructure: formData.value.legalStructure,
|
||||
registeredLocation: formData.value.registeredLocation,
|
||||
isLegallyRegistered: formData.value.isLegallyRegistered,
|
||||
}),
|
||||
(newData) => {
|
||||
updateCoopInfo(newData);
|
||||
},
|
||||
{ deep: true }
|
||||
);
|
||||
|
||||
// Auto-save to localStorage (removed immediate to prevent overwriting)
|
||||
watch(
|
||||
formData,
|
||||
|
|
@ -1072,9 +1317,30 @@ 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",
|
||||
cooperativeName: getDisplayName(),
|
||||
section: "membership-agreement",
|
||||
exportedAt: new Date().toISOString(),
|
||||
// Include computed/dynamic values for complete export
|
||||
decisionFrameworkDetails: getFrameworkDetails(
|
||||
formData.value.decisionFramework
|
||||
),
|
||||
decisionFrameworkLabel: getFrameworkLabel(formData.value.decisionFramework),
|
||||
structuralChangeRequirement: getStructuralChangeRequirement(
|
||||
formData.value.decisionFramework
|
||||
),
|
||||
paymentDayLabel: formData.value.paymentDay
|
||||
? `${formData.value.paymentDay}${getOrdinalSuffix(
|
||||
formData.value.paymentDay
|
||||
)}`
|
||||
: "15th",
|
||||
// Include selected dropdown labels for readability
|
||||
decisionFrameworkName:
|
||||
decisionFrameworkOptions.find(
|
||||
(opt) => opt.value === formData.value.decisionFramework
|
||||
)?.label || "Consent-Based - No one objects strongly enough to block",
|
||||
payPolicyName:
|
||||
payPolicyOptions.find((opt) => opt.value === formData.value.payPolicy)
|
||||
?.label || "Equal Pay - All members receive equal compensation",
|
||||
}));
|
||||
</script>
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue