From 0d9370349fc5bb1e16bebfe4f4a3f90473d8a1a6 Mon Sep 17 00:00:00 2001
From: idrissDouelfiqar <idriss.douelfiqar@marketingconfort.com>
Date: Thu, 8 Aug 2024 12:21:29 +0100
Subject: [PATCH] job list view job details update display

---
 src/app/freelancers/job/[id]/page.tsx         |   2 +-
 src/app/freelancers/page.tsx                  |   2 +-
 src/shared/_mock/_job.ts                      |  91 +++-----
 .../sections/job/job-details-content.tsx      |   8 +-
 src/shared/sections/job/job-item.tsx          | 200 +++++++-----------
 src/shared/sections/job/job-list.tsx          |   8 +-
 .../sections/job/view/job-details-view.tsx    |  32 +--
 .../sections/job/view/job-list-view.tsx       |   8 +-
 8 files changed, 146 insertions(+), 205 deletions(-)

diff --git a/src/app/freelancers/job/[id]/page.tsx b/src/app/freelancers/job/[id]/page.tsx
index 7a4d9d8..f278a6b 100644
--- a/src/app/freelancers/job/[id]/page.tsx
+++ b/src/app/freelancers/job/[id]/page.tsx
@@ -5,7 +5,7 @@ import { JobDetailsView } from 'src/shared/sections/job/view';
 
 // ----------------------------------------------------------------------
 
