buy service and discount and text + ...
This commit is contained in:
@@ -1,16 +1,19 @@
|
||||
import { FC } from 'react'
|
||||
import { FC, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import Input from '../../components/Input'
|
||||
import Select from '../../components/Select'
|
||||
import ServiceSection from '../../components/ServiceSection'
|
||||
import StatusCircle from '../../components/StatusCircle'
|
||||
import BannerImage from '../../assets/images/banner.png'
|
||||
import { Link } from 'react-router-dom'
|
||||
import { Pages } from '../../config/Pages'
|
||||
import { useGetMyServices } from './hooks/useServiceData'
|
||||
import { MyServicesItem } from './types/ServiecTypes'
|
||||
|
||||
const MyServices: FC = () => {
|
||||
|
||||
const { t } = useTranslation('global')
|
||||
const [search, setSearch] = useState<string>('')
|
||||
const getServices = useGetMyServices(search)
|
||||
|
||||
return (
|
||||
<div className='w-full flex gap-6 mt-4'>
|
||||
@@ -25,10 +28,11 @@ const MyServices: FC = () => {
|
||||
variant='search'
|
||||
placeholder={t('service.search')}
|
||||
className='bg-white w-full'
|
||||
onChangeSearchFinal={(value) => setSearch(value)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
{/* <div>
|
||||
<Select
|
||||
items={[
|
||||
{ label: t('all'), value: 'all' },
|
||||
@@ -37,122 +41,47 @@ const MyServices: FC = () => {
|
||||
]}
|
||||
className='max-w-[100px]'
|
||||
/>
|
||||
</div>
|
||||
</div> */}
|
||||
</div>
|
||||
|
||||
<div className='flex flex-wrap xl:gap-6 gap-4 items-center mt-8'>
|
||||
|
||||
<Link to={Pages.services.detail + '1'} className='flex-1 min-w-[40%] xl:min-w-[20%] bg-white rounded-3xl p-6'>
|
||||
<ServiceSection
|
||||
item={{
|
||||
author: "داناک",
|
||||
createDate: "1403-11-23T20:34:16.000Z",
|
||||
createdAt: "2025-02-12T07:24:31.499Z",
|
||||
description: "توضیح کوتاه",
|
||||
icon: "https://dsc.storage.iran.liara.space/images/19216818-b1ce-4339-b238-9e7ac866d6dc1739345063078.png",
|
||||
id: "53c3f206-d262-4376-ba9b-92d6c1c3d8fa",
|
||||
isActive: true,
|
||||
isDanakSuggest: true,
|
||||
link: "https://google.com",
|
||||
metaDescription: "<p><br></p><p>asd asd asd</p>",
|
||||
name: "تست",
|
||||
serviceLanguage: "fa",
|
||||
softwareLanguage: "جاوا اسکریپت",
|
||||
updatedAt: "2025-02-12T07:40:08.939Z",
|
||||
userCount: 222
|
||||
}}
|
||||
/>
|
||||
<div className='mt-6 flex gap-1 items-center'>
|
||||
<StatusCircle
|
||||
color='#00BA4B'
|
||||
/>
|
||||
<div className='text-xs text-description'>1 {t('service.active_menu')}</div>
|
||||
</div>
|
||||
{
|
||||
getServices.data?.data?.subscriptions?.map((item: MyServicesItem) => {
|
||||
return (
|
||||
<Link key={item.id} to={Pages.services.detail + item.id} className='flex-1 min-w-[40%] xl:min-w-[20%] bg-white rounded-3xl p-6'>
|
||||
<ServiceSection
|
||||
item={{
|
||||
author: item.plan.service.author,
|
||||
createDate: item.plan?.service?.createDate,
|
||||
createdAt: item.createdAt,
|
||||
description: item.plan?.service?.description,
|
||||
icon: item.plan?.service.icon,
|
||||
id: item.plan.service.id,
|
||||
isActive: item.plan.isActive,
|
||||
isDanakSuggest: item.plan.service.isDanakSuggest,
|
||||
link: item.plan.service.link,
|
||||
metaDescription: item.plan.service.metaDescription,
|
||||
name: item.plan.service.name,
|
||||
serviceLanguage: item.plan.service.serviceLanguage,
|
||||
softwareLanguage: item.plan.service.softwareLanguage,
|
||||
updatedAt: item.plan.service.updatedAt,
|
||||
userCount: item.plan.service?.userCount
|
||||
}}
|
||||
/>
|
||||
<div className='mt-6 flex gap-1 items-center'>
|
||||
<StatusCircle
|
||||
color='#00BA4B'
|
||||
/>
|
||||
<div className='text-xs text-description'>1 {t('service.active_menu')}</div>
|
||||
</div>
|
||||
|
||||
</Link>
|
||||
<Link to={Pages.services.detail + '1'} className='flex-1 min-w-[40%] xl:min-w-[20%] bg-white rounded-3xl p-6'>
|
||||
<ServiceSection
|
||||
item={{
|
||||
author: "داناک",
|
||||
createDate: "1403-11-23T20:34:16.000Z",
|
||||
createdAt: "2025-02-12T07:24:31.499Z",
|
||||
description: "توضیح کوتاه",
|
||||
icon: "https://dsc.storage.iran.liara.space/images/19216818-b1ce-4339-b238-9e7ac866d6dc1739345063078.png",
|
||||
id: "53c3f206-d262-4376-ba9b-92d6c1c3d8fa",
|
||||
isActive: true,
|
||||
isDanakSuggest: true,
|
||||
link: "https://google.com",
|
||||
metaDescription: "<p><br></p><p>asd asd asd</p>",
|
||||
name: "تست",
|
||||
serviceLanguage: "fa",
|
||||
softwareLanguage: "جاوا اسکریپت",
|
||||
updatedAt: "2025-02-12T07:40:08.939Z",
|
||||
userCount: 222
|
||||
}}
|
||||
/>
|
||||
<div className='mt-6 flex gap-1 items-center'>
|
||||
<StatusCircle
|
||||
color='#00BA4B'
|
||||
/>
|
||||
<div className='text-xs text-description'>1 {t('service.active_menu')}</div>
|
||||
</div>
|
||||
</Link>
|
||||
<Link to={Pages.services.detail + '1'} className='flex-1 min-w-[40%] xl:min-w-[20%] bg-white rounded-3xl p-6'>
|
||||
<ServiceSection
|
||||
item={{
|
||||
author: "داناک",
|
||||
createDate: "1403-11-23T20:34:16.000Z",
|
||||
createdAt: "2025-02-12T07:24:31.499Z",
|
||||
description: "توضیح کوتاه",
|
||||
icon: "https://dsc.storage.iran.liara.space/images/19216818-b1ce-4339-b238-9e7ac866d6dc1739345063078.png",
|
||||
id: "53c3f206-d262-4376-ba9b-92d6c1c3d8fa",
|
||||
isActive: true,
|
||||
isDanakSuggest: true,
|
||||
link: "https://google.com",
|
||||
metaDescription: "<p><br></p><p>asd asd asd</p>",
|
||||
name: "تست",
|
||||
serviceLanguage: "fa",
|
||||
softwareLanguage: "جاوا اسکریپت",
|
||||
updatedAt: "2025-02-12T07:40:08.939Z",
|
||||
userCount: 222
|
||||
}}
|
||||
/>
|
||||
<div className='mt-6 flex gap-1 items-center'>
|
||||
<StatusCircle
|
||||
color='#00BA4B'
|
||||
/>
|
||||
<div className='text-xs text-description'>1 {t('service.active_menu')}</div>
|
||||
</div>
|
||||
</Link>
|
||||
</Link>
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
<Link to={Pages.services.detail + '1'} className='flex-1 min-w-[40%] xl:min-w-[20%] bg-white rounded-3xl p-6'>
|
||||
<ServiceSection
|
||||
item={{
|
||||
author: "داناک",
|
||||
createDate: "1403-11-23T20:34:16.000Z",
|
||||
createdAt: "2025-02-12T07:24:31.499Z",
|
||||
description: "توضیح کوتاه",
|
||||
icon: "https://dsc.storage.iran.liara.space/images/19216818-b1ce-4339-b238-9e7ac866d6dc1739345063078.png",
|
||||
id: "53c3f206-d262-4376-ba9b-92d6c1c3d8fa",
|
||||
isActive: true,
|
||||
isDanakSuggest: true,
|
||||
link: "https://google.com",
|
||||
metaDescription: "<p><br></p><p>asd asd asd</p>",
|
||||
name: "تست",
|
||||
serviceLanguage: "fa",
|
||||
softwareLanguage: "جاوا اسکریپت",
|
||||
updatedAt: "2025-02-12T07:40:08.939Z",
|
||||
userCount: 222
|
||||
}}
|
||||
/>
|
||||
<div className='mt-6 flex gap-1 items-center'>
|
||||
<StatusCircle
|
||||
color='#00BA4B'
|
||||
/>
|
||||
<div className='text-xs text-description'>1 {t('service.active_menu')}</div>
|
||||
</div>
|
||||
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
<div className='bg-white w-sidebar hidden xl:block rounded-3xl overflow-hidden relative'>
|
||||
|
||||
@@ -1,10 +1,16 @@
|
||||
import { FC, useState } from 'react'
|
||||
import { FC, useEffect, useState } from 'react'
|
||||
import RadioGroup from '../../../components/RadioGroup'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import ShareIcon from '../../../assets/images/share.svg'
|
||||
import Button from '../../../components/Button'
|
||||
import { ArrowLeft } from 'iconsax-react'
|
||||
import { ServiceDetailDataType } from '../types/ServiecTypes'
|
||||
import { PlanItemType, ServiceDetailDataType } from '../types/ServiecTypes'
|
||||
import { NumberFormat } from '../../../config/func'
|
||||
import { useBuyService } from '../hooks/useServiceData'
|
||||
import { toast } from 'react-toastify'
|
||||
import { useNavigate } from 'react-router-dom'
|
||||
import { Pages } from '../../../config/Pages'
|
||||
import { ErrorType } from '../../../helpers/types'
|
||||
|
||||
type Props = {
|
||||
data: ServiceDetailDataType
|
||||
@@ -12,9 +18,38 @@ type Props = {
|
||||
|
||||
const ServiceHeader: FC<Props> = (props: Props) => {
|
||||
|
||||
const navigate = useNavigate()
|
||||
const { data } = props
|
||||
const { t } = useTranslation('global')
|
||||
const [planSelected, setPlanSelected] = useState<'year' | '3month' | 'month'>('year')
|
||||
const [planSelected, setPlanSelected] = useState<string>(data?.subscriptionPlans[0]?.id)
|
||||
const [price, setPrice] = useState<number>(data?.subscriptionPlans[0]?.price)
|
||||
const [finalPrice, setFinalPrice] = useState<number>(0)
|
||||
const [planText, setPlanText] = useState<string>('')
|
||||
const buyService = useBuyService()
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
const plan: PlanItemType = data?.subscriptionPlans.find((item) => item.id === planSelected)
|
||||
console.log(plan);
|
||||
|
||||
setPlanText(plan.name)
|
||||
setFinalPrice(plan.finalPrice)
|
||||
setPrice(plan?.price)
|
||||
|
||||
}, [planSelected])
|
||||
|
||||
const handleBuy = () => {
|
||||
buyService.mutate({ serviceId: data.id, planId: planSelected }, {
|
||||
onSuccess: () => {
|
||||
toast.success(t('success'))
|
||||
navigate(Pages.services.mine)
|
||||
},
|
||||
onError: (error: ErrorType) => {
|
||||
toast.error(error.response?.data?.error?.message[0])
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
return (
|
||||
<div className='w-full p-6 bg-white rounded-3xl flex xl:flex-row flex-col xl:justify-between'>
|
||||
@@ -27,27 +62,19 @@ const ServiceHeader: FC<Props> = (props: Props) => {
|
||||
{data?.name}
|
||||
</div>
|
||||
<div className='text-xs xl:mt-3 mt-1.5 text-[#4E505A]'>
|
||||
منوی رستوران
|
||||
{data?.title}
|
||||
</div>
|
||||
<p className='text-description mt-1 text-[11px]'>
|
||||
{data?.description}
|
||||
</p>
|
||||
<div className='hidden xl:flex gap-5 mt-5'>
|
||||
<RadioGroup
|
||||
items={[
|
||||
{
|
||||
label: t('service.year'),
|
||||
value: 'year'
|
||||
},
|
||||
{
|
||||
label: t('service.month3'),
|
||||
value: '3month'
|
||||
},
|
||||
{
|
||||
label: t('service.month'),
|
||||
value: 'month'
|
||||
items={data?.subscriptionPlans?.map((item) => {
|
||||
return {
|
||||
label: item?.name,
|
||||
value: item?.id
|
||||
}
|
||||
]}
|
||||
})}
|
||||
onChange={setPlanSelected}
|
||||
selected={planSelected}
|
||||
/>
|
||||
@@ -58,20 +85,12 @@ const ServiceHeader: FC<Props> = (props: Props) => {
|
||||
<div className='flex flex-col justify-between xl:items-end'>
|
||||
<div className='xl:hidden flex gap-5 mt-5'>
|
||||
<RadioGroup
|
||||
items={[
|
||||
{
|
||||
label: t('service.year'),
|
||||
value: 'year'
|
||||
},
|
||||
{
|
||||
label: t('service.month3'),
|
||||
value: '3month'
|
||||
},
|
||||
{
|
||||
label: t('service.month'),
|
||||
value: 'month'
|
||||
items={data?.subscriptionPlans?.map((item) => {
|
||||
return {
|
||||
label: item?.name,
|
||||
value: item?.id
|
||||
}
|
||||
]}
|
||||
})}
|
||||
onChange={setPlanSelected}
|
||||
selected={planSelected}
|
||||
/>
|
||||
@@ -80,8 +99,21 @@ const ServiceHeader: FC<Props> = (props: Props) => {
|
||||
<img src={ShareIcon} className='w-4' />
|
||||
</div>
|
||||
<div className='flex gap-4 mt-5 xl:mt-0 items-center justify-between xl:justify-normal'>
|
||||
<div className='text-xs whitespace-nowrap'>2,000,000 تومان {t('service.year')}</div>
|
||||
<div className='text-xs whitespace-nowrap flex gap-1 items-center'>
|
||||
<div className='flex gap-2'>
|
||||
{
|
||||
finalPrice !== price &&
|
||||
<div className='line-through text-xs text-description'>
|
||||
{NumberFormat(Number(price))}
|
||||
</div>
|
||||
}
|
||||
<div>{NumberFormat(Number(finalPrice))}</div>
|
||||
</div>
|
||||
<span>{planText}</span>
|
||||
</div>
|
||||
<Button
|
||||
onClick={handleBuy}
|
||||
isLoading={buyService.isPending}
|
||||
className='bg-description xl:max-w-full max-w-[100px] text-xs h-8 bg-opacity-20 text-black px-4'
|
||||
>
|
||||
<div className='flex gap-1 items-center'>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import { useMutation, useQuery } from "@tanstack/react-query";
|
||||
import * as api from "../service/ServiceService";
|
||||
import { BuyServiceType } from "../types/ServiecTypes";
|
||||
|
||||
export const useGetSuggestedServices = () => {
|
||||
return useQuery({
|
||||
@@ -30,3 +31,16 @@ export const useGetDetailService = (serviceId: string) => {
|
||||
enabled: !!serviceId,
|
||||
});
|
||||
};
|
||||
|
||||
export const useBuyService = () => {
|
||||
return useMutation({
|
||||
mutationFn: (variables: BuyServiceType) => api.buyService(variables),
|
||||
});
|
||||
};
|
||||
|
||||
export const useGetMyServices = (search: string) => {
|
||||
return useQuery({
|
||||
queryKey: ["myservices", search],
|
||||
queryFn: () => api.getMyServices(search),
|
||||
});
|
||||
};
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import axios from "../../../config/axios";
|
||||
import { BuyServiceType } from "../types/ServiecTypes";
|
||||
|
||||
export const getServiceSuggestedDanak = async () => {
|
||||
const { data } = await axios.get(`/danak-services/suggested`);
|
||||
@@ -19,3 +20,15 @@ export const getDetailService = async (serviceId: string) => {
|
||||
const { data } = await axios.get(`/danak-services/${serviceId}`);
|
||||
return data;
|
||||
};
|
||||
|
||||
export const buyService = async (params: BuyServiceType) => {
|
||||
const { data } = await axios.post(
|
||||
`/subscriptions/${params.serviceId}/subscribe`,
|
||||
params
|
||||
);
|
||||
return data;
|
||||
};
|
||||
export const getMyServices = async (search: string) => {
|
||||
const { data } = await axios.get(`/subscriptions/user?q=${search}`);
|
||||
return data;
|
||||
};
|
||||
|
||||
@@ -44,4 +44,69 @@ export type ServiceDetailDataType = {
|
||||
subscriptionPlans: any[];
|
||||
updatedAt: string;
|
||||
userCount: number;
|
||||
title: string;
|
||||
};
|
||||
|
||||
export type PlanItemType = {
|
||||
createdAt: string;
|
||||
discounts: {
|
||||
amount: number;
|
||||
calculationType: string;
|
||||
code: string;
|
||||
createdAt: string;
|
||||
endDate: string;
|
||||
id: string;
|
||||
isActive: boolean;
|
||||
startDate: string;
|
||||
title: string;
|
||||
type: string;
|
||||
}[];
|
||||
duration: number;
|
||||
finalPrice: number;
|
||||
id: string;
|
||||
isActive: boolean;
|
||||
name: string;
|
||||
price: number;
|
||||
updatedAt: string;
|
||||
};
|
||||
|
||||
export type BuyServiceType = {
|
||||
planId: string;
|
||||
serviceId: string;
|
||||
};
|
||||
|
||||
export type MyServicesItem = {
|
||||
createdAt: string;
|
||||
endDate: string;
|
||||
id: string;
|
||||
isCanceled: boolean;
|
||||
plan: {
|
||||
id: string;
|
||||
createdAt: string;
|
||||
duration: number;
|
||||
isActive: boolean;
|
||||
name: string;
|
||||
price: number;
|
||||
service: {
|
||||
author: string;
|
||||
createDate: string;
|
||||
createdAt: string;
|
||||
description: string;
|
||||
icon: string;
|
||||
id: string;
|
||||
isActive: boolean;
|
||||
isDanakSuggest: boolean;
|
||||
link: string;
|
||||
metaDescription: string;
|
||||
name: string;
|
||||
serviceLanguage: string;
|
||||
softwareLanguage: string;
|
||||
title: string;
|
||||
updatedAt: string;
|
||||
userCount: number;
|
||||
};
|
||||
};
|
||||
startDate: string;
|
||||
status: string;
|
||||
updatedAt: string;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user