fix hidden free plan + show remain days
This commit is contained in:
@@ -5,6 +5,8 @@ import { ArrowLeft, More } from 'iconsax-react'
|
|||||||
import Button from './Button'
|
import Button from './Button'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { ItemServiceType } from '../pages/service/types/ServiecTypes'
|
import { ItemServiceType } from '../pages/service/types/ServiecTypes'
|
||||||
|
import moment from 'moment-jalaali'
|
||||||
|
import { NumberFormat } from '../config/func'
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
item: ItemServiceType,
|
item: ItemServiceType,
|
||||||
@@ -15,6 +17,7 @@ type Props = {
|
|||||||
isQuikAccess?: boolean,
|
isQuikAccess?: boolean,
|
||||||
onMoreClick?: () => void,
|
onMoreClick?: () => void,
|
||||||
subscriptionId?: string,
|
subscriptionId?: string,
|
||||||
|
endDate?: string,
|
||||||
}
|
}
|
||||||
|
|
||||||
const ServiceItem: FC<Props> = (props: Props) => {
|
const ServiceItem: FC<Props> = (props: Props) => {
|
||||||
@@ -22,6 +25,34 @@ const ServiceItem: FC<Props> = (props: Props) => {
|
|||||||
const { t } = useTranslation('global')
|
const { t } = useTranslation('global')
|
||||||
const { item } = props
|
const { item } = props
|
||||||
|
|
||||||
|
const getRemainingDays = (endDate: string): number => {
|
||||||
|
const now = moment()
|
||||||
|
const end = moment(endDate)
|
||||||
|
const diff = end.diff(now, 'days')
|
||||||
|
return diff
|
||||||
|
}
|
||||||
|
|
||||||
|
const getRemainingDaysColor = (days: number): string => {
|
||||||
|
if (days < 0) return 'text-red-600'
|
||||||
|
if (days <= 7) return 'text-red-500'
|
||||||
|
if (days <= 30) return 'text-orange-500'
|
||||||
|
return 'text-green-600'
|
||||||
|
}
|
||||||
|
|
||||||
|
const getRemainingDaysText = (endDate: string): string => {
|
||||||
|
const days = getRemainingDays(endDate)
|
||||||
|
if (days < 0) {
|
||||||
|
return `${NumberFormat(Math.abs(days))} روز گذشته`
|
||||||
|
}
|
||||||
|
if (days === 0) {
|
||||||
|
return 'امروز آخرین روز'
|
||||||
|
}
|
||||||
|
if (days === 1) {
|
||||||
|
return '۱ روز باقی مانده'
|
||||||
|
}
|
||||||
|
return `${NumberFormat(days)} روز باقی مانده`
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={`flex-1 relative flex flex-col self-stretch min-w-[45%] xl:min-w-[30%] bg-white rounded-3xl xl:p-6 p-4 ${props.className} ${props.isDisabled ? 'opacity-50' : ''}`}>
|
<div className={`flex-1 relative flex flex-col self-stretch min-w-[45%] xl:min-w-[30%] bg-white rounded-3xl xl:p-6 p-4 ${props.className} ${props.isDisabled ? 'opacity-50' : ''}`}>
|
||||||
{
|
{
|
||||||
@@ -44,8 +75,16 @@ const ServiceItem: FC<Props> = (props: Props) => {
|
|||||||
{props.businessName}
|
{props.businessName}
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
{
|
||||||
|
props.isLinkPanel && props.endDate &&
|
||||||
|
<div className={`mt-1 text-[11px] ${getRemainingDaysColor(getRemainingDays(props.endDate))}`}>
|
||||||
|
{getRemainingDaysText(props.endDate)}
|
||||||
|
</div>
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{
|
{
|
||||||
!props.isLinkPanel &&
|
!props.isLinkPanel &&
|
||||||
<div className='mt-4 text-xs'>
|
<div className='mt-4 text-xs'>
|
||||||
|
|||||||
+2
-1
@@ -136,7 +136,8 @@
|
|||||||
"short_description": "توضیح کوتاه",
|
"short_description": "توضیح کوتاه",
|
||||||
"confrim_and_invoice": "تایید و صدور صورت حساب",
|
"confrim_and_invoice": "تایید و صدور صورت حساب",
|
||||||
"extent": "تمدید پلن",
|
"extent": "تمدید پلن",
|
||||||
"extend": "تمدید"
|
"extend": "تمدید",
|
||||||
|
"end_date": "تاریخ پایان"
|
||||||
},
|
},
|
||||||
"loading": "در حال بارگذاری",
|
"loading": "در حال بارگذاری",
|
||||||
"footer": {
|
"footer": {
|
||||||
|
|||||||
@@ -66,6 +66,7 @@ const MyServices: FC = () => {
|
|||||||
businessName={item.businessName}
|
businessName={item.businessName}
|
||||||
isDisabled={item.status === 'INACTIVE'}
|
isDisabled={item.status === 'INACTIVE'}
|
||||||
subscriptionId={item.id}
|
subscriptionId={item.id}
|
||||||
|
endDate={item.endDate}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { FC, useEffect, useState } from 'react'
|
import { FC, useEffect, useState, useMemo } from 'react'
|
||||||
import RadioGroup from '../../../components/RadioGroup'
|
import RadioGroup from '../../../components/RadioGroup'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import Button from '../../../components/Button'
|
import Button from '../../../components/Button'
|
||||||
@@ -6,7 +6,7 @@ import { ArrowLeft } from 'iconsax-react'
|
|||||||
import { PlanItemType, ServiceDetailDataType } from '../types/ServiecTypes'
|
import { PlanItemType, ServiceDetailDataType } from '../types/ServiecTypes'
|
||||||
import { NumberFormat } from '../../../config/func'
|
import { NumberFormat } from '../../../config/func'
|
||||||
import { useBuyService } from '../hooks/useServiceData'
|
import { useBuyService } from '../hooks/useServiceData'
|
||||||
import { Link } from 'react-router-dom'
|
import { Link, useSearchParams } from 'react-router-dom'
|
||||||
import { Pages } from '../../../config/Pages'
|
import { Pages } from '../../../config/Pages'
|
||||||
import ExtendPlan from './ExtendPlan'
|
import ExtendPlan from './ExtendPlan'
|
||||||
|
|
||||||
@@ -14,33 +14,48 @@ type Props = {
|
|||||||
data: ServiceDetailDataType,
|
data: ServiceDetailDataType,
|
||||||
}
|
}
|
||||||
|
|
||||||
const ServiceHeader: FC<Props> = (props: Props) => {
|
const ServiceHeader: FC<Props> = ({ data }) => {
|
||||||
|
|
||||||
const { data } = props
|
|
||||||
const { t } = useTranslation('global')
|
const { t } = useTranslation('global')
|
||||||
// Get query params from URL
|
const [searchParams] = useSearchParams()
|
||||||
const urlParams = new URLSearchParams(window.location.search)
|
const subscriptionId = searchParams.get('id') || ''
|
||||||
const [subscriptionId, setSubscriptionId] = useState<string>('')
|
|
||||||
|
|
||||||
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 buyService = useBuyService()
|
const buyService = useBuyService()
|
||||||
|
|
||||||
|
// فیلتر کردن پلنهای رایگان هنگام تمدید
|
||||||
|
const availablePlans = useMemo(() => {
|
||||||
|
if (!data?.subscriptionPlans) return []
|
||||||
|
|
||||||
|
return subscriptionId
|
||||||
|
? data.subscriptionPlans.filter((plan: PlanItemType) => plan.price > 0)
|
||||||
|
: data.subscriptionPlans
|
||||||
|
}, [subscriptionId, data?.subscriptionPlans])
|
||||||
|
|
||||||
|
const [planSelected, setPlanSelected] = useState<string>(availablePlans[0]?.id || '')
|
||||||
|
const [finalPrice, setFinalPrice] = useState<number>(0)
|
||||||
|
const [originalPrice, setOriginalPrice] = useState<number>(0)
|
||||||
|
|
||||||
|
// بهروزرسانی قیمتها هنگام تغییر پلن انتخاب شده
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
const selectedPlan = availablePlans.find((plan) => plan.id === planSelected)
|
||||||
|
if (selectedPlan) {
|
||||||
|
setFinalPrice(selectedPlan.price)
|
||||||
|
setOriginalPrice(selectedPlan.originalPrice)
|
||||||
|
}
|
||||||
|
}, [planSelected, availablePlans])
|
||||||
|
|
||||||
const plan: PlanItemType = data?.subscriptionPlans.find((item) => item.id === planSelected)
|
// انتخاب خودکار اولین پلن موجود در صورت عدم وجود پلن انتخاب شده
|
||||||
setFinalPrice(plan.price)
|
|
||||||
setPrice(plan?.originalPrice)
|
|
||||||
|
|
||||||
}, [planSelected])
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setSubscriptionId(urlParams.get('id') || '')
|
if (availablePlans.length > 0 && !availablePlans.find(p => p.id === planSelected)) {
|
||||||
}, [window.location.search])
|
setPlanSelected(availablePlans[0].id)
|
||||||
|
}
|
||||||
|
}, [availablePlans, planSelected])
|
||||||
|
|
||||||
|
// تبدیل پلنها به فرمت مورد نیاز RadioGroup
|
||||||
|
const planItems = useMemo(() => {
|
||||||
|
return availablePlans.map((plan) => ({
|
||||||
|
label: plan.name,
|
||||||
|
value: plan.id
|
||||||
|
}))
|
||||||
|
}, [availablePlans])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='w-full p-6 bg-white rounded-3xl flex xl:flex-row flex-col items-end xl:justify-between'>
|
<div className='w-full p-6 bg-white rounded-3xl flex xl:flex-row flex-col items-end xl:justify-between'>
|
||||||
@@ -58,12 +73,7 @@ const ServiceHeader: FC<Props> = (props: Props) => {
|
|||||||
</p>
|
</p>
|
||||||
<div className='hidden xl:flex gap-5 mt-5'>
|
<div className='hidden xl:flex gap-5 mt-5'>
|
||||||
<RadioGroup
|
<RadioGroup
|
||||||
items={data?.subscriptionPlans?.map((item) => {
|
items={planItems}
|
||||||
return {
|
|
||||||
label: item?.name,
|
|
||||||
value: item?.id
|
|
||||||
}
|
|
||||||
})}
|
|
||||||
onChange={setPlanSelected}
|
onChange={setPlanSelected}
|
||||||
selected={planSelected}
|
selected={planSelected}
|
||||||
/>
|
/>
|
||||||
@@ -74,12 +84,7 @@ const ServiceHeader: FC<Props> = (props: Props) => {
|
|||||||
<div className='flex w-full flex-col justify-between xl:items-end'>
|
<div className='flex w-full flex-col justify-between xl:items-end'>
|
||||||
<div className='flex xl:!hidden gap-5 mt-5'>
|
<div className='flex xl:!hidden gap-5 mt-5'>
|
||||||
<RadioGroup
|
<RadioGroup
|
||||||
items={data?.subscriptionPlans?.map((item) => {
|
items={planItems}
|
||||||
return {
|
|
||||||
label: item?.name,
|
|
||||||
value: item?.id
|
|
||||||
}
|
|
||||||
})}
|
|
||||||
onChange={setPlanSelected}
|
onChange={setPlanSelected}
|
||||||
selected={planSelected}
|
selected={planSelected}
|
||||||
/>
|
/>
|
||||||
@@ -87,43 +92,36 @@ const ServiceHeader: FC<Props> = (props: Props) => {
|
|||||||
<div className='flex gap-4 mt-5 xl:mt-0 items-center justify-between xl:justify-normal'>
|
<div className='flex gap-4 mt-5 xl:mt-0 items-center justify-between xl:justify-normal'>
|
||||||
<div className='text-xs whitespace-nowrap flex gap-1 items-center'>
|
<div className='text-xs whitespace-nowrap flex gap-1 items-center'>
|
||||||
<div className='flex gap-2'>
|
<div className='flex gap-2'>
|
||||||
{
|
{finalPrice !== originalPrice && (
|
||||||
finalPrice !== price &&
|
|
||||||
<div className='line-through text-xs text-description'>
|
<div className='line-through text-xs text-description'>
|
||||||
{NumberFormat(Number(price))}
|
{NumberFormat(originalPrice)}
|
||||||
</div>
|
</div>
|
||||||
}
|
)}
|
||||||
<div>{finalPrice === 0 ? t('free') : NumberFormat(Number(finalPrice))}</div>
|
<div>
|
||||||
|
{finalPrice === 0 ? t('free') : NumberFormat(finalPrice)}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{
|
{finalPrice !== 0 && <span>{t('toman')}</span>}
|
||||||
finalPrice !== 0 && <span>{t('toman')}</span>
|
|
||||||
}
|
|
||||||
</div>
|
</div>
|
||||||
{
|
{subscriptionId ? (
|
||||||
subscriptionId ? (
|
<ExtendPlan
|
||||||
<ExtendPlan
|
subscriptionId={subscriptionId}
|
||||||
subscriptionId={subscriptionId}
|
planId={planSelected}
|
||||||
planId={planSelected}
|
serviceId={data.id}
|
||||||
serviceId={data.id}
|
/>
|
||||||
/>
|
) : planSelected && (
|
||||||
) :
|
<Link to={`${Pages.services.buy}${data.id}/${planSelected}`}>
|
||||||
planSelected ?
|
<Button
|
||||||
<Link to={Pages.services.buy + `${data.id}/${planSelected}`}>
|
isLoading={buyService.isPending}
|
||||||
<Button
|
className='bg-description xl:max-w-full max-w-[100px] text-xs h-8 bg-opacity-20 text-black px-4'
|
||||||
// onClick={handleBuy}
|
>
|
||||||
isLoading={buyService.isPending}
|
<div className='flex gap-1 items-center'>
|
||||||
className='bg-description xl:max-w-full max-w-[100px] text-xs h-8 bg-opacity-20 text-black px-4'
|
<div>{t('service.buy')}</div>
|
||||||
>
|
<ArrowLeft className='size-4' color='black' />
|
||||||
<div className='flex gap-1 items-center'>
|
</div>
|
||||||
<div>
|
</Button>
|
||||||
{t('service.buy')}
|
</Link>
|
||||||
</div>
|
)}
|
||||||
<ArrowLeft className='size-4' color='black' />
|
|
||||||
</div>
|
|
||||||
</Button>
|
|
||||||
</Link>
|
|
||||||
: null
|
|
||||||
}
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user