single service + 404 page and 500 page
This commit is contained in:
@@ -0,0 +1,81 @@
|
||||
export default function Loading() {
|
||||
return (
|
||||
<div className='w-full flex gap-6 mt-4'>
|
||||
<div className='flex-1 max-w-full'>
|
||||
{/* Service Header Skeleton */}
|
||||
<div className="bg-white p-6 rounded-3xl animate-pulse">
|
||||
<div className="h-8 w-60 bg-gray-200 rounded-md"></div>
|
||||
<div className="mt-4 flex justify-between items-center">
|
||||
<div className="h-5 w-32 bg-gray-200 rounded-md"></div>
|
||||
<div className="h-10 w-32 bg-gray-200 rounded-3xl"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Stats Skeleton */}
|
||||
<div className='mt-8 flex xl:flex-row flex-col overflowX justify-between items-center xl:gap-8 gap-5'>
|
||||
{[1, 2, 3, 4, 5].map((i) => (
|
||||
<div key={`stat-${i}`} className='bg-white flex xl:min-w-[127px] w-full flex-1 flex-col justify-center items-center h-[109px] rounded-2xl py-6 px-4 animate-pulse'>
|
||||
<div className='h-4 w-20 bg-gray-200 rounded-md'></div>
|
||||
<div className='mt-3 h-5 w-16 bg-gray-200 rounded-md'></div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* Service Images Skeleton */}
|
||||
<div className="mt-8 grid grid-cols-2 gap-4 animate-pulse">
|
||||
<div className="h-64 bg-gray-200 rounded-2xl"></div>
|
||||
<div className="h-64 bg-gray-200 rounded-2xl"></div>
|
||||
</div>
|
||||
|
||||
{/* Description Skeleton */}
|
||||
<div className='mt-8 bg-white p-6 rounded-3xl animate-pulse'>
|
||||
<div className="h-6 w-32 bg-gray-200 rounded-md"></div>
|
||||
<div className="mt-4 space-y-3">
|
||||
<div className="h-4 w-full bg-gray-200 rounded-md"></div>
|
||||
<div className="h-4 w-full bg-gray-200 rounded-md"></div>
|
||||
<div className="h-4 w-full bg-gray-200 rounded-md"></div>
|
||||
<div className="h-4 w-3/4 bg-gray-200 rounded-md"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Reviews Skeleton */}
|
||||
<div className='mt-8 flex xl:flex-row flex-col gap-8 items-start'>
|
||||
<div className='flex-1 w-full max-w-full bg-white p-6 rounded-3xl animate-pulse'>
|
||||
<div className="h-6 w-32 bg-gray-200 rounded-md"></div>
|
||||
|
||||
{[1, 2].map((i) => (
|
||||
<div key={`review-${i}`} className='mt-5 border border-gray-200 rounded-3xl p-6'>
|
||||
<div className='flex gap-2 items-center'>
|
||||
<div className="h-6 w-6 bg-gray-200 rounded-full"></div>
|
||||
<div className="h-4 w-32 bg-gray-200 rounded-md"></div>
|
||||
</div>
|
||||
<div className='mt-4 flex justify-between'>
|
||||
<div className="h-5 w-3/4 bg-gray-200 rounded-md"></div>
|
||||
<div className="h-4 w-20 bg-gray-200 rounded-md"></div>
|
||||
</div>
|
||||
<div className='mt-2 flex'>
|
||||
{[1, 2, 3, 4, 5].map((star) => (
|
||||
<div key={`star-${i}-${star}`} className="h-4 w-4 bg-gray-200 rounded-sm mr-1"></div>
|
||||
))}
|
||||
</div>
|
||||
<div className='mt-4 space-y-2'>
|
||||
<div className="h-3 w-full bg-gray-200 rounded-md"></div>
|
||||
<div className="h-3 w-full bg-gray-200 rounded-md"></div>
|
||||
<div className="h-3 w-1/2 bg-gray-200 rounded-md"></div>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Sidebar Ad Skeleton */}
|
||||
<div className='bg-white w-sidebar h-[550px] hidden xl:block rounded-3xl overflow-hidden sticky top-4 animate-pulse'>
|
||||
<div className="w-full h-full bg-gray-200"></div>
|
||||
<div className='absolute flex items-center px-4 w-full bottom-0 h-[86px] bg-gray-100'>
|
||||
<div className="h-5 w-3/4 bg-gray-200 rounded-md"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -1,9 +1,39 @@
|
||||
import React from 'react'
|
||||
import { Suspense } from 'react'
|
||||
import { dehydrate, HydrationBoundary, QueryClient } from '@tanstack/react-query'
|
||||
import { detailServiceQueryOptions } from '../hooks/useProductData'
|
||||
import { NextPage } from 'next'
|
||||
import DetailService from '../DetailService'
|
||||
import Loading from './loading'
|
||||
|
||||
interface PageProps {
|
||||
params: Promise<{
|
||||
id: string
|
||||
}>
|
||||
}
|
||||
|
||||
const SingleService: NextPage<PageProps> = async ({ params }) => {
|
||||
|
||||
const { id } = await params
|
||||
|
||||
const page = () => {
|
||||
return (
|
||||
<div>page</div>
|
||||
<Suspense fallback={<Loading />}>
|
||||
<SingleServicePage id={id} />
|
||||
</Suspense>
|
||||
)
|
||||
}
|
||||
|
||||
export default page
|
||||
async function SingleServicePage({ id }: { id: string }) {
|
||||
const queryClient = new QueryClient()
|
||||
|
||||
await Promise.all([
|
||||
queryClient.prefetchQuery(detailServiceQueryOptions(id)),
|
||||
])
|
||||
|
||||
return (
|
||||
<HydrationBoundary state={dehydrate(queryClient)}>
|
||||
<DetailService id={id} />
|
||||
</HydrationBoundary>
|
||||
)
|
||||
}
|
||||
|
||||
export default SingleService
|
||||
Reference in New Issue
Block a user