mad-lawsuit/resources/js/Pages/Admin/Subscribers/Index.vue
TheMaddax b7125cf2b7 Phase 4: Production deployment configuration
- 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
2025-12-17 19:12:32 -07:00

224 lines
11 KiB
Vue
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<script setup lang="ts">
import { Head, Link, router } from '@inertiajs/vue3';
interface Subscriber {
id: number;
email: string;
is_active: boolean;
created_at: string;
}
interface Pagination {
current_page: number;
last_page: number;
per_page: number;
total: number;
}
interface Stats {
total: number;
active: number;
inactive: number;
}
interface Props {
subscribers: Subscriber[];
pagination: Pagination;
stats: Stats;
}
const props = defineProps<Props>();
const deactivateSubscriber = (id: number, email: string) => {
if (confirm(`Are you sure you want to deactivate ${email}?`)) {
router.delete(route('admin.subscribers.destroy', id));
}
};
</script>
<template>
<div class="min-h-screen bg-gray-100">
<Head title="Manage Subscribers" />
<!-- Header -->
<header class="bg-white shadow">
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-6">
<div class="flex justify-between items-center">
<div>
<h1 class="text-3xl font-bold text-gray-900">
Manage Subscribers
</h1>
<p class="text-sm text-gray-600 mt-1">
{{ props.stats.active }} active {{ props.stats.inactive }} inactive {{ props.stats.total }} total
</p>
</div>
<Link
:href="route('admin.dashboard')"
class="px-4 py-2 text-sm text-gray-700 hover:text-gray-900 transition-colors"
>
Back to Dashboard
</Link>
</div>
</div>
</header>
<!-- Main Content -->
<main class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
<!-- Stats Cards -->
<div class="grid grid-cols-1 md:grid-cols-3 gap-6 mb-8">
<div class="bg-white rounded-lg shadow p-6">
<div class="flex items-center justify-between">
<div>
<p class="text-sm font-medium text-gray-600">Total Subscribers</p>
<p class="text-3xl font-bold text-gray-900 mt-2">
{{ props.stats.total }}
</p>
</div>
<div class="p-3 bg-blue-100 rounded-full">
<svg class="w-8 h-8 text-blue-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17 20h5v-2a3 3 0 00-5.356-1.857M17 20H7m10 0v-2c0-.656-.126-1.283-.356-1.857M7 20H2v-2a3 3 0 015.356-1.857M7 20v-2c0-.656.126-1.283.356-1.857m0 0a5.002 5.002 0 019.288 0M15 7a3 3 0 11-6 0 3 3 0 016 0zm6 3a2 2 0 11-4 0 2 2 0 014 0zM7 10a2 2 0 11-4 0 2 2 0 014 0z" />
</svg>
</div>
</div>
</div>
<div class="bg-white rounded-lg shadow p-6">
<div class="flex items-center justify-between">
<div>
<p class="text-sm font-medium text-gray-600">Active Subscribers</p>
<p class="text-3xl font-bold text-green-600 mt-2">
{{ props.stats.active }}
</p>
</div>
<div class="p-3 bg-green-100 rounded-full">
<svg class="w-8 h-8 text-green-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" />
</svg>
</div>
</div>
</div>
<div class="bg-white rounded-lg shadow p-6">
<div class="flex items-center justify-between">
<div>
<p class="text-sm font-medium text-gray-600">Inactive Subscribers</p>
<p class="text-3xl font-bold text-gray-400 mt-2">
{{ props.stats.inactive }}
</p>
</div>
<div class="p-3 bg-gray-100 rounded-full">
<svg class="w-8 h-8 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M18.364 18.364A9 9 0 005.636 5.636m12.728 12.728A9 9 0 015.636 5.636m12.728 12.728L5.636 5.636" />
</svg>
</div>
</div>
</div>
</div>
<!-- Subscribers Table -->
<div class="bg-white rounded-lg shadow">
<div class="overflow-x-auto">
<table class="min-w-full divide-y divide-gray-200">
<thead class="bg-gray-50">
<tr>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
Email
</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
Status
</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
Subscribed On
</th>
<th class="px-6 py-3 text-right text-xs font-medium text-gray-500 uppercase tracking-wider">
Actions
</th>
</tr>
</thead>
<tbody class="bg-white divide-y divide-gray-200">
<tr
v-for="subscriber in props.subscribers"
:key="subscriber.id"
class="hover:bg-gray-50 transition-colors"
>
<td class="px-6 py-4 text-sm font-medium text-gray-900">
{{ subscriber.email }}
</td>
<td class="px-6 py-4 whitespace-nowrap text-sm">
<span
v-if="subscriber.is_active"
class="px-2 py-1 text-xs font-medium text-green-700 bg-green-100 rounded-full"
>
Active
</span>
<span
v-else
class="px-2 py-1 text-xs font-medium text-gray-700 bg-gray-100 rounded-full"
>
Inactive
</span>
</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-600">
{{ subscriber.created_at }}
</td>
<td class="px-6 py-4 whitespace-nowrap text-right text-sm font-medium">
<button
v-if="subscriber.is_active"
@click="deactivateSubscriber(subscriber.id, subscriber.email)"
class="text-red-600 hover:text-red-900 transition-colors"
>
Deactivate
</button>
<span v-else class="text-gray-400">
Deactivated
</span>
</td>
</tr>
<tr v-if="props.subscribers.length === 0">
<td colspan="4" class="px-6 py-12 text-center text-gray-500">
No subscribers found.
</td>
</tr>
</tbody>
</table>
</div>
<!-- Pagination -->
<div v-if="props.pagination.last_page > 1" class="px-6 py-4 border-t border-gray-200">
<div class="flex items-center justify-between">
<div class="text-sm text-gray-700">
Showing page {{ props.pagination.current_page }} of {{ props.pagination.last_page }}
</div>
<div class="flex gap-2">
<Link
v-if="props.pagination.current_page > 1"
:href="route('admin.subscribers.index', { page: props.pagination.current_page - 1 })"
class="px-3 py-1 text-sm bg-white border border-gray-300 rounded-md hover:bg-gray-50 transition-colors"
>
Previous
</Link>
<Link
v-if="props.pagination.current_page < props.pagination.last_page"
:href="route('admin.subscribers.index', { page: props.pagination.current_page + 1 })"
class="px-3 py-1 text-sm bg-white border border-gray-300 rounded-md hover:bg-gray-50 transition-colors"
>
Next
</Link>
</div>
</div>
</div>
</div>
<!-- Info Box -->
<div class="mt-6 bg-blue-50 border border-blue-200 rounded-lg p-4">
<h3 class="text-sm font-medium text-blue-900 mb-2">
About Subscriber Management
</h3>
<p class="text-sm text-blue-700">
Deactivating a subscriber will prevent them from receiving future email notifications.
They can resubscribe at any time through the public website.
</p>
</div>
</main>
</div>
</template>