monacousa-portal/pages/board/governance/index.vue

350 lines
10 KiB
Vue

<template>
<v-container fluid>
<!-- Header -->
<v-row class="mb-6">
<v-col>
<h1 class="text-h3 font-weight-bold mb-2">Governance Documents</h1>
<p class="text-body-1 text-medium-emphasis">Access bylaws, policies, and governance materials</p>
</v-col>
<v-col cols="auto">
<v-btn
color="primary"
variant="flat"
prepend-icon="mdi-file-upload"
@click="showUploadDialog = true"
>
Upload Document
</v-btn>
</v-col>
</v-row>
<!-- Document Categories -->
<v-row class="mb-6">
<v-col cols="12">
<v-chip-group
v-model="selectedCategory"
selected-class="bg-primary"
mandatory
>
<v-chip
v-for="category in categories"
:key="category.value"
:value="category.value"
variant="outlined"
>
<v-icon start>{{ category.icon }}</v-icon>
{{ category.title }}
<v-badge
:content="category.count"
color="primary"
inline
class="ml-2"
/>
</v-chip>
</v-chip-group>
</v-col>
</v-row>
<!-- Documents List -->
<v-row>
<v-col
v-for="document in filteredDocuments"
:key="document.id"
cols="12"
md="6"
lg="4"
>
<v-card elevation="2" hover>
<v-card-text>
<div class="d-flex align-start">
<v-icon
:icon="getDocumentIcon(document.type)"
size="40"
:color="getDocumentColor(document.type)"
class="mr-3"
/>
<div class="flex-grow-1">
<h3 class="text-body-1 font-weight-medium mb-1">
{{ document.title }}
</h3>
<p class="text-caption text-medium-emphasis mb-2">
{{ document.description }}
</p>
<div class="d-flex align-center text-caption">
<v-icon size="x-small" class="mr-1">mdi-calendar</v-icon>
<span class="text-medium-emphasis">
Updated {{ formatDate(document.updatedAt) }}
</span>
</div>
<div class="d-flex align-center text-caption mt-1">
<v-icon size="x-small" class="mr-1">mdi-file-outline</v-icon>
<span class="text-medium-emphasis">
{{ document.fileSize }}
</span>
</div>
</div>
</div>
</v-card-text>
<v-divider />
<v-card-actions>
<v-btn
variant="text"
color="primary"
size="small"
@click="viewDocument(document)"
>
<v-icon start>mdi-eye</v-icon>
View
</v-btn>
<v-btn
variant="text"
color="primary"
size="small"
@click="downloadDocument(document)"
>
<v-icon start>mdi-download</v-icon>
Download
</v-btn>
<v-spacer />
<v-btn
icon="mdi-dots-vertical"
size="small"
variant="text"
>
<v-menu activator="parent">
<v-list density="compact">
<v-list-item @click="shareDocument(document)">
<v-list-item-title>
<v-icon size="small" class="mr-2">mdi-share-variant</v-icon>
Share
</v-list-item-title>
</v-list-item>
<v-list-item @click="editDocument(document)">
<v-list-item-title>
<v-icon size="small" class="mr-2">mdi-pencil</v-icon>
Edit Details
</v-list-item-title>
</v-list-item>
<v-list-item @click="archiveDocument(document)">
<v-list-item-title>
<v-icon size="small" class="mr-2">mdi-archive</v-icon>
Archive
</v-list-item-title>
</v-list-item>
<v-divider />
<v-list-item @click="deleteDocument(document)" class="text-error">
<v-list-item-title>
<v-icon size="small" class="mr-2">mdi-delete</v-icon>
Delete
</v-list-item-title>
</v-list-item>
</v-list>
</v-menu>
</v-btn>
</v-card-actions>
</v-card>
</v-col>
</v-row>
<!-- Upload Dialog -->
<v-dialog v-model="showUploadDialog" max-width="600">
<v-card>
<v-card-title>Upload Document</v-card-title>
<v-card-text>
<v-form ref="uploadForm">
<v-row>
<v-col cols="12">
<v-file-input
v-model="uploadForm.file"
label="Select Document"
accept=".pdf,.doc,.docx"
variant="outlined"
prepend-icon="mdi-file-document"
required
/>
</v-col>
<v-col cols="12">
<v-text-field
v-model="uploadForm.title"
label="Document Title"
variant="outlined"
required
/>
</v-col>
<v-col cols="12">
<v-textarea
v-model="uploadForm.description"
label="Description"
variant="outlined"
rows="2"
/>
</v-col>
<v-col cols="12">
<v-select
v-model="uploadForm.category"
label="Category"
:items="categories"
item-title="title"
item-value="value"
variant="outlined"
required
/>
</v-col>
</v-row>
</v-form>
</v-card-text>
<v-card-actions>
<v-spacer />
<v-btn variant="text" @click="showUploadDialog = false">Cancel</v-btn>
<v-btn color="primary" variant="flat" @click="uploadDocument">Upload</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
</v-container>
</template>
<script setup lang="ts">
definePageMeta({
layout: 'board',
middleware: 'board'
});
// State
const showUploadDialog = ref(false);
const selectedCategory = ref('all');
// Form data
const uploadForm = ref({
file: null,
title: '',
description: '',
category: ''
});
// Categories
const categories = [
{ title: 'All Documents', value: 'all', icon: 'mdi-file-multiple', count: 12 },
{ title: 'Bylaws', value: 'bylaws', icon: 'mdi-gavel', count: 2 },
{ title: 'Policies', value: 'policies', icon: 'mdi-shield-check', count: 4 },
{ title: 'Minutes', value: 'minutes', icon: 'mdi-clock-outline', count: 3 },
{ title: 'Reports', value: 'reports', icon: 'mdi-chart-box', count: 3 }
];
// Mock documents
const documents = ref([
{
id: 1,
title: 'Association Bylaws 2024',
description: 'Updated bylaws governing the association operations',
type: 'bylaws',
fileSize: '2.4 MB',
updatedAt: new Date('2024-01-01')
},
{
id: 2,
title: 'Code of Conduct Policy',
description: 'Member code of conduct and ethics guidelines',
type: 'policies',
fileSize: '548 KB',
updatedAt: new Date('2023-12-15')
},
{
id: 3,
title: 'Board Meeting Minutes - January 2024',
description: 'Minutes from the January board meeting',
type: 'minutes',
fileSize: '128 KB',
updatedAt: new Date('2024-01-10')
},
{
id: 4,
title: 'Annual Financial Report 2023',
description: 'Comprehensive financial report for fiscal year 2023',
type: 'reports',
fileSize: '4.2 MB',
updatedAt: new Date('2024-01-05')
},
{
id: 5,
title: 'Conflict of Interest Policy',
description: 'Policy for managing conflicts of interest',
type: 'policies',
fileSize: '315 KB',
updatedAt: new Date('2023-11-20')
},
{
id: 6,
title: 'Strategic Plan 2024-2026',
description: 'Three-year strategic planning document',
type: 'reports',
fileSize: '1.8 MB',
updatedAt: new Date('2023-12-01')
}
]);
// Computed
const filteredDocuments = computed(() => {
if (selectedCategory.value === 'all') {
return documents.value;
}
return documents.value.filter(d => d.type === selectedCategory.value);
});
// Methods
const getDocumentIcon = (type: string) => {
switch (type) {
case 'bylaws': return 'mdi-gavel';
case 'policies': return 'mdi-shield-check';
case 'minutes': return 'mdi-clock-outline';
case 'reports': return 'mdi-chart-box';
default: return 'mdi-file-document';
}
};
const getDocumentColor = (type: string) => {
switch (type) {
case 'bylaws': return 'error';
case 'policies': return 'warning';
case 'minutes': return 'info';
case 'reports': return 'success';
default: return 'primary';
}
};
const formatDate = (date: Date) => {
return new Date(date).toLocaleDateString('en-US', {
month: 'short',
day: 'numeric',
year: 'numeric'
});
};
const viewDocument = (document: any) => {
console.log('View document:', document);
};
const downloadDocument = (document: any) => {
console.log('Download document:', document);
};
const shareDocument = (document: any) => {
console.log('Share document:', document);
};
const editDocument = (document: any) => {
console.log('Edit document:', document);
};
const archiveDocument = (document: any) => {
console.log('Archive document:', document);
};
const deleteDocument = (document: any) => {
console.log('Delete document:', document);
};
const uploadDocument = () => {
console.log('Upload document:', uploadForm.value);
showUploadDialog.value = false;
};
</script>