File size: 8,097 Bytes
56c7b6d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
# 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.