Complete adaptation from BukidBountyApp to Philippine barangay governance: - Barangay models: Resident, Household, HouseholdMember, Blotter, BlotterHearing, DocumentRequest, RequestPayment, RequestType, BarangayProject, BarangayBudget - Controllers: ResidentController, HouseholdController, BlotterController, BlotterHearingController, DocumentRequestController, RequestTypeController, ProjectController, BudgetController, QRPHController, AdminConsoleController, UserController, FileController, ChapterController, LoginController - Vue pages: Home, ManageResidents, ResidentProfile, ManageHouseholds, ManageBlotters, BlotterDetail, RequestDocument, ManageDocumentRequests, DocumentRequestDetail, ManageRequestTypes, ManageProjects, BudgetLedger, AdminConsole - Barangay roles: PunongBarangay, Kagawad, Secretary, Treasurer, SK, Tanod, BHW, Staff, Resident - UserPermissions matrix rewritten with barangay-specific permission mappings - VueRouteMap replaced with barangay SPA routes - UserActions enum references corrected across all controllers - Removed all market/cooperative/POS/subscription code and models
189 lines
8.4 KiB
Vue
189 lines
8.4 KiB
Vue
<script setup>
|
|
import { ref, onMounted, computed } from 'vue';
|
|
import { usePageTitle } from '../../composables/Core/usePageTitle';
|
|
import { executeRequest } from '../../utils/executeRequest.js';
|
|
import { navigate } from '../../utils/navigate.js';
|
|
import { useAuth } from '../../composables/Core/useAuth.js';
|
|
|
|
usePageTitle('Document Request Detail');
|
|
|
|
const { isBarangayStaff } = useAuth();
|
|
|
|
const request = ref(null);
|
|
const loading = ref(false);
|
|
|
|
const urlParams = new URLSearchParams(window.location.search);
|
|
const target = urlParams.get('target');
|
|
|
|
const statusColors = {
|
|
PENDING: 'bg-yellow-100 text-yellow-700',
|
|
PAYMENT_PENDING: 'bg-orange-100 text-orange-700',
|
|
PAID: 'bg-blue-100 text-blue-700',
|
|
PROCESSING:'bg-indigo-100 text-indigo-700',
|
|
READY: 'bg-teal-100 text-teal-700',
|
|
CLAIMED: 'bg-green-100 text-green-700',
|
|
CANCELLED: 'bg-red-100 text-red-700',
|
|
};
|
|
|
|
const statusLabels = {
|
|
PENDING: 'Pending',
|
|
PAYMENT_PENDING: 'Awaiting Payment',
|
|
PAID: 'Paid',
|
|
PROCESSING:'Processing',
|
|
READY: 'Ready for Pickup',
|
|
CLAIMED: 'Claimed',
|
|
CANCELLED: 'Cancelled',
|
|
};
|
|
|
|
const getStatus = computed(() => request.value?.status?.value ?? request.value?.status ?? '');
|
|
|
|
const loadRequest = async () => {
|
|
loading.value = true;
|
|
const res = await executeRequest('/admin/documents/show', 'POST', { target });
|
|
if (res.success) request.value = res.data;
|
|
loading.value = false;
|
|
};
|
|
|
|
const confirmPayment = async () => {
|
|
if (!confirm('Confirm payment received?')) return;
|
|
const res = await executeRequest('/admin/documents/confirm-payment', 'POST', {
|
|
target,
|
|
amount_paid: request.value?.base_fee ?? 0,
|
|
payment_method: 'CASH',
|
|
});
|
|
if (res.success) loadRequest();
|
|
};
|
|
|
|
const markReady = async () => {
|
|
if (!confirm('Mark as ready for pickup?')) return;
|
|
const res = await executeRequest('/admin/documents/mark-ready', 'POST', { target });
|
|
if (res.success) loadRequest();
|
|
};
|
|
|
|
const markClaimed = async () => {
|
|
if (!confirm('Mark as claimed by resident?')) return;
|
|
const res = await executeRequest('/admin/documents/mark-claimed', 'POST', { target });
|
|
if (res.success) loadRequest();
|
|
};
|
|
|
|
const cancel = async () => {
|
|
if (!confirm('Cancel this request?')) return;
|
|
const res = await executeRequest('/documents/cancel', 'POST', { target });
|
|
if (res.success) loadRequest();
|
|
};
|
|
|
|
onMounted(loadRequest);
|
|
</script>
|
|
|
|
<template>
|
|
<div class="p-4 max-w-3xl mx-auto">
|
|
<button @click="navigate(isBarangayStaff ? '/barangay/managedocumentrequests' : '/barangay/requestdocument')"
|
|
class="text-sm text-blue-500 mb-4 inline-flex items-center gap-1">
|
|
← Back
|
|
</button>
|
|
|
|
<div v-if="loading" class="text-center py-8 text-gray-400">Loading...</div>
|
|
|
|
<div v-else-if="request">
|
|
<!-- Header card -->
|
|
<div class="bg-white rounded-xl shadow p-5 mb-4">
|
|
<div class="flex justify-between items-start">
|
|
<div>
|
|
<div class="flex items-center gap-2 mb-1">
|
|
<span class="font-mono font-semibold text-blue-600 text-lg">{{ request.request_no }}</span>
|
|
<span :class="`text-xs px-2 py-0.5 rounded-full font-medium ${statusColors[getStatus] ?? 'bg-gray-100'}`">
|
|
{{ statusLabels[getStatus] ?? getStatus }}
|
|
</span>
|
|
</div>
|
|
<p class="text-xl font-bold text-gray-800">{{ request.document_type?.name ?? request.request_type }}</p>
|
|
<p class="text-sm text-gray-500 mt-1">Submitted: {{ request.created_at }}</p>
|
|
</div>
|
|
<div class="text-right">
|
|
<div class="text-2xl font-bold text-green-600">
|
|
{{ request.base_fee > 0 ? `₱${Number(request.base_fee).toFixed(2)}` : 'Free' }}
|
|
</div>
|
|
<div class="text-xs text-gray-400">Fee</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Requester info -->
|
|
<div class="bg-white rounded-xl shadow p-5 mb-4">
|
|
<h2 class="font-semibold text-gray-700 mb-3 border-b pb-2">Requester Information</h2>
|
|
<div class="grid grid-cols-2 gap-3 text-sm">
|
|
<div><span class="text-gray-400">Name:</span> {{ request.resident?.fullname ?? request.requester_name ?? '—' }}</div>
|
|
<div><span class="text-gray-400">Purok:</span> {{ request.resident?.purok ?? '—' }}</div>
|
|
<div class="col-span-2"><span class="text-gray-400">Purpose:</span> {{ request.purpose ?? '—' }}</div>
|
|
<div v-if="request.remarks" class="col-span-2">
|
|
<span class="text-gray-400">Remarks:</span> {{ request.remarks }}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Payment history -->
|
|
<div v-if="request.payments && request.payments.length" class="bg-white rounded-xl shadow p-5 mb-4">
|
|
<h2 class="font-semibold text-gray-700 mb-3 border-b pb-2">Payment Records</h2>
|
|
<div v-for="p in request.payments" :key="p.id" class="flex justify-between text-sm py-1 border-b last:border-0">
|
|
<span>{{ p.payment_method }} — {{ p.created_at }}</span>
|
|
<span class="font-semibold text-green-600">₱{{ Number(p.amount_paid).toFixed(2) }}</span>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Staff actions -->
|
|
<div v-if="isBarangayStaff" class="bg-white rounded-xl shadow p-5">
|
|
<h2 class="font-semibold text-gray-700 mb-3">Actions</h2>
|
|
<div class="flex flex-wrap gap-2">
|
|
<button
|
|
v-if="['PENDING','PAYMENT_PENDING'].includes(getStatus)"
|
|
@click="confirmPayment"
|
|
class="btn-sm bg-green-500 text-white">
|
|
Confirm Payment
|
|
</button>
|
|
<button
|
|
v-if="['PAID','PROCESSING'].includes(getStatus)"
|
|
@click="markReady"
|
|
class="btn-sm bg-teal-500 text-white">
|
|
Mark Ready for Pickup
|
|
</button>
|
|
<button
|
|
v-if="getStatus === 'READY'"
|
|
@click="markClaimed"
|
|
class="btn-sm bg-blue-500 text-white">
|
|
Mark Claimed
|
|
</button>
|
|
<button
|
|
v-if="!['CLAIMED','CANCELLED'].includes(getStatus)"
|
|
@click="cancel"
|
|
class="btn-sm bg-red-100 text-red-600">
|
|
Cancel Request
|
|
</button>
|
|
<p v-if="['CLAIMED','CANCELLED'].includes(getStatus)" class="text-sm text-gray-400">
|
|
This request is {{ statusLabels[getStatus].toLowerCase() }}. No further actions available.
|
|
</p>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Resident view: status tracker -->
|
|
<div v-else class="bg-white rounded-xl shadow p-5">
|
|
<h2 class="font-semibold text-gray-700 mb-3">Request Progress</h2>
|
|
<div class="flex items-center gap-1 text-xs">
|
|
<template v-for="(step, i) in ['PENDING','PAID','PROCESSING','READY','CLAIMED']" :key="step">
|
|
<div :class="`px-2 py-1 rounded font-medium ${['PENDING','PAYMENT_PENDING','PAID','PROCESSING','READY','CLAIMED'].indexOf(getStatus) >= i ? 'bg-blue-500 text-white' : 'bg-gray-100 text-gray-400'}`">
|
|
{{ statusLabels[step] ?? step }}
|
|
</div>
|
|
<div v-if="i < 4" class="flex-1 h-0.5 bg-gray-200"></div>
|
|
</template>
|
|
</div>
|
|
<p v-if="getStatus === 'READY'" class="mt-3 text-sm text-teal-600 font-medium">
|
|
Your document is ready for pickup at the barangay hall.
|
|
</p>
|
|
<p v-else-if="getStatus === 'CANCELLED'" class="mt-3 text-sm text-red-500">
|
|
This request has been cancelled.
|
|
</p>
|
|
</div>
|
|
</div>
|
|
|
|
<p v-else class="text-center text-gray-400 py-8">Request not found.</p>
|
|
</div>
|
|
</template>
|