494 lines
24 KiB
Vue
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>
|