Imported from ita-social-projects/VictoryCenter-Client (
AGENTS.md). Install upstream withnpx skills add ita-social-projects/VictoryCenter-Client. Copyright stays with the author.
AGENTS.md
This file provides context and instructions for AI coding agents (GitHub Copilot, Cursor, etc.) working on the Victory Center project.
Project Context
Victory Center is a React 19 + TypeScript SPA for a hippotherapy/rehabilitation center with:
- Public website (multilingual: Ukrainian/English)
- Admin CMS panel (JWT-authenticated content management)
- Backend API: https://backend.victorycenter.online/api
Tech Stack
Framework: React 19.1.0
Language: TypeScript 5.9.3
Router: React Router DOM 7.5.3
UI Library: Material-UI 7.3.1 + Emotion CSS-in-JS
Forms: React Hook Form 7.60.0 + Yup 1.6.1
Rich Text: Lexical 0.39.0
i18n: i18next 25.5.3 (uk, en)
HTTP Client: Axios 1.10.0
Build Tool: Create React App + Craco
Testing: Jest 29 + React Testing Library
Node: 20+
File Structure
src/
├── components/ # UI components (admin/, public/, common/)
├── pages/ # Page components (admin/, public/)
├── hooks/ # Custom hooks (admin/, common/)
├── contexts/ # React contexts (auth, toast, visitor pages)
├── services/api/ # API services (admin/, public/)
├── types/ # TypeScript types
├── validation/ # Yup validation schemas
├── const/ # Constants & config
├── utils/ # Helper functions
├── locales/ # i18n translations (uk/, en/)
├── assets/ # Static assets
└── routes/ # Router setup
Code Style & Conventions
TypeScript Patterns
Always use TypeScript interfaces for props:
interface ComponentProps {
title: string;
onSubmit: (data: FormData) => Promise<void>;
isLoading?: boolean;
}
export const Component: React.FC<ComponentProps> = ({ title, onSubmit, isLoading = false }) => {
// Implementation
};
Use path aliases (REQUIRED):
// ✅ Always use this
import { Button } from '@/components/admin/button';
import { useAdminClient } from '@/hooks/admin/use-admin-client';
// ❌ Never use relative paths
import { Button } from '../../../components/admin/button';
Naming Conventions
- Components: PascalCase (
TeamMemberCard.tsx) - Hooks: camelCase with 'use' prefix (
useDataFetch.ts) - Types/Interfaces: PascalCase (
ProgramCreateUpdate,TeamMemberProps) - Constants: UPPER_SNAKE_CASE (
MAX_CHARACTER_LIMIT,API_BASE_URL) - Functions: camelCase (
getCroppedImage,formatBankDetails) - Files: kebab-case for non-components (
api-routes.ts,text-formatters.ts) - SASS: kebab-case modules (
component-name.module.scss)
Component Structure
// Standard component template
import React from 'react';
import { useTranslation } from 'react-i18next';
import styles from './ComponentName.module.scss';
interface ComponentNameProps {
// Props
}
export const ComponentName: React.FC<ComponentNameProps> = ({ props }) => {
const { t } = useTranslation('namespace');
// Hooks
// Handlers
// Effects
return (
<div className={styles.container}>
{/* JSX */}
</div>
);
};
Import Order
- React & external libraries
- Internal components (
@/components/*) - Hooks (
@/hooks/*) - Services (
@/services/*) - Types (
@/types/*) - Constants (
@/const/*) - Utils (
@/utils/*) - Styles
- Assets
Common Patterns
Authentication
Use AdminContext for all admin operations:
import { useAdminClient } from '@/hooks/admin/use-admin-client';
const { adminClient, isAuthenticated, login, logout } = useAdminClient();
// Authenticated API call
const response = await adminClient.post('/admin/programs', data);
Forms with Validation
Always use React Hook Form + Yup schema:
import { useFormManager } from '@/hooks/admin/use-form-manager';
import { programSchema } from '@/validation/admin/program-schema';
const { register, handleSubmit, formState: { errors }, control } = useFormManager({
schema: programSchema,
defaultValues: initialData
});
const onSubmit = async (data: ProgramFormData) => {
try {
await saveProgram(data);
showToast('Saved successfully!', 'success');
} catch (error) {
showToast('Failed to save', 'error');
}
};
Data Fetching
Use custom hooks for data fetching:
// Simple fetch
import { useDataFetch } from '@/hooks/common/use-data-fetch';
const { data, loading, error } = useDataFetch(() => getPublicPrograms());
// Paginated admin fetch
import { useDataPaginationFetch } from '@/hooks/admin/fetch/use-data-pagination-fetch';
const { data, loading, hasMore, loadMore } = useDataPaginationFetch(
(params) => getPrograms(params),
{ limit: 20 }
);
Toast Notifications
Always provide user feedback:
import { useToast } from '@/contexts/admin/toast-context-provider';
const { showToast } = useToast();
// Success, error, info, warning
showToast('Operation completed!', 'success');
Internationalization
Use i18next for all text:
import { useTranslation } from 'react-i18next';
const { t, i18n } = useTranslation('programsPage');
return (
<>
<h1>{t('title')}</h1>
<button onClick={() => i18n.changeLanguage('en')}>EN</button>
</>
);
For admin forms with multilingual content:
import { useLocalizationToolkit } from '@/hooks/admin/use-localization-toolkit';
const { currentLocale, switchLocale, getLocalization } = useLocalizationToolkit();
Workflows
Creating a New Admin Page
- Create page component in
src/pages/admin/[page-name]/ - Create necessary child components in subdirectories
- Add route in
src/const/admin/routes.ts - Update router in
src/routes/app-router/AppRouter.tsxwith<PrivateRoute> - Add navigation link in
src/components/admin/admin-navigation/ - Create API service in
src/services/api/admin/[feature]/ - Add TypeScript types in
src/types/admin/[feature].ts - Create validation schema in
src/validation/admin/[feature]-schema/ - Add i18n keys to
src/locales/[uk|en]/adminPanel.json - Write tests
Creating a New Public Page
- Create page component in
src/pages/public/[page-name]/ - Add route in
src/const/public/routes.ts - Update router in
src/routes/app-router/AppRouter.tsx - Add navigation link in
src/components/public/header/ - Create API service in
src/services/api/public/[feature]/ - Add types in
src/types/public/[feature].ts - Add i18n translations in
src/locales/[uk|en]/[page-name].json - Write tests
Adding a New Form
- Define TypeScript interface for form data in
src/types/admin/ - Create Yup validation schema in
src/validation/admin/[feature]-schema/ - Use
useFormManagerhook with schema - Use input components from
src/components/admin/input-groups/ - Add character limits (constants in
src/const/admin/) - Implement multilingual fields with
LocalizationToolkit - Handle submission with API service
- Show toast notifications for success/error
Adding a New API Endpoint
- Define types in
src/types/admin/orsrc/types/public/ - Add endpoint constant in
src/const/common/api-routes/main-api.ts - Create service function in
src/services/api/[admin|public]/[feature]/ - Use
adminClientfor authenticated requests - Add error handling
- Write tests with mocked responses
Testing Requirements
Unit Tests
- Test utilities and helper functions
- Test custom hooks with
renderHook - Mock external dependencies (axios, router, contexts)
Component Tests
- Use React Testing Library
- Test user interactions with
@testing-library/user-event - Test accessibility (roles, labels)
- Mock API calls and contexts
Coverage Targets
Statements: 93.5%
Branches: 86.9%
Functions: 91.1%
Lines: 94.9%
Run: npm run test:cover
Commands
# Development
npm start # Dev server HTTP (port 3000)
npm run start-with-cert # Dev server HTTPS (auto-generates SSL cert)
# Testing
npm test # Jest watch mode
npm run test:cover # Coverage report
# Code Quality
npm run lint # ESLint (max 10 warnings)
npm run lint:fix # Auto-fix lint issues
npm run format # Prettier formatting
# Build
npm run build # Production build → /build/
Important Rules
DO:
✅ Always use TypeScript path aliases (@/*)
✅ Always use useTranslation for text content
✅ Always validate forms with Yup schemas
✅ Always show toast notifications for user actions
✅ Always use adminClient from useAdminClient() for admin API calls
✅ Always write tests for new components and utilities
✅ Always handle loading and error states
✅ Always sanitize HTML content with DOMPurify before rendering
✅ Use Material-UI components for consistency
✅ Use SASS modules for component-scoped styles
✅ Keep components small and focused (single responsibility)
✅ Use custom hooks for shared logic
✅ Follow existing patterns in similar components
DON'T:
❌ Don't use relative imports (../../../) - use @/* aliases
❌ Don't hardcode text - use i18next translations
❌ Don't skip form validation
❌ Don't make API calls without error handling
❌ Don't forget to show user feedback (toasts, loading states)
❌ Don't bypass authentication checks
❌ Don't render unsanitized HTML (XSS risk)
❌ Don't create global styles (use modules or MUI)
❌ Don't ignore TypeScript errors
❌ Don't skip tests for new features
❌ Don't mutate props or state directly
❌ Don't use any type (use proper types or unknown)
❌ Don't commit console.log statements
❌ Don't use inline styles (use SASS or Emotion)
❌ Don't create components over 300 lines (split them)
Security Guidelines
Authentication
- JWT tokens stored in
localStorage - Tokens auto-refresh before expiration
- Use
PrivateRoutefor all admin pages - Always use
adminClientfrom context (includes auth headers)
XSS Prevention
import DOMPurify from 'isomorphic-dompurify';
// Sanitize HTML before rendering
const sanitizedHtml = DOMPurify.sanitize(userContent);
return <div dangerouslySetInnerHTML={{ __html: sanitizedHtml }} />;
Input Validation
- Client-side: Yup schemas with strict validation
- Character limits enforced
- File upload validation (type, size, dimensions)
- URL validation for external links
Domain-Specific Terms
- Hippotherapy: Therapeutic horseback riding programs
- Program: A therapeutic program with title, description, sections
- Program Section: Content block (text-only, single-image-top/bottom/right)
- Team Member: Staff profile with photo, bio, position, category
- FAQ: Question/answer pair assigned to specific pages
- Visitor Page: Public pages where FAQ can appear
- Localization: Multi-language content (Ukrainian/English)
- Visibility Status: Published (visible to public) or Draft (admin-only)
- Category: Grouping for programs or team members
- Admin Client: Authenticated Axios instance with JWT
Current Branch Context
Branch: fix-issues-with-reach-text
Recent Work:
- Rich text editor (Lexical) improvements
- EnterKey plugin implementation
- Bug fixes in rich text input components
Key File: src/components/admin/rich-text-input/plugins/EnterKeyPlugin.tsx
Dependencies & Tools
Key Libraries
-
Lexical: Rich text editor (Meta's framework)
- Custom plugins in
src/components/admin/rich-text-input/plugins/ - Plugins: MaxLength, OnChange, Focus, Toolbar, EnterKey, InitialValue
- Custom plugins in
-
React Hook Form: Form state management
- Use with
useFormManagerhook - Integration with Yup validation
- Use with
-
Material-UI (MUI): UI component library
- Use existing MUI components first
- Custom styling via Emotion or SASS modules
-
Swiper: Carousel/slider component
- Used in public site for image galleries
-
React Image Crop: Image cropping tool
- Used in admin for photo uploads
File References
Key files to reference:
- Router:
src/routes/app-router/AppRouter.tsx - Auth Context:
src/contexts/admin/admin-context-provider/AdminContextProvider.tsx - API Config:
src/const/common/api-routes/main-api.ts - Admin Routes:
src/const/admin/routes.ts - Public Routes:
src/const/public/routes.ts - TypeScript Config:
tsconfig.json - Build Config:
craco.config.js
For examples of patterns:
- Admin form:
src/pages/admin/programs/components/program-form/ - Public page:
src/pages/public/programs-page/ - Custom hook:
src/hooks/admin/use-form-manager/ - API service:
src/services/api/admin/programs/ - Validation schema:
src/validation/admin/program-schema/
Agent Behavior
When working on this codebase:
- Analyze before coding: Read similar components/patterns first
- Follow existing patterns: Don't introduce new patterns without discussion
- Be consistent: Match the style of surrounding code
- Think multilingual: Always consider Ukrainian and English content
- Consider authentication: Know which features are admin-only vs public
- Test your changes: Write or update tests for your code
- Check types: Ensure TypeScript compilation succeeds
- Validate forms: Use existing validation schemas or create new ones
- Handle errors: Always add try-catch and user feedback
- Update tests: Maintain high coverage (93%+ target)
Additional Resources
- README:
README.md- Setup instructions - Contributing:
CONTRIBUTING.md- Contribution guidelines - CLAUDE.md: Claude-specific context (similar to this file)
- Codex:
.codex/- OpenAI Codex-specific project config, rules, and skills - Frontend Repo: https://github.com/ita-social-projects/VictoryCenter-Client
- Backend Repo: https://github.com/ita-social-projects/VictoryCenter-Back
Codex-Specific Guidance
OpenAI Codex should treat this file as the shared project guidance and use
.codex/ only for Codex-specific workflow, review, and command-approval
details. Do not change .claude/, .github/ Copilot instructions, or
CLAUDE.md unless the user explicitly asks for those assistant-specific files.
Last Updated: 2026-06-29 Maintained By: Development team
This file should be updated when significant changes are made to project structure, tech stack, or coding conventions.