initial: bootstrap from BukidBountyApp base
This commit is contained in:
169
resources/js/Pages/Fragments/Home/HomeCoopOfficer.vue
Normal file
169
resources/js/Pages/Fragments/Home/HomeCoopOfficer.vue
Normal file
@@ -0,0 +1,169 @@
|
||||
<script setup>
|
||||
import { ref, computed, onMounted } from 'vue';
|
||||
import usePageData from '../../../composables/usePageData.js';
|
||||
import { useNavigate } from '../../../composables/Core/useNavigate.js';
|
||||
import { useAuth } from '../../../composables/Core/useAuth.js';
|
||||
import { useModal } from '../../../composables/Core/useModal.js';
|
||||
import HomeSkeleton from '../../../Components/Core/Skeleton/HomeSkeleton.vue';
|
||||
|
||||
const { user } = useAuth();
|
||||
const { navigate } = useNavigate();
|
||||
const modal = useModal();
|
||||
|
||||
const { data, loading, fetchPageData } = usePageData();
|
||||
|
||||
const chapterInfo = computed(() => data.value?.chapter_info ?? null);
|
||||
const statsData = computed(() => data.value?.stats ?? {});
|
||||
|
||||
const stats = computed(() => [
|
||||
{ title: 'Members', number: statsData.value.chapter_member_count ?? 0, unit: 'In Chapter' },
|
||||
{ title: 'Sub-Chapters', number: statsData.value.child_chapter_count ?? 0, unit: 'Direct' },
|
||||
{ title: 'New (7d)', number: statsData.value.new_members_7d ?? 0, unit: 'Members' },
|
||||
]);
|
||||
|
||||
const chapterBadge = computed(() => {
|
||||
if (!chapterInfo.value) return '';
|
||||
const level = (chapterInfo.value.chapter_level || '').toUpperCase();
|
||||
return `${level} — ${chapterInfo.value.chapter_name || ''}`;
|
||||
});
|
||||
|
||||
const services = [
|
||||
{ icon: 'fas fa-sitemap', title: 'Org Chart', pagename: 'ChapterOrgChart' },
|
||||
{ icon: 'fas fa-search', title: 'Search Members', pagename: 'CoopMemberSearch' },
|
||||
{ icon: 'fas fa-user-plus', title: 'Create User', pagename: 'CreateCoopUser' },
|
||||
{ icon: 'fas fa-user-tie', title: 'Assign Officer', pagename: 'AssignChapterOfficer' },
|
||||
{ icon: 'fas fa-map-marker-alt', title: 'Create Chapter', pagename: 'CreateChapter' },
|
||||
{ icon: 'fas fa-share-alt', title: 'Share Invite', action: 'shareChapterLink' },
|
||||
];
|
||||
|
||||
const sideButtons = [
|
||||
{ text: 'My Cooperative', action: 'viewMyCoop' },
|
||||
{ text: 'My Profile', pagename: 'UserInfoEdit' },
|
||||
{ text: 'Member Ledger', pagename: 'AccountingDashboard' },
|
||||
];
|
||||
|
||||
const activeOrgHash = computed(
|
||||
() => chapterInfo.value?.cooperative_hash ?? user.value?.settings?.cooperatives?.[0] ?? null
|
||||
);
|
||||
|
||||
const viewMyCoop = () => {
|
||||
if (activeOrgHash.value) {
|
||||
navigate({ page: 'CooperativeDetail', props: { target: activeOrgHash.value } });
|
||||
} else {
|
||||
modal.quickDismiss({ title: 'No Cooperative', body: 'You are not linked to a cooperative yet.' });
|
||||
}
|
||||
};
|
||||
|
||||
const shareChapterLink = () => {
|
||||
const coopHash = chapterInfo.value?.cooperative_hash;
|
||||
const chapterHash = chapterInfo.value?.chapter_hashkey;
|
||||
if (!coopHash || !chapterHash) {
|
||||
modal.quickDismiss({ title: 'Unavailable', body: 'No chapter link is available yet.' });
|
||||
return;
|
||||
}
|
||||
const encoded = btoa(JSON.stringify({ coop_hash: coopHash, chapter_hash: chapterHash }));
|
||||
const url = `${window.location.origin}/register-chapter--e:${encoded}`;
|
||||
if (navigator.share) {
|
||||
navigator.share({ title: 'Join our cooperative chapter', url }).catch(() => {});
|
||||
} else {
|
||||
navigator.clipboard?.writeText(url);
|
||||
modal.quickDismiss({ title: 'Link Copied', body: 'Registration link copied to clipboard.' });
|
||||
}
|
||||
};
|
||||
|
||||
const handleAction = (item) => {
|
||||
if (item.action === 'shareChapterLink') return shareChapterLink();
|
||||
if (item.action === 'viewMyCoop') return viewMyCoop();
|
||||
if (item.pagename) navigate({ page: item.pagename });
|
||||
};
|
||||
|
||||
onMounted(async () => {
|
||||
await fetchPageData('/home-data', {});
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="home-coop-officer-fragment pb-5">
|
||||
<HomeSkeleton v-if="loading" />
|
||||
|
||||
<template v-else>
|
||||
<div class="tf-container mt-3">
|
||||
<div class="chapter-badge-card rounded-4 p-3 mb-3">
|
||||
<div class="small text-uppercase opacity-75" style="letter-spacing:.05em;">Your Chapter</div>
|
||||
<div class="fw-bold fs-5">{{ chapterBadge || 'No chapter assigned' }}</div>
|
||||
</div>
|
||||
|
||||
<div class="row g-2 mb-2">
|
||||
<div v-for="s in stats" :key="s.title" class="col-4">
|
||||
<div class="stat-card rounded-4 p-3 text-center h-100">
|
||||
<div class="fw-bold fs-4">{{ s.number }}</div>
|
||||
<div class="small fw-semibold">{{ s.title }}</div>
|
||||
<div class="small opacity-75">{{ s.unit }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="tf-container mt-4">
|
||||
<h5 class="fw_7 mb-3">Officer Tools</h5>
|
||||
<div class="row g-2">
|
||||
<div v-for="item in services" :key="item.title" class="col-4 col-md-3">
|
||||
<button
|
||||
class="service-tile rounded-4 p-3 w-100 h-100 d-flex flex-column align-items-center justify-content-center gap-2"
|
||||
@click="handleAction(item)"
|
||||
>
|
||||
<i :class="item.icon" class="fa-lg" style="color: var(--accent-color);"></i>
|
||||
<span class="small fw-semibold text-center">{{ item.title }}</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="tf-container mt-4">
|
||||
<h5 class="fw_7 mb-3">Quick Actions</h5>
|
||||
<div class="d-grid gap-2">
|
||||
<button
|
||||
v-for="b in sideButtons"
|
||||
:key="b.text"
|
||||
class="side-btn rounded-pill text-start px-4 py-2 d-flex align-items-center justify-content-between"
|
||||
@click="handleAction(b)"
|
||||
>
|
||||
<span class="fw-semibold">{{ b.text }}</span>
|
||||
<i class="fas fa-chevron-right small opacity-50"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.chapter-badge-card {
|
||||
background: var(--accent-color);
|
||||
color: #fff;
|
||||
}
|
||||
.stat-card {
|
||||
background: var(--bg-card);
|
||||
color: var(--text-primary);
|
||||
border: 1px solid rgba(var(--bg-card-rgb, 0, 0, 0), 0.08);
|
||||
}
|
||||
.service-tile {
|
||||
background: var(--bg-card);
|
||||
color: var(--text-primary);
|
||||
border: 1px solid rgba(0, 0, 0, 0.06);
|
||||
transition: transform 0.15s;
|
||||
}
|
||||
.service-tile:hover {
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
.side-btn {
|
||||
background: var(--bg-card);
|
||||
color: var(--text-primary);
|
||||
border: 1px solid rgba(0, 0, 0, 0.06);
|
||||
}
|
||||
:global(.dark-mode) .stat-card,
|
||||
:global(.dark-mode) .service-tile,
|
||||
:global(.dark-mode) .side-btn {
|
||||
border-color: rgba(255, 255, 255, 0.08);
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user