From 08bb8deec5d51df5e6b754769029884006c0c0e4 Mon Sep 17 00:00:00 2001 From: quasar Date: Fri, 30 May 2025 13:49:03 +0200 Subject: [PATCH] joblist --- frontend/src/App.tsx | 10 +- frontend/src/components/JobList.tsx | 156 ++++++++++++++++++++++++++++ frontend/src/types.ts | 18 ++-- 3 files changed, 170 insertions(+), 14 deletions(-) create mode 100644 frontend/src/components/JobList.tsx 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 {