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
138 lines
5.9 KiB
Vue
138 lines
5.9 KiB
Vue
<script setup>
|
|
import { ref, onMounted } from 'vue';
|
|
import { usePageTitle } from '../../composables/Core/usePageTitle';
|
|
import { executeRequest } from '../../utils/executeRequest.js';
|
|
import { navigate } from '../../utils/navigate.js';
|
|
|
|
usePageTitle('Request a Document');
|
|
|
|
const requestTypes = ref([]);
|
|
const myRequests = ref([]);
|
|
const loading = ref(false);
|
|
const submitting = ref(false);
|
|
|
|
const form = ref({ request_type_id: '', purpose: '' });
|
|
const selectedType = ref(null);
|
|
const submitted = ref(false);
|
|
const submittedDoc = ref(null);
|
|
|
|
const statusLabels = {
|
|
DRAFT: 'Draft', PENDING_PAYMENT: 'Pending Payment', PAID: 'Paid',
|
|
PROCESSING: 'Processing', READY: 'Ready for Pickup', CLAIMED: 'Claimed', CANCELLED: 'Cancelled',
|
|
};
|
|
|
|
const loadData = async () => {
|
|
loading.value = true;
|
|
const [typesRes, myRes] = await Promise.all([
|
|
executeRequest('/request-types'),
|
|
executeRequest('/documents/my'),
|
|
]);
|
|
if (typesRes.success) requestTypes.value = typesRes.data;
|
|
if (myRes.success) myRequests.value = myRes.data;
|
|
loading.value = false;
|
|
};
|
|
|
|
const onTypeSelect = () => {
|
|
selectedType.value = requestTypes.value.find(t => t.id == form.value.request_type_id);
|
|
};
|
|
|
|
const submit = async () => {
|
|
submitting.value = true;
|
|
const res = await executeRequest('/documents/submit', 'POST', form.value);
|
|
if (res.success) {
|
|
submittedDoc.value = res.data;
|
|
submitted.value = true;
|
|
loadData();
|
|
}
|
|
submitting.value = false;
|
|
};
|
|
|
|
const resetForm = () => {
|
|
submitted.value = false;
|
|
submittedDoc.value = null;
|
|
form.value = { request_type_id: '', purpose: '' };
|
|
selectedType.value = null;
|
|
};
|
|
|
|
const getStatus = (r) => r.status?.value ?? r.status;
|
|
|
|
onMounted(loadData);
|
|
</script>
|
|
|
|
<template>
|
|
<div class="p-4 max-w-3xl mx-auto">
|
|
<div class="mb-6">
|
|
<h1 class="text-2xl font-bold">Request a Document</h1>
|
|
<p class="text-gray-500 text-sm">Submit a request for a barangay certificate or clearance.</p>
|
|
</div>
|
|
|
|
<div v-if="loading" class="text-center py-8 text-gray-400">Loading...</div>
|
|
|
|
<div v-else-if="!submitted">
|
|
<div class="bg-white rounded-xl shadow p-5 mb-6">
|
|
<h2 class="font-semibold text-gray-700 mb-3">Select Document Type</h2>
|
|
<div class="grid grid-cols-1 sm:grid-cols-2 gap-3 mb-4">
|
|
<div
|
|
v-for="t in requestTypes"
|
|
:key="t.id"
|
|
@click="form.request_type_id = t.id; onTypeSelect()"
|
|
:class="`border rounded-lg p-3 cursor-pointer transition ${form.request_type_id == t.id ? 'border-blue-500 bg-blue-50' : 'border-gray-200 hover:border-gray-300'}`"
|
|
>
|
|
<div class="font-medium text-sm">{{ t.name }}</div>
|
|
<div class="text-xs text-gray-500 mt-1">{{ t.description }}</div>
|
|
<div class="mt-2 flex justify-between text-xs">
|
|
<span class="font-semibold text-green-600">{{ t.base_fee > 0 ? `₱${t.base_fee}` : 'Free' }}</span>
|
|
<span class="text-gray-400">{{ t.processing_days }} day(s)</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div v-if="selectedType" class="mt-2">
|
|
<label class="label">Purpose / Reason *</label>
|
|
<textarea v-model="form.purpose" class="input h-20" :placeholder="`State your purpose for requesting ${selectedType.name}...`"></textarea>
|
|
</div>
|
|
|
|
<div class="flex justify-end mt-4">
|
|
<button
|
|
@click="submit"
|
|
:disabled="!form.request_type_id || !form.purpose || submitting"
|
|
class="btn-primary disabled:opacity-50 disabled:cursor-not-allowed"
|
|
>
|
|
{{ submitting ? 'Submitting...' : 'Submit Request' }}
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div v-else class="bg-white rounded-xl shadow p-5 mb-6">
|
|
<div class="text-center">
|
|
<div class="text-4xl mb-2">✅</div>
|
|
<h2 class="text-xl font-bold text-green-600">Request Submitted!</h2>
|
|
<p class="text-gray-600 mt-1">Request No: <span class="font-mono font-bold">{{ submittedDoc?.request_no }}</span></p>
|
|
<p class="text-gray-500 text-sm mt-2">
|
|
{{ submittedDoc?.fee_amount > 0 ? `Please proceed to the barangay hall to pay ₱${submittedDoc.fee_amount}.` : 'Your request is free and will be processed shortly.' }}
|
|
</p>
|
|
<button @click="resetForm" class="btn-primary mt-4">Request Another</button>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- My Requests -->
|
|
<div class="bg-white rounded-xl shadow p-5">
|
|
<h2 class="font-semibold text-gray-700 mb-3">My Requests</h2>
|
|
<div v-if="myRequests.length">
|
|
<div v-for="r in myRequests" :key="r.id" class="border-b py-3 flex justify-between items-center">
|
|
<div>
|
|
<div class="font-medium text-sm">{{ r.request_type?.name }}</div>
|
|
<div class="text-xs text-gray-400 font-mono">{{ r.request_no }}</div>
|
|
<div class="text-xs text-gray-500 mt-0.5">{{ r.created_at?.slice(0, 10) }}</div>
|
|
</div>
|
|
<span :class="`px-2 py-1 rounded-full text-xs font-medium ${getStatus(r) === 'CLAIMED' ? 'bg-green-100 text-green-700' : getStatus(r) === 'READY' ? 'bg-teal-100 text-teal-700' : 'bg-gray-100 text-gray-700'}`">
|
|
{{ statusLabels[getStatus(r)] ?? getStatus(r) }}
|
|
</span>
|
|
</div>
|
|
</div>
|
|
<p v-else class="text-gray-400 text-sm">No previous requests.</p>
|
|
</div>
|
|
</div>
|
|
</template>
|