Component Structure
Organizacja komponentów
Dział zatytułowany „Organizacja komponentów”Vista zawiera ~330 komponentów React zorganizowanych w domenowe katalogi:
src/components/├── ai/ # 12 komponentów AI├── analytics/ # 8 komponentów raportów├── audio/ # 15 komponentów audio├── auth/ # 9 komponentów auth├── calendar/ # 18 komponentów kalendarza├── chat/ # 11 komponentów czatu AI├── dashboard/ # 14 komponentów dashboardu├── layout/ # 7 komponentów layoutu├── onboarding/ # 12 komponentów onboardingu├── patients/ # 22 komponenty pacjentów├── settings/ # 16 komponentów ustawień├── tasks/ # 9 komponentów zadań├── ui/ # 70+ reusable UI components└── visits/ # 38 komponentów wizytCore Components by Domain
Dział zatytułowany „Core Components by Domain”Visits (/components/visits/)
Dział zatytułowany „Visits (/components/visits/)”Najważniejszy moduł - workflow tworzenia wizyt medycznych.
| Komponent | Opis |
|---|---|
NewVisitView.tsx | Główny widok tworzenia wizyty |
VisitEditor.tsx | Edycja istniejącej wizyty |
SOAPEditor.tsx | Edytor notatek SOAP |
AudioRecordingSection.tsx | Sekcja nagrywania |
TranscriptionViewer.tsx | Podgląd transkrypcji |
AISuggestionsViewer.tsx | Sugestie AI |
VisitsList.tsx | Lista wizyt z filtrowaniem |
VisitCard.tsx | Karta pojedynczej wizyty |
VisitDetails.tsx | Szczegóły wizyty |
PatientSelectionStep.tsx | Wybór pacjenta |
VisitTypeSelector.tsx | Wybór typu wizyty |
flowchart TD NVV[NewVisitView] --> PSS[PatientSelectionStep] NVV --> VTS[VisitTypeSelector] NVV --> ARS[AudioRecordingSection] NVV --> SE[SOAPEditor]
SE --> TV[TranscriptionViewer] SE --> ASV[AISuggestionsViewer]
ARS --> RC[RecordingControls] ARS --> WF[WaveformDisplay]Patients (/components/patients/)
Dział zatytułowany „Patients (/components/patients/)”Zarządzanie pacjentami - zwierzęta i właściciele.
| Komponent | Opis |
|---|---|
PatientsView.tsx | Główny widok pacjentów |
PatientsList.tsx | Lista z wyszukiwaniem |
PatientCard.tsx | Karta pacjenta |
PatientDetails.tsx | Szczegóły pacjenta |
NewPatientForm.tsx | Formularz nowego pacjenta |
PatientEditForm.tsx | Edycja pacjenta |
PatientHistory.tsx | Historia wizyt |
OwnerInfoSection.tsx | Dane właściciela |
MedicalInfoSection.tsx | Dane medyczne |
VaccinationStatus.tsx | Status szczepień |
Calendar (/components/calendar/)
Dział zatytułowany „Calendar (/components/calendar/)”System planowania wizyt z pełnym workflow.
| Komponent | Opis |
|---|---|
CalendarView.tsx | Główny widok kalendarza |
DayView.tsx | Widok dzienny |
WeekView.tsx | Widok tygodniowy |
MonthView.tsx | Widok miesięczny |
MiniCalendar.tsx | Mały kalendarz (picker) |
AppointmentForm.tsx | Formularz wizyty |
AppointmentCard.tsx | Karta wizyty |
TimeSlotPicker.tsx | Wybór slotu czasowego |
ConflictWarning.tsx | Ostrzeżenie o konflikcie |
RecurringAppointment.tsx | Wizyty cykliczne |
Audio (/components/audio/)
Dział zatytułowany „Audio (/components/audio/)”Przetwarzanie audio - nagrywanie i transkrypcja.
| Komponent | Opis |
|---|---|
RecordingControls.tsx | Przyciski start/stop/pause |
WaveformDisplay.tsx | Wizualizacja fali dźwiękowej |
AudioPlayer.tsx | Odtwarzacz nagrań |
TranscriptionProgress.tsx | Pasek postępu STT |
SpeakerLabels.tsx | Etykiety mówców (diaryzacja) |
AudioSettings.tsx | Ustawienia mikrofonu |
VoiceActivityIndicator.tsx | Wskaźnik VAD |
NoiseReductionToggle.tsx | Redukcja szumów |
Settings (/components/settings/)
Dział zatytułowany „Settings (/components/settings/)”Konfiguracja aplikacji - wszystkie preferencje.
| Komponent | Opis |
|---|---|
SettingsView.tsx | Główny widok ustawień |
ProfileSettings.tsx | Profil użytkownika |
AIPreferences.tsx | Preferencje AI |
NotificationSettings.tsx | Powiadomienia |
SecuritySettings.tsx | Bezpieczeństwo |
BiometricSetup.tsx | Konfiguracja biometrii |
ThemeSelector.tsx | Wybór motywu |
LanguageSelector.tsx | Wybór języka |
DataRetention.tsx | Retencja danych |
ImportExport.tsx | Import/eksport |
UI Library (/components/ui/)
Dział zatytułowany „UI Library (/components/ui/)”70+ reusable components - design system.
ui/├── Button.tsx # Przycisk z wariantami├── Input.tsx # Pole tekstowe├── Select.tsx # Dropdown├── Checkbox.tsx # Checkbox├── Radio.tsx # Radio buttons├── Switch.tsx # Toggle switch├── Slider.tsx # Suwak├── DatePicker.tsx # Wybór daty├── TimePicker.tsx # Wybór czasu└── FileUpload.tsx # Upload plikówui/├── Card.tsx # Karta z shadow├── Modal.tsx # Dialog modalny├── Drawer.tsx # Panel boczny├── Tabs.tsx # Zakładki├── Accordion.tsx # Akordeon├── Divider.tsx # Separator├── Stack.tsx # Flexbox helper└── Grid.tsx # CSS Grid helperui/├── Toast.tsx # Notyfikacja toast├── Alert.tsx # Alert box├── Badge.tsx # Badge/etykieta├── Spinner.tsx # Loading spinner├── Progress.tsx # Progress bar├── Skeleton.tsx # Loading skeleton└── Tooltip.tsx # TooltipComponent Patterns
Dział zatytułowany „Component Patterns”Props Interface Pattern
Dział zatytułowany „Props Interface Pattern”// Każdy komponent ma zdefiniowany interfejs propsinterface PatientCardProps { patient: Patient; onSelect?: (patient: Patient) => void; onEdit?: (patient: Patient) => void; isSelected?: boolean; showActions?: boolean; className?: string;}
export const PatientCard: React.FC<PatientCardProps> = ({ patient, onSelect, onEdit, isSelected = false, showActions = true, className,}) => { // ...};Compound Component Pattern
Dział zatytułowany „Compound Component Pattern”// Dla złożonych komponentów (np. Form, Modal)<Form onSubmit={handleSubmit}> <Form.Field name="name" label="Imię"> <Form.Input placeholder="Wpisz imię..." /> </Form.Field>
<Form.Field name="species" label="Gatunek"> <Form.Select options={speciesOptions} /> </Form.Field>
<Form.Actions> <Form.Submit>Zapisz</Form.Submit> <Form.Cancel>Anuluj</Form.Cancel> </Form.Actions></Form>Controller Pattern (Forms)
Dział zatytułowany „Controller Pattern (Forms)”// Formularze z react-hook-form + zodimport { useForm } from 'react-hook-form';import { zodResolver } from '@hookform/resolvers/zod';
const PatientForm = () => { const form = useForm<PatientFormData>({ resolver: zodResolver(PatientSchema), defaultValues: { name: '', species: 'dog', }, });
return ( <form onSubmit={form.handleSubmit(onSubmit)}> <Controller name="name" control={form.control} render={({ field, fieldState }) => ( <Input {...field} error={fieldState.error?.message} /> )} /> </form> );};Styling Conventions
Dział zatytułowany „Styling Conventions”Tailwind + cn() utility
Dział zatytułowany „Tailwind + cn() utility”import { cn } from '@/utils/cn';
interface ButtonProps { variant?: 'primary' | 'secondary' | 'ghost'; size?: 'sm' | 'md' | 'lg'; className?: string;}
const Button = ({ variant = 'primary', size = 'md', className, ...props }) => { return ( <button className={cn( // Base styles 'inline-flex items-center justify-center rounded-lg font-medium transition-colors',
// Variant styles { 'bg-blue-600 text-white hover:bg-blue-700': variant === 'primary', 'bg-gray-200 text-gray-900 hover:bg-gray-300': variant === 'secondary', 'bg-transparent hover:bg-gray-100': variant === 'ghost', },
// Size styles { 'px-3 py-1.5 text-sm': size === 'sm', 'px-4 py-2 text-base': size === 'md', 'px-6 py-3 text-lg': size === 'lg', },
// Custom className override className )} {...props} /> );};Dark Mode Support
Dział zatytułowany „Dark Mode Support”// Wszystkie komponenty wspierają dark mode<div className="bg-white dark:bg-gray-900"> <h1 className="text-gray-900 dark:text-white"> {title} </h1> <p className="text-gray-600 dark:text-gray-400"> {description} </p></div>Error Boundaries
Dział zatytułowany „Error Boundaries”// Każdy major view ma error boundaryimport { ErrorBoundary } from 'react-error-boundary';
const VisitsView = () => ( <ErrorBoundary FallbackComponent={ErrorFallback} onReset={() => window.location.reload()} > <VisitsList /> </ErrorBoundary>);
const ErrorFallback = ({ error, resetErrorBoundary }) => ( <div className="p-6 text-center"> <h2 className="text-xl font-bold text-red-600"> Coś poszło nie tak </h2> <p className="text-gray-600 mt-2">{error.message}</p> <Button onClick={resetErrorBoundary} className="mt-4"> Spróbuj ponownie </Button> </div>);Testing Components
Dział zatytułowany „Testing Components”import { render, screen, fireEvent } from '@testing-library/react';import { PatientCard } from '../PatientCard';
const mockPatient = { patient_id: '123', name: 'Burek', species: 'dog', breed: 'Labrador', owner_name: 'Jan Kowalski',};
describe('PatientCard', () => { it('displays patient information', () => { render(<PatientCard patient={mockPatient} />);
expect(screen.getByText('Burek')).toBeInTheDocument(); expect(screen.getByText('Labrador')).toBeInTheDocument(); expect(screen.getByText('Jan Kowalski')).toBeInTheDocument(); });
it('calls onSelect when clicked', () => { const onSelect = vi.fn(); render(<PatientCard patient={mockPatient} onSelect={onSelect} />);
fireEvent.click(screen.getByRole('button'));
expect(onSelect).toHaveBeenCalledWith(mockPatient); });});