feature: phase1 - org-type navigation, Cases permissions, staff filtering, and route guards.
This commit is contained in:
@@ -3,22 +3,32 @@
|
||||
* Add presentational pieces under ./components/ as the UI grows.
|
||||
*/
|
||||
|
||||
import type { OrgTypeName } from '@/components/shared/permissions';
|
||||
|
||||
export const STAFF_FEATURE_GROUPS = [
|
||||
{ labelKey: 'featureToday', read: 'TAB_TODAY_READ', edit: 'TAB_TODAY_EDIT' },
|
||||
{ labelKey: 'featureStaff', read: 'TAB_STAFF_READ', edit: 'TAB_STAFF_EDIT' },
|
||||
{ labelKey: 'featureOrganizations', read: 'TAB_ORGANIZATIONS_READ', edit: 'TAB_ORGANIZATIONS_EDIT' },
|
||||
{ labelKey: 'featurePatients', read: 'TAB_PATIENTS_READ', edit: 'TAB_PATIENTS_EDIT' },
|
||||
{ labelKey: 'featureAppointment', read: 'TAB_APPOINTMENTS_READ', edit: 'TAB_APPOINTMENTS_EDIT' },
|
||||
{ labelKey: 'featureTreatment', read: 'TAB_TREATMENT_READ', edit: 'TAB_TREATMENT_EDIT' },
|
||||
{ labelKey: 'featureBilling', read: 'TAB_BILLING_READ', edit: 'TAB_BILLING_EDIT' },
|
||||
{ labelKey: 'featureReports', read: 'TAB_REPORTS_READ', edit: 'TAB_REPORTS_EDIT' },
|
||||
{ labelKey: 'featureToday', read: 'TAB_TODAY_READ', edit: 'TAB_TODAY_EDIT', orgTypes: ['CLINIC', 'LAB'] as const },
|
||||
{ labelKey: 'featureStaff', read: 'TAB_STAFF_READ', edit: 'TAB_STAFF_EDIT', orgTypes: ['CLINIC', 'LAB'] as const },
|
||||
{ labelKey: 'featureOrganizations', read: 'TAB_ORGANIZATIONS_READ', edit: 'TAB_ORGANIZATIONS_EDIT', orgTypes: ['CLINIC', 'LAB'] as const },
|
||||
{ labelKey: 'featurePatients', read: 'TAB_PATIENTS_READ', edit: 'TAB_PATIENTS_EDIT', orgTypes: ['CLINIC'] as const },
|
||||
{ labelKey: 'featureAppointment', read: 'TAB_APPOINTMENTS_READ', edit: 'TAB_APPOINTMENTS_EDIT', orgTypes: ['CLINIC'] as const },
|
||||
{ labelKey: 'featureTreatment', read: 'TAB_TREATMENT_READ', edit: 'TAB_TREATMENT_EDIT', orgTypes: ['CLINIC'] as const },
|
||||
{ labelKey: 'featureCases', read: 'TAB_CASES_READ', edit: 'TAB_CASES_EDIT', orgTypes: ['LAB'] as const },
|
||||
{ labelKey: 'featureBilling', read: 'TAB_BILLING_READ', edit: 'TAB_BILLING_EDIT', orgTypes: ['CLINIC', 'LAB'] as const },
|
||||
{ labelKey: 'featureReports', read: 'TAB_REPORTS_READ', edit: 'TAB_REPORTS_EDIT', orgTypes: ['CLINIC', 'LAB'] as const },
|
||||
] as const;
|
||||
|
||||
export type FeaturePermState = Record<string, { read: boolean; edit: boolean }>;
|
||||
export type OrgType = 'CLINIC' | 'LAB' | null | undefined;
|
||||
export type OrgType = OrgTypeName | null | undefined;
|
||||
|
||||
type StaffFeaturesTranslate = (key: string) => string;
|
||||
|
||||
export function staffFeatureGroupsForOrgType(organizationType: OrgType) {
|
||||
if (!organizationType) return [...STAFF_FEATURE_GROUPS];
|
||||
return STAFF_FEATURE_GROUPS.filter((g) =>
|
||||
(g.orgTypes as readonly OrgTypeName[]).includes(organizationType),
|
||||
);
|
||||
}
|
||||
|
||||
export function resolveStaffFeatureLabel(
|
||||
group: (typeof STAFF_FEATURE_GROUPS)[number],
|
||||
organizationType: OrgType,
|
||||
@@ -30,18 +40,21 @@ export function resolveStaffFeatureLabel(
|
||||
return t(group.labelKey);
|
||||
}
|
||||
|
||||
export function emptyFeaturePermissionState(): FeaturePermState {
|
||||
export function emptyFeaturePermissionState(organizationType?: OrgType): FeaturePermState {
|
||||
const s: FeaturePermState = {};
|
||||
for (const g of STAFF_FEATURE_GROUPS) {
|
||||
for (const g of staffFeatureGroupsForOrgType(organizationType)) {
|
||||
s[g.edit] = { read: false, edit: false };
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
export function featureStateFromPermissionNames(names: string[]): FeaturePermState {
|
||||
export function featureStateFromPermissionNames(
|
||||
names: string[],
|
||||
organizationType?: OrgType,
|
||||
): FeaturePermState {
|
||||
const set = new Set(names);
|
||||
const s = emptyFeaturePermissionState();
|
||||
for (const g of STAFF_FEATURE_GROUPS) {
|
||||
const s = emptyFeaturePermissionState(organizationType);
|
||||
for (const g of staffFeatureGroupsForOrgType(organizationType)) {
|
||||
const hasEdit = set.has(g.edit);
|
||||
const hasRead = set.has(g.read) || hasEdit;
|
||||
s[g.edit] = { read: hasRead, edit: hasEdit };
|
||||
@@ -73,7 +86,7 @@ export function formatAccessSummary(
|
||||
if (!permissionNames?.length) return t('noTabAccess');
|
||||
const set = new Set(permissionNames);
|
||||
const parts: string[] = [];
|
||||
for (const g of STAFF_FEATURE_GROUPS) {
|
||||
for (const g of staffFeatureGroupsForOrgType(organizationType)) {
|
||||
const hasEdit = set.has(g.edit);
|
||||
const hasRead = set.has(g.read) || hasEdit;
|
||||
if (!hasRead) continue;
|
||||
|
||||
Reference in New Issue
Block a user