single service

This commit is contained in:
hamid zarghami
2025-02-12 15:46:39 +03:30
parent 65415ba676
commit c9781b9074
7 changed files with 258 additions and 208 deletions
+1
View File
@@ -98,6 +98,7 @@
"year_make": "سال ساخت", "year_make": "سال ساخت",
"lang_app": "زبان نرم افزار", "lang_app": "زبان نرم افزار",
"persian": "فارسی", "persian": "فارسی",
"english": "انگیلیسی",
"score": "امتیاز", "score": "امتیاز",
"compelete_description": "توضیحات تکمیلی", "compelete_description": "توضیحات تکمیلی",
"submit_comment": "ثبت نظر", "submit_comment": "ثبت نظر",
+23 -9
View File
@@ -1,4 +1,4 @@
import { FC } from 'react' import { FC, Fragment } from 'react'
import RobotImage from '../../assets/images/robot.jpeg' import RobotImage from '../../assets/images/robot.jpeg'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import Button from '../../components/Button' import Button from '../../components/Button'
@@ -8,17 +8,29 @@ import Input from '../../components/Input'
import Textarea from '../../components/Textarea' import Textarea from '../../components/Textarea'
import AvatarImage from '../../assets/images/Avatar.png' import AvatarImage from '../../assets/images/Avatar.png'
import ServiceHeader from './components/ServiceHeader' import ServiceHeader from './components/ServiceHeader'
import { useGetDetailService } from './hooks/useServiceData'
import { useParams } from 'react-router-dom'
import PageLoading from '../../components/PageLoading'
import moment from 'moment-jalaali'
const DetailService: FC = () => { const DetailService: FC = () => {
const { id } = useParams()
const { t } = useTranslation('global') const { t } = useTranslation('global')
const getDetailService = useGetDetailService(id ? id : '')
return ( return (
<div className='w-full flex gap-6 mt-4'> <div className='w-full flex gap-6 mt-4'>
{
getDetailService.isPending ?
<PageLoading />
:
<Fragment>
<div className='flex-1 max-w-full'> <div className='flex-1 max-w-full'>
<ServiceHeader /> <ServiceHeader data={getDetailService?.data?.data?.danakService} />
<div className='mt-8 flex overflowX justify-between items-center xl:gap-8 gap-5'> <div className='mt-8 flex overflowX justify-between items-center xl:gap-8 gap-5'>
<div className='bg-white flex xl:min-w-max min-w-[127px] flex-1 flex-col justify-center items-center h-[109px] rounded-2xl py-6 px-4'> <div className='bg-white flex xl:min-w-max min-w-[127px] flex-1 flex-col justify-center items-center h-[109px] rounded-2xl py-6 px-4'>
<div className='text-description xl:text-xs text-[11px]'> <div className='text-description xl:text-xs text-[11px]'>
@@ -33,7 +45,7 @@ const DetailService: FC = () => {
{t('service.user_count')} {t('service.user_count')}
</div> </div>
<div className='mt-3 text-sm'> <div className='mt-3 text-sm'>
+۵۰۰ +{getDetailService?.data?.data?.danakService?.userCount}
</div> </div>
</div> </div>
<div className='bg-white flex xl:min-w-max min-w-[127px] flex-1 flex-col justify-center items-center h-[109px] rounded-2xl py-6 px-4'> <div className='bg-white flex xl:min-w-max min-w-[127px] flex-1 flex-col justify-center items-center h-[109px] rounded-2xl py-6 px-4'>
@@ -41,7 +53,7 @@ const DetailService: FC = () => {
{t('service.year_make')} {t('service.year_make')}
</div> </div>
<div className='mt-3 text-sm'> <div className='mt-3 text-sm'>
۱۴۰۰ {moment(getDetailService?.data?.data?.danakService?.createDate, 'jYYYY-jMM-jDD').format('jYYYY')}
</div> </div>
</div> </div>
<div className='bg-white flex xl:min-w-max min-w-[127px] flex-1 flex-col justify-center items-center h-[109px] rounded-2xl py-6 px-4'> <div className='bg-white flex xl:min-w-max min-w-[127px] flex-1 flex-col justify-center items-center h-[109px] rounded-2xl py-6 px-4'>
@@ -49,7 +61,7 @@ const DetailService: FC = () => {
{t('service.lang_app')} {t('service.lang_app')}
</div> </div>
<div className='mt-3 text-sm'> <div className='mt-3 text-sm'>
{t('service.persian')} {getDetailService?.data?.data?.danakService?.serviceLanguage === 'fa' ? t('service.persian') : t('service.english')}
</div> </div>
</div> </div>
<div className='bg-white flex xl:min-w-max min-w-[127px] flex-1 flex-col justify-center items-center h-[109px] rounded-2xl py-6 px-4'> <div className='bg-white flex xl:min-w-max min-w-[127px] flex-1 flex-col justify-center items-center h-[109px] rounded-2xl py-6 px-4'>
@@ -67,14 +79,13 @@ const DetailService: FC = () => {
</div> </div>
</div> </div>
<ServiceImages /> <ServiceImages images={getDetailService?.data?.data?.danakService?.images} />
<div className='mt-8 bg-white p-6 rounded-3xl'> <div className='mt-8 bg-white p-6 rounded-3xl'>
<div> <div>
{t('service.compelete_description')} {t('service.compelete_description')}
</div> </div>
<p className='text-[11px] mt-4 leading-6'> <p dangerouslySetInnerHTML={{ __html: getDetailService.data?.data?.danakService?.metaDescription }} className='text-[11px] mt-4 leading-6'>
لورم ایپسوم متن ساختگی با تولید سادگی نامفهوم از صنعت چاپ، و با استفاده از طراحان گرافیک است، چاپگرها و متون بلکه روزنامه و مجله در ستون و سطرآنچنان که لازم است، و برای شرایط فعلی تکنولوژی مورد نیاز، و کاربردهای متنوع با هدف بهبود ابزارهای کاربردی می باشد، کتابهای زیادی در شصت و سه درصد گذشته حال و آینده، شناخت فراوان جامعه و متخصصان را می طلبد، تا با نرم افزارها شناخت بیشتری را برای طراحان رایانه ای علی الخصوص طراحان خلاقی، و فرهنگ پیشرو در زبان فارسی ایجاد کرد، در این صورت می توان امید داشت که تمام و دشواری موجود در ارائه راهکارها، و شرایط سخت تایپ به پایان رسد و زمان مورد نیاز شامل حروفچینی دستاوردهای اصلی، و جوابگوی سوالات پیوسته اهل دنیای موجود طراحی اساسا مورد استفاده قرار گیرد.
</p> </p>
</div> </div>
@@ -193,7 +204,6 @@ const DetailService: FC = () => {
</div> </div>
</div> </div>
</div> </div>
<div className='bg-white w-sidebar h-fit hidden xl:block rounded-3xl overflow-hidden relative'> <div className='bg-white w-sidebar h-fit hidden xl:block rounded-3xl overflow-hidden relative'>
<img <img
src={RobotImage} src={RobotImage}
@@ -206,6 +216,10 @@ const DetailService: FC = () => {
</div> </div>
</div> </div>
</div> </div>
</Fragment>
}
</div> </div>
) )
} }
+12 -4
View File
@@ -4,25 +4,33 @@ import { useTranslation } from 'react-i18next'
import ShareIcon from '../../../assets/images/share.svg' import ShareIcon from '../../../assets/images/share.svg'
import Button from '../../../components/Button' import Button from '../../../components/Button'
import { ArrowLeft } from 'iconsax-react' import { ArrowLeft } from 'iconsax-react'
import { ServiceDetailDataType } from '../types/ServiecTypes'
const ServiceHeader: FC = () => { type Props = {
data: ServiceDetailDataType
}
const ServiceHeader: FC<Props> = (props: Props) => {
const { data } = props
const { t } = useTranslation('global') const { t } = useTranslation('global')
const [planSelected, setPlanSelected] = useState<'year' | '3month' | 'month'>('year') const [planSelected, setPlanSelected] = useState<'year' | '3month' | 'month'>('year')
return ( return (
<div className='w-full p-6 bg-white rounded-3xl flex xl:flex-row flex-col xl:justify-between'> <div className='w-full p-6 bg-white rounded-3xl flex xl:flex-row flex-col xl:justify-between'>
<div className='flex xl:gap-8 gap-4'> <div className='flex xl:gap-8 gap-4'>
<div className='xl:size-[70px] size-[50px] bg-blue-400 rounded-xl'></div> <div className='xl:size-[70px] size-[50px] rounded-xl'>
<img src={data?.icon} className='w-full h-full rounded-xl' />
</div>
<div> <div>
<div> <div>
دی منو {data?.name}
</div> </div>
<div className='text-xs xl:mt-3 mt-1.5 text-[#4E505A]'> <div className='text-xs xl:mt-3 mt-1.5 text-[#4E505A]'>
منوی رستوران منوی رستوران
</div> </div>
<p className='text-description mt-1 text-[11px]'> <p className='text-description mt-1 text-[11px]'>
دی منو، راهی ساده و هوشمند برای مدیریت منو شما! {data?.description}
</p> </p>
<div className='hidden xl:flex gap-5 mt-5'> <div className='hidden xl:flex gap-5 mt-5'>
<RadioGroup <RadioGroup
+13 -19
View File
@@ -1,13 +1,16 @@
import { FC } from 'react' import { FC } from 'react'
import { Swiper, SwiperSlide } from 'swiper/react' import { Swiper, SwiperSlide } from 'swiper/react'
import AppImage from '../../../assets/images/appimage.png'
const SWIPER_SLIDE_STYLE = { const SWIPER_SLIDE_STYLE = {
overflow: 'visible !important', overflow: 'visible !important',
// width: 220, // width: 220,
} }
const ServiceImages: FC = () => { type Props = {
images: { id: string, imageUrl: string }[]
}
const ServiceImages: FC<Props> = ({ images }) => {
return ( return (
<div className='w-full mt-8'> <div className='w-full mt-8'>
<Swiper <Swiper
@@ -16,26 +19,17 @@ const ServiceImages: FC = () => {
slidesPerView='auto' slidesPerView='auto'
> >
<SwiperSlide className='max-w-[38%]' style={SWIPER_SLIDE_STYLE}> {
images.map((item) => {
return (
<SwiperSlide key={item.id} className='max-w-[38%]' style={SWIPER_SLIDE_STYLE}>
<div className='bg-white bg-opacity-50 w-full p-2 rounded-2xl'> <div className='bg-white bg-opacity-50 w-full p-2 rounded-2xl'>
<img src={AppImage} className='w-full' /> <img src={item.imageUrl} className='w-full rounded-2xl' />
</div>
</SwiperSlide>
<SwiperSlide className='max-w-[38%]' style={SWIPER_SLIDE_STYLE}>
<div className='bg-white bg-opacity-50 w-full p-2 rounded-2xl'>
<img src={AppImage} className='w-full' />
</div>
</SwiperSlide>
<SwiperSlide className='max-w-[38%]' style={SWIPER_SLIDE_STYLE}>
<div className='bg-white bg-opacity-50 w-full p-2 rounded-2xl'>
<img src={AppImage} className='w-full' />
</div>
</SwiperSlide>
<SwiperSlide className='max-w-[38%]' style={SWIPER_SLIDE_STYLE}>
<div className='bg-white bg-opacity-50 w-full p-2 rounded-2xl'>
<img src={AppImage} className='w-full' />
</div> </div>
</SwiperSlide> </SwiperSlide>
)
})
}
</Swiper> </Swiper>
</div> </div>
) )
@@ -22,3 +22,11 @@ export const useGetServicesByCategory = (categoryId: string) => {
enabled: !!categoryId, enabled: !!categoryId,
}); });
}; };
export const useGetDetailService = (serviceId: string) => {
return useQuery({
queryKey: ["service", serviceId],
queryFn: () => api.getDetailService(serviceId),
enabled: !!serviceId,
});
};
@@ -14,3 +14,8 @@ export const getServicesByCategory = async (categoryId: string) => {
); );
return data; return data;
}; };
export const getDetailService = async (serviceId: string) => {
const { data } = await axios.get(`/danak-services/${serviceId}`);
return data;
};
+20
View File
@@ -25,3 +25,23 @@ export type CategoryItemType = {
title: string; title: string;
updatedAt: string; updatedAt: string;
}; };
export type ServiceDetailDataType = {
author: string;
createDate: string;
createdAt: string;
description: string;
icon: string;
id: string;
images: { id: string; createdAt: string; imageUrl: string }[];
isActive: boolean;
isDanakSuggest: boolean;
link: string;
metaDescription: string;
name: string;
serviceLanguage: string;
softwareLanguage: string;
subscriptionPlans: any[];
updatedAt: string;
userCount: number;
};