fix hidden free plan + show remain days

This commit is contained in:
hamid zarghami
2025-11-15 16:32:59 +03:30
parent 0e63aaaab8
commit 56e79d0a08
4 changed files with 107 additions and 68 deletions
+39
View File
@@ -5,6 +5,8 @@ import { ArrowLeft, More } from 'iconsax-react'
import Button from './Button'
import { useTranslation } from 'react-i18next'
import { ItemServiceType } from '../pages/service/types/ServiecTypes'
import moment from 'moment-jalaali'
import { NumberFormat } from '../config/func'
type Props = {
item: ItemServiceType,
@@ -15,6 +17,7 @@ type Props = {
isQuikAccess?: boolean,
onMoreClick?: () => void,
subscriptionId?: string,
endDate?: string,
}
const ServiceItem: FC<Props> = (props: Props) => {
@@ -22,6 +25,34 @@ const ServiceItem: FC<Props> = (props: Props) => {
const { t } = useTranslation('global')
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 (
<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}
</div>
}
{
props.isLinkPanel && props.endDate &&
<div className={`mt-1 text-[11px] ${getRemainingDaysColor(getRemainingDays(props.endDate))}`}>
{getRemainingDaysText(props.endDate)}
</div>
}
</div>
</div>
{
!props.isLinkPanel &&
<div className='mt-4 text-xs'>
+2 -1
View File
@@ -136,7 +136,8 @@
"short_description": "توضیح کوتاه",
"confrim_and_invoice": "تایید و صدور صورت حساب",
"extent": "تمدید پلن",
"extend": "تمدید"
"extend": "تمدید",
"end_date": "تاریخ پایان"
},
"loading": "در حال بارگذاری",
"footer": {
+1
View File
@@ -66,6 +66,7 @@ const MyServices: FC = () => {
businessName={item.businessName}
isDisabled={item.status === 'INACTIVE'}
subscriptionId={item.id}
endDate={item.endDate}
/>
)
})
+65 -67
View File
@@ -1,4 +1,4 @@
import { FC, useEffect, useState } from 'react'
import { FC, useEffect, useState, useMemo } from 'react'
import RadioGroup from '../../../components/RadioGroup'
import { useTranslation } from 'react-i18next'
import Button from '../../../components/Button'
@@ -6,7 +6,7 @@ import { ArrowLeft } from 'iconsax-react'
import { PlanItemType, ServiceDetailDataType } from '../types/ServiecTypes'
import { NumberFormat } from '../../../config/func'
import { useBuyService } from '../hooks/useServiceData'
import { Link } from 'react-router-dom'
import { Link, useSearchParams } from 'react-router-dom'
import { Pages } from '../../../config/Pages'
import ExtendPlan from './ExtendPlan'
@@ -14,33 +14,48 @@ type Props = {
data: ServiceDetailDataType,
}
const ServiceHeader: FC<Props> = (props: Props) => {
const { data } = props
const ServiceHeader: FC<Props> = ({ data }) => {
const { t } = useTranslation('global')
// Get query params from URL
const urlParams = new URLSearchParams(window.location.search)
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 [searchParams] = useSearchParams()
const subscriptionId = searchParams.get('id') || ''
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(() => {
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(() => {
setSubscriptionId(urlParams.get('id') || '')
}, [window.location.search])
if (availablePlans.length > 0 && !availablePlans.find(p => p.id === planSelected)) {
setPlanSelected(availablePlans[0].id)
}
}, [availablePlans, planSelected])
// تبدیل پلن‌ها به فرمت مورد نیاز RadioGroup
const planItems = useMemo(() => {
return availablePlans.map((plan) => ({
label: plan.name,
value: plan.id
}))
}, [availablePlans])
return (
<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>
<div className='hidden xl:flex gap-5 mt-5'>
<RadioGroup
items={data?.subscriptionPlans?.map((item) => {
return {
label: item?.name,
value: item?.id
}
})}
items={planItems}
onChange={setPlanSelected}
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 xl:!hidden gap-5 mt-5'>
<RadioGroup
items={data?.subscriptionPlans?.map((item) => {
return {
label: item?.name,
value: item?.id
}
})}
items={planItems}
onChange={setPlanSelected}
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='text-xs whitespace-nowrap flex gap-1 items-center'>
<div className='flex gap-2'>
{
finalPrice !== price &&
{finalPrice !== originalPrice && (
<div className='line-through text-xs text-description'>
{NumberFormat(Number(price))}
{NumberFormat(originalPrice)}
</div>
}
<div>{finalPrice === 0 ? t('free') : NumberFormat(Number(finalPrice))}</div>
)}
<div>
{finalPrice === 0 ? t('free') : NumberFormat(finalPrice)}
</div>
</div>
{
finalPrice !== 0 && <span>{t('toman')}</span>
}
{finalPrice !== 0 && <span>{t('toman')}</span>}
</div>
{
subscriptionId ? (
<ExtendPlan
subscriptionId={subscriptionId}
planId={planSelected}
serviceId={data.id}
/>
) :
planSelected ?
<Link to={Pages.services.buy + `${data.id}/${planSelected}`}>
<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'>
<div>
{t('service.buy')}
</div>
<ArrowLeft className='size-4' color='black' />
</div>
</Button>
</Link>
: null
}
{subscriptionId ? (
<ExtendPlan
subscriptionId={subscriptionId}
planId={planSelected}
serviceId={data.id}
/>
) : planSelected && (
<Link to={`${Pages.services.buy}${data.id}/${planSelected}`}>
<Button
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'>
<div>{t('service.buy')}</div>
<ArrowLeft className='size-4' color='black' />
</div>
</Button>
</Link>
)}
</div>
</div>