- Add Docker configuration (Dockerfile, docker-compose.yml) - Add Nginx and Supervisor configuration - Add deployment documentation (DEPLOYMENT.md) - Complete Phase 3 data migration (63 entries, 63 docs, 28 subs) - Add responsive PDF viewer component - Fix date format to American (MM/DD/YYYY) - Update typography to match v1.0 - Add admin dashboard with full CRUD operations - Configure PostgreSQL with secure password - Connect to caddy_network for reverse proxy - Ready for production deployment
247 lines
9.9 KiB
Vue
247 lines
9.9 KiB
Vue
<script setup lang="ts">
|
|
import { Head } from '@inertiajs/vue3';
|
|
import { ref } from 'vue';
|
|
import PDFViewer from '@/Components/PDFViewer.vue';
|
|
|
|
interface Document {
|
|
id: number;
|
|
title: string;
|
|
file_path: string;
|
|
}
|
|
|
|
interface DocketEntry {
|
|
id: number;
|
|
date: string;
|
|
title: string;
|
|
summary: string;
|
|
documents: Document[];
|
|
}
|
|
|
|
interface CaseInfo {
|
|
title: string;
|
|
status: string;
|
|
lastUpdated: string;
|
|
}
|
|
|
|
interface Props {
|
|
docketEntries: DocketEntry[];
|
|
caseInfo: CaseInfo;
|
|
}
|
|
|
|
const props = defineProps<Props>();
|
|
|
|
const expandedEntry = ref<number | null>(null);
|
|
const email = ref('');
|
|
const subscribeMessage = ref('');
|
|
const selectedDocument = ref<{ title: string; url: string } | null>(null);
|
|
|
|
const toggleEntry = (id: number) => {
|
|
expandedEntry.value = expandedEntry.value === id ? null : id;
|
|
};
|
|
|
|
const openDocument = (doc: Document, event: MouseEvent) => {
|
|
event.preventDefault();
|
|
event.stopPropagation();
|
|
selectedDocument.value = {
|
|
title: doc.title,
|
|
url: `/api/documents/${doc.id}/download`
|
|
};
|
|
};
|
|
|
|
const closeViewer = () => {
|
|
selectedDocument.value = null;
|
|
};
|
|
|
|
const subscribe = async () => {
|
|
if (!email.value) {
|
|
subscribeMessage.value = 'Please enter your email address.';
|
|
setTimeout(() => {
|
|
subscribeMessage.value = '';
|
|
}, 3000);
|
|
return;
|
|
}
|
|
|
|
try {
|
|
const response = await fetch('/api/subscribe', {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]')?.getAttribute('content') || '',
|
|
},
|
|
body: JSON.stringify({ email: email.value }),
|
|
});
|
|
|
|
const data = await response.json();
|
|
|
|
if (data.success) {
|
|
subscribeMessage.value = data.message;
|
|
email.value = ''; // Clear the input
|
|
} else {
|
|
subscribeMessage.value = data.message;
|
|
}
|
|
} catch (error) {
|
|
subscribeMessage.value = 'An error occurred. Please try again.';
|
|
}
|
|
|
|
setTimeout(() => {
|
|
subscribeMessage.value = '';
|
|
}, 5000);
|
|
};
|
|
</script>
|
|
|
|
<template>
|
|
<Head title="Court Docket - Elizabeth Kragh v. Montana Association of the Deaf" />
|
|
|
|
<div class="min-h-screen" style="background-color: #4a5568;">
|
|
<!-- Hero Section -->
|
|
<div class="py-16 px-4" style="background: linear-gradient(135deg, #3f4a5c 0%, #4a5568 100%);">
|
|
<div class="max-w-4xl mx-auto text-center">
|
|
<h1 class="text-[2.5rem] font-bold text-white mb-2 leading-tight">
|
|
ELIZABETH KRAGH<br />
|
|
v.<br />
|
|
MONTANA ASSOCIATION OF THE DEAF
|
|
</h1>
|
|
<p class="text-base text-[#7CAE7A] mb-8">Court Docket & Legal Documents</p>
|
|
|
|
<!-- Email Subscription -->
|
|
<div class="bg-white/10 backdrop-blur-sm rounded-lg p-6 max-w-2xl mx-auto">
|
|
<h3 class="text-lg font-medium text-white mb-4">Stay Informed</h3>
|
|
<div class="flex flex-col sm:flex-row gap-2">
|
|
<input
|
|
v-model="email"
|
|
type="email"
|
|
placeholder="Enter your email address"
|
|
class="flex-1 px-3 py-2 text-sm rounded-md border border-gray-300 focus:ring-2 focus:ring-green-500"
|
|
/>
|
|
<button
|
|
@click="subscribe"
|
|
class="px-6 py-3 rounded-lg font-semibold text-white transition-colors"
|
|
style="background-color: #6b9080;"
|
|
@mouseover="$event.target.style.backgroundColor = '#5a8070'"
|
|
@mouseout="$event.target.style.backgroundColor = '#6b9080'"
|
|
>
|
|
Subscribe to Updates
|
|
</button>
|
|
</div>
|
|
<p v-if="subscribeMessage" class="mt-3 text-green-300">{{ subscribeMessage }}</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Main Content -->
|
|
<div class="max-w-4xl mx-auto px-4 py-12">
|
|
<!-- Case Information Card -->
|
|
<div class="bg-white rounded-lg shadow-lg p-8 mb-8">
|
|
<h2 class="text-2xl font-bold text-center mb-6">Case Information</h2>
|
|
|
|
<div class="space-y-4">
|
|
<div class="text-center">
|
|
<p class="text-sm text-gray-600 mb-1">Case Title</p>
|
|
<p class="text-lg font-semibold">{{ caseInfo.title }}</p>
|
|
</div>
|
|
|
|
<div class="text-center">
|
|
<p class="text-sm text-gray-600 mb-1">Status</p>
|
|
<span class="inline-block px-4 py-2 rounded-full text-sm font-semibold"
|
|
style="background-color: #d1fae5; color: #10b981;">
|
|
{{ caseInfo.status }}
|
|
</span>
|
|
</div>
|
|
|
|
<div class="text-center">
|
|
<p class="text-sm text-gray-600 mb-1">Last Updated</p>
|
|
<p class="text-lg font-semibold">{{ caseInfo.lastUpdated }}</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Court Docket Entries -->
|
|
<div class="bg-white rounded-lg shadow-lg p-8">
|
|
<h2 class="text-2xl font-bold text-center mb-4">Court Docket Entries</h2>
|
|
<p class="text-center text-gray-600 mb-8">
|
|
Chronological record of all court filings and proceedings
|
|
</p>
|
|
|
|
<div v-if="docketEntries.length === 0" class="text-center text-gray-500 py-8">
|
|
No docket entries yet.
|
|
</div>
|
|
|
|
<div v-else class="space-y-4">
|
|
<div
|
|
v-for="(entry, index) in docketEntries"
|
|
:key="entry.id"
|
|
class="border rounded-lg overflow-hidden transition-shadow hover:shadow-md cursor-pointer"
|
|
@click="toggleEntry(entry.id)"
|
|
>
|
|
<div class="p-4 flex items-start gap-4">
|
|
<!-- Entry Number Badge -->
|
|
<div class="flex-shrink-0 w-10 h-10 rounded-full flex items-center justify-center text-white font-bold"
|
|
style="background-color: #3f4a5c;">
|
|
{{ docketEntries.length - index }}
|
|
</div>
|
|
|
|
<!-- Entry Content -->
|
|
<div class="flex-1 min-w-0">
|
|
<p class="text-sm text-gray-500 mb-1">{{ entry.date }}</p>
|
|
<h3 class="text-lg font-semibold text-gray-900 mb-2">{{ entry.title }}</h3>
|
|
|
|
<!-- Expanded Content -->
|
|
<div v-if="expandedEntry === entry.id" class="mt-4 space-y-4">
|
|
<div>
|
|
<p class="font-semibold text-gray-700 mb-2">Brief Summary:</p>
|
|
<p class="text-gray-600">{{ entry.summary }}</p>
|
|
</div>
|
|
|
|
<div v-if="entry.documents.length > 0">
|
|
<button
|
|
v-for="doc in entry.documents"
|
|
:key="doc.id"
|
|
@click="openDocument(doc, $event)"
|
|
class="inline-block px-4 py-2 rounded-lg text-white font-semibold mr-2 mb-2 transition-colors"
|
|
style="background-color: #6b9080;"
|
|
@mouseover="$event.target.style.backgroundColor = '#5a8070'"
|
|
@mouseout="$event.target.style.backgroundColor = '#6b9080'"
|
|
>
|
|
📄 {{ doc.title }}
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Expand/Collapse Icon -->
|
|
<div class="flex-shrink-0">
|
|
<svg
|
|
class="w-6 h-6 text-gray-400 transition-transform"
|
|
:class="{ 'rotate-180': expandedEntry === entry.id }"
|
|
fill="none"
|
|
stroke="currentColor"
|
|
viewBox="0 0 24 24"
|
|
>
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7" />
|
|
</svg>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Footer -->
|
|
<footer class="py-8 px-4 text-center border-t" style="background-color: rgba(57, 64, 83, 0.95); border-color: #4E4A59;">
|
|
<span class="text-gray-400">Designed by </span>
|
|
<a href="http://deafgain.org" target="_blank" rel="noopener noreferrer"
|
|
class="text-yellow-400 hover:text-yellow-500 transition-colors">
|
|
DeafGain LLC
|
|
</a>
|
|
</footer>
|
|
|
|
<!-- PDF Viewer Modal -->
|
|
<PDFViewer
|
|
v-if="selectedDocument"
|
|
:is-open="!!selectedDocument"
|
|
:document-title="selectedDocument.title"
|
|
:document-url="selectedDocument.url"
|
|
@close="closeViewer"
|
|
/>
|
|
</div>
|
|
</template>
|