96 lines
3.0 KiB
Markdown
96 lines
3.0 KiB
Markdown
# Frontend Guide
|
|
|
|
## Stack
|
|
|
|
- React 18
|
|
- Vite 6
|
|
- Ant Design 5
|
|
- React Router DOM 6 with `MemoryRouter`
|
|
- Redux 5, redux-saga, redux-persist, reselect
|
|
- Apollo Client 3
|
|
- SCSS modules/files by component where present
|
|
|
|
## Component Layout
|
|
|
|
Components are organized by a loose atomic design convention:
|
|
|
|
- `src/components/atoms/`
|
|
- `src/components/molecules/`
|
|
- `src/components/organisms/`
|
|
- `src/components/templates/`
|
|
- `src/components/pages/`
|
|
|
|
File naming usually includes the level:
|
|
|
|
- `jobs-detail.organism.jsx`
|
|
- `jobs-list-item.molecule.jsx`
|
|
- `loading-spinner.atom.jsx`
|
|
- `error-boundary.template.jsx`
|
|
- `jobs.page.jsx`
|
|
|
|
Preserve this style for new code.
|
|
|
|
## AntD 5 Rules
|
|
|
|
Use current AntD 5 APIs:
|
|
|
|
- `Dropdown menu={{ items, onClick }}` instead of `overlay`.
|
|
- `Collapse items={[...]}` instead of `Collapse.Panel` children.
|
|
- `expandIconPosition="start"` or `"end"`, not `"left"` or `"right"`.
|
|
- `DatePicker.RangePicker presets={...}` instead of `ranges`.
|
|
- `Table rowKey="stableId"` or a function using a real stable field; do not rely on the deprecated index argument.
|
|
- Prefer AntD `App` context-aware feedback APIs.
|
|
|
|
Global feedback:
|
|
|
|
- Use `src/util/antdFeedback.js`.
|
|
- Import `antdMessage`/`antdNotification` instead of static `message`/`notification` from `antd` in files outside the AntD app context.
|
|
- `src/App/App.jsx` configures these through `AntdFeedbackBridge`.
|
|
|
|
## Theming
|
|
|
|
`src/App/App.jsx` wraps the app with:
|
|
|
|
- `ConfigProvider`
|
|
- `theme.darkAlgorithm` or `theme.defaultAlgorithm` based on Redux `darkMode`
|
|
- AntD locale `en_US`
|
|
- AntD `App`
|
|
|
|
Dark mode is stored in Redux `user.darkMode`.
|
|
|
|
## Data Loading Notes
|
|
|
|
Apollo defaults are `network-only` for `query` and `watchQuery`. Components should be resilient to loading states and should not assume cached data is available.
|
|
|
|
Pagination:
|
|
|
|
- Latest jobs and search jobs use offset/limit style pagination.
|
|
- Apollo cache merge policies exist for `Query.jobs` and `Query.search_jobs`.
|
|
- Guard `fetchMoreResult` and previous data as arrays before spreading; an earlier crash came from assuming `prev.search_jobs` was iterable.
|
|
|
|
Job detail:
|
|
|
|
- Selection is debounced briefly to prevent a stale left-panel flash.
|
|
- Show stable loading/skeleton states during selection/query transitions.
|
|
- Guard against stale Apollo data that does not match the currently selected job id.
|
|
|
|
## Redux Notes
|
|
|
|
Reducers are old-style switch reducers with action constants. Sagas are used for side effects. When adding logic:
|
|
|
|
- Add action type constants.
|
|
- Add action creators.
|
|
- Update reducers immutably.
|
|
- Add selectors with `reselect` where state is consumed.
|
|
- Add sagas for async or cross-system side effects.
|
|
|
|
## Common UI Pitfalls
|
|
|
|
- Avoid static AntD feedback APIs.
|
|
- Avoid adding in-component globals/listeners without cleanup.
|
|
- Keep table/list row keys stable.
|
|
- Keep list pagination state defensive around empty or missing arrays.
|
|
- Do not introduce new routing assumptions based on browser history; this is a `MemoryRouter` Electron app.
|
|
- Use existing visual density. This is an operational desktop app, not a marketing site.
|
|
|