Skip to content

Commit

Permalink
feat: update car post
Browse files Browse the repository at this point in the history
  • Loading branch information
Mzem committed Nov 4, 2024
1 parent 2558290 commit 1c0907a
Show file tree
Hide file tree
Showing 7 changed files with 280 additions and 30 deletions.
28 changes: 27 additions & 1 deletion api/services/car-posts.service.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { apiGet } from 'api/apiClient'
import { apiGet, apiPatch } from 'api/apiClient'
import { Region } from './regions.service'
import { MerchantListItem } from './merchants.service'
import { CarModel } from './car-model.service'
Expand Down Expand Up @@ -168,3 +168,29 @@ export async function getCarPost(id: string): Promise<CarPost | undefined> {
throw e
}
}

export async function updateCarPost(
id: string,
authKey: string,
km?: number,
year?: number,
price?: number,
estimation?: number,
make?: string,
model?: string
): Promise<void> {
try {
await apiPatch(`car-posts/${id}`, {
authKey,
km,
year,
price,
estimation,
make,
model
})
} catch (e) {
console.error('PATCH car post error')
throw e
}
}
66 changes: 52 additions & 14 deletions app/_components/car-posts/CarPostModal.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
'use client'

import { useRouter } from 'next/navigation'
import React, { useEffect, useRef, useState } from 'react'
import { CarPost } from '../../../api/services/car-posts.service'
import Link from 'next/link'
import { useRouter } from 'next/navigation'
import CarPostUpdateModal from './CarPostUpdateModal'

const urlRegex = /(https?:\/\/[^\s]+)/g