-export const metadata = { title: `Job details | Dashboard - ${CONFIG.site.name}` };
+export const metadata = { title: `Job details | Freelance - ${CONFIG.site.name}` };
 
 type Props = {
   params: { id: string };
diff --git a/src/app/freelancers/page.tsx b/src/app/freelancers/page.tsx
index 7530162..30d8b82 100644
--- a/src/app/freelancers/page.tsx
+++ b/src/app/freelancers/page.tsx
@@ -4,7 +4,7 @@ import { BlankView } from 'src/shared/sections/blank/view';
 
 // ----------------------------------------------------------------------
 
-export const metadata = { title: `Dashboard - ${CONFIG.site.name}` };
+export const metadata = { title: `Freelance - ${CONFIG.site.name}` };
 
 export default function Page() {
   return <BlankView title="Freelancers" />;
diff --git a/src/shared/_mock/_job.ts b/src/shared/_mock/_job.ts
index 5cf4f54..b39a55f 100644
--- a/src/shared/_mock/_job.ts
+++ b/src/shared/_mock/_job.ts
@@ -4,7 +4,7 @@ import { _mock } from './_mock';
 
 export const JOB_DETAILS_TABS = [
   { label: 'Contenu du poste', value: 'contenu' },
-  { label: 'Candidats', value: 'candidats' },
+  // { label: 'Candidats', value: 'candidats' },
 ];
 
 export const JOB_SKILL_OPTIONS = [
@@ -29,19 +29,6 @@ export const JOB_SKILL_OPTIONS = [
 
 export const JOB_BADGE_OPTIONS = ['Badge A', 'Badge B', 'Badge C'];
 
-export const JOB_WORKING_SCHEDULE_OPTIONS = [
-  'Du lundi au vendredi',
-  'Disponibilité le week-end',
-  'Horaires de jour',
-];
-
-export const JOB_EMPLOYMENT_TYPE_OPTIONS = [
-  { label: 'Temps plein', value: 'Temps plein' },
-  { label: 'Temps partiel', value: 'Temps partiel' },
-  { label: 'Sur demande', value: 'Sur demande' },
-  { label: 'Négociable', value: 'Négociable' },
-];
-
 export const JOB_EXPERIENCE_OPTIONS = [
   { label: 'Aucune expérience', value: 'Aucune expérience' },
   { label: "1 an d'expérience", value: "1 an d'expérience" },
@@ -49,19 +36,6 @@ export const JOB_EXPERIENCE_OPTIONS = [
   { label: "> 3 ans d'expérience", value: "> 3 ans d'expérience" },
 ];
 
-export const JOB_BENEFIT_OPTIONS = [
-  { label: 'Free parking', value: 'Free parking' },
-  { label: 'Bonus commission', value: 'Bonus commission' },
-  { label: 'Travel', value: 'Travel' },
-  { label: 'Device support', value: 'Device support' },
-  { label: 'Health care', value: 'Health care' },
-  { label: 'Training', value: 'Training' },
-  { label: 'Health insurance', value: 'Health insurance' },
-  { label: 'Retirement plans', value: 'Retirement plans' },
-  { label: 'Paid time off', value: 'Paid time off' },
-  { label: 'Flexible work schedule', value: 'Flexible work schedule' },
-];
-
 export const JOB_PUBLISH_OPTIONS = [
   { label: 'Published', value: 'published' },
   { label: 'Draft', value: 'draft' },
@@ -80,42 +54,45 @@ const CANDIDATES = [...Array(12)].map((_, index) => ({
   avatarUrl: _mock.image.avatar(index),
 }));
 
-const CONTENT = `
-<h6>Job description</h6>
+const CONTENT = `Nous recherchons un développeur freelance expérimenté pour concevoir et développer un site web e-commerce complet. Le site doit être moderne, intuitif et adapté aux besoins de notre clientèle.`;
 
-<p>Occaecati est et illo quibusdam accusamus qui. Incidunt aut et excepturi harum nihil tenetur facilis. Ut omnis voluptates nihil accusantium doloribus eaque debitis.</p>
+const PRESTATIONS = `
+<h6>Design et UX/UI :</h6>
 
-<h6>Key responsibilities</h6>
+Création d'une interface utilisateur moderne et responsive<br>
+Optimisation de l'expérience utilisateur pour améliorer la conversion<br>
+<h6>Fonctionnalités principales :</h6>
 
-<ul>
-  <li>Working with agency for design drawing detail, quotation and local production.</li>
-  <li>Produce window displays, signs, interior displays, floor plans and special promotions displays.</li>
-</ul>
-`;
+Système de gestion des produits (ajout, modification, suppression)<br>
+Intégration de méthodes de paiement sécurisées<br>
+Système de gestion des commandes et des livraisons<br>
+Interface d'administration pour gérer les produits, commandes et clients<br>
+Fonctionnalités de recherche et de filtrage des produits<br>
+<h6>Performances et sécurité :</h6>
 
-const PRESTATIONS = `
-<h6>Avantages de l'entreprise</h6>
-<ul>
-  <li>Mutuelle santé prise en charge à 70%</li>
-  <li>Prévoyance</li>
-  <li>Participation aux transports à hauteur de 50%</li>
-  <li>Tickets restaurant (9€/jour)</li>
-  <li>RTT (12 jours/an)</li>
-</ul>
+Optimisation du site pour un chargement rapide<br>
+Implémentation de mesures de sécurité pour protéger les données des clients<br>
+<h6>Support et maintenance :</h6>
+
+Support technique pendant les trois premiers mois après le lancement
+Documentation détaillée pour la gestion du site
 `;
 
 const EXIGENCES = `
-<h6>Profil recherché</h6>
-<ul>
-  <li>Diplôme Bac+5 en informatique ou équivalent</li>
-  <li>3 à 5 ans d'expérience en développement web</li>
-</ul>
-
-<h6>Compétences techniques requises</h6>
-<ul>
-  <li>JavaScript / TypeScript</li>
-  <li>React et React Native</li>
-</ul>
+<h6>Technologies requises :</h6>
+
+Langages : HTML5, CSS3, JavaScript<br>
+Frameworks : React ou Angular pour le front-end, Spring Boot pour le back-end<br>
+Bases de données : MySQL ou PostgreSQL<br>
+Autres : API REST, Docker, Git<br>
+<h6>Compétences souhaitées :</h6>
+
+Expérience confirmée en développement web full-stack<br>
+Capacité à créer des interfaces utilisateur réactives et intuitives<br>
+Connaissance des pratiques de SEO<br>
+Expérience avec les méthodes de paiement en ligne (ex : Stripe, PayPal)<br>
+Connaissance des bonnes pratiques de sécurité web<br>
+
 `;
 
 export const _jobs = [...Array(12)].map((_, index) => {
@@ -143,7 +120,7 @@ export const _jobs = [...Array(12)].map((_, index) => {
     totalViews: _mock.number.nativeL(index),
     prestations: PRESTATIONS, // Add a sample value
     exigences: EXIGENCES, // Add a sample value
-    certifs: ['Sample certification'], // Add a sample array with one certification
+    certifs: ['certification A, Certification B'], // Add a sample array with one certification
     createdAt: _mock.time(index),
     candidates: CANDIDATES,
   };
diff --git a/src/shared/sections/job/job-details-content.tsx b/src/shared/sections/job/job-details-content.tsx
index b44e4e1..3f5cb09 100644
--- a/src/shared/sections/job/job-details-content.tsx
+++ b/src/shared/sections/job/job-details-content.tsx
@@ -25,9 +25,14 @@ export function JobDetailsContent({ job }: Props) {
   const renderContent = (
     <Card sx={{ p: 3, gap: 3, display: 'flex', flexDirection: 'column' }}>
       <Typography variant="h4">{job?.title}</Typography>
-
       <Markdown children={job?.content} />
       <Markdown children={job?.prestations} />
+      <Stack spacing={2}>
+        <Typography variant="h6">Certifications</Typography>
+        <Stack direction="row" alignItems="center" spacing={1}>
+          {job?.certifs.map((certif, index) => <Chip key={index} label={certif} variant="soft" />)}
+        </Stack>
+      </Stack>
       <Markdown children={job?.exigences} />
       {/* <Stack spacing={2}>
         <Typography variant="h6">Skills</Typography>
@@ -35,7 +40,6 @@ export function JobDetailsContent({ job }: Props) {
           {job?.skills.map((skill) => <Chip key={skill} label={skill} variant="soft" />)}
         </Stack>
       </Stack> */}
-
       {/* <Stack spacing={2}>
         <Typography variant="h6">Benefits</Typography>
         <Stack direction="row" alignItems="center" spacing={1}>
diff --git a/src/shared/sections/job/job-item.tsx b/src/shared/sections/job/job-item.tsx
index 500604a..1dafabe 100644
--- a/src/shared/sections/job/job-item.tsx
+++ b/src/shared/sections/job/job-item.tsx
@@ -1,5 +1,6 @@
 import type { IJobItem } from 'src/shared/types/job';
 
+import React from 'react';
 import Box from '@mui/material/Box';
 import Link from '@mui/material/Link';
 import Card from '@mui/material/Card';
@@ -20,8 +21,23 @@ import { fCurrency } from 'src/utils/format-number';
 
 import { Iconify } from 'src/shared/components/iconify';
 import { usePopover, CustomPopover } from 'src/shared/components/custom-popover';
+import { Button, Chip } from '@mui/material';
 
 // ----------------------------------------------------------------------
+function getTimeAgo(date: string | number | Date | null) {
+  if (date == null) return null;
+
+  const now = new Date();
+  const past = new Date(date);
+  const diffInSeconds = Math.floor((now.getTime() - past.getTime()) / 1000);
+
+  if (diffInSeconds < 60) return "à l'instant";
+  if (diffInSeconds < 3600) return `il y a ${Math.floor(diffInSeconds / 60)} minute(s)`;
+  if (diffInSeconds < 86400) return `il y a ${Math.floor(diffInSeconds / 3600)} heure(s)`;
+  if (diffInSeconds < 2592000) return `il y a ${Math.floor(diffInSeconds / 86400)} jour(s)`;
+  if (diffInSeconds < 31536000) return `il y a ${Math.floor(diffInSeconds / 2592000)} mois`;
+  return `il y a ${Math.floor(diffInSeconds / 31536000)} an(s)`;
+}
 
 type Props = {
   job: IJobItem;
@@ -29,130 +45,72 @@ type Props = {
   onEdit: () => void;
   onDelete: () => void;
 };
-
 export function JobItem({ job, onView, onEdit, onDelete }: Props) {
-  const popover = usePopover();
+  // const timeAgo = getTimeAgo(job.createdAt);
 
   return (
-    <>
-      <Card>
-        <IconButton onClick={popover.onOpen} sx={{ position: 'absolute', top: 8, right: 8 }}>
-          <Iconify icon="eva:more-vertical-fill" />
-        </IconButton>
-
-        <Stack sx={{ p: 3, pb: 2 }}>
-          <Avatar
-            alt={job.company.name}
-            src={job.company.logo}
-            variant="rounded"
-            sx={{ width: 48, height: 48, mb: 2 }}
-          />
-
-          <ListItemText
-            sx={{ mb: 1 }}
-            primary={
-              <Link component={RouterLink} href={paths.freelancers.details(job.id)} color="inherit">
-                {job.title}
-              </Link>
-            }
-            secondary={`Posted date: ${fDate(job.createdAt)}`}
-            primaryTypographyProps={{ typography: 'subtitle1' }}
-            secondaryTypographyProps={{
-              mt: 1,
-              component: 'span',
-              typography: 'caption',
-              color: 'text.disabled',
-            }}
-          />
-
-          <Stack
-            spacing={0.5}
-            direction="row"
-            alignItems="center"
-            sx={{ color: 'primary.main', typography: 'caption' }}
-          >
-            <Iconify width={16} icon="solar:users-group-rounded-bold" />
-            {job.candidates.length} candidates
-          </Stack>
-        </Stack>
-
-        <Divider sx={{ borderStyle: 'dashed' }} />
-
-        {/* <Box rowGap={1.5} display="grid" gridTemplateColumns="repeat(2, 1fr)" sx={{ p: 3 }}>
-          {[
-            {
-              label: job.experience,
-              icon: <Iconify width={16} icon="carbon:skill-level-basic" sx={{ flexShrink: 0 }} />,
-            },
-            {
-              label: job.employmentTypes.join(', '),
-              icon: <Iconify width={16} icon="solar:clock-circle-bold" sx={{ flexShrink: 0 }} />,
-            },
-            {
-              label: job.salary.negotiable ? 'Negotiable' : fCurrency(job.salary.price),
-              icon: <Iconify width={16} icon="solar:wad-of-money-bold" sx={{ flexShrink: 0 }} />,
-            },
-            {
-              label: job.role,
-              icon: <Iconify width={16} icon="solar:user-rounded-bold" sx={{ flexShrink: 0 }} />,
-            },
-          ].map((item) => (
-            <Stack
-              key={item.label}
-              spacing={0.5}
-              flexShrink={0}
-              direction="row"
-              alignItems="center"
-              sx={{ color: 'text.disabled', minWidth: 0 }}
+    <Card
+      onClick={onView}
+      sx={{
+        cursor: 'pointer',
+        '&:hover': { bgcolor: 'action.hover' },
+        position: 'relative',
+        pt: 5,
+      }}
+    >
+      <Box sx={{ position: 'absolute', left: 16 }}>
+        <Avatar
+          src={job.company?.logo || '/path/to/default-logo.png'}
+          alt={job.company?.name || 'Company Logo'}
+          variant="rounded"
+          sx={{ width: 40, height: 40 }}
+        />
+      </Box>
+
+      <Box sx={{ px: 10, pb: 3 }}>
+        <ListItemText
+          sx={{ mb: 1 }}
+          primary={
+            <Link
+              component={RouterLink}
+              sx={{ fontSize: '18px' }}
+              href={paths.freelancers.details(job.id)}
+              color="inherit"
             >
-              {item.icon}
-              <Typography variant="caption" noWrap>
-                {item.label}
-              </Typography>
-            </Stack>
-          ))}
-        </Box> */}
-      </Card>
-
-      <CustomPopover
-        open={popover.open}
-        anchorEl={popover.anchorEl}
-        onClose={popover.onClose}
-        slotProps={{ arrow: { placement: 'right-top' } }}
-      >
-        <MenuList>
-          <MenuItem
-            onClick={() => {
-              popover.onClose();
-              onView();
-            }}
-          >
-            <Iconify icon="solar:eye-bold" />
-            View
-          </MenuItem>
-
-          <MenuItem
-            onClick={() => {
-              popover.onClose();
-              onEdit();
-            }}
-          >
-            <Iconify icon="solar:pen-bold" />
-            Edit
-          </MenuItem>
-
-          <MenuItem
-            onClick={() => {
-              popover.onClose();
-              onDelete();
-            }}
-            sx={{ color: 'error.main' }}
-          >
-            <Iconify icon="solar:trash-bin-trash-bold" />
-            Delete
-          </MenuItem>
-        </MenuList>
-      </CustomPopover>
-    </>
+              {job.title}
+            </Link>
+          }
+        />
+
+        <Typography variant="body2" sx={{ color: 'text.secondary', mb: 1 }}>
+          {`${job.salary.price ? `${job.salary.price}€` : 'Salaire non spécifié'} • ${job.totalViews} vues`}
+        </Typography>
+
+        <Typography
+          variant="body2"
+          sx={{
+            color: 'text.secondary',
+            overflow: 'hidden',
+            textOverflow: 'ellipsis',
+            display: '-webkit-box',
+            WebkitLineClamp: 2,
+            WebkitBoxOrient: 'vertical',
+            lineHeight: '1.5em',
+            height: '3em',
+            mb: 1,
+          }}
+        >
+          {job.content.slice(0, 200)}
+        </Typography>
+
+        <Typography variant="body2" sx={{ fontWeight: 'bold', mb: 1 }}>
+          {job.certifs.join(', ')}
+        </Typography>
+
+        <Typography variant="caption" sx={{ color: 'text.secondary', display: 'block' }}>
+          {`Il y a ${getTimeAgo(job.createdAt)} • Client #${job.id.slice(0, 8)}`}
+        </Typography>
+      </Box>
+    </Card>
   );
 }
diff --git a/src/shared/sections/job/job-list.tsx b/src/shared/sections/job/job-list.tsx
index 7cafc43..b6cc05a 100644
--- a/src/shared/sections/job/job-list.tsx
+++ b/src/shared/sections/job/job-list.tsx
@@ -40,9 +40,11 @@ export function JobList({ jobs }: Props) {
   return (
     <>
       <Box
-        gap={3}
-        display="grid"
-        gridTemplateColumns={{ xs: 'repeat(1, 1fr)', sm: 'repeat(2, 1fr)', md: 'repeat(3, 1fr)' }}
+        sx={{
+          display: 'flex',
+          flexDirection: 'column',
+          gap: 2, // Espacement vertical entre les éléments
+        }}
       >
         {jobs.map((job) => (
           <JobItem
diff --git a/src/shared/sections/job/view/job-details-view.tsx b/src/shared/sections/job/view/job-details-view.tsx
index 93c6a30..a14cf69 100644
--- a/src/shared/sections/job/view/job-details-view.tsx
+++ b/src/shared/sections/job/view/job-details-view.tsx
@@ -29,11 +29,11 @@ type Props = {
 export function JobDetailsView({ job }: Props) {
   const tabs = useTabs('content');
 
-  const [publish, setPublish] = useState(job?.publish);
+  // const [publish, setPublish] = useState(job?.publish);
 
-  const handleChangePublish = useCallback((newValue: string) => {
-    setPublish(newValue);
-  }, []);
+  // const handleChangePublish = useCallback((newValue: string) => {
+  //   setPublish(newValue);
+  // }, []);
 
   const renderTabs = (
     <Tabs value={tabs.value} onChange={tabs.onChange} sx={{ mb: { xs: 3, md: 5 } }}>
@@ -57,19 +57,19 @@ export function JobDetailsView({ job }: Props) {
 
   return (
     <DashboardContent>
-      <JobDetailsToolbar
+      {/* <JobDetailsToolbar
         backLink={paths.freelancers.jobs}
-        editLink={paths.freelancers.edit(`${job?.id}`)}
-        liveLink="#"
-        publish={publish || ''}
-        onChangePublish={handleChangePublish}
-        publishOptions={JOB_PUBLISH_OPTIONS}
-      />
-      {renderTabs}
-
-      {tabs.value === 'content' && <JobDetailsContent job={job} />}
-
-      {tabs.value === 'candidates' && <JobDetailsCandidates candidates={job?.candidates ?? []} />}
+        // editLink={paths.freelancers.edit(`${job?.id}`)}
+        // liveLink="#"
+        // publish={publish || ''}
+        // onChangePublish={handleChangePublish}
+        // publishOptions={JOB_PUBLISH_OPTIONS}
+      /> */}
+      {/* {renderTabs} */}
+
+      {/* {tabs.value === 'content' && <JobDetailsContent job={job} />} */}
+      <JobDetailsContent job={job} />
+      {/* {tabs.value === 'candidates' && <JobDetailsCandidates candidates={job?.candidates ?? []} />} */}
     </DashboardContent>
   );
 }
diff --git a/src/shared/sections/job/view/job-list-view.tsx b/src/shared/sections/job/view/job-list-view.tsx
index 416f48c..17ba883 100644
--- a/src/shared/sections/job/view/job-list-view.tsx
+++ b/src/shared/sections/job/view/job-list-view.tsx
@@ -20,9 +20,9 @@ import {
   _jobs,
   _roles,
   JOB_SORT_OPTIONS,
-  JOB_BENEFIT_OPTIONS,
-  JOB_EXPERIENCE_OPTIONS,
-  JOB_EMPLOYMENT_TYPE_OPTIONS,
+  // JOB_BENEFIT_OPTIONS,
+  // JOB_EXPERIENCE_OPTIONS,
+  // JOB_EMPLOYMENT_TYPE_OPTIONS,
 } from 'src/shared/_mock';
 
 import { Iconify } from 'src/shared/components/iconify';
@@ -123,7 +123,7 @@ export function JobListView() {
       <CustomBreadcrumbs
         heading="List"
         links={[
-          { name: 'Dashboard', href: paths.dashboard.root },
+          { name: 'Freelance', href: paths.freelancers.root },
           { name: 'Job', href: paths.freelancers.jobs },
           { name: 'List' },
         ]}
-- 
GitLab