feature: a minor refactor in folder structure done.

This commit is contained in:
2026-05-07 03:46:18 +03:30
parent a70cbc7860
commit 58cb35e26d
9 changed files with 6 additions and 6 deletions

View File

@@ -0,0 +1,76 @@
/**
* Staff route only: tab matrix + checkbox state ↔ TAB_* permission names.
* Add presentational pieces under ./components/ as the UI grows.
*/
export const STAFF_FEATURE_GROUPS = [
{ label: 'Today', read: 'TAB_TODAY_READ', edit: 'TAB_TODAY_EDIT' },
{ label: 'Staff', read: 'TAB_STAFF_READ', edit: 'TAB_STAFF_EDIT' },
{ label: 'Organizations', read: 'TAB_ORGANIZATIONS_READ', edit: 'TAB_ORGANIZATIONS_EDIT' },
{ label: 'Patients', read: 'TAB_PATIENTS_READ', edit: 'TAB_PATIENTS_EDIT' },
{ label: 'Appointment', read: 'TAB_APPOINTMENTS_READ', edit: 'TAB_APPOINTMENTS_EDIT' },
{ label: 'Treatment', read: 'TAB_TREATMENT_READ', edit: 'TAB_TREATMENT_EDIT' },
{ label: 'Billing', read: 'TAB_BILLING_READ', edit: 'TAB_BILLING_EDIT' },
{ label: 'Reports', read: 'TAB_REPORTS_READ', edit: 'TAB_REPORTS_EDIT' },
] as const;
export type FeaturePermState = Record<string, { read: boolean; edit: boolean }>;
export type OrgType = 'CLINIC' | 'LAB' | null | undefined;
export function resolveStaffFeatureLabel(
group: (typeof STAFF_FEATURE_GROUPS)[number],
organizationType: OrgType,
): string {
if (group.read === 'TAB_ORGANIZATIONS_READ') {
return organizationType === 'LAB' ? 'Clinics' : 'Labs';
}
return group.label;
}
export function emptyFeaturePermissionState(): FeaturePermState {
const s: FeaturePermState = {};
for (const g of STAFF_FEATURE_GROUPS) {
s[g.edit] = { read: false, edit: false };
}
return s;
}
export function featureStateFromPermissionNames(names: string[]): FeaturePermState {
const set = new Set(names);
const s = emptyFeaturePermissionState();
for (const g of STAFF_FEATURE_GROUPS) {
const hasEdit = set.has(g.edit);
const hasRead = set.has(g.read) || hasEdit;
s[g.edit] = { read: hasRead, edit: hasEdit };
}
return s;
}
export function permissionNamesFromFeatureState(state: FeaturePermState): string[] {
const out: string[] = [];
for (const g of STAFF_FEATURE_GROUPS) {
const cell = state[g.edit];
if (!cell) continue;
if (cell.edit) out.push(g.edit);
else if (cell.read) out.push(g.read);
}
return out;
}
/** Human-readable access for the team table — feature name, or "Feature (Read only)" */
export function formatAccessSummary(
permissionNames: string[] | null | undefined,
organizationType?: OrgType,
): string {
if (!permissionNames?.length) return 'No tab access';
const set = new Set(permissionNames);
const parts: string[] = [];
for (const g of STAFF_FEATURE_GROUPS) {
const hasEdit = set.has(g.edit);
const hasRead = set.has(g.read) || hasEdit;
if (!hasRead) continue;
const label = resolveStaffFeatureLabel(g, organizationType);
parts.push(hasEdit ? label : `${label} (Read only)`);
}
return parts.length ? parts.join(' · ') : 'No tab access';
}

View File

@@ -0,0 +1,48 @@
/** Feature groups for staff invite/edit UI — matches backend seed */
export const STAFF_FEATURE_GROUPS = [
{ label: 'Today', read: 'TAB_TODAY_READ', edit: 'TAB_TODAY_EDIT' },
{ label: 'Staff', read: 'TAB_STAFF_READ', edit: 'TAB_STAFF_EDIT' },
{
label: 'Organizations',
read: 'TAB_ORGANIZATIONS_READ',
edit: 'TAB_ORGANIZATIONS_EDIT',
},
{ label: 'Patients', read: 'TAB_PATIENTS_READ', edit: 'TAB_PATIENTS_EDIT' },
{ label: 'Appointment', read: 'TAB_APPOINTMENTS_READ', edit: 'TAB_APPOINTMENTS_EDIT' },
{ label: 'Treatment', read: 'TAB_TREATMENT_READ', edit: 'TAB_TREATMENT_EDIT' },
{ label: 'Billing', read: 'TAB_BILLING_READ', edit: 'TAB_BILLING_EDIT' },
{ label: 'Reports', read: 'TAB_REPORTS_READ', edit: 'TAB_REPORTS_EDIT' },
] as const;
/** Map EDIT key -> { read, edit } for checkbox grid */
export type FeaturePermState = Record<string, { read: boolean; edit: boolean }>;
export function emptyFeaturePermissionState(): FeaturePermState {
const s: FeaturePermState = {};
for (const g of STAFF_FEATURE_GROUPS) {
s[g.edit] = { read: false, edit: false };
}
return s;
}
export function featureStateFromPermissionNames(names: string[]): FeaturePermState {
const set = new Set(names);
const s = emptyFeaturePermissionState();
for (const g of STAFF_FEATURE_GROUPS) {
const hasEdit = set.has(g.edit);
const hasRead = set.has(g.read) || hasEdit;
s[g.edit] = { read: hasRead, edit: hasEdit };
}
return s;
}
export function permissionNamesFromFeatureState(state: FeaturePermState): string[] {
const out: string[] = [];
for (const g of STAFF_FEATURE_GROUPS) {
const cell = state[g.edit];
if (!cell) continue;
if (cell.edit) out.push(g.edit);
else if (cell.read) out.push(g.read);
}
return out;
}

View File

@@ -2,7 +2,7 @@
import { useId } from 'react';
import { FDI_LOWER_LEFT_TO_RIGHT, FDI_UPPER_LEFT_TO_RIGHT, getToothShapeKind } from '@/components/treatment/fdiToothMeta';
import { ToothGlyph } from '@/components/treatment/ToothGlyph';
import { ToothGlyph } from '@/components/ui/treatment/ToothGlyph';
import type { FdiToothId } from '@/types/treatment';
function quadrantMirrored(fdi: FdiToothId): boolean {

View File

@@ -1,9 +1,9 @@
'use client';
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { AppointmentsStrip } from '@/components/treatment/AppointmentsStrip';
import { FdiToothChart } from '@/components/treatment/FdiToothChart';
import { PastTreatmentsPanel } from '@/components/treatment/PastTreatmentsPanel';
import { AppointmentsStrip } from '@/components/ui/treatment/AppointmentsStrip';
import { FdiToothChart } from '@/components/ui/treatment/FdiToothChart';
import { PastTreatmentsPanel } from '@/components/ui/treatment/PastTreatmentsPanel';
import { Checkbox } from '@/components/ui/common/Checkbox';
import { Button } from '@/components/ui/common/Button';
import { isSameLocalCalendarDay, startOfLocalDay } from '@/lib/appointmentTime';