bugfix: a small refactor done in folder structure and naming conventions.

This commit is contained in:
2026-05-18 12:31:21 +03:30
parent 4590255b31
commit eb636db653
39 changed files with 68 additions and 68 deletions

View File

@@ -0,0 +1,89 @@
import type { Organization } from '@/types/organization';
const ROUTE_TAB_READ: { prefix: string; permission: string }[] = [
{ prefix: '/today', permission: 'TAB_TODAY_READ' },
{ prefix: '/staff', permission: 'TAB_STAFF_READ' },
{ prefix: '/organizations', permission: 'TAB_ORGANIZATIONS_READ' },
{ prefix: '/patients', permission: 'TAB_PATIENTS_READ' },
{ prefix: '/appointments', permission: 'TAB_APPOINTMENTS_READ' },
{ prefix: '/treatment', permission: 'TAB_TREATMENT_READ' },
{ prefix: '/billing', permission: 'TAB_BILLING_READ' },
{ prefix: '/reports', permission: 'TAB_REPORTS_READ' },
];
export function hasPermission(org: Organization | null, permission: string): boolean {
if (!org) return false;
return Boolean(org.permissions?.includes(permission));
}
/** Sidebar / route guard: READ access to a tab */
export function canViewTab(org: Organization | null, readPermission: string): boolean {
return hasPermission(org, readPermission);
}
export function getRequiredReadPermissionForPath(pathname: string): string | null {
for (const { prefix, permission } of ROUTE_TAB_READ) {
if (pathname === prefix || pathname.startsWith(`${prefix}/`)) {
return permission;
}
}
return null;
}
/** First dashboard route the user may open (ordered). Fallback: account settings. */
export function firstAccessibleDashboardPath(org: Organization | null): string {
if (!org) return '/today';
for (const { prefix, permission } of ROUTE_TAB_READ) {
if (hasPermission(org, permission)) return prefix;
}
return '/settings/account';
}
export function canEditStaff(org: Organization | null): boolean {
return hasPermission(org, 'TAB_STAFF_EDIT');
}
export function canViewStaff(org: Organization | null): boolean {
return (
hasPermission(org, 'TAB_STAFF_READ') || hasPermission(org, 'TAB_STAFF_EDIT')
);
}
/**
* Create/delete/book slots: owners, appointment editors, or treatment editors (schedule columns).
* Aligns with backend appointment mutations.
*/
export function canEditAppointments(org: Organization | null): boolean {
if (!org) {
return false;
}
if (org.isOwner) {
return true;
}
return (
hasPermission(org, 'TAB_APPOINTMENTS_EDIT') ||
hasPermission(org, 'TAB_TREATMENT_EDIT')
);
}
/** Route + sidebar: view appointments page if user can read appointments or manage treatment (column staff). */
export function canAccessAppointmentsSection(org: Organization | null): boolean {
if (!org) {
return false;
}
if (org.isOwner) {
return true;
}
return (
hasPermission(org, 'TAB_APPOINTMENTS_READ') ||
hasPermission(org, 'TAB_APPOINTMENTS_EDIT') ||
hasPermission(org, 'TAB_TREATMENT_EDIT')
);
}
/** Treatment composer, scheduling columns, and saving clinical workflows */
export function canEditTreatment(org: Organization | null): boolean {
if (!org) return false;
if (org.isOwner) return true;
return hasPermission(org, 'TAB_TREATMENT_EDIT');
}

View File

@@ -1,9 +1,9 @@
'use client';
import { useEffect, useState } from 'react';
import { Button } from '@/components/ui/common/Button';
import { DialogCloseButton } from '@/components/ui/common/DialogCloseButton';
import { Dropdown } from '@/components/ui/common/Dropdown';
import { Button } from '@/components/ui/shared/Button';
import { DialogCloseButton } from '@/components/ui/shared/DialogCloseButton';
import { Dropdown } from '@/components/ui/shared/Dropdown';
import type { AppointmentPurpose, AppointmentRecord } from '@/types/appointment';
import { APPOINTMENT_PURPOSE_LABEL } from '@/components/ui/appointments/appointmentPurposeStyles';
import type { Patient } from '@/types/patient';

View File

