Instruction file imported from EficodeDemoOrg/copilot-training-tieto-ws2-2026 (
.github/instructions/frontend.instructions.md). Copyright stays with the author.
Frontend Instructions
React 18 + TypeScript + Vite 5. No state library, no CSS framework, no component library — plain React, hand-written CSS in src/styles.css, interactjs for drag/resize.
Structure
src/App.tsx— top-level composition; pulls state fromuseChartand passes callbacks down.src/hooks/useChart.ts— single source of truth for chart state and all API calls. Components never callapi.*directly.src/api/client.ts— thinfetchwrapper. Uses relative/api/...URLs (proxied by Vite to the backend in dev).src/components/— function components only, named exports, props typed inline astype Props = { ... }.src/types.ts— sharedChart/Tasktypes. Mirrors backend shapes; update in lockstep.src/utils/dates.ts— date math on ISOYYYY-MM-DDstrings (addDays,daySpan,dayIndex,parseDate,clamp,isWeekend).
Conventions
- Function components with named exports (
export function GanttChart(...)). No default exports for components. - Dates are ISO
YYYY-MM-DDstrings end-to-end. Use helpers inutils/dates.tsinstead of newDate()arithmetic. When parsing, treat values as UTC (seeparseDate). - Memoize derived arrays/objects with
useMemo; wrap callbacks passed into effects or third-party libs withuseCallback. - Optimistic UI: mutations in
useChartupdate local state first, then call the API, and re-refresh()on failure (seeupdateTask/deleteTask). Follow this pattern for new mutations. - Errors surface via the
errorstate inuseChart; don'talert()orthrowfrom event handlers.
Styling
- Add styles to
src/styles.css. Reuse existing CSS variables (e.g.--day-width,--task-color-*). - When a layout constant is shared between JS and CSS (like
DAY_WIDTHinGanttChart.tsx), keep both in sync and note it with a brief comment.
Drag & resize (interact.js)
- Initialize
interact(el)inside auseEffectand returninst.unset()from the cleanup. - Keep mutable per-drag values in a
useRefobject (seeTaskBar.tsx'sstateRef) so listeners closed over the initial render still see current props. - Show transient drag state via local
useState; commit final values with theonCommitcallback only onend, and only if they actually changed. - Constrain to chart bounds and a 1-day minimum inside the
movehandler.
Don'ts
- No Redux/Zustand/Recoil/React Query —
useChartis the state layer. - Don't hardcode
http://localhost:3000in fetch calls; always use relative/api/...paths.