| # Job Apply AI - React Frontend |
|
|
| A modern, SaaS-like React frontend for the Job Application AI Agent with beautiful animations, dark theme, and professional UI. |
|
|
| ## π Features |
|
|
| - **Modern React 18** with TypeScript |
| - **State Management** with Zustand for efficient state handling |
| - **Tailwind CSS** with custom emerald/black SaaS theme |
| - **Framer Motion** animations for smooth interactions |
| - **Component Library** with reusable, animated components |
| - **Responsive Design** that works on all devices |
| - **REST API Integration** with the Python backend |
| - **Dark Mode** with professional styling |
|
|
| ## π οΈ Tech Stack |
|
|
| - **React 18** - UI framework |
| - **TypeScript** - Type safety |
| - **Vite** - Build tool and dev server |
| - **Tailwind CSS** - Utility-first CSS framework |
| - **Framer Motion** - Animation library |
| - **Zustand** - State management |
| - **Axios** - HTTP client |
| - **Lucide React** - Icon library |
|
|
| ## π¦ Installation |
|
|
| ### Prerequisites |
|
|
| - Node.js 18+ and npm/yarn |
| - Python backend running on port 5050 |
|
|
| ### Setup |
|
|
| 1. **Install Dependencies** |
| ```bash |
| cd frontend |
| npm install |
| ``` |
|
|
| 2. **Configure Environment** |
| ```bash |
| # Copy environment template |
| cp .env.example .env |
| |
| # Edit .env if needed |
| # VITE_API_URL=http://localhost:5050 |
| ``` |
|
|
| 3. **Start Development Server** |
| ```bash |
| npm run dev |
| ``` |
|
|
| The app will be available at `http://localhost:3000` |
|
|
| ## ποΈ Project Structure |
|
|
| ``` |
| frontend/ |
| βββ src/ |
| β βββ components/ |
| β β βββ common/ # Reusable UI components |
| β β β βββ Button.tsx |
| β β β βββ Card.tsx |
| β β β βββ Input.tsx |
| β β β βββ Modal.tsx |
| β β β βββ ... |
| β β βββ pages/ # Full page components |
| β β β βββ HomePage.tsx |
| β β β βββ WorkflowPage.tsx |
| β β β βββ JobListPage.tsx |
| β β β βββ SettingsModal.tsx |
| β β βββ sections/ # Reusable page sections |
| β β βββ Header.tsx |
| β β βββ Footer.tsx |
| β β βββ CVUpload.tsx |
| β β βββ JobSearch.tsx |
| β βββ store/ # Zustand state management |
| β β βββ appStore.ts |
| β βββ types/ # TypeScript type definitions |
| β β βββ index.ts |
| β βββ utils/ # Utility functions |
| β β βββ api.ts |
| β β βββ helpers.ts |
| β βββ styles/ # Global styles |
| β β βββ globals.css |
| β βββ App.tsx # Root component |
| β βββ main.tsx # Entry point |
| βββ public/ # Static assets |
| βββ index.html # HTML template |
| βββ package.json |
| βββ tailwind.config.js # Tailwind CSS config |
| βββ tsconfig.json |
| βββ vite.config.ts # Vite config |
| ``` |
|
|
| ## π¨ Styling & Theming |
|
|
| The project uses Tailwind CSS with a custom color scheme: |
|
|
| ### Colors |
| - **Background**: `#0A0E27` (black) |
| - **Primary**: `#22c55e` (emerald-500) |
| - **Secondary**: Slate gray colors |
| - **Accents**: Emerald shades for highlights |
|
|
| ### Key Tailwind Config Features |
| - Custom gradient backgrounds |
| - Glow effects with custom shadows |
| - Animation utilities |
| - Responsive breakpoints |
|
|
| ### Using Layout Classes |
| ```tsx |
| // Dark SaaS background |
| <div className="bg-gradient-saas"> |
| |
| // Primary button with glow |
| <Button className="shadow-glow">Generate CVs</Button> |
| |
| // Card with optional glow and inner glow |
| <Card glow innerGlow>Content</Card> |
| |
| // Emerald gradient text |
| <h1 className="bg-gradient-emerald bg-clip-text text-transparent"> |
| Title |
| </h1> |
| ``` |
|
|
| ## π§© Components |
|
|
| ### Common Components |
|
|
| All components are in `src/components/common/`: |
|
|
| #### Button |
| ```tsx |
| <Button |
| variant="primary" // primary, secondary, outline, ghost, danger |
| size="lg" // sm, md, lg |
| loading={false} |
| icon={<Icon />} |
| fullWidth |
| > |
| Click Me |
| </Button> |
| ``` |
|
|
| #### Card |
| ```tsx |
| <Card hover glow innerGlow> |
| Content with animations |
| </Card> |
| ``` |
|
|
| #### Input |
| ```tsx |
| <Input |
| label="Your Name" |
| placeholder="Enter name" |
| error={errors.name} |
| icon={<Icon />} |
| helperText="Optional" |
| /> |
| ``` |
|
|
| #### Badge |
| ```tsx |
| <Badge variant="primary" size="md" icon={<Icon />}> |
| Label |
| </Badge> |
| ``` |
|
|
| #### Modal |
| ```tsx |
| <Modal isOpen={isOpen} onClose={handleClose} title="Dialog"> |
| Content |
| </Modal> |
| ``` |
|
|
| #### Toast Notification |
| ```tsx |
| <Toast |
| type="success" // success, error, warning, info |
| message="Success!" |
| title="Great" |
| onClose={() => {}} |
| autoClose={true} |
| /> |
| ``` |
|
|
| ## π State Management with Zustand |
|
|
| The app uses Zustand for state management. Store is located in `src/store/appStore.ts`: |
|
|
| ```tsx |
| import { useJobStore } from '@/store/appStore'; |
| |
| function MyComponent() { |
| const { jobs, setJobs, cvTemplate, setCVTemplate } = useJobStore(); |
| |
| // State is automatically persisted to localStorage |
| // Update state by calling setter functions |
| } |
| ``` |
|
|
| ### Available State |
| - `jobs` - Array of found jobs |
| - `cvTemplate` - Uploaded CV template |
| - `tailoringMode` - 'local' or 'api' |
| - `isSearching`, `isGenerating` - Loading states |
| - `selectedJobIds` - Jobs selected for batch generation |
| - `batchProgress` - Progress of batch operation |
| - `notification` - Toast notification data |
|
|
| ## π API Integration |
|
|
| The frontend communicates with the backend via REST API endpoints in `src/utils/api.ts`: |
|
|
| ```tsx |
| import { jobsAPI } from '@/utils/api'; |
| |
| // Search jobs |
| const result = await jobsAPI.searchJobs({ |
| keyword: 'React Developer', |
| location: 'San Francisco', |
| maxJobs: 10 |
| }); |
| |
| // Upload CV |
| await jobsAPI.uploadCV(file); |
| |
| // Generate CV |
| await jobsAPI.generateCV(jobId); |
| |
| // Batch generate |
| await jobsAPI.generateAllCVs(jobIds); |
| |
| // Download file |
| const blob = await jobsAPI.downloadFile(filename); |
| ``` |
|
|
| ## π¬ Animations with Framer Motion |
|
|
| All components use Framer Motion for smooth animations: |
|
|
| ```tsx |
| import { motion } from 'framer-motion'; |
| |
| <motion.div |
| initial={{ opacity: 0, y: 20 }} |
| animate={{ opacity: 1, y: 0 }} |
| exit={{ opacity: 0, y: -20 }} |
| whileHover={{ scale: 1.05 }} |
| whileTap={{ scale: 0.95 }} |
| > |
| Animated content |
| </motion.div> |
| ``` |
|
|
| ## π§ Development |
|
|
| ### Commands |
|
|
| ```bash |
| # Start dev server |
| npm run dev |
| |
| # Build for production |
| npm run build |
| |
| # Preview production build |
| npm run preview |
| |
| # Type check |
| npm run type-check |
| |
| # Lint code |
| npm run lint |
| ``` |
|
|
| ### File Paths |
|
|
| Components use path aliases for clean imports: |
|
|
| ```tsx |
| // Instead of: |
| import Button from '../../../components/common/Button'; |
| |
| // Use: |
| import { Button } from '@/components/common'; |
| import type { Job } from '@/types'; |
| ``` |
|
|
| Available aliases: |
| - `@/components/*` - Components |
| - `@/store/*` - State management |
| - `@/types/*` - Type definitions |
| - `@/utils/*` - Utilities |
| - `@/hooks/*` - Custom hooks |
|
|
| ## π Build & Deployment |
|
|
| ### Production Build |
|
|
| ```bash |
| npm run build |
| ``` |
|
|
| This generates a production-optimized build in `dist/` folder that gets served by the Flask backend. |
|
|
| ### Integration with Flask |
|
|
| The Vite config is set up to build directly into the Flask static folder: |
|
|
| ``` |
| frontend/dist/ β job_apply_ai/ui/static/dist/ |
| ``` |
|
|
| The Flask app serves these files at `/static/dist/` or `/app/` routes. |
|
|
| ## π± Responsive Design |
|
|
| The app is fully responsive with Tailwind breakpoints: |
|
|
| ```tsx |
| <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4"> |
| // 1 column on mobile, 2 on tablet, 4 on desktop |
| </div> |
| ``` |
|
|
| ## βΏ Accessibility |
|
|
| - Semantic HTML |
| - ARIA labels where needed |
| - Keyboard navigation support |
| - Focus states for all interactive elements |
| - Color contrast compliance |
|
|
| ## π Troubleshooting |
|
|
| ### Dev server not connecting to backend |
| - Ensure Flask is running on port 5050 |
| - Check `VITE_API_URL` in `.env` |
| - Clear browser cache |
|
|
| ### Tailwind styles not applying |
| - Restart dev server |
| - Verify file paths in `tailwind.config.js` include all source files |
|
|
| ### Type errors |
| - Run `npm run type-check` |
| - Ensure `tsconfig.json` paths are correct |
|
|
| ## π License |
|
|
| MIT |
|
|
| ## π€ Contributing |
|
|
| Contributions welcome! Please follow the existing code style and component patterns. |
|
|