feat: implement barangay system phases 2-14
Some checks failed
tests / PHP 8.2 (swoole-5.1.6) (push) Has been cancelled
tests / PHP 8.3 (swoole-5.1.6) (push) Has been cancelled
tests / PHP 8.4 (swoole-6.0) (push) Has been cancelled

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
This commit is contained in:
Jonathan Sykes
2026-06-07 03:09:09 +08:00
parent 19fec0933b
commit fbb7e3ff37
234 changed files with 5582 additions and 39457 deletions

View File

@@ -1,53 +1,35 @@
import { ref, computed, onMounted } from 'vue';
import { ref, computed } from 'vue';
import axios from 'axios';
import { UserTypes } from '../../utils/UserTypes.js';
import { UserTypes, ADMIN_ROLES, STAFF_ROLES } from '../../utils/UserTypes.js';
import { useUserStore } from '../../stores/user.js';
// Global reactive state to persist throughout the SPA session
const globalRole = ref(sessionStorage.getItem('user_acct_type') || UserTypes.PUBLIC);
const isFetching = ref(false);
/**
* Fetches the user account type from the server.
* Ensures only one request is made per session.
*/
async function fetchRole() {
if (isFetching.value) return;
// If we already have a specialized role in sessionStorage, don't fetch again
const cached = sessionStorage.getItem('user_acct_type');
if (cached && cached !== UserTypes.PUBLIC) {
return;
}
if (cached && cached !== UserTypes.PUBLIC) return;
isFetching.value = true;
try {
const response = await axios.get('/get/user/acct-type');
let acctType = response.data?.acct_type;
// Handle case where acct_type might be an object (Enum serialization)
if (acctType && typeof acctType === 'object' && acctType.value) {
acctType = acctType.value;
}
if (acctType && typeof acctType === 'object' && acctType.value) acctType = acctType.value;
if (acctType) {
globalRole.value = acctType;
sessionStorage.setItem('user_acct_type', acctType);
}
} catch (error) {
// If 401, we are likely a guest
if (error.response?.status === 401) {
globalRole.value = UserTypes.PUBLIC;
sessionStorage.setItem('user_acct_type', UserTypes.PUBLIC);
} else {
console.warn('Failed to fetch user acct type from server:', error);
}
} finally {
isFetching.value = false;
}
}
// Initial fetch attempt if we don't have a definitive role
if (!sessionStorage.getItem('user_acct_type') || sessionStorage.getItem('user_acct_type') === UserTypes.PUBLIC) {
fetchRole();
}
@@ -58,90 +40,79 @@ export function resetRole() {
sessionStorage.removeItem('user_acct_type');
}
/**
* Composable for managing user roles and permissions in the frontend.
* @param {Object} [user] - Optional user object for legacy support or specific overrides
*/
export function useAuth(user = null) {
const userStore = useUserStore();
// Priority: Explicitly passed user prop > user store > sessionStorage fallback
const currentUser = computed(() => {
if (user?.value ?? user) return user?.value ?? user;
const storeUser = userStore.user;
if (storeUser && Object.keys(storeUser).length > 0) return storeUser;
try {
const stored = sessionStorage.getItem('currentUser');
return stored ? JSON.parse(stored) : null;
} catch (e) {
} catch {
return null;
}
});
const role = computed(() => {
// Priority 1: User object passed directly or from store
const localRole = userStore.acctType || currentUser.value?.acct_type;
if (localRole) {
if (typeof localRole === 'object' && localRole.value) return localRole.value;
return localRole;
}
// Priority 2: Global fetched role
return globalRole.value;
});
const hasRole = (targetRole) => {
if (Array.isArray(targetRole)) {
return targetRole.some(r => role.value === r);
}
if (Array.isArray(targetRole)) return targetRole.some(r => role.value === r);
return role.value === targetRole;
};
// Role-specific helpers
const isUltimate = computed(() => role.value === UserTypes.ULTIMATE);
const isSuperOperator = computed(() => role.value === UserTypes.SUPER_OPERATOR);
const isOperator = computed(() => role.value === UserTypes.OPERATOR);
const isCoordinator = computed(() => role.value === UserTypes.COORDINATOR);
const isStoreOwner = computed(() => role.value === UserTypes.STORE_OWNER);
const isStoreManager = computed(() => role.value === UserTypes.STORE_MANAGER);
const isRider = computed(() => role.value === UserTypes.RIDER);
const isSupplier = computed(() => role.value === UserTypes.SUPPLIER);
const isSupplierOverseer = computed(() => role.value === UserTypes.SUPPLIER_OVERSEER);
const isWholesaleBuyer = computed(() => role.value === UserTypes.WHOLESALE_BUYER);
const isAudit = computed(() => role.value === UserTypes.AUDIT);
const isUser = computed(() => role.value === UserTypes.USER);
const isCoopOfficer = computed(() => role.value === UserTypes.COOP_OFFICER);
const isCoopMember = computed(() => role.value === UserTypes.COOP_MEMBER);
const isPOSTerminal = computed(() => role.value === UserTypes.POS_TERMINAL);
const isPublic = computed(() => role.value === UserTypes.PUBLIC || !userStore.isLoggedIn);
const isLoggedIn = computed(() => userStore.isLoggedIn);
// Barangay-specific role helpers
const isSuperAdmin = computed(() => role.value === UserTypes.SUPER_ADMIN);
const isPunongBarangay = computed(() => role.value === UserTypes.PUNONG_BARANGAY);
const isKagawad = computed(() => role.value === UserTypes.KAGAWAD);
const isSecretary = computed(() => role.value === UserTypes.SECRETARY);
const isTreasurer = computed(() => role.value === UserTypes.TREASURER);
const isSkChairperson = computed(() => role.value === UserTypes.SK_CHAIRPERSON);
const isSkCouncilor = computed(() => role.value === UserTypes.SK_COUNCILOR);
const isTanod = computed(() => role.value === UserTypes.TANOD);
const isBhw = computed(() => role.value === UserTypes.BHW);
const isDaycareWorker = computed(() => role.value === UserTypes.DAYCARE_WORKER);
const isStaff = computed(() => role.value === UserTypes.STAFF);
const isResident = computed(() => role.value === UserTypes.RESIDENT);
const isAudit = computed(() => role.value === UserTypes.AUDIT);
const isPublic = computed(() => role.value === UserTypes.PUBLIC || !userStore.isLoggedIn);
const isLoggedIn = computed(() => userStore.isLoggedIn);
// Group helpers
const isAdmin = computed(() => ADMIN_ROLES.includes(role.value));
const isBarangayStaff = computed(() => STAFF_ROLES.includes(role.value));
return {
user: currentUser,
role,
hasRole,
isUltimate,
isSuperOperator,
isOperator,
isCoordinator,
isStoreOwner,
isStoreManager,
isRider,
isSupplier,
isSupplierOverseer,
isWholesaleBuyer,
isSuperAdmin,
isPunongBarangay,
isKagawad,
isSecretary,
isTreasurer,
isSkChairperson,
isSkCouncilor,
isTanod,
isBhw,
isDaycareWorker,
isStaff,
isResident,
isAudit,
isUser,
isCoopOfficer,
isCoopMember,
isPOSTerminal,
isPublic,
isLoggedIn,
isAdmin,
isBarangayStaff,
UserTypes,
refreshRole: fetchRole,
// Expose the user store for direct access to user data
userStore
userStore,
};
}