improvement: billing and report tabs turned invisible. removed from permissions dialog too. this is temporary.
This commit is contained in:
44
frontend/src/components/shared/hidden-tabs.ts
Normal file
44
frontend/src/components/shared/hidden-tabs.ts
Normal file
@@ -0,0 +1,44 @@
|
||||
/**
|
||||
* Tabs hidden from navigation and staff permission UI until features ship.
|
||||
* Routes, pages, and backend permissions stay in place — flip flags to re-enable.
|
||||
*/
|
||||
export const HIDDEN_TAB_FEATURE_FLAGS = {
|
||||
billing: true,
|
||||
reports: true,
|
||||
} as const;
|
||||
|
||||
const HIDDEN_PATHS: readonly string[] = [
|
||||
...(HIDDEN_TAB_FEATURE_FLAGS.billing ? (['/billing'] as const) : []),
|
||||
...(HIDDEN_TAB_FEATURE_FLAGS.reports ? (['/reports'] as const) : []),
|
||||
];
|
||||
|
||||
const HIDDEN_PERMISSIONS: readonly string[] = [
|
||||
...(HIDDEN_TAB_FEATURE_FLAGS.billing
|
||||
? (['TAB_BILLING_READ', 'TAB_BILLING_EDIT'] as const)
|
||||
: []),
|
||||
...(HIDDEN_TAB_FEATURE_FLAGS.reports
|
||||
? (['TAB_REPORTS_READ', 'TAB_REPORTS_EDIT'] as const)
|
||||
: []),
|
||||
];
|
||||
|
||||
const HIDDEN_PATH_SET = new Set<string>(HIDDEN_PATHS);
|
||||
const HIDDEN_PERMISSION_SET = new Set<string>(HIDDEN_PERMISSIONS);
|
||||
|
||||
export function isHiddenTabPath(path: string): boolean {
|
||||
return HIDDEN_PATH_SET.has(path);
|
||||
}
|
||||
|
||||
export function isHiddenTabPermission(permission: string): boolean {
|
||||
return HIDDEN_PERMISSION_SET.has(permission);
|
||||
}
|
||||
|
||||
/** Keep hidden-tab grants when saving staff permissions the UI no longer shows. */
|
||||
export function preserveHiddenTabPermissions(
|
||||
fromForm: string[],
|
||||
existing?: string[] | null,
|
||||
): string[] {
|
||||
if (!existing?.length) return fromForm;
|
||||
const preserved = existing.filter((p) => isHiddenTabPermission(p));
|
||||
if (!preserved.length) return fromForm;
|
||||
return [...new Set([...fromForm, ...preserved])];
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
import type { Organization } from '@/types/organization';
|
||||
import { isHiddenTabPath } from '@/components/shared/hidden-tabs';
|
||||
|
||||
export type OrgTypeName = 'CLINIC' | 'LAB';
|
||||
|
||||
@@ -64,6 +65,10 @@ export function canAccessDashboardRoute(org: Organization | null, pathname: stri
|
||||
const route = getRouteConfigForPath(pathname);
|
||||
if (!route) return true;
|
||||
|
||||
if (isHiddenTabPath(route.prefix)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!isRouteAllowedForOrgType(pathname, org.type)) {
|
||||
return false;
|
||||
}
|
||||
@@ -89,6 +94,7 @@ export function firstAccessibleDashboardPath(org: Organization | null): string {
|
||||
|
||||
for (const route of DASHBOARD_ROUTES) {
|
||||
if (!route.orgTypes.includes(org.type)) continue;
|
||||
if (isHiddenTabPath(route.prefix)) continue;
|
||||
if (route.prefix === '/appointments') {
|
||||
if (canAccessAppointmentsSection(org)) return route.prefix;
|
||||
continue;
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
*/
|
||||
|
||||
import type { OrgTypeName } from '@/components/shared/permissions';
|
||||
import { isHiddenTabPermission } from '@/components/shared/hidden-tabs';
|
||||
|
||||
export const STAFF_FEATURE_GROUPS = [
|
||||
{ labelKey: 'featureToday', read: 'TAB_TODAY_READ', edit: 'TAB_TODAY_EDIT', orgTypes: ['CLINIC', 'LAB'] as const },
|
||||
@@ -24,8 +25,9 @@ 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) =>
|
||||
const visible = STAFF_FEATURE_GROUPS.filter((g) => !isHiddenTabPermission(g.read));
|
||||
if (!organizationType) return [...visible];
|
||||
return visible.filter((g) =>
|
||||
(g.orgTypes as readonly OrgTypeName[]).includes(organizationType),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@ import {
|
||||
canViewTasks,
|
||||
canViewTab,
|
||||
} from '@/components/shared/permissions';
|
||||
import { isHiddenTabPath } from '@/components/shared/hidden-tabs';
|
||||
import {
|
||||
counterpartOrganizationType,
|
||||
organizationTypeIcon,
|
||||
@@ -82,6 +83,9 @@ function Sidebar({ mobileOpen = false, onClose }: SidebarProps) {
|
||||
const visibleMenu = useMemo(
|
||||
() =>
|
||||
menu.filter((item) => {
|
||||
if (isHiddenTabPath(item.path)) {
|
||||
return false;
|
||||
}
|
||||
if (!orgType || !item.orgTypes.includes(orgType)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ import {
|
||||
canEditStaff,
|
||||
canViewStaff,
|
||||
} from '@/components/shared/permissions';
|
||||
import { preserveHiddenTabPermissions } from '@/components/shared/hidden-tabs';
|
||||
import {
|
||||
permissionNamesFromFeatureState,
|
||||
emptyFeaturePermissionState,
|
||||
@@ -464,7 +465,10 @@ export function StaffPage() {
|
||||
|
||||
await staffApi.updateMember(editing.id, {
|
||||
name: editName.trim(),
|
||||
permissionNames: permissionNamesFromFeatureState(editPerms),
|
||||
permissionNames: preserveHiddenTabPermissions(
|
||||
permissionNamesFromFeatureState(editPerms),
|
||||
editing.permissions,
|
||||
),
|
||||
});
|
||||
|
||||
toast.showSuccess(t('successMemberUpdated'));
|
||||
|
||||
Reference in New Issue
Block a user