import { ref, computed } from 'vue' import type { Ref, ComputedRef } from 'vue' import { ABILITIES } from '@/scripts/config/abilities' import type { Ability } from '@/scripts/config/abilities' export interface UserAbility { name: string [key: string]: unknown } export interface UsePermissionsReturn { currentAbilities: Ref isOwner: Ref isSuperAdmin: Ref setAbilities: (abilities: UserAbility[]) => void setOwner: (owner: boolean) => void setSuperAdmin: (superAdmin: boolean) => void hasAbility: (ability: Ability | Ability[]) => boolean hasAllAbilities: (abilities: Ability[]) => boolean canViewCustomer: ComputedRef canCreateCustomer: ComputedRef canEditCustomer: ComputedRef canDeleteCustomer: ComputedRef canViewInvoice: ComputedRef canCreateInvoice: ComputedRef canEditInvoice: ComputedRef canDeleteInvoice: ComputedRef canViewEstimate: ComputedRef canCreateEstimate: ComputedRef canEditEstimate: ComputedRef canDeleteEstimate: ComputedRef canViewPayment: ComputedRef canCreatePayment: ComputedRef canEditPayment: ComputedRef canDeletePayment: ComputedRef canViewExpense: ComputedRef canCreateExpense: ComputedRef canEditExpense: ComputedRef canDeleteExpense: ComputedRef canViewDashboard: ComputedRef canViewFinancialReport: ComputedRef } const currentAbilities = ref([]) const isOwner = ref(false) const isSuperAdmin = ref(false) /** * Composable for managing user permissions and abilities. * Extracted from the user store's hasAbilities/hasAllAbilities logic, * with typed convenience computed properties for common CRUD checks. */ export function usePermissions(): UsePermissionsReturn { function setAbilities(abilities: UserAbility[]): void { currentAbilities.value = abilities } function setOwner(owner: boolean): void { isOwner.value = owner } function setSuperAdmin(superAdmin: boolean): void { isSuperAdmin.value = superAdmin } /** * Check if the current user has a given ability or any of the given abilities. * A wildcard ability ('*') grants access to everything. * * @param ability - A single ability string or array of abilities * @returns True if the user has the ability */ function hasAbility(ability: Ability | Ability[]): boolean { return !!currentAbilities.value.find((ab) => { if (ab.name === '*') return true if (typeof ability === 'string') { return ab.name === ability } return !!ability.find((p) => ab.name === p) }) } /** * Check if the current user has ALL of the given abilities. * * @param abilities - Array of abilities that must all be present * @returns True if the user has every listed ability */ function hasAllAbilities(abilities: Ability[]): boolean { return abilities.every((ability) => currentAbilities.value.some( (ab) => ab.name === '*' || ab.name === ability ) ) } // Convenience computed properties for common permission checks const canViewCustomer = computed(() => hasAbility(ABILITIES.VIEW_CUSTOMER)) const canCreateCustomer = computed(() => hasAbility(ABILITIES.CREATE_CUSTOMER)) const canEditCustomer = computed(() => hasAbility(ABILITIES.EDIT_CUSTOMER)) const canDeleteCustomer = computed(() => hasAbility(ABILITIES.DELETE_CUSTOMER)) const canViewInvoice = computed(() => hasAbility(ABILITIES.VIEW_INVOICE)) const canCreateInvoice = computed(() => hasAbility(ABILITIES.CREATE_INVOICE)) const canEditInvoice = computed(() => hasAbility(ABILITIES.EDIT_INVOICE)) const canDeleteInvoice = computed(() => hasAbility(ABILITIES.DELETE_INVOICE)) const canViewEstimate = computed(() => hasAbility(ABILITIES.VIEW_ESTIMATE)) const canCreateEstimate = computed(() => hasAbility(ABILITIES.CREATE_ESTIMATE)) const canEditEstimate = computed(() => hasAbility(ABILITIES.EDIT_ESTIMATE)) const canDeleteEstimate = computed(() => hasAbility(ABILITIES.DELETE_ESTIMATE)) const canViewPayment = computed(() => hasAbility(ABILITIES.VIEW_PAYMENT)) const canCreatePayment = computed(() => hasAbility(ABILITIES.CREATE_PAYMENT)) const canEditPayment = computed(() => hasAbility(ABILITIES.EDIT_PAYMENT)) const canDeletePayment = computed(() => hasAbility(ABILITIES.DELETE_PAYMENT)) const canViewExpense = computed(() => hasAbility(ABILITIES.VIEW_EXPENSE)) const canCreateExpense = computed(() => hasAbility(ABILITIES.CREATE_EXPENSE)) const canEditExpense = computed(() => hasAbility(ABILITIES.EDIT_EXPENSE)) const canDeleteExpense = computed(() => hasAbility(ABILITIES.DELETE_EXPENSE)) const canViewDashboard = computed(() => hasAbility(ABILITIES.DASHBOARD)) const canViewFinancialReport = computed(() => hasAbility(ABILITIES.VIEW_FINANCIAL_REPORT)) return { currentAbilities, isOwner, isSuperAdmin, setAbilities, setOwner, setSuperAdmin, hasAbility, hasAllAbilities, canViewCustomer, canCreateCustomer, canEditCustomer, canDeleteCustomer, canViewInvoice, canCreateInvoice, canEditInvoice, canDeleteInvoice, canViewEstimate, canCreateEstimate, canEditEstimate, canDeleteEstimate, canViewPayment, canCreatePayment, canEditPayment, canDeletePayment, canViewExpense, canCreateExpense, canEditExpense, canDeleteExpense, canViewDashboard, canViewFinancialReport, } }