Coding practices for frontend development in Atomic CRM. Use when creating or modifying React components, forms, list pages, detail views, filters, data fetching, or responsive layouts.
The frontend uses ra-core (react-admin headless) for data fetching, routing, and CRUD logic, with shadcn-admin-kit and shadcn/ui for the UI layer.
TextInput, SelectInput, ReferenceInput, etc.) from @/components/admin/, not from shadcn/ui directly. The admin layer wraps shadcn with ra-core integration (labels, validation, data binding).Card, Button, Badge, Sheet, etc.) from @/components/ui/.useConfigurationContext(), never hardcoded.Each resource follows this file structure (e.g. contacts/):
ContactList.tsx — list page (desktop + mobile variants)ContactShow.tsx — detail viewContactEdit.tsx / ContactCreate.tsx — form pagesContactInputs.tsx — shared form fields reused between create and editindex.tsx — exports { list, show, edit, create, recordRepresentation }Resources are registered in root/CRM.tsx via <Resource name="contacts" {...contacts} />.
useListContext(), useShowContext(), useGetList(), useGetOne(), useGetIdentity().useQuery/useMutation with useDataProvider<CrmDataProvider>() (e.g. dataProvider.getActivityLog() in ActivityLog.tsx, dataProvider.salesCreate() in SalesCreate.tsx).Form from ra-core + FormToolbar for submit/cancel actions.Form uses React Hook Form under the hood. Use useFormContext() for imperative operations (setValue, reset, getValues).CreateBase/EditBase with Card (e.g. contacts), or Dialog (e.g. deals).CreateSheet/EditSheet from misc/ (e.g. notes, tasks).ContactIdentityInputs, ContactPositionInputs).ToggleFilterButton / ActiveFilterButton components for filter UI.useIsMobile() to branch.MobileHeader/MobileContent.InfiniteListBase for scroll pagination.