From 56e79d0a08a8d542b1ce4d409a96a5f395fe6149 Mon Sep 17 00:00:00 2001 From: hamid zarghami Date: Sat, 15 Nov 2025 16:32:59 +0330 Subject: [PATCH] fix hidden free plan + show remain days --- src/components/ServiceItem.tsx | 39 ++++++ src/langs/fa.json | 3 +- src/pages/service/MyServices.tsx | 1 + .../service/components/ServiceHeader.tsx | 132 +++++++++--------- 4 files changed, 107 insertions(+), 68 deletions(-) diff --git a/src/components/ServiceItem.tsx b/src/components/ServiceItem.tsx index d884aab..8034b9b 100644 --- a/src/components/ServiceItem.tsx +++ b/src/components/ServiceItem.tsx @@ -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) => { @@ -22,6 +25,34 @@ const ServiceItem: FC = (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 (
{ @@ -44,8 +75,16 @@ const ServiceItem: FC = (props: Props) => { {props.businessName}
} + { + props.isLinkPanel && props.endDate && +
+ {getRemainingDaysText(props.endDate)} +
+ } + + { !props.isLinkPanel &&
diff --git a/src/langs/fa.json b/src/langs/fa.json index 41e2e0f..a6c83da 100644 --- a/src/langs/fa.json +++ b/src/langs/fa.json @@ -136,7 +136,8 @@ "short_description": "توضیح کوتاه", "confrim_and_invoice": "تایید و صدور صورت حساب", "extent": "تمدید پلن", - "extend": "تمدید" + "extend": "تمدید", + "end_date": "تاریخ پایان" }, "loading": "در حال بارگذاری", "footer": { diff --git a/src/pages/service/MyServices.tsx b/src/pages/service/MyServices.tsx index d815a7d..084506e 100644 --- a/src/pages/service/MyServices.tsx +++ b/src/pages/service/MyServices.tsx @@ -66,6 +66,7 @@ const MyServices: FC = () => { businessName={item.businessName} isDisabled={item.status === 'INACTIVE'} subscriptionId={item.id} + endDate={item.endDate} /> ) }) diff --git a/src/pages/service/components/ServiceHeader.tsx b/src/pages/service/components/ServiceHeader.tsx index b1810f4..03003cd 100644 --- a/src/pages/service/components/ServiceHeader.tsx +++ b/src/pages/service/components/ServiceHeader.tsx @@ -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) => { - - const { data } = props +const ServiceHeader: FC = ({ data }) => { const { t } = useTranslation('global') - // Get query params from URL - const urlParams = new URLSearchParams(window.location.search) - const [subscriptionId, setSubscriptionId] = useState('') - - const [planSelected, setPlanSelected] = useState(data?.subscriptionPlans[0]?.id) - const [price, setPrice] = useState(data?.subscriptionPlans[0]?.price) - const [finalPrice, setFinalPrice] = useState(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(availablePlans[0]?.id || '') + const [finalPrice, setFinalPrice] = useState(0) + const [originalPrice, setOriginalPrice] = useState(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 (
@@ -58,12 +73,7 @@ const ServiceHeader: FC = (props: Props) => {

{ - return { - label: item?.name, - value: item?.id - } - })} + items={planItems} onChange={setPlanSelected} selected={planSelected} /> @@ -74,12 +84,7 @@ const ServiceHeader: FC = (props: Props) => {
{ - return { - label: item?.name, - value: item?.id - } - })} + items={planItems} onChange={setPlanSelected} selected={planSelected} /> @@ -87,43 +92,36 @@ const ServiceHeader: FC = (props: Props) => {
- { - finalPrice !== price && + {finalPrice !== originalPrice && (
- {NumberFormat(Number(price))} + {NumberFormat(originalPrice)}
- } -
{finalPrice === 0 ? t('free') : NumberFormat(Number(finalPrice))}
+ )} +
+ {finalPrice === 0 ? t('free') : NumberFormat(finalPrice)} +
- { - finalPrice !== 0 && {t('toman')} - } + {finalPrice !== 0 && {t('toman')}}
- { - subscriptionId ? ( - - ) : - planSelected ? - - - - : null - } + {subscriptionId ? ( + + ) : planSelected && ( + + + + )}