Expand Down Expand Up @@ -185,7 +185,9 @@ const CarPostModal: React.FC<PostModalProps> = ({
isFull
}) => {
const [post, setPost] = useState<CarPost | null | 'error'>(null)
const [showModalUpdate, setShowModalUpdate] = useState(false)
const modalRef = useRef<HTMLDivElement | null>(null)
const updateModalRef = useRef<HTMLDivElement | null>(null)

const router = useRouter()

Expand All @@ -206,7 +208,9 @@ const CarPostModal: React.FC<PostModalProps> = ({
const handleClickOutside = (event: MouseEvent) => {
if (
modalRef.current &&
!modalRef.current.contains(event.target as Node)
!modalRef.current.contains(event.target as Node) &&
(!updateModalRef.current ||
!updateModalRef.current.contains(event.target as Node)) // Ignore clicks inside nested modal
) {
if (onClose) onClose()
}
Expand Down Expand Up @@ -287,6 +291,14 @@ const CarPostModal: React.FC<PostModalProps> = ({
{post && post !== 'error' && (
<div>
<div className='flex justify-between mb-4 items-start'>
<button
className='text-whiteBG cursor-none'
onClick={() => {
setShowModalUpdate(true)
}}
>
|
</button>
<h2 className='text-sm lg:text-xl font-bold w-full'>
{post.title}
</h2>
Expand All @@ -306,17 +318,28 @@ const CarPostModal: React.FC<PostModalProps> = ({
<div className='mt-4 lg:mt-6 mb-4 flex flex-col mx-auto w-full text-center items-center text-2xl font-bold'>
<span>{post.price ? post.price + ' DT' : 'Prix N.C.'}</span>
{post.estimatedPrice && (
<span
className={`font-normal text-sm lg:text-lg ${
post.estimatedPrice.color === 'GREEN'
? 'text-green'
: post.estimatedPrice.color === 'RED'
? 'text-rolexgold'
: 'text-blackopac2'
}`}
>
{post.estimatedPrice.text}
</span>
<div className='flex items-center space-x-1'>
<div
className={`w-[8px] h-[8px] lg:w-[10px] lg:h-[10px] rounded-full ${
post.estimatedPrice.color === 'GREEN'
? 'bg-greenopac'
: post.estimatedPrice.color === 'RED'
? 'bg-rolexgoldopac'
: 'bg-titanopac'
}`}
/>
<span
className={`font-normal text-sm lg:text-lg italic ${
post.estimatedPrice.color === 'GREEN'
? 'text-green'
: post.estimatedPrice.color === 'RED'
? 'text-rolexgold'
: 'text-blackopac2'
}`}
>
{post.estimatedPrice.text}
</span>
</div>
)}
</div>

Expand Down Expand Up @@ -443,6 +466,21 @@ const CarPostModal: React.FC<PostModalProps> = ({
</div>
)}
{isFull && <PostDetails />}
{showModalUpdate && post !== 'error' && (
<CarPostUpdateModal
ref={updateModalRef}
onClose={setShowModalUpdate}
carData={{
id: post?.id,
km: post?.km,
year: post?.year,
price: post?.price,
estimation: post?.estimatedPrice?.value,
make: post?.make,
model: post?.model
}}
/>
)}
</div>
)
}
Expand Down
172 changes: 172 additions & 0 deletions app/_components/car-posts/CarPostUpdateModal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
'use client'

import { forwardRef, useState } from 'react'

function CarPostUpdateModal(
{
onClose,
carData
}: {
onClose: any
carData: {
id?: string
km?: number
year?: number
price?: number
estimation?: number
make?: string
model?: string
}
},
ref: any
) {
const [success, setSuccess] = useState(true)
const [formData, setFormData] = useState({
authKey: '',
km: carData.km || '',
year: carData.year || '',
price: carData.price || '',
estimation: carData.estimation || '',
make: carData.make || '',
model: carData.model || ''
})

// Handle form data changes
const handleChange = (e: any) => {
const { name, value } = e.target
setFormData((prevData) => ({
...prevData,
[name]: value
}))
}

// Submit the form
const handleSubmit = (e: any) => {
e.preventDefault()
try {
fetch('/api/car-post', {
method: 'PATCH',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
postId: carData.id,
authKey: formData.authKey || undefined,
km: formData.km || undefined,
year: formData.year || undefined,
price: formData.price || undefined,
estimation: formData.estimation || undefined,
make: formData.make || undefined,
model: formData.model || undefined
})
}).then((res) => {
if (res.ok) {
setSuccess(true)
onClose(false) // Close the modal after submitting
}
setSuccess(false)
})
} catch (e) {
setSuccess(false)
}
}

return (
<div
ref={ref}
className='fixed inset-0 flex items-center justify-center bg-black bg-opacity-50 z-50'
>
<div className='bg-white w-full max-w-md p-6 rounded-lg shadow-lg'>
<h2 className='text-xl font-semibold mb-1'>Modifier</h2>
<form onSubmit={handleSubmit} className='space-y-2'>
<div>
<label className='block text-titan'>Kilométrage</label>
<input
type='number'
name='km'
value={formData.km}
onChange={handleChange}
className='w-full px-3 py-1 border border-black rounded focus:outline-none focus:ring focus:ring-vividred'
/>
</div>
<div>
<label className='block text-titan'>Année</label>
<input
type='number'
name='year'
value={formData.year}
onChange={handleChange}
className='w-full px-3 py-1 border border-black rounded focus:outline-none focus:ring focus:ring-vividred'
/>
</div>
<div>
<label className='block text-titan'>Prix</label>
<input
type='number'
name='price'
value={formData.price}
onChange={handleChange}
className='w-full px-3 py-1 border border-black rounded focus:outline-none focus:ring focus:ring-vividred'
/>
</div>
<div>
<label className='block text-titan'>Estimation</label>
<input
type='number'
name='estimation'
value={formData.estimation}
onChange={handleChange}
className='w-full px-3 py-1 border border-black rounded focus:outline-none focus:ring focus:ring-vividred'
/>
</div>
<div>
<label className='block text-titan'>Marque</label>
<input
type='text'
name='make'
value={formData.make}
onChange={handleChange}
className='w-full px-3 py-1 border border-black rounded focus:outline-none focus:ring focus:ring-vividred'
/>
</div>
<div>
<label className='block text-titan'>Modèle</label>
<input
type='text'
name='model'
value={formData.model}
onChange={handleChange}
className='w-full px-3 py-1 border border-black rounded focus:outline-none focus:ring focus:ring-red'
/>
</div>
<div>
<label className='block text-titan'>Clé utilisateur</label>
<input
type='text'
name='authKey'
value={formData.authKey}
onChange={handleChange}
className='w-full px-3 py-1 border border-black rounded focus:outline-none focus:ring focus:ring-red'
/>
</div>
<div className='flex justify-end space-x-4 items-center'>
{!success && <p className='text-vividred'>Erreur</p>}
<button
type='button'
onClick={() => onClose(false)}
className='px-4 py-1 bg-black text-titan rounded-lg hover:bg-red'
>
Cancel
</button>
<button
type='submit'
className='px-4 py-1 text-white rounded-lg bg-vividred hover:bg-titan'
>
Save
</button>
</div>
</form>
</div>
</div>
)
}

export default forwardRef(CarPostUpdateModal)
15 changes: 2 additions & 13 deletions app/_components/car-posts/CarPosts.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -422,25 +422,14 @@ export default function CarPostsFeed({
{post.fuel}
</span>
{post.gearbox && <span>{post.gearbox}</span>}
<div className='mt-auto mb-[1px] flex flex-col lg:flex-row lg:space-x-4 text-left'>
<div className='mt-auto flex space-x-1 lg:space-x-2 lg:flex-row text-left'>
<span className='font-bold text-pureblack'>
{post.price ? post.price + ' DT' : 'Prix N.C.'}
</span>
{post.estimatedPrice && (
<div className='flex items-center space-x-1'>
{post.estimatedPrice.color !== 'NORMAL' && (
<div
className={`w-[8px] h-[8px] lg:w-[10px] lg:h-[10px] rounded-full ${
post.estimatedPrice.color === 'GREEN'
? 'bg-green'
: post.estimatedPrice.color === 'RED'
? 'bg-rolexgold'
: 'bg-blackopac2'
}`}
/>
)}
<span
className={`font-normal italic ${
className={`font-normal italic text-[0.6rem] lg:text-xs ${
post.estimatedPrice.color === 'GREEN'
? 'text-green'
: post.estimatedPrice.color === 'RED'
Expand Down
3 changes: 3 additions & 0 deletions app/_styles/globals.css
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

:root {
--green: #105415;
--greenopac: #105415aa;
--blue: #08085e;
--yellow: #b3ae14;
--orange: #b36b14;
Expand All @@ -19,11 +20,13 @@
--whiteopac2: #ffffff10;
--whiteopac3: #ffffff05;
--titan: #cecdcd;
--titanopac: #cecdcdaa;
--cream: #ede7d1;
--red: #371211;
--vividred: #b31414ee;
--gold: #d4af37;
--rolexgold: #a37e2c;
--rolexgoldopac: #a37e2caa;
}

body {
Expand Down
21 changes: 20 additions & 1 deletion app/api/car-post/route.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,28 @@
import { NextRequest } from 'next/server'
import { getCarPost } from '../../../api/services/car-posts.service'
import {
getCarPost,
updateCarPost
} from '../../../api/services/car-posts.service'

export async function GET(req: NextRequest) {
const postId = req.nextUrl.searchParams.get('postId')!
const post = await getCarPost(postId)

return Response.json(post)
}
export async function PATCH(req: NextRequest) {
const { postId, authKey, km, year, price, estimation, make, model } =
await req.json()

await updateCarPost(
postId,
authKey,
Number(km),
Number(year),
Number(price),
Number(estimation),
make,
model
)
return Response.json({ message: 'ok' }, { status: 200 })
}
Loading

0 comments on commit 1c0907a

Please sign in to comment.