AI_CONTEXT_FRONTEND - AvengerDisassemble/KU-connect GitHub Wiki
Background
KU-Connect is a job board platform for Kasetsart University students and employers.
- Users: Students, Employers, Professors, Admins
- Features: Role-based dashboards, login with KU Gmail (OAuth), job posting, application, saved jobs, moderation.
- Frontend Goal: Clean, responsive UI connected to backend APIs, with consistent structure and maintainable code.
Current Objective
- Stabilize the student browse-jobs experience (quick filters, advanced sheet, tabs).
- Keep job application dialog in sync with backend resume storage-key validation and metadata.
- Maintain smooth Radix sheet/tab animations and consistent button theming.
Recent Wins
- Advanced filter sheet extracted to
components/advanced-filters/AdvancedFiltersSheet.tsxwith forced-mount portal to stop flicker. JobFilterBar.tsxnow coordinates keyword search, quick filters, and advanced sheet state in one place.- Resume chooser dialog accepts both profile resumes and uploaded storage keys without validator conflicts.
Tech Stack
- Vite + React + TypeScript
- Tailwind v4 + shadcn/ui (Radix primitives)
- React Router
- TanStack Query for data fetching/caching
- ESLint + Prettier
- Alias: @ → src
Folder Structure
src/components/shared layout/auth pieces (Header, Guard, Footer, upload widgets) alongsideui/primitives.src/components/ui/wraps Radix primitives (sheet, tabs, button, etc.) with Tailwind + cva variants.src/pages/student/browse-jobs/holds the page shell,components/(filter bar, advanced sheet, job list/detail, application dialog),types/, andutils/.src/hooks/houses global hooks likeuseAuth; page-specific hooks stay co-located when scoped.src/services/typed API helpers (jobs.ts, resumes, auth); no direct network calls elsewhere.src/lib/shared utilities (cn, query helpers);src/utils/small constants/helpers shared across pages.src/styles/Tailwind globals (global.css,lovable.css);App.tsxwires routes;main.tsxbootstraps React.
Naming Conventions
- Components: PascalCase .tsx
- Files/helpers: camelCase
- Types/interfaces: PascalCase
- Constants: UPPER_CASE
- Variables/functions: camelCase
- Booleans: prefix is/has/can
Component Rules
- Functional components only
- Order: imports → state/hooks → handlers → return
- Props typed with TS interfaces
- Optional props with ? and defaults
Styling
- MUST use Tailwind
- Group class names logically
- Conditional classes via template/clsx
State & Hooks
- React hooks only
- Explicit types if not inferred
- Extract reusable logic into hooks/
Imports
- React
- External libs
- Local files (@/...)
- MUST use absolute imports
- No unused imports
Event Handlers
- Verb-prefixed names
- Defined above return
- MUST type events
Routing & Guards
- Routes in App.tsx
- Private routes wrap with Guard + useAuth
- Pages under src/pages/{role}/
API Layer
- All API calls via services/api.ts
- Typed functions
- DO NOT use fetch directly in components
UI Components
- Prefer shadcn/ui
- Shared UI in components/ui/
- Reuse before creating new
Key Surfaces
src/pages/student/browse-jobs/page orchestrates data fetching, tab state, and renders filter/application components.components/AdvancedFiltersSheet.tsxmemoizes the sheet, forces mount, and relies onSheetClosefor exits.components/JobFilterBar.tsxis the single source of truth for keyword input, quick filters, and advanced sheet toggling.components/JobApplicationDialog.tsxhandles resume selection; ensure storage-key values flow to submit handler unchanged.- Filter buttons override shadcn variants via Tailwind; avoid conflicting hover/active states when tweaking colors.
Active Constraints
- No direct
fetch; all data viaservices/api.tswith typed helpers. - Keep animations glitch-free: sheet should not unmount between openings and tabs should ease without layout jumps.
- Preserve accessibility on interactive elements (aria labels, focus trapping in sheets/dialogs).
- Match backend resume validation (storage keys shaped like
resume:student:{id}:{uuid}) and expose helpful errors.
Animation Notes
src/components/ui/sheet.tsxaugments Radix dialogs withdata-[state]slide/fade classes and 300–500 ms easing.AdvancedFiltersSheetkeepsSheetPortalforced-mounted to avoid close/open flicker and preserve exit animations.- Tab and filter interactions rely on Tailwind transitions (
transition-all duration-200) and CSS variables for brand colors. - Mobile job detail sheet reuses the same Radix animation hooks; new sheets must respect
data-[state=open|closed]classes.
Open Risks / TODOs
- Manually verify advanced sheet close/open cycle after every major filter change.
- Revisit quick filter button palette once design team finalizes brand colors.
- Add UI tests around resume selection edge cases (no profile resume, multiple uploads) when time permits.
Testing
- Vitest + React Testing Library
- Test props, handlers, rendering conditions
PR Checklist
- Naming/structure correct
- Types explicit
- Uses Tailwind + shadcn/ui
- API calls via services/api.ts
- Guarded routes where needed
- ESLint + Prettier + type check pass
- Minimal tests added
- No unused imports/dead code
Prompt Patterns
New Page: Create src/pages/student/ProfilePage.tsx.
- Wrap with Guard, use useAuth
- Fetch from services/api.ts:getStudentProfile()
- Show loading/error states
- Use Tailwind + shadcn/ui Card
- Types must be defined, no inline fetch
New Component: Create src/components/ui/JobCard.tsx. Props: { title: string; company: string; salary?: string; onApply?: () => void }
- Use shadcn/ui Card, Tailwind spacing
- Render Apply button only if onApply exists
New Hook: Create src/hooks/useJobs.ts.
- Expose { jobs, isLoading, error, refresh }
- Fetch via services/api.ts:getJobs()
- Cache last result, refresh triggers refetch