diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx
index 2c80ccf..3773200 100644
--- a/frontend/src/App.tsx
+++ b/frontend/src/App.tsx
@@ -1,7 +1,7 @@
// job/frontend/src/App.tsx
import React from 'react';
import { BrowserRouter as Router, Routes, Route } from 'react-router-dom';
-import JobSearch from './components/JobSearch';
+import JobList from './components/JobList';
import JobDetail from './components/JobDetail';
import Sidebar from './components/Sidebar';
import { ThemeProvider, createTheme } from '@mui/material/styles';
@@ -99,14 +99,16 @@ const App: React.FC = () => {
sx={{
flexGrow: 1,
p: { xs: 2, md: 4 },
- width: { sm: '100%' },
- ml: { sm: drawerWidth },
+ width: { sm: `calc(100% - ${drawerWidth}px)` },
+ ml: { sm: `${drawerWidth}px` },
overflowY: 'auto',
+ height: '100vh',
+ boxSizing: 'border-box',
backgroundColor: 'background.default',
}}
>
- } />
+ } />
} />
diff --git a/frontend/src/components/JobList.tsx b/frontend/src/components/JobList.tsx
new file mode 100644
index 0000000..9f40f16
--- /dev/null
+++ b/frontend/src/components/JobList.tsx
@@ -0,0 +1,156 @@
+import React, { useEffect, useState } from 'react';
+import {
+ Container,
+ Typography,
+ CircularProgress,
+ Alert,
+ Grid,
+ Card,
+ CardContent,
+ Button,
+ Box,
+ Chip,
+} from '@mui/material';
+import { Link } from 'react-router-dom';
+import axios from 'axios';
+import type { JobOffer } from '../types';
+
+const API_BASE_URL = 'http://localhost:3000/api/jobs';
+
+const JobList: React.FC = () => {
+ const [jobs, setJobs] = useState([]);
+ const [loading, setLoading] = useState(true);
+ const [error, setError] = useState(null);
+
+ useEffect(() => {
+ const fetchJobs = async () => {
+ try {
+ setLoading(true);
+ const response = await axios.get(API_BASE_URL);
+ setJobs(response.data);
+ setError(null);
+ } catch (err) {
+ console.error("Erreur lors de la récupération des offres:", err);
+ setError("Impossible de charger les offres pour le moment. Veuillez réessayer plus tard.");
+ setJobs([]);
+ } finally {
+ setLoading(false);
+ }
+ };
+
+ fetchJobs();
+ }, []);
+
+ return (
+
+
+ Découvrez les dernières offres d'emploi
+
+
+ {loading && (
+
+
+
+ )}
+
+ {error && (
+
+ {error}
+
+ )}
+
+ {!loading && !error && jobs.length === 0 && (
+
+ Aucune offre d'emploi disponible pour le moment.
+
+ )}
+
+ {!loading && !error && jobs.length > 0 && (
+
+ {jobs.map((job) => (
+
+
+
+
+ {job.title}
+
+
+
+ {job.companyName || 'Entreprise non spécifiée'}
+
+
+
+ {job.contractType && (
+
+ )}
+ {job.locationLabel && (
+
+ )}
+
+
+
+ {job.description}
+
+
+
+
+
+
+
+
+ ))}
+
+ )}
+
+ );
+};
+
+export default JobList;
\ No newline at end of file
diff --git a/frontend/src/types.ts b/frontend/src/types.ts
index fdb0f08..88f1a0f 100644
--- a/frontend/src/types.ts
+++ b/frontend/src/types.ts
@@ -1,19 +1,17 @@
export interface JobOffer {
id: string;
title: string;
- description: string;
- publicationDate: string; // Ou Date, si vous traitez les dates côté frontend
- romeCode?: string;
- romeLabel?: string;
- locationLabel?: string;
- postalCode?: string;
- departmentCode?: string;
- cityName?: string;
companyName?: string;
+ locationLabel?: string;
+ cityName?: string;
contractType?: string;
contractLabel?: string;
- urlOffre?: string; // <-- AJOUTEZ CETTE LIGNE
- // Ajoutez d'autres champs si votre modèle Prisma JobOffer en contient
+ description: string;
+ publicationDate: string;
+ urlOffre?: string;
+ romeLabel?: string;
+ postalCode?: string;
+ departmentCode?: string;
}
export interface JobSearchResponse {