@@ -1,7 +1,7 @@
'use client';
import { useEffect, useRef } from 'react';
import { DialogCloseButton } from '@/components/ui/common/DialogCloseButton';
import { DialogCloseButton } from '@/components/ui/shared/DialogCloseButton';
import {
APPOINTMENT_PURPOSE_LABEL,
purposeStyle,

View File

@@ -1,8 +1,8 @@
'use client';
import { Search } from 'lucide-react';
import { Button } from '@/components/ui/common/Button';
import { Input } from '@/components/ui/common/Input';
import { Button } from '@/components/ui/shared/Button';
import { Input } from '@/components/ui/shared/Input';
import type { Patient } from '@/types/patient';
interface AppointmentsPatientSearchProps {

View File

@@ -2,7 +2,7 @@
import { Building2, Mail } from 'lucide-react';
import type { FieldErrors, UseFormRegister, UseFormSetValue } from 'react-hook-form';
import { Input } from '@/components/ui/common/Input';
import { Input } from '@/components/ui/shared/Input';
export type OrganizationDetailsFormValues = {
organizationName: string;

View File

@@ -1,10 +1,10 @@
'use client';
import { DialogCloseButton } from '@/components/ui/common/DialogCloseButton';
import { ToastStack, type ToastMessages } from '@/components/ui/common/Toast';
import { DialogCloseButton } from '@/components/ui/shared/DialogCloseButton';
import { ToastStack, type ToastMessages } from '@/components/ui/shared/Toast';
import type { OrganizationInvitationHistoryItemDto } from '@/lib/api/organization';
import { Badge, organizationConnectionStatusVariant } from '@/components/ui/common/Badge';
import { Table } from '@/components/ui/common/Table';
import { Badge, organizationConnectionStatusVariant } from '@/components/ui/shared/Badge';
import { Table } from '@/components/ui/shared/Table';
import { CopyInvitationLinkButton } from '@/components/ui/organizations/CopyInvitationLinkButton';
function formatInvitationStatusLabel(status: OrganizationInvitationHistoryItemDto['status']): string {

View File

@@ -3,8 +3,8 @@
import { useState } from 'react';
import { useAuth } from '@/lib/hooks/useAuth';
import { Building2, Beaker, Mail } from 'lucide-react';
import { Input } from '@/components/ui/common/Input';
import { Button } from '@/components/ui/common/Button';
import { Input } from '@/components/ui/shared/Input';
import { Button } from '@/components/ui/shared/Button';
export function OrganizationSelectorContent() {
const { organizations, selectOrganization, createOrganization, isLoading, error, clearError } = useAuth();

View File

@@ -1,7 +1,7 @@
'use client';
import { Button } from '@/components/ui/common/Button';
import { Input } from '@/components/ui/common/Input';
import { Button } from '@/components/ui/shared/Button';
import { Input } from '@/components/ui/shared/Input';
import { CreatePatientInput } from '@/types/patient';
interface CreatePatientModalProps {

View File

@@ -1,7 +1,7 @@
'use client';
import { Search } from 'lucide-react';
import { Input } from '@/components/ui/common/Input';
import { Input } from '@/components/ui/shared/Input';
import { Patient } from '@/types/patient';
interface PatientSearchSelectProps {

View File

@@ -13,7 +13,7 @@ import {
CreditCard,
} from 'lucide-react';
import { useAuth } from '@/lib/hooks/useAuth';
import { canAccessAppointmentsSection, canViewTab } from '@/shared/permissions';
import { canAccessAppointmentsSection, canViewTab } from '@/components/shared/permissions';
const menu = [
{ name: 'Today', path: '/today', icon: LayoutDashboard, read: 'TAB_TODAY_READ' as const },

View File

@@ -1,5 +1,5 @@
import type { ReactNode } from 'react';
import type { BadgeVariant } from '@/components/ui/common/Badge';
import type { BadgeVariant } from '@/components/ui/shared/Badge';
interface ToastProps {
children: ReactNode;

View File

@@ -2,8 +2,8 @@
import { CalendarDays } from 'lucide-react';
import { purposeStyle } from '@/components/ui/appointments/appointmentPurposeStyles';
import { Card } from '@/components/ui/common/Card';
import { ScheduleDayPicker } from '@/components/ui/common/ScheduleDayPicker';
import { Card } from '@/components/ui/shared/Card';
import { ScheduleDayPicker } from '@/components/ui/shared/ScheduleDayPicker';
import { startOfLocalDay } from '@/lib/appointmentTime';
import type { TreatmentAppointment } from '@/types/treatment';

View File

@@ -4,11 +4,11 @@ import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
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 { Dropdown } from '@/components/ui/common/Dropdown';
import { SearchBar } from '@/components/ui/common/SearchBar';
import { Toast } from '@/components/ui/common/Toast';
import { Checkbox } from '@/components/ui/shared/Checkbox';
import { Button } from '@/components/ui/shared/Button';
import { Dropdown } from '@/components/ui/shared/Dropdown';
import { SearchBar } from '@/components/ui/shared/SearchBar';
import { Toast } from '@/components/ui/shared/Toast';
import { isSameLocalCalendarDay, startOfLocalDay } from '@/lib/appointmentTime';
import {
fetchLinkedOrganizations,
@@ -18,7 +18,7 @@ import {
sendTreatmentRecord,
} from '@/lib/mocks/treatmentMockApi';
import { pickAutoAppointment } from '@/lib/treatmentSelection';
import { canEditTreatment } from '@/shared/permissions';
import { canEditTreatment } from '@/components/shared/permissions';
import type { Organization } from '@/types/organization';
import type {
FdiToothId,