2171 lines
76 KiB
Vue
2171 lines
76 KiB
Vue
<template>
|
||
<div>
|
||
<!-- Export Options - Top -->
|
||
|
||
<ExportOptions
|
||
:export-data="exportData"
|
||
filename="conflict-resolution-framework"
|
||
title="Conflict Resolution" />
|
||
|
||
<div
|
||
class="template-wrapper bg-white dark:bg-neutral-950 text-neutral-900 dark:text-neutral-100">
|
||
<!-- Document Container -->
|
||
<div class="document-page">
|
||
<div class="template-content">
|
||
<!-- Document Header -->
|
||
<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="getOrgName()">
|
||
CONFLICT RESOLUTION
|
||
</h1>
|
||
</div>
|
||
|
||
<!-- Section 1: Cooperative Information -->
|
||
<div class="section-card">
|
||
<div class="space-y-6">
|
||
<UFormField label="Cooperative Name" class="form-group-large">
|
||
<UInput
|
||
v-model="formData.orgName"
|
||
placeholder="Enter your cooperative name"
|
||
size="xl"
|
||
class="w-full"
|
||
:error="validationErrors.orgName"
|
||
@input="debouncedAutoSave" />
|
||
</UFormField>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Section 2: Core Values -->
|
||
<div class="section-card">
|
||
<div class="flex flex-row justify-between items-center">
|
||
<h2 class="section-title">2. Values</h2>
|
||
<div class="flex flex-row gap-2 items-center no-print no-pdf">
|
||
<USwitch
|
||
v-model="sectionsEnabled.values"
|
||
size="sm"
|
||
label="Include this section"
|
||
:ui="{
|
||
label: 'text-xs text-neutral-700 dark:text-neutral-300',
|
||
}" />
|
||
</div>
|
||
</div>
|
||
|
||
<div class="space-y-6" v-show="sectionsEnabled.values">
|
||
<UFormField
|
||
label="Select core values (check all that apply)"
|
||
class="form-group-large">
|
||
<div class="values-grid">
|
||
<div
|
||
v-for="(value, index) in coreValues"
|
||
:key="index"
|
||
class="relative">
|
||
<!-- Dithered shadow for selected items -->
|
||
<div
|
||
v-if="value.checked"
|
||
class="absolute top-2 left-2 w-full h-full dither-shadow"></div>
|
||
|
||
<div
|
||
:class="[
|
||
'checkbox-item p-3 border border-black dark:border-white transition-all',
|
||
value.checked
|
||
? 'item-selected bg-white dark:bg-neutral-950'
|
||
: 'bg-transparent',
|
||
]">
|
||
<UCheckbox
|
||
v-model="value.checked"
|
||
:id="`core-value-${index}`"
|
||
:label="value.label"
|
||
class="w-full"
|
||
@change="autoSave" />
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</UFormField>
|
||
|
||
<UFormField
|
||
label="Additional values or principles"
|
||
class="form-group-large">
|
||
<UTextarea
|
||
v-model="formData.customValues"
|
||
:rows="3"
|
||
placeholder="Add any additional values specific to your cooperative..."
|
||
size="xl"
|
||
class="w-full"
|
||
@input="debouncedAutoSave" />
|
||
</UFormField>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Section 3: Conflict Types -->
|
||
<div class="section-card">
|
||
<h2 class="section-title">3. Types of Conflicts Covered</h2>
|
||
<p class="mb-4">
|
||
Select which types of conflicts this framework will address:
|
||
</p>
|
||
|
||
<div class="checkbox-group space-y-3">
|
||
<div
|
||
v-for="(conflict, index) in conflictTypes"
|
||
:key="index"
|
||
class="relative">
|
||
<!-- Dithered shadow for selected items -->
|
||
<div
|
||
v-if="conflict.checked"
|
||
class="absolute top-2 left-2 w-full h-full dither-shadow"></div>
|
||
|
||
<div
|
||
:class="[
|
||
'checkbox-item p-3 border border-black dark:border-white transition-all',
|
||
conflict.checked
|
||
? 'item-selected bg-white dark:bg-neutral-950'
|
||
: 'bg-transparent',
|
||
]">
|
||
<UCheckbox
|
||
v-model="conflict.checked"
|
||
:id="`conflict-type-${index}`"
|
||
:label="conflict.label"
|
||
class="w-full"
|
||
@change="autoSave" />
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div v-if="validationErrors.conflictTypes" class="validation-error">
|
||
{{ validationErrors.conflictTypes }}
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Section 4: Resolution Approach -->
|
||
<div class="section-card">
|
||
<h2 class="section-title">4. Primary Resolution Approach</h2>
|
||
|
||
<div class="space-y-6">
|
||
<UFormField
|
||
label="Choose your primary conflict resolution philosophy:">
|
||
<URadioGroup
|
||
v-model="formData.approach"
|
||
:items="approachOptions"
|
||
variant="card"
|
||
size="lg"
|
||
class="mt-2" />
|
||
<div v-if="validationErrors.approach" class="validation-error">
|
||
{{ validationErrors.approach }}
|
||
</div>
|
||
</UFormField>
|
||
|
||
<UFormField class="form-group-large">
|
||
<UCheckbox
|
||
v-model="formData.anonymousReporting"
|
||
id="anonymous-reporting"
|
||
label="Allow anonymous reporting"
|
||
help="Members can report issues without revealing their identity"
|
||
class="w-full"
|
||
@change="autoSave" />
|
||
</UFormField>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Section 5: Roles & Responsibilities -->
|
||
<div class="section-card">
|
||
<h2 class="section-title">5. Roles & Responsibilities</h2>
|
||
|
||
<div class="space-y-6">
|
||
<UFormField
|
||
label="Who can receive initial conflict reports? (check all that apply)"
|
||
class="form-group-large">
|
||
<div class="checkbox-group space-y-2 mt-4">
|
||
<div
|
||
v-for="(receiver, index) in reportReceivers"
|
||
:key="index"
|
||
class="relative">
|
||
<!-- Dithered shadow for selected items -->
|
||
<div
|
||
v-if="receiver.checked"
|
||
class="absolute top-2 left-2 w-full h-full dither-shadow"></div>
|
||
|
||
<div
|
||
:class="[
|
||
'checkbox-item p-3 border border-black dark:border-white transition-all',
|
||
receiver.checked
|
||
? 'item-selected bg-white dark:bg-neutral-950'
|
||
: 'bg-transparent',
|
||
]">
|
||
<UCheckbox
|
||
v-model="receiver.checked"
|
||
:id="`report-receiver-${index}`"
|
||
:label="receiver.label"
|
||
class="w-full"
|
||
@change="autoSave" />
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div
|
||
v-if="validationErrors.reportReceivers"
|
||
class="validation-error">
|
||
{{ validationErrors.reportReceivers }}
|
||
</div>
|
||
</UFormField>
|
||
|
||
<UFormField
|
||
label="Mediator/facilitator structure"
|
||
class="form-group-large">
|
||
<USelect
|
||
v-model="formData.mediatorType"
|
||
:items="mediatorTypeOptions"
|
||
placeholder="Select mediator structure..."
|
||
size="xl"
|
||
class="w-full"
|
||
:error="validationErrors.mediatorType"
|
||
@change="autoSave" />
|
||
</UFormField>
|
||
|
||
<UFormField class="form-group-large">
|
||
<UCheckbox
|
||
v-model="formData.supportPeople"
|
||
id="support-people"
|
||
label="Allow support people in mediation sessions"
|
||
help="Parties can bring a trusted person for emotional support"
|
||
class="w-full"
|
||
@change="autoSave" />
|
||
</UFormField>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Section 6: Timeline & Process -->
|
||
<div class="section-card">
|
||
<h2 class="section-title">6. Timeline & Process Steps</h2>
|
||
|
||
<div class="space-y-6">
|
||
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||
<UFormField
|
||
label="Initial Response Time"
|
||
class="form-group-large">
|
||
<USelect
|
||
v-model="formData.initialResponse"
|
||
:items="responseTimeOptions"
|
||
placeholder="Select response time..."
|
||
size="xl"
|
||
class="w-full"
|
||
:error="validationErrors.initialResponse"
|
||
@change="autoSave" />
|
||
</UFormField>
|
||
|
||
<UFormField
|
||
label="Target Resolution Time"
|
||
class="form-group-large">
|
||
<USelect
|
||
v-model="formData.resolutionTarget"
|
||
:items="resolutionTimeOptions"
|
||
placeholder="Select target time..."
|
||
size="xl"
|
||
class="w-full"
|
||
:error="validationErrors.resolutionTarget"
|
||
@change="autoSave" />
|
||
</UFormField>
|
||
</div>
|
||
|
||
<UFormField
|
||
label="Process Steps (select applicable steps)"
|
||
class="form-group-large">
|
||
<div class="checkbox-group mt-4 space-y-3">
|
||
<div
|
||
v-for="(step, index) in processSteps"
|
||
:key="index"
|
||
class="relative">
|
||
<!-- Dithered shadow for selected items -->
|
||
<div
|
||
v-if="step.checked"
|
||
class="absolute top-2 left-2 w-full h-full dither-shadow"></div>
|
||
|
||
<div
|
||
:class="[
|
||
'checkbox-item p-3 border border-black dark:border-white transition-all',
|
||
step.checked
|
||
? 'item-selected bg-white dark:bg-neutral-950'
|
||
: 'bg-transparent',
|
||
]">
|
||
<UCheckbox
|
||
v-model="step.checked"
|
||
:id="`process-step-${index}`"
|
||
:label="`${index + 1}. ${step.label}`"
|
||
class="w-full"
|
||
@change="autoSave" />
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div
|
||
v-if="validationErrors.processSteps"
|
||
class="validation-error">
|
||
{{ validationErrors.processSteps }}
|
||
</div>
|
||
</UFormField>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Section 7: Documentation & Privacy -->
|
||
<div class="section-card">
|
||
<div
|
||
class="section-header flex flex-row justify-between items-center">
|
||
<h2 class="section-title">7. Documentation & Privacy</h2>
|
||
<div class="flex flex-row gap-2 items-center no-print no-pdf">
|
||
<USwitch
|
||
v-model="sectionsEnabled.documentation"
|
||
size="sm"
|
||
label="Include this section"
|
||
:ui="{
|
||
label: 'text-xs text-neutral-700 dark:text-neutral-300',
|
||
}" />
|
||
</div>
|
||
</div>
|
||
|
||
<div class="space-y-6" v-show="sectionsEnabled.documentation">
|
||
<UFormField label="Documentation Level" class="form-group-large">
|
||
<USelect
|
||
v-model="formData.docLevel"
|
||
:items="docLevelOptions"
|
||
placeholder="Select documentation level..."
|
||
size="xl"
|
||
class="w-full"
|
||
@change="autoSave" />
|
||
</UFormField>
|
||
|
||
<UFormField
|
||
label="Confidentiality Level"
|
||
class="form-group-large">
|
||
<USelect
|
||
v-model="formData.confidentiality"
|
||
:items="confidentialityOptions"
|
||
placeholder="Select confidentiality level..."
|
||
size="xl"
|
||
class="w-full"
|
||
@change="autoSave" />
|
||
</UFormField>
|
||
|
||
<UFormField
|
||
label="Record Retention Period"
|
||
class="form-group-large">
|
||
<USelect
|
||
v-model="formData.retention"
|
||
:items="retentionOptions"
|
||
placeholder="Select retention period..."
|
||
size="xl"
|
||
class="w-full"
|
||
@change="autoSave" />
|
||
</UFormField>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Section 8: Consequences & Actions -->
|
||
<div class="section-card">
|
||
<h2 class="section-title">8. Consequences & Remedial Actions</h2>
|
||
|
||
<div class="space-y-6">
|
||
<UFormField
|
||
label="Available actions (check all that apply)"
|
||
class="form-group-large">
|
||
<div class="checkbox-group mt-4 space-y-3">
|
||
<div
|
||
v-for="(action, index) in availableActions"
|
||
:key="index"
|
||
class="relative">
|
||
<!-- Dithered shadow for selected items -->
|
||
<div
|
||
v-if="action.checked"
|
||
class="absolute top-2 left-2 w-full h-full dither-shadow"></div>
|
||
|
||
<div
|
||
:class="[
|
||
'checkbox-item p-3 border border-black dark:border-white transition-all',
|
||
action.checked
|
||
? 'item-selected bg-white dark:bg-neutral-950'
|
||
: 'bg-transparent',
|
||
]">
|
||
<UCheckbox
|
||
v-model="action.checked"
|
||
:id="`available-action-${index}`"
|
||
:label="action.label"
|
||
class="w-full"
|
||
@change="autoSave" />
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div
|
||
v-if="validationErrors.availableActions"
|
||
class="validation-error">
|
||
{{ validationErrors.availableActions }}
|
||
</div>
|
||
</UFormField>
|
||
|
||
<UFormField
|
||
class="form-group-large border-t border-neutral-200 dark:border-neutral-800 pt-4">
|
||
<UCheckbox
|
||
v-model="formData.appealProcess"
|
||
id="appeal-process"
|
||
label="Include appeals process"
|
||
help="Parties can request review of decisions"
|
||
class="w-full"
|
||
@change="autoSave" />
|
||
</UFormField>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Section 9: Special Circumstances -->
|
||
<div class="section-card">
|
||
<div
|
||
class="section-header flex flex-row justify-between items-center">
|
||
<h2 class="section-title">9. Special Circumstances</h2>
|
||
<div class="flex flex-row gap-2 items-center no-print no-pdf">
|
||
<USwitch
|
||
v-model="sectionsEnabled.special"
|
||
size="sm"
|
||
label="Include this section"
|
||
:ui="{
|
||
label: 'text-xs text-neutral-700 dark:text-neutral-300',
|
||
}" />
|
||
</div>
|
||
</div>
|
||
|
||
<div class="space-y-6" v-show="sectionsEnabled.special">
|
||
<div class="checkbox-group space-y-3">
|
||
<div
|
||
v-for="(circumstance, index) in specialCircumstances"
|
||
:key="index"
|
||
class="relative">
|
||
<!-- Dithered shadow for selected items -->
|
||
<div
|
||
v-if="circumstance.checked"
|
||
class="absolute top-2 left-2 w-full h-full dither-shadow"></div>
|
||
|
||
<div
|
||
:class="[
|
||
'checkbox-item p-3 border border-black dark:border-white transition-all',
|
||
circumstance.checked
|
||
? 'item-selected bg-white dark:bg-neutral-950'
|
||
: 'bg-transparent',
|
||
]">
|
||
<UCheckbox
|
||
v-model="circumstance.checked"
|
||
:id="`special-circumstance-${index}`"
|
||
:label="circumstance.label"
|
||
class="w-full"
|
||
@change="autoSave" />
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Section 10: Implementation -->
|
||
<div class="section-card">
|
||
<h2 class="section-title">10. Implementation Details</h2>
|
||
|
||
<div class="space-y-6">
|
||
<UFormField
|
||
label="Training Requirements"
|
||
class="form-group-large">
|
||
<UTextarea
|
||
v-model="formData.training"
|
||
:rows="3"
|
||
class="w-full"
|
||
placeholder="Describe any training needed for member-workers, facilitators, or committee members..."
|
||
size="xl"
|
||
@input="debouncedAutoSave" />
|
||
</UFormField>
|
||
|
||
<div class="flex flex-row space-x-4">
|
||
<UFormField
|
||
label="Policy Review Schedule"
|
||
class="form-group-large">
|
||
<USelect
|
||
v-model="formData.reviewSchedule"
|
||
:items="reviewScheduleOptions"
|
||
placeholder="Select review schedule..."
|
||
size="xl"
|
||
class="w-full"
|
||
:error="validationErrors.reviewSchedule"
|
||
@change="autoSave" />
|
||
</UFormField>
|
||
<UFormField
|
||
label="How can this policy be amended?"
|
||
class="form-group-large">
|
||
<USelect
|
||
v-model="formData.amendments"
|
||
:items="amendmentOptions"
|
||
placeholder="Select amendment process..."
|
||
size="xl"
|
||
class="w-full"
|
||
:error="validationErrors.amendments"
|
||
@change="autoSave" />
|
||
</UFormField>
|
||
</div>
|
||
|
||
<div class="p-6 bg-neutral-50 dark:bg-neutral-900 rounded-lg">
|
||
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||
<UFormField label="Framework Created Date">
|
||
<UInput
|
||
v-model="formData.createdDate"
|
||
type="date"
|
||
size="xl"
|
||
class="w-full mb-0"
|
||
@change="autoSave" />
|
||
</UFormField>
|
||
|
||
<UFormField label="Next Review Date">
|
||
<UInput
|
||
v-model="formData.reviewDate"
|
||
type="date"
|
||
size="xl"
|
||
class="w-full mb-0"
|
||
@change="autoSave" />
|
||
</UFormField>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Section 11: Reflection Process -->
|
||
<div class="section-card">
|
||
<div
|
||
class="section-header flex flex-row justify-between items-center">
|
||
<h2 class="section-title">11. Reflection Process</h2>
|
||
<div class="flex flex-row gap-2 items-center no-print no-pdf">
|
||
<USwitch
|
||
v-model="sectionsEnabled.reflection"
|
||
size="sm"
|
||
label="Include detailed reflection guidance"
|
||
:ui="{
|
||
label: 'text-xs text-neutral-700 dark:text-neutral-300',
|
||
}" />
|
||
</div>
|
||
</div>
|
||
|
||
<div class="space-y-6" v-show="sectionsEnabled.reflection">
|
||
<UFormField
|
||
label="Reflection Period Timeframe"
|
||
class="form-group-large">
|
||
<USelect
|
||
v-model="formData.reflectionPeriod"
|
||
:items="reflectionPeriodOptions"
|
||
placeholder="Select reflection timeframe..."
|
||
size="xl"
|
||
class="w-full md:w-1/2 mt-2"
|
||
@change="autoSave" />
|
||
</UFormField>
|
||
|
||
<UFormField
|
||
label="Additional Reflection Prompts"
|
||
class="form-group-large">
|
||
<UTextarea
|
||
v-model="formData.customReflectionPrompts"
|
||
:rows="4"
|
||
placeholder="Add any organization-specific reflection questions or prompts..."
|
||
size="xl"
|
||
class="w-full mt-2"
|
||
@input="debouncedAutoSave" />
|
||
</UFormField>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Section 12: Direct Resolution Guidelines -->
|
||
<div class="section-card">
|
||
<div
|
||
class="section-header flex flex-row justify-between items-center">
|
||
<h2 class="section-title">12. Direct Resolution Guidelines</h2>
|
||
<div class="flex flex-row gap-2 items-center no-print no-pdf">
|
||
<USwitch
|
||
v-model="sectionsEnabled.directResolution"
|
||
size="sm"
|
||
label="Include detailed conversation guidance"
|
||
:ui="{
|
||
label: 'text-xs text-neutral-700 dark:text-neutral-300',
|
||
}" />
|
||
</div>
|
||
</div>
|
||
|
||
<div class="space-y-6" v-show="sectionsEnabled.directResolution">
|
||
<UFormField
|
||
label="Communication Channels (select preferred escalation order)"
|
||
class="form-group-large">
|
||
<div class="checkbox-group space-y-3 mt-4">
|
||
<div
|
||
v-for="(channel, index) in communicationChannels"
|
||
:key="index"
|
||
class="relative">
|
||
<!-- Dithered shadow for selected items -->
|
||
<div
|
||
v-if="channel.checked"
|
||
class="absolute top-2 left-2 w-full h-full dither-shadow"></div>
|
||
|
||
<div
|
||
:class="[
|
||
'checkbox-item p-3 border border-black dark:border-white transition-all',
|
||
channel.checked
|
||
? 'item-selected bg-white dark:bg-neutral-950'
|
||
: 'bg-transparent',
|
||
]">
|
||
<UCheckbox
|
||
v-model="channel.checked"
|
||
:id="`comm-channel-${index}`"
|
||
:label="channel.label"
|
||
class="w-full"
|
||
@change="autoSave" />
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</UFormField>
|
||
|
||
<UFormField
|
||
class="form-group-large border-t border-neutral-200 dark:border-neutral-800 pt-4">
|
||
<UCheckbox
|
||
v-model="formData.requireDirectAttempt"
|
||
id="require-direct-attempt"
|
||
label="Require direct resolution attempt before escalation"
|
||
help="Parties must try to resolve directly before filing complaints"
|
||
class="w-full"
|
||
@change="autoSave" />
|
||
</UFormField>
|
||
|
||
<UFormField
|
||
class="form-group-large border-t border-neutral-200 dark:border-neutral-800 pt-4">
|
||
<UCheckbox
|
||
v-model="formData.documentDirectResolution"
|
||
id="document-direct-resolution"
|
||
label="Require written record of direct resolution attempts"
|
||
help="Parties should document outcomes of direct conversations"
|
||
class="w-full"
|
||
@change="autoSave" />
|
||
</UFormField>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Section 13: Responsible Contact People -->
|
||
<div class="section-card">
|
||
<h2 class="section-title">
|
||
13. Responsible Contact People Structure
|
||
</h2>
|
||
|
||
<div class="space-y-6">
|
||
<UFormField
|
||
label="Internal Advisor Designation"
|
||
class="form-group-large">
|
||
<USelect
|
||
v-model="formData.internalAdvisorType"
|
||
:items="internalAdvisorOptions"
|
||
placeholder="Select internal advisor structure..."
|
||
class="w-full md:w-1/2"
|
||
size="xl"
|
||
@change="autoSave" />
|
||
</UFormField>
|
||
|
||
<UFormField
|
||
label="Member Liaison for Conflict Resolution Committee"
|
||
class="form-group-large">
|
||
<UInput
|
||
v-model="formData.staffLiaison"
|
||
placeholder="Title/role of designated member liaison"
|
||
size="xl"
|
||
class="w-full md:w-1/2"
|
||
@input="debouncedAutoSave" />
|
||
</UFormField>
|
||
|
||
<UFormField
|
||
label="Elected Board Chair Role in Conflict Resolution"
|
||
class="form-group-large">
|
||
<USelect
|
||
v-model="formData.boardChairRole"
|
||
:items="boardChairRoleOptions"
|
||
placeholder="Select board chair involvement..."
|
||
size="xl"
|
||
class="w-full md:w-1/2"
|
||
@change="autoSave" />
|
||
</UFormField>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Section 14: Formal Complaint Process -->
|
||
<div class="section-card">
|
||
<h2 class="section-title">14. Formal Complaint Requirements</h2>
|
||
|
||
<div class="space-y-6">
|
||
<UFormField
|
||
label="Required Complaint Elements"
|
||
class="form-group-large">
|
||
<div class="checkbox-group space-y-3 mt-4">
|
||
<div
|
||
v-for="(element, index) in formalComplaintElements"
|
||
:key="index"
|
||
class="relative">
|
||
<!-- Dithered shadow for selected items -->
|
||
<div
|
||
v-if="element.checked"
|
||
class="absolute top-2 left-2 w-full h-full dither-shadow"></div>
|
||
|
||
<div
|
||
:class="[
|
||
'checkbox-item p-3 border border-black dark:border-white transition-all',
|
||
element.checked
|
||
? 'item-selected bg-white dark:bg-neutral-950'
|
||
: 'bg-transparent',
|
||
]">
|
||
<UCheckbox
|
||
v-model="element.checked"
|
||
:id="`complaint-element-${index}`"
|
||
:label="element.label"
|
||
class="w-full"
|
||
@change="autoSave" />
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</UFormField>
|
||
|
||
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||
<UFormField
|
||
label="Formal Complaint Acknowledgment Time"
|
||
class="form-group-large">
|
||
<USelect
|
||
v-model="formData.formalAcknowledgmentTime"
|
||
:items="acknowledgmentTimeOptions"
|
||
placeholder="Select acknowledgment timeframe..."
|
||
class="w-full"
|
||
size="xl"
|
||
@change="autoSave" />
|
||
</UFormField>
|
||
|
||
<UFormField
|
||
label="Formal Review Completion Time"
|
||
class="form-group-large">
|
||
<USelect
|
||
v-model="formData.formalReviewTime"
|
||
:items="reviewTimeOptions"
|
||
placeholder="Select review timeframe..."
|
||
size="xl"
|
||
class="w-full"
|
||
@change="autoSave" />
|
||
</UFormField>
|
||
</div>
|
||
|
||
<UFormField class="form-group-large">
|
||
<UCheckbox
|
||
v-model="formData.requireExternalAdvice"
|
||
id="require-external-advice"
|
||
label="Require external legal advice for complex complaints"
|
||
help="Seek external expertise for multi-party or member-coordinator complaints"
|
||
class="w-full"
|
||
@change="autoSave" />
|
||
</UFormField>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Section 15: Settlement & Documentation -->
|
||
<div class="section-card">
|
||
<h2 class="section-title">15. Settlement & Documentation</h2>
|
||
|
||
<div class="space-y-6">
|
||
<UFormField class="form-group-large">
|
||
<UCheckbox
|
||
v-model="formData.requireMinutesOfSettlement"
|
||
id="minutes-of-settlement"
|
||
label="Require 'Minutes of Settlement' for resolved complaints"
|
||
help="Agreements must be documented in writing and signed by both parties"
|
||
class="w-full"
|
||
@change="autoSave" />
|
||
</UFormField>
|
||
|
||
<div class="flex flex-row space-x-4">
|
||
<UFormField
|
||
label="Settlement Confidentiality Level"
|
||
class="form-group-large">
|
||
<USelect
|
||
v-model="formData.settlementConfidentiality"
|
||
:items="confidentialityOptions"
|
||
placeholder="Select confidentiality level..."
|
||
size="xl"
|
||
class="w-full"
|
||
@change="autoSave" />
|
||
</UFormField>
|
||
<UFormField
|
||
label="Conflict Resolution File Retention"
|
||
class="form-group-large">
|
||
<USelect
|
||
v-model="formData.conflictFileRetention"
|
||
:items="retentionOptions"
|
||
placeholder="Select retention period..."
|
||
size="xl"
|
||
class="w-full"
|
||
@change="autoSave" />
|
||
</UFormField>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Section 16: External Resources -->
|
||
<div class="section-card">
|
||
<div
|
||
class="section-header flex flex-row justify-between items-center">
|
||
<h2 class="section-title">16. External Resources & Redress</h2>
|
||
<div class="flex flex-row gap-2 items-center no-print no-pdf">
|
||
<USwitch
|
||
v-model="sectionsEnabled.externalResources"
|
||
size="sm"
|
||
label="Include external resource information"
|
||
:ui="{
|
||
label: 'text-xs text-neutral-700 dark:text-neutral-300',
|
||
}" />
|
||
</div>
|
||
</div>
|
||
|
||
<div class="space-y-6" v-show="sectionsEnabled.externalResources">
|
||
<UFormField class="form-group-large">
|
||
<UCheckbox
|
||
v-model="formData.includeHumanRights"
|
||
id="include-human-rights"
|
||
label="Include Human Rights Commission information"
|
||
help="Reference external discrimination complaint options"
|
||
class="w-full"
|
||
@change="autoSave" />
|
||
</UFormField>
|
||
|
||
<UFormField
|
||
label="Additional External Resources"
|
||
class="form-group-large">
|
||
<UTextarea
|
||
v-model="formData.additionalResources"
|
||
:rows="3"
|
||
class="w-full"
|
||
placeholder="List any other external resources, legal aid contacts, or specialized support services..."
|
||
size="xl"
|
||
@input="debouncedAutoSave" />
|
||
</UFormField>
|
||
|
||
<UFormField
|
||
label="Acknowledgment/Attribution"
|
||
class="form-group-large">
|
||
<UTextarea
|
||
v-model="formData.acknowledgments"
|
||
:rows="2"
|
||
placeholder="Credit any sources used in developing this policy..."
|
||
class="w-full"
|
||
size="xl"
|
||
@input="debouncedAutoSave" />
|
||
</UFormField>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Document Preview Section -->
|
||
<div class="no-print" v-if="showPreview">
|
||
<div
|
||
class="border border-neutral-200 dark:border-neutral-800 bg-white dark:bg-neutral-950 p-5 rounded-lg shadow-sm">
|
||
<div class="flex flex-row justify-between items-center mb-4">
|
||
<h2 class="section-title m-0">📄 Policy Document Preview</h2>
|
||
<UButton
|
||
size="sm"
|
||
variant="ghost"
|
||
@click="showPreview = false"
|
||
title="Hide preview">
|
||
✕
|
||
</UButton>
|
||
</div>
|
||
<div
|
||
class="policy-preview prose prose-neutral dark:prose-invert max-w-none px-6 py-5 bg-neutral-50 dark:bg-neutral-900 border border-neutral-200 dark:border-neutral-900 rounded-md max-h-[600px] overflow-y-auto text-left"
|
||
v-html="markdownToHtml(generatePolicyDocument())"></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Export Options - Bottom -->
|
||
<ExportOptions
|
||
:export-data="exportData"
|
||
filename="conflict-resolution-framework"
|
||
title="Conflict Resolution Framework" />
|
||
</div>
|
||
</template>
|
||
|
||
<script setup>
|
||
import { ref, watch, computed } from "vue";
|
||
|
||
// Import centralized coop info
|
||
const { coopInfo, updateCoopInfo, getOrgName } = useCoopInfo();
|
||
|
||
definePageMeta({
|
||
layout: false,
|
||
});
|
||
|
||
useHead({
|
||
title: "Conflict Resolution Framework - Co-op Pay & Value Tool",
|
||
meta: [
|
||
{
|
||
name: "description",
|
||
content:
|
||
"Create a customized conflict resolution framework for your cooperative or organization with restorative justice principles.",
|
||
},
|
||
],
|
||
});
|
||
|
||
const showPreview = ref(false);
|
||
|
||
const approachOptions = [
|
||
{
|
||
value: "restorative",
|
||
label: "Restorative/Loving Justice",
|
||
description:
|
||
"Focus on healing, understanding root causes, and repairing relationships",
|
||
},
|
||
{
|
||
value: "mediation",
|
||
label: "Mediation-First",
|
||
description: "Neutral third-party facilitates dialogue between parties",
|
||
},
|
||
{
|
||
value: "progressive",
|
||
label: "Progressive Discipline",
|
||
description: "Clear escalation steps with defined consequences",
|
||
},
|
||
{
|
||
value: "hybrid",
|
||
label: "Hybrid Approach",
|
||
description: "Combines multiple approaches based on conflict type",
|
||
},
|
||
];
|
||
|
||
const mediatorTypeOptions = [
|
||
"Internal trained mediators",
|
||
"External professional mediators",
|
||
"Rotating member facilitators",
|
||
"Standing committee",
|
||
"Decided case-by-case",
|
||
];
|
||
|
||
const responseTimeOptions = [
|
||
"Within 24 hours",
|
||
"Within 48 hours",
|
||
"Within 72 hours",
|
||
"Within 1 week",
|
||
"Within 2 weeks",
|
||
];
|
||
|
||
const resolutionTimeOptions = [
|
||
"1 week",
|
||
"2 weeks",
|
||
"30 days",
|
||
"60 days",
|
||
"90 days",
|
||
];
|
||
|
||
const docLevelOptions = [
|
||
"Minimal - outcomes only",
|
||
"Standard - key points and decisions",
|
||
"Comprehensive - detailed records",
|
||
];
|
||
|
||
const confidentialityOptions = [
|
||
"Strict - only parties and facilitators",
|
||
"Need-to-know basis",
|
||
"Transparent to membership",
|
||
];
|
||
|
||
const retentionOptions = ["1 year", "3 years", "5 years", "Permanent"];
|
||
|
||
const reviewScheduleOptions = [
|
||
"Every 6 months",
|
||
"Annually",
|
||
"Every 2 years",
|
||
"As needed",
|
||
];
|
||
|
||
const amendmentOptions = [
|
||
"Full consensus required",
|
||
"Consent process (no objections)",
|
||
"2/3 majority vote",
|
||
"Simple majority vote",
|
||
];
|
||
|
||
const reflectionPeriodOptions = [
|
||
"Before any escalation",
|
||
"24-48 hours before complaint",
|
||
"1 week before formal process",
|
||
"Optional but encouraged",
|
||
"Not required",
|
||
];
|
||
|
||
const internalAdvisorOptions = [
|
||
"Single elected advisor",
|
||
"Rotating member representatives",
|
||
"External neutral advisor",
|
||
"Committee-designated advisor",
|
||
"Trained member facilitator",
|
||
];
|
||
|
||
const boardChairRoleOptions = [
|
||
"First contact for coordinator complaints",
|
||
"Appeals reviewer",
|
||
"Participates in collective decision",
|
||
"Advisory role only",
|
||
"Not involved in conflicts",
|
||
];
|
||
|
||
const acknowledgmentTimeOptions = [
|
||
"Within 24 hours",
|
||
"Within 48 hours",
|
||
"Within 1 week",
|
||
"Within 2 weeks",
|
||
];
|
||
|
||
const reviewTimeOptions = [
|
||
"2 weeks",
|
||
"1 month",
|
||
"6 weeks",
|
||
"2 months",
|
||
"3 months",
|
||
];
|
||
|
||
const sectionsEnabled = ref({
|
||
values: true,
|
||
documentation: true,
|
||
special: true,
|
||
reflection: true,
|
||
directResolution: true,
|
||
externalResources: true,
|
||
});
|
||
|
||
const communicationChannels = ref([
|
||
{ label: "Asynchronous text (Slack, email)", checked: true },
|
||
{ label: "Synchronous text (planned chat session)", checked: true },
|
||
{ label: "Audio call or huddle", checked: true },
|
||
{ label: "Video conference", checked: true },
|
||
{ label: "In-person meeting", checked: false },
|
||
]);
|
||
|
||
const formalComplaintElements = ref([
|
||
{ label: "The complainant's name", checked: true },
|
||
{ label: "The respondent's name", checked: true },
|
||
{
|
||
label: "Detailed information about the issue (what, where, when)",
|
||
checked: true,
|
||
},
|
||
{ label: "Details of all prior resolution attempts", checked: true },
|
||
{
|
||
label: "The specific outcome(s) the complainant is seeking",
|
||
checked: true,
|
||
},
|
||
{ label: "Supporting documentation or evidence", checked: false },
|
||
{ label: "Names of potential witnesses", checked: false },
|
||
]);
|
||
|
||
const coreValues = ref([
|
||
{ label: "Mutual Care", checked: true },
|
||
{ label: "Transparency", checked: true },
|
||
{ label: "Accountability", checked: false },
|
||
{ label: "Consent", checked: false },
|
||
{ label: "Anti-Oppression", checked: false },
|
||
{ label: "Restorative Justice", checked: false },
|
||
{ label: "Collective Liberation", checked: false },
|
||
{ label: "Accessibility", checked: false },
|
||
]);
|
||
|
||
const conflictTypes = ref([
|
||
{ label: "Interpersonal disputes between member-workers", checked: true },
|
||
{ label: "Code of Conduct violations", checked: true },
|
||
{ label: "Work allocation and responsibility disagreements", checked: true },
|
||
{ label: "Decision-making process conflicts", checked: true },
|
||
{ label: "Harassment or discrimination", checked: false },
|
||
{ label: "Member-owner responsibility disputes", checked: false },
|
||
{ label: "Collective ownership tensions", checked: false },
|
||
{ label: "External organization disputes", checked: false },
|
||
{ label: "Financial disagreements", checked: false },
|
||
]);
|
||
|
||
const reportReceivers = ref([
|
||
{ label: "Designated conflict resolution committee", checked: true },
|
||
{ label: "Any elected board member", checked: false },
|
||
{ label: "Administrative Coordinator(s)", checked: false },
|
||
{ label: "Designated member liaison", checked: false },
|
||
{ label: "Any member-worker", checked: false },
|
||
]);
|
||
|
||
const processSteps = ref([
|
||
{ label: "Initial report/complaint received", checked: true },
|
||
{ label: "Acknowledgment sent to complainant", checked: true },
|
||
{ label: "Initial assessment by designated party", checked: true },
|
||
{ label: "Informal resolution attempted", checked: true },
|
||
{ label: "Formal investigation if needed", checked: false },
|
||
{ label: "Mediation/facilitated dialogue", checked: true },
|
||
{ label: "Agreement/resolution documented", checked: true },
|
||
{ label: "Follow-up check-in", checked: false },
|
||
]);
|
||
|
||
const availableActions = ref([
|
||
{ label: "Verbal warning", checked: true },
|
||
{ label: "Written warning", checked: true },
|
||
{ label: "Required training/education", checked: true },
|
||
{ label: "Temporary suspension", checked: true },
|
||
{ label: "Role/responsibility changes", checked: false },
|
||
{ label: "Mediated agreement", checked: false },
|
||
{ label: "Removal from the cooperative", checked: true },
|
||
{ label: "Restorative circle/process", checked: false },
|
||
]);
|
||
|
||
const specialCircumstances = ref([
|
||
{
|
||
label: "Include immediate removal protocol for safety threats",
|
||
checked: true,
|
||
},
|
||
{
|
||
label: "Reference external reporting options (Human Rights Tribunal, etc.)",
|
||
checked: true,
|
||
},
|
||
{ label: "Include anti-retaliation provisions", checked: true },
|
||
{ label: "Include trauma-informed approach language", checked: false },
|
||
]);
|
||
|
||
const formData = ref({
|
||
orgName: "",
|
||
orgType: "",
|
||
memberCount: "",
|
||
customValues: "",
|
||
approach: "restorative",
|
||
anonymousReporting: true,
|
||
mediatorType: "Internal trained mediators",
|
||
supportPeople: true,
|
||
initialResponse: "Within 1 week",
|
||
resolutionTarget: "30 days",
|
||
docLevel: "Standard - key points and decisions",
|
||
confidentiality: "Need-to-know basis",
|
||
retention: "5 years",
|
||
appealProcess: true,
|
||
training: "",
|
||
reviewSchedule: "Annually",
|
||
amendments: "Consent process (no objections)",
|
||
createdDate: new Date().toISOString().split("T")[0],
|
||
reviewDate: "",
|
||
// New fields for enhanced sections
|
||
reflectionPeriod: "Before any escalation",
|
||
customReflectionPrompts: "",
|
||
requireDirectAttempt: true,
|
||
documentDirectResolution: true,
|
||
internalAdvisorType: "Single Board-appointed advisor",
|
||
staffLiaison: "",
|
||
boardChairRole: "First contact for coordinator complaints",
|
||
formalAcknowledgmentTime: "Within 1 week",
|
||
formalReviewTime: "1 month",
|
||
requireExternalAdvice: true,
|
||
requireMinutesOfSettlement: true,
|
||
settlementConfidentiality: "Need-to-know basis",
|
||
conflictFileRetention: "5 years",
|
||
includeHumanRights: true,
|
||
additionalResources: "",
|
||
acknowledgments: "",
|
||
});
|
||
|
||
// Validation logic
|
||
const validationErrors = ref({});
|
||
|
||
// Auto-save functionality
|
||
const autoSave = () => {
|
||
// Clear validation errors when users start correcting fields
|
||
clearValidationErrors();
|
||
|
||
if (typeof window !== "undefined") {
|
||
const dataToSave = {
|
||
formData: formData.value,
|
||
coreValues: coreValues.value,
|
||
conflictTypes: conflictTypes.value,
|
||
reportReceivers: reportReceivers.value,
|
||
processSteps: processSteps.value,
|
||
availableActions: availableActions.value,
|
||
specialCircumstances: specialCircumstances.value,
|
||
communicationChannels: communicationChannels.value,
|
||
formalComplaintElements: formalComplaintElements.value,
|
||
sectionsEnabled: sectionsEnabled.value,
|
||
};
|
||
localStorage.setItem(
|
||
"conflict-resolution-framework-data",
|
||
JSON.stringify(dataToSave)
|
||
);
|
||
}
|
||
};
|
||
|
||
const clearValidationErrors = () => {
|
||
validationErrors.value = {};
|
||
};
|
||
|
||
// Simple Markdown to HTML converter for preview
|
||
const markdownToHtml = (markdown) => {
|
||
return (
|
||
markdown
|
||
// Headers
|
||
.replace(/^### (.*$)/gm, "<h3>$1</h3>")
|
||
.replace(/^## (.*$)/gm, "<h2>$1</h2>")
|
||
.replace(/^# (.*$)/gm, "<h1>$1</h1>")
|
||
// Bold and italic
|
||
.replace(/\*\*\*(.*?)\*\*\*/g, "<strong><em>$1</em></strong>")
|
||
.replace(/\*\*(.*?)\*\*/g, "<strong>$1</strong>")
|
||
.replace(/\*(.*?)\*/g, "<em>$1</em>")
|
||
// Lists
|
||
.replace(/^- (.*$)/gm, "<li>$1</li>")
|
||
.replace(/(<li>.*<\/li>)/s, "<ul>$1</ul>")
|
||
.replace(/<\/li>\s*<ul>/g, "</li>")
|
||
.replace(/<\/ul>\s*<li>/g, "<li>")
|
||
// Tables (basic support)
|
||
.replace(/^\|(.+)\|$/gm, (_, content) => {
|
||
const cells = content.split("|").map((cell) => cell.trim());
|
||
if (cells.every((cell) => cell.match(/^-+$/))) {
|
||
return ""; // Skip separator rows
|
||
}
|
||
const cellTags = cells
|
||
.map((cell) =>
|
||
cell.startsWith("**") && cell.endsWith("**")
|
||
? `<th>${cell.slice(2, -2)}</th>`
|
||
: `<td>${cell}</td>`
|
||
)
|
||
.join("");
|
||
return `<tr>${cellTags}</tr>`;
|
||
})
|
||
.replace(/(<tr>.*<\/tr>)/s, "<table>$1</table>")
|
||
.replace(/<\/tr>\s*<table>/g, "</tr>")
|
||
.replace(/<\/table>\s*<tr>/g, "<tr>")
|
||
// Line breaks
|
||
.replace(/\n\n/g, "</p><p>")
|
||
.replace(/^(.+)$/gm, "<p>$1</p>")
|
||
// Horizontal rules
|
||
.replace(/^---$/gm, "<hr>")
|
||
// Clean up extra paragraphs around headers and lists
|
||
.replace(/<p><h([1-6])>/g, "<h$1>")
|
||
.replace(/<\/h([1-6])><\/p>/g, "</h$1>")
|
||
.replace(/<p><ul>/g, "<ul>")
|
||
.replace(/<\/ul><\/p>/g, "</ul>")
|
||
.replace(/<p><table>/g, "<table>")
|
||
.replace(/<\/table><\/p>/g, "</table>")
|
||
.replace(/<p><hr><\/p>/g, "<hr>")
|
||
.replace(/<p><\/p>/g, "")
|
||
);
|
||
};
|
||
|
||
// Debounced auto-save
|
||
const debouncedAutoSave = debounce(autoSave, 300);
|
||
|
||
function debounce(func, wait) {
|
||
let timeout;
|
||
return function executedFunction(...args) {
|
||
const later = () => {
|
||
clearTimeout(timeout);
|
||
func(...args);
|
||
};
|
||
clearTimeout(timeout);
|
||
timeout = setTimeout(later, 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(
|
||
[
|
||
formData,
|
||
coreValues,
|
||
conflictTypes,
|
||
reportReceivers,
|
||
processSteps,
|
||
availableActions,
|
||
specialCircumstances,
|
||
communicationChannels,
|
||
formalComplaintElements,
|
||
sectionsEnabled,
|
||
],
|
||
autoSave,
|
||
{ deep: true }
|
||
);
|
||
|
||
// Comprehensive generatePolicyDocument function with procedural structure
|
||
const generatePolicyDocument = () => {
|
||
const cooperativeName = formData.value.orgName || "[Cooperative Name]";
|
||
let content = `# ${cooperativeName} Conflict Resolution Policy\n\n`;
|
||
|
||
content += `*Framework Created: ${
|
||
formData.value.createdDate || new Date().toISOString().split("T")[0]
|
||
}*\n`;
|
||
if (formData.value.reviewDate) {
|
||
content += `*Next Review: ${formData.value.reviewDate}*\n`;
|
||
}
|
||
content += `\n---\n\n`;
|
||
|
||
// PURPOSE SECTION
|
||
content += `## Purpose\n\n`;
|
||
content += `Disagreements in groups are par for the course. But ignoring conflicts, or managing them poorly, can deeply harm individuals and our whole community.\n\n`;
|
||
content += `Addressing conflict head-on is **a way of caring for each other**.\n\n`;
|
||
content += `This policy aims to offer a straightforward, consistently enforced, and transparent approach to resolving conflicts and disputes that may emerge in relation to ${cooperativeName}'s programs, governance, or the actions of its members.\n\n`;
|
||
|
||
// GUIDING PRINCIPLES
|
||
content += `## Guiding Principles\n\n`;
|
||
content += `- All parties to a complaint will **actively participate** and strive to achieve a **collaborative** outcome at the earliest possible stage of the process\n`;
|
||
content += `- Information about a complaint will only be given to parties directly involved and others on a need-to-know basis\n`;
|
||
content += `- Parties will be provided with clear and understandable reasons for complaint decisions\n`;
|
||
content += `- Complaints will be dealt with promptly and resolved as quickly as possible\n`;
|
||
content += `- Review of complaints will be fair, impartial, and respectful, allowing all parties to have their perspectives heard\n`;
|
||
content += `- The review will be thorough and as detailed as possible based on the information provided\n`;
|
||
content += `- The process will be accessible and clearly communicated to all members\n\n`;
|
||
|
||
// Add selected values if enabled
|
||
if (sectionsEnabled.value.values) {
|
||
const selectedValues = coreValues.value.filter((v) => v.checked);
|
||
if (selectedValues.length > 0) {
|
||
content += `Additionally, this framework is guided by our core values:\n\n`;
|
||
selectedValues.forEach((value) => {
|
||
content += `- **${value.label}**\n`;
|
||
});
|
||
content += `\n`;
|
||
}
|
||
if (formData.value.customValues) {
|
||
content += `${formData.value.customValues}\n\n`;
|
||
}
|
||
}
|
||
|
||
// DEFINITIONS SECTION
|
||
content += `## Definitions\n\n`;
|
||
content += `- **Conflict/Dispute**: Ongoing experiences of tension and misunderstandings, often leading to interpersonal discord. These terms are used interchangeably.\n`;
|
||
content += `- **Complainant**: The individual lodging a complaint against another party, policy, or practice.\n`;
|
||
content += `- **Respondent**: An individual against whom a complaint has been made.\n`;
|
||
|
||
// Add definitions based on selections
|
||
const selectedReceivers = reportReceivers.value.filter((r) => r.checked);
|
||
if (selectedReceivers.length > 0) {
|
||
content += `- **Responsible Contact People**: Those accountable for assisting in conflict resolution (${selectedReceivers
|
||
.map((r) => r.label)
|
||
.join(
|
||
", "
|
||
)}). They act as neutral implementers of this policy, not advocates.\n`;
|
||
}
|
||
|
||
if (formData.value.internalAdvisorType) {
|
||
content += `- **Internal Advisor**: ${formData.value.internalAdvisorType} who facilitates the conflict resolution process as a neutral intermediary.\n`;
|
||
}
|
||
|
||
if (formData.value.supportPeople) {
|
||
content += `- **Support People**: Individuals not connected to the conflict whom parties may choose to have present for emotional support during mediation.\n`;
|
||
}
|
||
content += `\n`;
|
||
|
||
// POLICY ROUTING TABLE
|
||
content += `## Which Policy Applies?\n\n`;
|
||
content += `| **Who Can File** | **Type of Complaint** | **Policy to Use** | **Initial Contact** |\n`;
|
||
content += `|------------------|----------------------|-------------------|--------------------|\n`;
|
||
|
||
const selectedConflictTypes = conflictTypes.value.filter((c) => c.checked);
|
||
selectedConflictTypes.forEach((conflict) => {
|
||
let policy = "This policy";
|
||
let contact = selectedReceivers[0]?.label || "Designated contact";
|
||
|
||
if (
|
||
conflict.label.includes("Harassment") ||
|
||
conflict.label.includes("discrimination")
|
||
) {
|
||
policy = "Code of Conduct / Human Rights";
|
||
if (formData.value.includeHumanRights) {
|
||
contact += " or Human Rights Tribunal";
|
||
}
|
||
} else if (conflict.label.includes("Code of Conduct")) {
|
||
policy = "Code of Conduct";
|
||
}
|
||
|
||
content += `| Members | ${conflict.label} | ${policy} | ${contact} |\n`;
|
||
});
|
||
|
||
if (formData.value.anonymousReporting) {
|
||
content += `| Any party | Anonymous reports | This policy | Anonymous reporting system |\n`;
|
||
}
|
||
content += `\n`;
|
||
|
||
// RESOLUTION APPROACH
|
||
const approachDescriptions = {
|
||
restorative:
|
||
"We use a **restorative/loving justice** approach that focuses on healing, understanding root causes, and repairing relationships rather than punishment.",
|
||
mediation:
|
||
"We use a **mediation-first** approach where neutral third-party facilitators help parties dialogue and find solutions.",
|
||
progressive:
|
||
"We use **progressive discipline** with clear escalation steps and defined consequences for violations.",
|
||
hybrid:
|
||
"We use a **hybrid approach** that combines multiple methods based on the type and severity of conflict.",
|
||
};
|
||
|
||
if (
|
||
formData.value.approach &&
|
||
approachDescriptions[formData.value.approach]
|
||
) {
|
||
content += `## Our Approach\n\n`;
|
||
content += `${approachDescriptions[formData.value.approach]}\n\n`;
|
||
content += `We do our best to resolve conflicts at the lowest possible escalation step (direct resolution), but agree to escalate conflicts (to assisted resolution) if they are not resolved.\n\n`;
|
||
}
|
||
|
||
// REFLECTION PROCESS (if enabled)
|
||
if (sectionsEnabled.value.reflection) {
|
||
content += `## Reflection Process\n\n`;
|
||
content += `Before engaging in direct resolution, we encourage taking time for reflection:\n\n`;
|
||
content += `1. **Set aside time to think** through what happened. What was the other person's behaviour? How did it affect you? *Distinguish other people's **actions** from your **feelings** about them.*\n`;
|
||
content += `2. **Consider uncertainties** or misunderstandings that may have occurred.\n`;
|
||
content += `3. **Distinguish disagreement from personal hostility.** Disagreement and dissent are part of healthy discussion. Hostility is not.\n`;
|
||
content += `4. **Use your personal support system** (friends, family, therapist, etc.) to work through and clarify your perspective.\n`;
|
||
content += `5. **Ask yourself** what part you played, how you could have behaved differently, and what your needs are.\n\n`;
|
||
|
||
if (formData.value.customReflectionPrompts) {
|
||
content += `### Additional Reflection Prompts\n\n`;
|
||
content += `${formData.value.customReflectionPrompts}\n\n`;
|
||
}
|
||
|
||
const reflectionTiming =
|
||
formData.value.reflectionPeriod || "Before any escalation";
|
||
content += `**Reflection Timing:** ${reflectionTiming}\n\n`;
|
||
}
|
||
|
||
// DIRECT RESOLUTION (if enabled)
|
||
if (sectionsEnabled.value.directResolution) {
|
||
content += `## Direct Resolution\n\n`;
|
||
content += `A *direct resolution* process occurs when individuals communicate their concerns and work together to resolve disputes without filing a formal complaint.\n\n`;
|
||
|
||
content += `### Have a Conversation\n\n`;
|
||
content += `When there is a disagreement, the involved people should first **communicate with each other** about their concerns.\n\n`;
|
||
|
||
content += `1. **Choose a time and place** to meet that is private and agreeable to both.\n`;
|
||
content += `2. **Allow reasonable time** for the conversation.\n`;
|
||
content += `3. **The point is mutual understanding**, not determining who is right or wrong.\n`;
|
||
content += `4. **Express thoughts and feelings directly** using "I" statements and active listening.\n`;
|
||
content += `5. **Communicate your wants and needs** and make offers and requests.\n`;
|
||
content += `6. **Learn for the future** – ask what can be done to prevent this from recurring.\n`;
|
||
|
||
if (formData.value.documentDirectResolution) {
|
||
content += `7. **Keep a written record** of the resolution agreed to by both parties.\n\n`;
|
||
} else {
|
||
content += `\n`;
|
||
}
|
||
|
||
// Communication Channels
|
||
const selectedChannels = communicationChannels.value.filter(
|
||
(c) => c.checked
|
||
);
|
||
if (selectedChannels.length > 0) {
|
||
content += `### Escalating Communication Bandwidth\n\n`;
|
||
content += `Whenever a misunderstanding or conflict arises, **escalate the bandwidth of the channel**:\n\n`;
|
||
selectedChannels.forEach((channel, index) => {
|
||
content += `${index + 1}. ${channel.label}\n`;
|
||
});
|
||
content += `\n`;
|
||
}
|
||
|
||
if (formData.value.requireDirectAttempt) {
|
||
content += `> **Note:** Direct resolution must be attempted before escalating to assisted resolution, unless safety concerns prevent this.\n\n`;
|
||
}
|
||
}
|
||
|
||
// RECEIVING REPORTS SECTION
|
||
content += `## Receiving Reports\n\n`;
|
||
|
||
content += `### Document the Initial Incident Report\n\n`;
|
||
content += `Collect the following information and enter it in the Incident Log:\n\n`;
|
||
content += `| Field | Information to Collect |\n`;
|
||
content += `|-------|------------------------|\n`;
|
||
content += `| **Participant Name** | Name of individual(s) involved |\n`;
|
||
content += `| **Issue/Violation** | Brief description of the behavior or conflict |\n`;
|
||
content += `| **Date & Time** | When the incident occurred |\n`;
|
||
content += `| **Circumstances** | Context or situation surrounding the incident |\n`;
|
||
content += `| **Others Involved** | Names of any witnesses or additional participants |\n`;
|
||
content += `| **Conversation Notes** | Summary of discussion with the complainant |\n\n`;
|
||
content += `*Gather this information from the complainant – do not "interview" witnesses unless they approach staff.*\n\n`;
|
||
|
||
// SUPPORTING THE COMPLAINANT
|
||
content += `### Supporting the Complainant\n\n`;
|
||
content += `Follow these steps to help the complainant feel safe:\n\n`;
|
||
content += `1. **Provide private space** for discussion (in digital spaces, use DM/private channels)\n`;
|
||
content += `2. **Allow the complainant to decide** if further action should be taken\n`;
|
||
content += `3. **Explain the process** – walk them through next steps per this policy\n`;
|
||
content += `4. **Assure confidentiality** – their identity will not be disclosed without permission\n`;
|
||
content += `5. **Confirm follow-up** – they will be informed about any actions taken\n\n`;
|
||
|
||
// ASSISTED RESOLUTION
|
||
content += `## Assisted Resolution\n\n`;
|
||
content += `If direct resolution doesn't work, parties can request assistance from a responsible contact person.\n\n`;
|
||
|
||
// Process Steps
|
||
const selectedSteps = processSteps.value.filter((s) => s.checked);
|
||
if (selectedSteps.length > 0) {
|
||
content += `### Resolution Process Steps\n\n`;
|
||
selectedSteps.forEach((step, index) => {
|
||
content += `${index + 1}. ${step.label}\n`;
|
||
});
|
||
content += `\n`;
|
||
}
|
||
|
||
// Responsible Contact People
|
||
content += `### Responsible Contact People\n\n`;
|
||
|
||
if (selectedReceivers.length > 0) {
|
||
content += `**Initial Contact Options:**\n`;
|
||
selectedReceivers.forEach((receiver) => {
|
||
content += `- ${receiver.label}\n`;
|
||
});
|
||
content += `\n`;
|
||
}
|
||
|
||
// Contact People Structure
|
||
if (formData.value.internalAdvisorType) {
|
||
content += `**Internal Advisor:** ${formData.value.internalAdvisorType}\n`;
|
||
}
|
||
|
||
if (formData.value.staffLiaison) {
|
||
content += `**Member Liaison:** ${formData.value.staffLiaison}\n`;
|
||
}
|
||
|
||
if (formData.value.boardChairRole) {
|
||
content += `**Board Chair Role:** ${formData.value.boardChairRole}\n`;
|
||
}
|
||
|
||
if (
|
||
formData.value.internalAdvisorType ||
|
||
formData.value.staffLiaison ||
|
||
formData.value.boardChairRole
|
||
) {
|
||
content += `\n`;
|
||
}
|
||
|
||
// Mediator Structure
|
||
if (formData.value.mediatorType) {
|
||
content += `**Mediation Structure:** ${formData.value.mediatorType}\n`;
|
||
|
||
if (formData.value.supportPeople) {
|
||
content += `**Support People:** Parties may bring a trusted person for emotional support during mediation sessions.\n`;
|
||
}
|
||
content += `\n`;
|
||
}
|
||
|
||
// Timeline
|
||
content += `### Response Timeline\n\n`;
|
||
content += `| Stage | Timeframe |\n`;
|
||
content += `|-------|----------|\n`;
|
||
if (formData.value.initialResponse) {
|
||
content += `| Initial Response | ${formData.value.initialResponse} |\n`;
|
||
}
|
||
if (formData.value.resolutionTarget) {
|
||
content += `| Target Resolution | ${formData.value.resolutionTarget} |\n`;
|
||
}
|
||
content += `\n`;
|
||
|
||
// COMMITTEE MEETING PROCEDURES (if committee-based)
|
||
if (
|
||
formData.value.mediatorType &&
|
||
formData.value.mediatorType.toLowerCase().includes("committee")
|
||
) {
|
||
content += `## Committee Meeting Procedures\n\n`;
|
||
|
||
content += `### Before the Meeting\n`;
|
||
content += `- Notify respondent of complaint\n`;
|
||
content += `- Allow respondent to provide their perspective\n`;
|
||
content += `- Schedule meeting within ${
|
||
formData.value.initialResponse || "specified timeframe"
|
||
}\n\n`;
|
||
|
||
content += `### During the Meeting\n`;
|
||
content += `Committee members should review the incident report and discuss:\n`;
|
||
content += `- What happened?\n`;
|
||
content += `- What are we doing about it?\n`;
|
||
content += `- Who is implementing the decision?\n`;
|
||
content += `- When will it be implemented?\n\n`;
|
||
content += `*Neither the complainant nor respondent should attend the deliberation.*\n\n`;
|
||
|
||
content += `### After the Meeting\n`;
|
||
content += `- Communicate decision to all parties\n`;
|
||
content += `- Document all communications\n`;
|
||
content += `- Follow up with complainant about outcomes\n`;
|
||
content += `- Prepare report for organizational records\n\n`;
|
||
}
|
||
|
||
// RESPONSE PROCEDURES MATRIX
|
||
content += `## Response Procedures\n\n`;
|
||
const selectedActions = availableActions.value.filter((a) => a.checked);
|
||
|
||
if (selectedActions.length > 0) {
|
||
content += `### Response Matrix\n\n`;
|
||
content += `| Issue Severity | Possible Response | Documentation Required |\n`;
|
||
content += `|----------------|-------------------|------------------------|\n`;
|
||
|
||
// Create severity-based responses
|
||
const hasVerbal = selectedActions.some((a) => a.label.includes("Verbal"));
|
||
const hasWritten = selectedActions.some((a) => a.label.includes("Written"));
|
||
const hasSuspension = selectedActions.some((a) =>
|
||
a.label.includes("suspension")
|
||
);
|
||
const hasRemoval = selectedActions.some(
|
||
(a) => a.label.includes("Removal") || a.label.includes("removal")
|
||
);
|
||
|
||
if (hasVerbal) {
|
||
content += `| First occurrence, minor | Verbal warning | Update incident log |\n`;
|
||
}
|
||
if (hasWritten) {
|
||
content += `| Repeated behavior | Written warning | Formal documentation |\n`;
|
||
}
|
||
if (hasSuspension) {
|
||
content += `| Serious violation | Temporary suspension | Full investigation report |\n`;
|
||
}
|
||
if (hasRemoval) {
|
||
content += `| Severe/safety threat | Immediate removal | Complete documentation + notifications |\n`;
|
||
}
|
||
content += `\n`;
|
||
|
||
content += `### Available Remedial Actions\n\n`;
|
||
selectedActions.forEach((action) => {
|
||
content += `- ${action.label}\n`;
|
||
});
|
||
content += `\n`;
|
||
}
|
||
|
||
if (formData.value.appealProcess) {
|
||
content += `### Appeals Process\n\n`;
|
||
content += `Parties may request review of decisions through our appeals process. Appeals must be submitted in writing within 30 days of the original decision.\n\n`;
|
||
}
|
||
|
||
// FORMAL COMPLAINTS
|
||
content += `## Formal Complaints\n\n`;
|
||
content += `If assisted resolution does not result in an acceptable outcome, a formal complaint may be filed in writing.\n\n`;
|
||
|
||
// Required Elements
|
||
const selectedElements = formalComplaintElements.value.filter(
|
||
(e) => e.checked
|
||
);
|
||
if (selectedElements.length > 0) {
|
||
content += `### Written Complaint Requirements\n\n`;
|
||
content += `The formal complaint must include:\n\n`;
|
||
selectedElements.forEach((element, index) => {
|
||
content += `${index + 1}. ${element.label}\n`;
|
||
});
|
||
content += `\n`;
|
||
}
|
||
|
||
// Formal Process Timeline
|
||
content += `### Formal Process Timeline\n\n`;
|
||
content += `| Stage | Timeframe |\n`;
|
||
content += `|-------|----------|\n`;
|
||
if (formData.value.formalAcknowledgmentTime) {
|
||
content += `| Acknowledgment of complaint | ${formData.value.formalAcknowledgmentTime} |\n`;
|
||
}
|
||
if (formData.value.formalReviewTime) {
|
||
content += `| Review completion | ${formData.value.formalReviewTime} |\n`;
|
||
}
|
||
content += `\n`;
|
||
|
||
if (formData.value.requireExternalAdvice) {
|
||
content += `> **External Expertise:** For complex complaints involving multiple parties or organizational leaders, external legal advice will be sought.\n\n`;
|
||
}
|
||
|
||
// PREVENTING RETALIATION (if anti-retaliation is selected)
|
||
const hasAntiRetaliation = specialCircumstances.value.some(
|
||
(c) => c.checked && c.label.toLowerCase().includes("retaliation")
|
||
);
|
||
|
||
if (hasAntiRetaliation) {
|
||
content += `## Preventing Retaliation\n\n`;
|
||
content += `**CRITICAL:** The privacy and safety of the complainant is paramount.\n\n`;
|
||
content += `- **DO NOT** share details of the incident without express permission from the complainant\n`;
|
||
content += `- **DO NOT** reveal the complainant's identity to the respondent or others\n`;
|
||
content += `- **MONITOR** for any retaliatory behavior following a complaint\n`;
|
||
content += `- **DOCUMENT** any instances of suspected retaliation\n`;
|
||
content += `- **TREAT** retaliation as a separate, serious violation requiring immediate action\n\n`;
|
||
}
|
||
|
||
// SETTLEMENT & DOCUMENTATION
|
||
content += `## Settlement & Documentation\n\n`;
|
||
|
||
if (formData.value.requireMinutesOfSettlement) {
|
||
content += `### Minutes of Settlement\n`;
|
||
content += `Any resolution must be documented in "Minutes of Settlement" that:\n`;
|
||
content += `- Clearly state the agreed-upon resolution\n`;
|
||
content += `- Include commitments from all parties\n`;
|
||
content += `- Are signed by both complainant and respondent\n`;
|
||
content += `- Are kept according to our confidentiality standards\n\n`;
|
||
}
|
||
|
||
// REGARDING APOLOGIES
|
||
content += `### Regarding Apologies\n\n`;
|
||
content += `We do not require or facilitate apologies unless explicitly requested by the complainant.\n\n`;
|
||
content += `- Forced apologies can constitute continued harassment\n`;
|
||
content += `- If offered, apologies should be brief and relayed through the mediator\n`;
|
||
content += `- Apologies should not require a response from the recipient\n`;
|
||
content += `- Pressing unwanted apologies may result in further disciplinary action\n\n`;
|
||
|
||
// DOCUMENTATION & PRIVACY
|
||
if (sectionsEnabled.value.documentation) {
|
||
content += `## Documentation & Privacy\n\n`;
|
||
|
||
content += `### Record Management\n\n`;
|
||
content += `| Record Type | Retention Period | Access Level | Storage Location |\n`;
|
||
content += `|-------------|------------------|--------------|------------------|\n`;
|
||
content += `| Initial incident reports | Permanent | Committee only | Secure database |\n`;
|
||
content += `| Investigation notes | ${
|
||
formData.value.retention || "5 years"
|
||
} | Designated roles | Confidential files |\n`;
|
||
content += `| Resolution agreements | ${
|
||
formData.value.conflictFileRetention ||
|
||
formData.value.retention ||
|
||
"5 years"
|
||
} | Parties + committee | Secure archive |\n`;
|
||
content += `| Committee meeting minutes | ${
|
||
formData.value.retention || "5 years"
|
||
} | Committee members | Meeting records |\n\n`;
|
||
|
||
if (formData.value.docLevel) {
|
||
content += `**Documentation Level:** ${formData.value.docLevel}\n`;
|
||
}
|
||
if (formData.value.confidentiality) {
|
||
content += `**General Confidentiality:** ${formData.value.confidentiality}\n`;
|
||
}
|
||
if (formData.value.settlementConfidentiality) {
|
||
content += `**Settlement Confidentiality:** ${formData.value.settlementConfidentiality}\n`;
|
||
}
|
||
content += `\n`;
|
||
}
|
||
|
||
// SPECIAL CIRCUMSTANCES (if enabled)
|
||
if (sectionsEnabled.value.special) {
|
||
const selectedCircumstances = specialCircumstances.value.filter(
|
||
(c) => c.checked
|
||
);
|
||
if (selectedCircumstances.length > 0) {
|
||
content += `## Special Circumstances\n\n`;
|
||
|
||
const hasImmediateRemoval = selectedCircumstances.some(
|
||
(c) =>
|
||
c.label.toLowerCase().includes("immediate removal") ||
|
||
c.label.toLowerCase().includes("safety")
|
||
);
|
||
|
||
if (hasImmediateRemoval) {
|
||
content += `### Immediate Safety Threats\n`;
|
||
content += `When anyone's physical safety is threatened:\n`;
|
||
content += `1. Immediately remove the offender from the space\n`;
|
||
content += `2. Implement permanent ban if warranted\n`;
|
||
content += `3. Notify relevant authorities if required\n`;
|
||
content += `4. Document all actions taken\n`;
|
||
content += `5. Inform stakeholders as appropriate while protecting victim privacy\n\n`;
|
||
}
|
||
|
||
const hasTraumaInformed = selectedCircumstances.some((c) =>
|
||
c.label.toLowerCase().includes("trauma")
|
||
);
|
||
|
||
if (hasTraumaInformed) {
|
||
content += `### Trauma-Informed Approach\n`;
|
||
content += `All conflict resolution processes will incorporate trauma-informed principles:\n`;
|
||
content += `- Recognize the impact of trauma on behavior\n`;
|
||
content += `- Prioritize physical and emotional safety\n`;
|
||
content += `- Provide choices and restore control\n`;
|
||
content += `- Collaborate rather than prescribe solutions\n`;
|
||
content += `- Build on strengths and resilience\n\n`;
|
||
}
|
||
}
|
||
}
|
||
|
||
// EXTERNAL RESOURCES (if enabled)
|
||
if (sectionsEnabled.value.externalResources) {
|
||
content += `## External Resources & Redress\n\n`;
|
||
|
||
if (formData.value.includeHumanRights) {
|
||
content += `### Human Rights Complaints\n`;
|
||
content += `Individuals who are not satisfied with the outcome of a harassment or discrimination complaint may file a complaint with:\n`;
|
||
content += `- [Canadian Human Rights Commission](https://www.chrc-ccdp.gc.ca/eng)\n`;
|
||
content += `- Provincial human rights tribunal\n`;
|
||
content += `- Other relevant regulatory bodies\n\n`;
|
||
}
|
||
|
||
if (formData.value.additionalResources) {
|
||
content += `### Additional Resources\n\n`;
|
||
content += `${formData.value.additionalResources}\n\n`;
|
||
}
|
||
}
|
||
|
||
// IMPLEMENTATION & TRAINING
|
||
content += `## Implementation\n\n`;
|
||
|
||
if (formData.value.training) {
|
||
content += `### Training Requirements\n\n`;
|
||
content += `${formData.value.training}\n\n`;
|
||
}
|
||
|
||
content += `### Policy Management\n\n`;
|
||
content += `| Aspect | Details |\n`;
|
||
content += `|--------|----------|\n`;
|
||
if (formData.value.reviewSchedule) {
|
||
content += `| Review Schedule | ${formData.value.reviewSchedule} |\n`;
|
||
}
|
||
if (formData.value.amendments) {
|
||
content += `| Amendment Process | ${formData.value.amendments} |\n`;
|
||
}
|
||
content += `| Last Updated | ${
|
||
formData.value.createdDate || new Date().toISOString().split("T")[0]
|
||
} |\n`;
|
||
if (formData.value.reviewDate) {
|
||
content += `| Next Review | ${formData.value.reviewDate} |\n`;
|
||
}
|
||
content += `\n`;
|
||
|
||
// Acknowledgments
|
||
if (formData.value.acknowledgments) {
|
||
content += `### Acknowledgments\n\n`;
|
||
content += `${formData.value.acknowledgments}\n\n`;
|
||
}
|
||
|
||
return content;
|
||
};
|
||
|
||
// Export data for the ExportOptions component - structured to match ExportOptions expectations
|
||
const exportData = computed(() => {
|
||
// Get selected values for arrays
|
||
const selectedCoreValues = coreValues.value
|
||
.filter((v) => v.checked)
|
||
.map((v) => v.label);
|
||
const selectedConflictTypes = conflictTypes.value
|
||
.filter((c) => c.checked)
|
||
.map((c) => c.label);
|
||
const selectedProcessSteps = processSteps.value
|
||
.filter((s) => s.checked)
|
||
.map((s) => s.label);
|
||
const selectedActions = availableActions.value
|
||
.filter((a) => a.checked)
|
||
.map((a) => a.label);
|
||
const selectedReceivers = reportReceivers.value
|
||
.filter((r) => r.checked)
|
||
.map((r) => r.label);
|
||
const selectedChannels = communicationChannels.value
|
||
.filter((c) => c.checked)
|
||
.map((c) => c.label);
|
||
const selectedComplaintElements = formalComplaintElements.value
|
||
.filter((e) => e.checked)
|
||
.map((e) => e.label);
|
||
const selectedCircumstances = specialCircumstances.value
|
||
.filter((c) => c.checked)
|
||
.map((c) => c.label);
|
||
|
||
return {
|
||
section: "conflict-resolution-framework",
|
||
// Add the generated policy document content for exports
|
||
content: generatePolicyDocument(),
|
||
// Enhanced formData with processed arrays
|
||
formData: {
|
||
...formData.value,
|
||
// Add processed arrays as lists for the formatter
|
||
coreValuesList: selectedCoreValues,
|
||
conflictTypesList: selectedConflictTypes,
|
||
processStepsList: selectedProcessSteps,
|
||
actionsList: selectedActions,
|
||
receiversList: selectedReceivers,
|
||
channelsList: selectedChannels,
|
||
complaintElementsList: selectedComplaintElements,
|
||
circumstancesList: selectedCircumstances,
|
||
},
|
||
sectionsEnabled: sectionsEnabled.value,
|
||
reportReceivers: reportReceivers.value,
|
||
coreValues: coreValues.value,
|
||
conflictTypes: conflictTypes.value,
|
||
processSteps: processSteps.value,
|
||
availableActions: availableActions.value,
|
||
specialCircumstances: specialCircumstances.value,
|
||
communicationChannels: communicationChannels.value,
|
||
formalComplaintElements: formalComplaintElements.value,
|
||
exportedAt: new Date().toISOString(),
|
||
};
|
||
});
|
||
</script>
|
||
|
||
<style scoped>
|
||
@reference "tailwindcss";
|
||
|
||
/* Template-specific styles that aren't in main.css */
|
||
|
||
/* Progress bar */
|
||
.progress-bar {
|
||
width: 100%;
|
||
height: 6px;
|
||
background: #e0e0e0;
|
||
border-radius: 3px;
|
||
margin-bottom: 30px;
|
||
overflow: hidden;
|
||
}
|
||
|
||
.progress-fill {
|
||
height: 100%;
|
||
background: linear-gradient(90deg, #4caf50, #66bb6a);
|
||
border-radius: 3px;
|
||
transition: width 0.3s ease;
|
||
}
|
||
|
||
/* Quick start section */
|
||
.quick-start {
|
||
background: #f0f7ff;
|
||
border: 1px solid #d0e3ff;
|
||
border-radius: 8px;
|
||
padding: 20px;
|
||
margin-bottom: 30px;
|
||
}
|
||
|
||
.quick-start h3 {
|
||
margin: 0 0 10px 0;
|
||
font-size: 1.2rem;
|
||
color: #333;
|
||
}
|
||
|
||
.preset-buttons {
|
||
display: flex;
|
||
gap: 10px;
|
||
flex-wrap: wrap;
|
||
margin-top: 15px;
|
||
}
|
||
|
||
.preset-btn {
|
||
padding: 8px 16px;
|
||
border: 2px solid #0066cc;
|
||
background: white;
|
||
color: #0066cc;
|
||
border-radius: 6px;
|
||
cursor: pointer;
|
||
transition: all 0.2s;
|
||
font-size: 0.9rem;
|
||
}
|
||
|
||
.preset-btn:hover {
|
||
background: #0066cc;
|
||
color: white;
|
||
}
|
||
|
||
.preset-btn.selected {
|
||
background: #0066cc;
|
||
color: white;
|
||
}
|
||
|
||
/* Styling for sections when toggled off */
|
||
.section-card:has(.space-y-6[style*="display: none"]) {
|
||
opacity: 0.7;
|
||
}
|
||
|
||
.section-card:has(.space-y-6[style*="display: none"]) .section-title {
|
||
color: #666;
|
||
}
|
||
|
||
/* Toggle styling */
|
||
.toggle-section {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 8px;
|
||
}
|
||
|
||
.toggle {
|
||
position: relative;
|
||
width: 48px;
|
||
height: 24px;
|
||
background: #ccc;
|
||
border-radius: 24px;
|
||
cursor: pointer;
|
||
transition: background 0.3s;
|
||
}
|
||
|
||
.toggle.active {
|
||
background: #4caf50;
|
||
}
|
||
|
||
.toggle-slider {
|
||
position: absolute;
|
||
top: 2px;
|
||
left: 2px;
|
||
width: 20px;
|
||
height: 20px;
|
||
background: white;
|
||
border-radius: 50%;
|
||
transition: transform 0.3s;
|
||
}
|
||
|
||
.toggle.active .toggle-slider {
|
||
transform: translateX(24px);
|
||
}
|
||
|
||
/* Moved validation-error to main.css for consistency */
|
||
|
||
/* Preview styling - template-specific */
|
||
.preview-controls {
|
||
text-align: center;
|
||
margin: 2rem 0;
|
||
}
|
||
|
||
.preview-btn {
|
||
background: #6366f1;
|
||
color: white;
|
||
border: none;
|
||
padding: 0.75rem 1.5rem;
|
||
border-radius: 8px;
|
||
font-size: 1rem;
|
||
cursor: pointer;
|
||
transition: background 0.2s;
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: 0.5rem;
|
||
}
|
||
|
||
.preview-btn:hover {
|
||
background: #5856eb;
|
||
}
|
||
|
||
.close-preview-btn {
|
||
background: #ef4444;
|
||
color: white;
|
||
border: none;
|
||
padding: 0.25rem 0.5rem;
|
||
border-radius: 4px;
|
||
cursor: pointer;
|
||
font-size: 1.2rem;
|
||
line-height: 1;
|
||
transition: background 0.2s;
|
||
}
|
||
|
||
.close-preview-btn:hover {
|
||
background: #dc2626;
|
||
}
|
||
|
||
.policy-preview {
|
||
line-height: 1.6;
|
||
font-family: ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto,
|
||
"Helvetica Neue", Arial, "Noto Sans", "Apple Color Emoji", "Segoe UI Emoji" !important;
|
||
font-size: 0.95rem;
|
||
}
|
||
|
||
.policy-preview h1 {
|
||
font-size: 2rem;
|
||
font-weight: bold;
|
||
color: #111827;
|
||
margin-bottom: 1.5rem;
|
||
border-bottom: 2px solid #e5e7eb;
|
||
padding-bottom: 0.5rem;
|
||
}
|
||
|
||
.policy-preview h2 {
|
||
font-size: 1.5rem;
|
||
font-weight: 600;
|
||
color: #374151;
|
||
margin-top: 2rem;
|
||
margin-bottom: 1rem;
|
||
}
|
||
|
||
.policy-preview h3 {
|
||
font-size: 1.25rem;
|
||
font-weight: 600;
|
||
color: #4b5563;
|
||
margin-top: 1.5rem;
|
||
margin-bottom: 0.75rem;
|
||
}
|
||
|
||
.policy-preview p {
|
||
margin-bottom: 1.25rem;
|
||
color: #374151;
|
||
}
|
||
|
||
.policy-preview p:last-child {
|
||
margin-bottom: 0;
|
||
}
|
||
|
||
.policy-preview :is(p, span, div, li, ol, ul, table, th, td, blockquote) {
|
||
font-family: ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto,
|
||
"Helvetica Neue", Arial, "Noto Sans", "Apple Color Emoji", "Segoe UI Emoji" !important;
|
||
}
|
||
|
||
.policy-preview a {
|
||
color: #2563eb;
|
||
text-decoration: underline;
|
||
}
|
||
|
||
html.dark .policy-preview a {
|
||
color: #93c5fd;
|
||
}
|
||
|
||
.policy-preview blockquote {
|
||
border-left: 4px solid #e5e7eb;
|
||
margin: 1rem 0;
|
||
padding: 0.5rem 1rem;
|
||
color: #4b5563;
|
||
background: #f9fafb;
|
||
}
|
||
|
||
html.dark .policy-preview blockquote {
|
||
border-left-color: #374151;
|
||
background: #0f1115;
|
||
color: #9ca3af;
|
||
}
|
||
|
||
.policy-preview code {
|
||
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas,
|
||
"Liberation Mono", "Courier New", monospace !important;
|
||
background: #f3f4f6;
|
||
padding: 0.1rem 0.35rem;
|
||
}
|
||
|
||
html.dark .policy-preview code {
|
||
background: #111827;
|
||
}
|
||
|
||
.policy-preview ul {
|
||
margin: 1rem 0;
|
||
padding-left: 1.5rem;
|
||
}
|
||
|
||
.policy-preview li {
|
||
margin-bottom: 0.5rem;
|
||
color: #374151;
|
||
}
|
||
|
||
.policy-preview table {
|
||
width: 100%;
|
||
border-collapse: collapse;
|
||
margin: 1.5rem 0;
|
||
background: white;
|
||
}
|
||
|
||
.policy-preview th,
|
||
.policy-preview td {
|
||
border: 1px solid #d1d5db;
|
||
padding: 0.75rem;
|
||
text-align: left;
|
||
}
|
||
|
||
.policy-preview th {
|
||
background: #f3f4f6;
|
||
font-weight: 600;
|
||
color: #374151;
|
||
}
|
||
|
||
.policy-preview hr {
|
||
border: none;
|
||
border-top: 1px solid #e5e7eb;
|
||
margin: 2rem 0;
|
||
}
|
||
|
||
.policy-preview strong {
|
||
font-weight: 600;
|
||
color: #111827;
|
||
}
|
||
|
||
.policy-preview em {
|
||
font-style: italic;
|
||
}
|
||
</style>
|