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

167 lines
6.3 KiB
Vue

<script setup>
import { ref, computed, watch, onMounted } from 'vue';
import { useChapters } from '../composables/useChapters.js';
import { useNavigate } from '../composables/Core/useNavigate.js';
import { usePageTitle } from '../composables/Core/usePageTitle';
usePageTitle('Create Chapter');
const { fetchOfficerScope, createChapter, loading } = useChapters();
const { navigate } = useNavigate();
const CHILD_LEVELS = {
national: ['region'],
region: ['province'],
province: ['city', 'municipal'],
city: ['barangay'],
municipal: ['barangay'],
barangay: [],
};
const ownChapter = ref(null);
const cooperative = ref(null);
const form = ref({ name: '', location_key: '', lat: '', lng: '' });
const userEditedKey = ref(false);
const errorMessage = ref('');
const submitting = ref(false);
const createdChapter = ref(null);
const childLevel = computed(() => {
if (!ownChapter.value) return null;
const levels = CHILD_LEVELS[ownChapter.value.level] || [];
return levels.length ? levels[0] : null;
});
const isBarangay = computed(() => ownChapter.value?.level === 'barangay');
watch(() => form.value.name, (val) => {
if (!userEditedKey.value) {
form.value.location_key = (val || '').toLowerCase().trim();
}
});
const canSubmit = computed(() => form.value.name && form.value.location_key && childLevel.value);
const submit = async () => {
if (submitting.value || !canSubmit.value) return;
errorMessage.value = '';
submitting.value = true;
try {
const res = await createChapter({
name: form.value.name,
locationKey: form.value.location_key,
lat: form.value.lat === '' ? null : Number(form.value.lat),
lng: form.value.lng === '' ? null : Number(form.value.lng),
});
if (res.success) {
createdChapter.value = res.chapter;
} else {
errorMessage.value = res.message || 'Failed to create chapter.';
}
} catch (err) {
errorMessage.value = err.response?.data?.message || err.response?.data?.error || 'An error occurred.';
} finally {
submitting.value = false;
}
};
onMounted(async () => {
const scope = await fetchOfficerScope();
ownChapter.value = scope?.own_chapter ?? null;
cooperative.value = scope?.cooperative ?? null;
});
</script>
<template>
<div class="container py-4" style="max-width: 560px;">
<h5 class="fw-bold mb-3"><i class="fas fa-map-marker-alt me-2"></i>Create Sub-Chapter</h5>
<div v-if="loading && !ownChapter" class="text-center py-5">
<div class="spinner-border text-primary" role="status"></div>
</div>
<div v-else-if="!ownChapter" class="text-center py-5 text-muted">
<i class="fas fa-exclamation-triangle fa-2x text-warning mb-2"></i>
<p>You are not assigned to a chapter.</p>
</div>
<div v-else-if="isBarangay" class="text-center py-5 text-muted">
<i class="fas fa-ban fa-2x text-danger mb-2"></i>
<p>Cannot create sub-chapters at barangay level.</p>
</div>
<div v-else-if="createdChapter" class="text-center py-5">
<i class="fas fa-check-circle fa-4x text-success mb-3"></i>
<h5 class="fw-bold">Chapter Created!</h5>
<p class="text-muted">
<strong>{{ createdChapter.name }}</strong>
<span class="badge rounded-pill level-badge ms-2">{{ (createdChapter.level || '').toUpperCase() }}</span>
</p>
<button class="btn btn-primary rounded-pill px-4" @click="navigate({ page: 'Home' })">Done</button>
</div>
<div v-else class="info-card rounded-4 p-4">
<div class="meta rounded-3 p-2 mb-3 small">
<div><i class="fas fa-layer-group me-1"></i> Level: <strong>{{ (childLevel || '').toUpperCase() }}</strong></div>
<div><i class="fas fa-sitemap me-1"></i> Parent: <strong>{{ ownChapter.name }}</strong></div>
<div v-if="cooperative"><i class="fas fa-handshake me-1"></i> Cooperative: <strong>{{ cooperative.name }}</strong></div>
</div>
<div v-if="errorMessage" class="alert alert-danger rounded-3 small py-2">{{ errorMessage }}</div>
<div class="mb-3">
<label class="form-label small fw-semibold">Chapter Name</label>
<input v-model="form.name" type="text" class="form-control rounded-pill" placeholder="e.g. Malaybalay City" />
</div>
<div class="mb-3">
<label class="form-label small fw-semibold">Location Key</label>
<input v-model="form.location_key" type="text" class="form-control rounded-pill"
placeholder="auto-generated" @input="userEditedKey = true" />
<div class="form-text small text-muted">Lowercase identifier (auto-filled from name).</div>
</div>
<div class="row g-2 mb-4">
<div class="col-6">
<label class="form-label small fw-semibold">Latitude <span class="text-muted">(optional)</span></label>
<input v-model="form.lat" type="number" step="any" class="form-control rounded-pill" />
</div>
<div class="col-6">
<label class="form-label small fw-semibold">Longitude <span class="text-muted">(optional)</span></label>
<input v-model="form.lng" type="number" step="any" class="form-control rounded-pill" />
</div>
</div>
<button class="btn btn-primary rounded-pill w-100 py-2 fw-semibold" :disabled="submitting || !canSubmit" @click="submit">
<span v-if="submitting" class="spinner-border spinner-border-sm me-2"></span>
<i v-else class="fas fa-plus me-2"></i>
{{ submitting ? 'Creating...' : 'Create Chapter' }}
</button>
</div>
</div>
</template>
<style scoped>
.info-card {
background: var(--bg-card);
color: var(--text-primary);
border: 1px solid rgba(0, 0, 0, 0.06);
}
.meta {
background: var(--bg-primary);
color: var(--text-primary);
border: 1px solid rgba(0, 0, 0, 0.08);
line-height: 1.6;
}
.level-badge {
background: var(--accent-color);
color: #fff;
}
:global(.dark-mode) .info-card,
:global(.dark-mode) .meta {
border-color: rgba(255, 255, 255, 0.08);
}
</style>