Files
BarangaySystem/resources/js/Pages/CooperativeMemberRegister.vue
2026-06-06 18:43:00 +08:00

494 lines
24 KiB
Vue

<template>
<div class="animate-fade-in pb-5">
<!-- Header -->
<div class="tf-container mb-4">
<div class="d-flex align-items-center justify-content-between mb-3">
<button @click="navigate({ page: 'CooperativeDetail', props: { target: target } })"
class="btn btn-link text-decoration-none p-0 d-flex align-items-center text-muted">
<i class="fas fa-arrow-left me-2"></i>
<span>Back to Cooperative</span>
</button>
</div>
<div v-if="loadingCoop" class="text-center py-5">
<div class="spinner-border text-primary" role="status">
<span class="visually-hidden">Loading...</span>
</div>
</div>
<div v-else-if="cooperative" class="coop-header-card p-4 rounded-20 shadow-sm mb-4 position-relative overflow-hidden">
<div class="header-overlay"></div>
<div class="position-relative z-1">
<div class="badge bg-white text-primary rounded-pill px-3 py-1 mb-2 mb-md-3 smallest fw-bold shadow-sm">
{{ cooperative.cooperative_type || 'COOPERATIVE' }}
</div>
<h1 class="h2 fw-black text-white mb-2">{{ cooperative.name }}</h1>
<div class="d-flex flex-wrap gap-3 text-white-50 small">
<div v-if="cooperative.address" class="d-flex align-items-center">
<i class="fas fa-map-marker-alt me-2"></i>
{{ cooperative.address }}
</div>
<div v-if="cooperative.registration_number" class="d-flex align-items-center">
<i class="fas fa-id-card me-2"></i>
Reg: {{ cooperative.registration_number }}
</div>
</div>
</div>
</div>
</div>
<!-- Registration Form -->
<div class="tf-container">
<div v-if="alreadyMember" class="alert alert-info rounded-15 border-0 shadow-sm mb-4 d-flex align-items-center p-3 animate-fade-in">
<div class="icon-circle bg-info text-white me-3 p-2 rounded-circle d-flex align-items-center justify-content-center" style="width: 40px; height: 40px;">
<i class="fas fa-info-circle"></i>
</div>
<div>
<h6 class="mb-0 fw-bold">You are already a member</h6>
<p class="mb-0 small opacity-75">You have already registered as a member of this cooperative.</p>
</div>
</div>
<CardSimple title="Membership Information" icon="fas fa-user-tag" class="mb-4 rounded-20 border-0 shadow-sm">
<div class="row g-3">
<div class="col-md-6 mb-3">
<label class="form-label small fw-bold text-muted">Membership Type</label>
<select v-model="form.membership_type" class="form-select premium-select" :disabled="alreadyMember">
<option value="">Select Type</option>
<option value="REGULAR">REGULAR</option>
<option value="ASSOCIATE">ASSOCIATE</option>
<option value="HONORARY">HONORARY</option>
<option value="LABORATORY">LABORATORY</option>
</select>
</div>
<div class="col-md-6 mb-3">
<label class="form-label small fw-bold text-muted">Membership Level</label>
<select v-model="form.membership_level" class="form-select premium-select" :disabled="alreadyMember">
<option value="">Select Level</option>
<option value="PRIMARY">PRIMARY</option>
<option value="SECONDARY">SECONDARY</option>
<option value="TERTIARY">TERTIARY</option>
</select>
</div>
<div class="col-md-6 mb-3">
<label class="form-label small fw-bold text-muted">Year Membership Began</label>
<input type="number" v-model="form.year_beginning" class="form-control premium-input"
placeholder="e.g. 2024" :disabled="alreadyMember" />
</div>
</div>
</CardSimple>
<CardSimple title="Position Details (Optional)" icon="fas fa-briefcase" class="mb-4 rounded-20 border-0 shadow-sm">
<div class="row g-3">
<div class="col-md-6 mb-3">
<label class="form-label small fw-bold text-muted">Officer Position</label>
<input type="text" v-model="form.officer_position" class="form-control premium-input"
placeholder="e.g. Board Member" :disabled="alreadyMember" />
</div>
<div class="col-md-6 mb-3">
<label class="form-label small fw-bold text-muted">Officer Level</label>
<select v-model="form.officer_level" class="form-select premium-select" :disabled="alreadyMember">
<option value="">Select Level</option>
<option value="PRIMARY">PRIMARY</option>
<option value="SECONDARY">SECONDARY</option>
<option value="TERTIARY">TERTIARY</option>
</select>
</div>
<div class="col-md-6 mb-3">
<label class="form-label small fw-bold text-muted">Concurrent Position</label>
<input type="text" v-model="form.concurrent_position" class="form-control premium-input"
placeholder="e.g. Treasurer" :disabled="alreadyMember" />
</div>
<div class="col-md-6 mb-3">
<label class="form-label small fw-bold text-muted">Concurrent Level</label>
<select v-model="form.concurrent_level" class="form-select premium-select" :disabled="alreadyMember">
<option value="">Select Level</option>
<option value="PRIMARY">PRIMARY</option>
<option value="SECONDARY">SECONDARY</option>
<option value="TERTIARY">TERTIARY</option>
</select>
</div>
<div class="col-md-12 mb-3">
<label class="form-label small fw-bold text-muted">Cooperative Position</label>
<input type="text" v-model="form.cooperative_position" class="form-control premium-input"
placeholder="e.g. Chairperson" :disabled="alreadyMember" />
</div>
</div>
</CardSimple>
<CardSimple title="Classification" icon="fas fa-tags" class="mb-4 rounded-20 border-0 shadow-sm">
<div class="row g-3">
<div class="col-12 mb-3">
<label class="form-label small fw-bold text-muted">Priority Sector <span class="fw-normal">(select all that apply)</span></label>
<div class="row g-2 mt-1">
<div class="col-6 col-md-4" v-for="s in prioritySectors" :key="s">
<div class="form-check">
<input class="form-check-input" type="checkbox" :id="'ps-reg-' + s" :value="s" v-model="form.priority_sector" :disabled="alreadyMember">
<label class="form-check-label small" :for="'ps-reg-' + s">{{ s }}</label>
</div>
</div>
</div>
</div>
<div class="col-md-6 mb-3">
<label class="form-label small fw-bold text-muted">Common Bond</label>
<select v-model="form.common_bond" class="form-select premium-select" :disabled="alreadyMember">
<option value=""> Select </option>
<option v-for="b in commonBonds" :key="b" :value="b">{{ b }}</option>
</select>
</div>
<div class="col-12">
<label class="form-label small fw-bold text-muted d-block mb-2">Vulnerability Classification</label>
<div class="row g-2">
<div class="col-6 col-md-4" v-for="opt in vulnerabilityOptions" :key="opt">
<div class="form-check">
<input class="form-check-input" type="checkbox" :id="'vuln-'+opt"
:value="opt" v-model="form.vulnerability_classifications" :disabled="alreadyMember" />
<label class="form-check-label small" :for="'vuln-'+opt">{{ opt }}</label>
</div>
</div>
</div>
</div>
</div>
</CardSimple>
<CardSimple title="Government Program Participation" icon="fas fa-list-check" class="mb-4 rounded-20 border-0 shadow-sm">
<div class="row g-2 mb-3">
<div class="col-6 col-md-4" v-for="prog in programOptions" :key="prog">
<div class="form-check">
<input class="form-check-input" type="checkbox" :id="'prog-'+prog"
:value="prog" v-model="form.program_participation" :disabled="alreadyMember" />
<label class="form-check-label small" :for="'prog-'+prog">{{ prog }}</label>
</div>
</div>
</div>
<!-- SLP -->
<template v-if="form.program_participation.includes('SLP')">
<hr class="my-3" />
<p class="small fw-bold text-success mb-2"><i class="fas fa-seedling me-1"></i>SLP Details</p>
<div class="row g-3 mb-3">
<div class="col-md-6">
<label class="form-label small fw-bold text-muted">SLP Track</label>
<select v-model="form.slp_track" class="form-select premium-select" :disabled="alreadyMember">
<option value=""> Select </option>
<option value="MD">Microenterprise Development (MD)</option>
<option value="EF">Employment Facilitation (EF)</option>
</select>
</div>
<div class="col-md-6">
<label class="form-label small fw-bold text-muted">SLPA / Association Name</label>
<input type="text" v-model="form.slp_association_name" class="form-control premium-input" :disabled="alreadyMember" />
</div>
<div class="col-md-6">
<label class="form-label small fw-bold text-muted">Listahanan (NHTO) ID</label>
<input type="text" v-model="form.listahanan_id" class="form-control premium-input" :disabled="alreadyMember" />
</div>
<div class="col-md-6">
<label class="form-label small fw-bold text-muted">4Ps Household ID</label>
<input type="text" v-model="form.fourtps_household_id" class="form-control premium-input" :disabled="alreadyMember" />
</div>
</div>
</template>
<!-- TUPAD -->
<template v-if="form.program_participation.includes('TUPAD')">
<hr class="my-3" />
<p class="small fw-bold text-warning mb-2"><i class="fas fa-hard-hat me-1"></i>TUPAD Details</p>
<div class="row g-3 mb-3">
<div class="col-12">
<label class="form-label small fw-bold text-muted">Beneficiary Category</label>
<select v-model="form.tupad_category" class="form-select premium-select" :disabled="alreadyMember">
<option value=""> Select </option>
<option v-for="c in tupadCategories" :key="c" :value="c">{{ c }}</option>
</select>
</div>
<div class="col-md-6">
<label class="form-label small fw-bold text-muted">Insurance Beneficiary Name</label>
<input type="text" v-model="form.tupad_insurance_beneficiary_name" class="form-control premium-input" :disabled="alreadyMember" />
</div>
<div class="col-md-6">
<label class="form-label small fw-bold text-muted">Relationship</label>
<input type="text" v-model="form.tupad_insurance_beneficiary_relation" class="form-control premium-input" placeholder="e.g. Spouse, Child" :disabled="alreadyMember" />
</div>
</div>
</template>
<!-- OSEC/NSRP -->
<template v-if="form.program_participation.includes('OSEC/NSRP')">
<hr class="my-3" />
<p class="small fw-bold text-primary mb-2"><i class="fas fa-briefcase me-1"></i>OSEC / NSRP Employment Profile</p>
<div class="row g-3 mb-3">
<div class="col-md-6">
<label class="form-label small fw-bold text-muted">Employment Status</label>
<select v-model="form.employment_status" class="form-select premium-select" :disabled="alreadyMember">
<option value=""> Select </option>
<option v-for="s in employmentStatuses" :key="s" :value="s">{{ s }}</option>
</select>
</div>
<div class="col-md-6">
<label class="form-label small fw-bold text-muted">Preferred Occupation</label>
<input type="text" v-model="form.preferred_occupation" class="form-control premium-input" placeholder="e.g. Farmer, Welder" :disabled="alreadyMember" />
</div>
<div class="col-12">
<label class="form-label small fw-bold text-muted d-block mb-2">Technical Skills</label>
<div v-if="!alreadyMember" class="d-flex gap-2 mb-2">
<input v-model="newSkill" type="text" class="form-control premium-input"
placeholder="Add a skill and press +" @keyup.enter="addSkill" />
<button @click="addSkill" class="btn btn-outline-primary rounded-pill px-3">+</button>
</div>
<div class="d-flex flex-wrap gap-1">
<span v-for="(sk, i) in form.nsrp_skills" :key="i"
class="badge bg-primary-subtle text-primary rounded-pill px-3 py-2">
{{ sk }}
<i v-if="!alreadyMember" class="fas fa-times ms-1 cursor-pointer" @click="form.nsrp_skills.splice(i, 1)"></i>
</span>
</div>
</div>
</div>
</template>
</CardSimple>
<CardSimple title="Government ID Numbers" icon="fas fa-id-badge" class="mb-4 rounded-20 border-0 shadow-sm">
<div class="row g-3">
<div class="col-md-4">
<label class="form-label small fw-bold text-muted">PhilSys ID</label>
<input type="text" v-model="form.philsys_id" class="form-control premium-input" placeholder="National ID" :disabled="alreadyMember" />
</div>
<div class="col-md-4">
<label class="form-label small fw-bold text-muted">SSS Number</label>
<input type="text" v-model="form.sss_number" class="form-control premium-input" placeholder="00-0000000-0" :disabled="alreadyMember" />
</div>
<div class="col-md-4">
<label class="form-label small fw-bold text-muted">Pag-IBIG Number</label>
<input type="text" v-model="form.pagibig_number" class="form-control premium-input" placeholder="0000-0000-0000" :disabled="alreadyMember" />
</div>
</div>
</CardSimple>
<CardSimple title="Other Information" icon="fas fa-ellipsis-h" class="mb-4 rounded-20 border-0 shadow-sm">
<div class="mb-3">
<label class="form-label small fw-bold text-muted">Alternative Cooperative Name</label>
<input type="text" v-model="form.cooperative_name_alt" class="form-control premium-input"
placeholder="If the cooperative is known by another name" :disabled="alreadyMember" />
</div>
</CardSimple>
<!-- Submit Button -->
<div class="px-3 px-md-0 mt-5">
<button
@click="handleRegister"
class="btn btn-premium-launch w-100 py-3 rounded-pill shadow-primary-sm d-flex align-items-center justify-content-center gap-2"
:disabled="isSaving || alreadyMember"
>
<span v-if="isSaving" class="spinner-border spinner-border-sm" role="status"></span>
<i v-else class="fas fa-check-circle"></i>
<span class="fw-black">{{ alreadyMember ? 'Already Registered' : 'Confirm Registration' }}</span>
</button>
</div>
</div>
</div>
</template>
<script setup>
import { ref, onMounted } from 'vue';
import axios from 'axios';
import { usePageTitle } from '../composables/Core/usePageTitle';
import { useNavigate } from '../composables/Core/useNavigate';
import { useModal } from '../composables/Core/useModal';
import CardSimple from '../Components/Core/CardSimple.vue';
const props = defineProps({
target: String
});
usePageTitle('Register as Member');
const { navigate } = useNavigate();
const modal = useModal();
const cooperative = ref(null);
const loadingCoop = ref(true);
const isSaving = ref(false);
const alreadyMember = ref(false);
const prioritySectors = ref([]);
const commonBonds = ['Residential', 'Institutional', 'Occupational', 'Associational'];
const employmentStatuses = ['Employed', 'Underemployed', 'Unemployed', 'Self-employed'];
const tupadCategories = ['Underemployed', 'Displaced Worker', 'Senior Citizen (fit to work)', 'PWD', 'Solo Parent', 'Indigenous Person', 'Former Rebel'];
const vulnerabilityOptions = ['Indigenous People (IP)', 'Person with Disability (PWD)', 'Senior Citizen', 'Solo Parent', 'Out-of-School Youth (OSY)', 'Internally Displaced Person (IDP)', 'Distressed OFW', 'Former Rebel'];
const programOptions = ['SLP', 'TUPAD', 'OSEC/NSRP', '4Ps/Pantawid Pamilya', 'Listahanan'];
const newSkill = ref('');
const addSkill = () => {
const s = newSkill.value.trim();
if (s && !form.value.nsrp_skills.includes(s)) form.value.nsrp_skills.push(s);
newSkill.value = '';
};
const form = ref({
membership_type: '',
membership_level: '',
officer_position: '',
officer_level: '',
concurrent_position: '',
concurrent_level: '',
cooperative_name_alt: '',
cooperative_position: '',
year_beginning: '',
// Classification
priority_sector: [],
common_bond: '',
vulnerability_classifications: [],
// Gov IDs
philsys_id: '',
sss_number: '',
pagibig_number: '',
// SLP
slp_track: '',
slp_association_name: '',
listahanan_id: '',
fourtps_household_id: '',
// TUPAD
tupad_category: '',
tupad_insurance_beneficiary_name: '',
tupad_insurance_beneficiary_relation: '',
// OSEC/NSRP
preferred_occupation: '',
nsrp_skills: [],
employment_status: '',
// Programs
program_participation: [],
});
const fetchCooperative = async () => {
loadingCoop.value = true;
try {
const [coopRes, settingsRes] = await Promise.all([
axios.post('/Cooperatives/Get', { hashkey: props.target }),
axios.get('/api/public/system-settings'),
]);
if (coopRes.data.success) {
cooperative.value = coopRes.data.data;
alreadyMember.value = coopRes.data.is_member;
if (alreadyMember.value && coopRes.data.membership) {
const m = coopRes.data.membership;
Object.keys(form.value).forEach(k => {
if (m[k] !== undefined && m[k] !== null) form.value[k] = m[k];
});
}
}
if (settingsRes.data?.priority_sectors) {
prioritySectors.value = settingsRes.data.priority_sectors;
}
} catch (error) {
console.error('[CoopRegister] Failed to fetch cooperative:', error);
} finally {
loadingCoop.value = false;
}
};
const handleRegister = async () => {
if (!form.value.membership_type) {
modal.open({ title: 'Missing Info', body: 'Please select a membership type.' });
return;
}
isSaving.value = true;
try {
const response = await axios.post('/Cooperatives/Member/Register', {
cooperative_hash: props.target,
...form.value,
});
if (response.data.success) {
modal.open({
title: 'Registration Successful',
body: 'You have been registered as a member of ' + cooperative.value.name,
onClose: () => navigate({ page: 'CooperativeDetail', props: { target: props.target } })
});
} else {
modal.open({
title: 'Registration Failed',
body: response.data.message || 'Something went wrong.'
});
}
} catch (error) {
modal.open({
title: 'Error',
body: error.response?.data?.message || 'Failed to complete registration. Please try again later.'
});
} finally {
isSaving.value = false;
}
};
onMounted(() => {
fetchCooperative();
});
</script>
<style scoped>
.coop-header-card {
background: linear-gradient(135deg, var(--accent-color), #2d3436);
color: white;
}
.header-overlay {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: url('https://www.transparenttextures.com/patterns/carbon-fibre.png');
opacity: 0.1;
}
.premium-input, .premium-select {
padding: 0.75rem 1rem;
border-radius: 12px;
border: 1px solid var(--border-color);
background-color: var(--bg-secondary);
transition: all 0.3s ease;
}
.premium-input:focus, .premium-select:focus {
border-color: var(--accent-color);
box-shadow: 0 0 0 4px var(--accent-soft);
background-color: var(--bg-primary);
}
.btn-premium-launch {
background: linear-gradient(135deg, var(--accent-color), #4834d4);
color: white;
border: none;
transition: all 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275);
}
.btn-premium-launch:hover:not(:disabled) {
transform: translateY(-2px);
box-shadow: 0 10px 20px rgba(83, 61, 234, 0.3);
}
.btn-premium-launch:active:not(:disabled) {
transform: translateY(1px);
}
.rounded-20 {
border-radius: 20px;
}
.rounded-15 {
border-radius: 15px;
}
:global(.dark-mode) .premium-input,
:global(.dark-mode) .premium-select {
background-color: var(--bg-card);
border-color: rgba(255, 255, 255, 0.1);
}
:global(.dark-mode) .premium-input:focus,
:global(.dark-mode) .premium-select:focus {
background-color: var(--bg-tertiary);
}
</style>