plan info

This commit is contained in:
hamid zarghami
2025-05-07 15:38:13 +03:30
parent afc033e9e8
commit 0cd101d807
6 changed files with 267 additions and 5 deletions
+46
View File
@@ -0,0 +1,46 @@
import { AddCircle } from 'iconsax-react'
import { FC, useState, useRef, useEffect } from 'react'
type Props = {
title: string
content: string
}
const Accordion: FC<Props> = ({ title, content }) => {
const [isOpen, setIsOpen] = useState(false)
const contentRef = useRef<HTMLDivElement>(null)
const [contentHeight, setContentHeight] = useState(0)
useEffect(() => {
if (contentRef.current) {
setContentHeight(isOpen ? contentRef.current.scrollHeight : 0)
}
}, [isOpen])
return (
<div className='bg-white rounded-xl p-3 flex-1 h-fit'>
<div className='flex gap-2 justify-between items-center cursor-pointer accordion-trigger' onClick={() => setIsOpen(!isOpen)}>
<div className='font-bold xl:text-sm text-xs'>
{title}
</div>
<AddCircle
size={24}
color='black'
className={`transition-transform duration-300 accordion-icon ${isOpen ? 'rotate-45' : 'rotate-0'}`}
/>
</div>
<div
ref={contentRef}
className='overflow-hidden transition-all duration-300 accordion-content'
style={{ maxHeight: `${contentHeight}px` }}
>
<p className='text-sm leading-6 py-2 text-[#7D818C]'>
{content}
</p>
</div>
</div>
)
}
export default Accordion
+1 -1
View File
@@ -27,7 +27,7 @@ const Tabs: FC<Props> = (props: Props) => {
spaceBetween={30} spaceBetween={30}
className='px-10 max-w-full w-fit items-center text-description mx-auto backdrop-blur-md border-2 border-white gap-10 flex h-[80px] rounded-[32px] bg-white bg-opacity-45'> className='px-10 max-w-full w-fit items-center text-description mx-auto backdrop-blur-md border-2 border-white gap-10 flex h-[80px] rounded-[32px] bg-white bg-opacity-45'>
{ {
props.items?.map((item: Item, index: number) => { props.items?.length > 0 && props.items?.map((item: Item, index: number) => {
return ( return (
<SwiperSlide style={SWIPER_SLIDE_STYLE} onClick={() => props.onChange(item.value)} key={item.value} className={clx( <SwiperSlide style={SWIPER_SLIDE_STYLE} onClick={() => props.onChange(item.value)} key={item.value} className={clx(
'flex flex-col max-w-fit mt-[15px] items-center gap-2 cursor-pointer', 'flex flex-col max-w-fit mt-[15px] items-center gap-2 cursor-pointer',
+1
View File
@@ -38,5 +38,6 @@ export const Pages = {
financial: "/financial", financial: "/financial",
support: { support: {
index: "/support", index: "/support",
info: "/support/info",
}, },
}; };
+13 -4
View File
@@ -3,7 +3,7 @@ import { Helmet } from 'react-helmet-async'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import SidebarHint from './components/SidebarHint' import SidebarHint from './components/SidebarHint'
import SupportImage from '../../assets/images/support.png' import SupportImage from '../../assets/images/support.png'
import { Building, CloseCircle, Component, Crown, TickCircle } from 'iconsax-react' import { ArrowLeft, Building, CloseCircle, Component, Crown, TickCircle } from 'iconsax-react'
import Tabs from '../../components/Tabs' import Tabs from '../../components/Tabs'
import { useGetSupportPlans } from './hooks/useSupportData' import { useGetSupportPlans } from './hooks/useSupportData'
import { NumberFormat } from '../../config/func' import { NumberFormat } from '../../config/func'
@@ -12,6 +12,8 @@ import SupportSkeleton from './components/SupportSkeleton'
import SupportIcon from './components/SupportIcon' import SupportIcon from './components/SupportIcon'
import { SupportPlanFeatureKey } from './enum/SupportEnum' import { SupportPlanFeatureKey } from './enum/SupportEnum'
import BuyPlan from './components/BuyPlan' import BuyPlan from './components/BuyPlan'
import { Link } from 'react-router-dom'
import { Pages } from '../../config/Pages'
const Support: FC = () => { const Support: FC = () => {
const { data, isLoading } = useGetSupportPlans() const { data, isLoading } = useGetSupportPlans()
@@ -36,8 +38,15 @@ const Support: FC = () => {
داناک | {t('support.title')} داناک | {t('support.title')}
</title> </title>
</Helmet> </Helmet>
<div> <div className='flex justify-between items-center'>
{t('support.title')} {t('support.title')}
<Link to={Pages.support.info}>
<div className='flex gap-2 items-center'>
<div className='text-sm'>بیشتر بدانید</div>
<ArrowLeft size={18} color='#000' />
</div>
</Link>
</div> </div>
<div className='xl:hidden mt-5'> <div className='xl:hidden mt-5'>
@@ -142,8 +151,8 @@ const Support: FC = () => {
<div className='text-center mb-6'> <div className='text-center mb-6'>
<div className='font-bold text-lg'>{plan.name}</div> <div className='font-bold text-lg'>{plan.name}</div>
<div className='text-sm text-[#595C67] mt-2'>سالیانه</div> <div className='text-sm text-[#595C67] mt-2'>سالیانه</div>
<div className='font-bold text-sm mt-1'>{NumberFormat(plan.price)}</div> <div className='font-bold text-sm mt-1'>{plan.price === 0 ? 'رایگان' : NumberFormat(plan.price)}</div>
<div className='mt-1 text-sm'>تومان</div> <div className='mt-1 text-sm'>{plan.price === 0 ? ' ' : 'تومان'}</div>
<BuyPlan <BuyPlan
id={plan.id} id={plan.id}
/> />
+204
View File
@@ -0,0 +1,204 @@
import { FC, useEffect, useState } from 'react'
import { Helmet } from 'react-helmet-async'
import { useTranslation } from 'react-i18next'
import { useGetSupportPlans } from './hooks/useSupportData'
import { Building, Component } from 'iconsax-react'
import { PlanItemType } from './types/SupportTypes'
import { Crown } from 'iconsax-react'
import SupportImage from '../../assets/images/support.png'
import { NumberFormat } from '../../config/func'
import { featureItemType } from './types/SupportTypes'
import SupportIcon from './components/SupportIcon'
import { TickCircle, CloseCircle } from 'iconsax-react'
import SidebarHint from './components/SidebarHint'
import { SupportPlanFeatureKey } from './enum/SupportEnum'
import Accordion from '../../components/Accordion'
import Tabs from '../../components/Tabs'
import SupportSkeleton from './components/SupportSkeleton'
const SupportInfo: FC = () => {
const { t } = useTranslation('global')
const { data, isPending } = useGetSupportPlans()
const [activeTab, setActiveTab] = useState<string>('')
useEffect(() => {
if (data?.data?.supportPlans?.length > 0 && !activeTab) {
setActiveTab(data.data.supportPlans[0].id)
}
}, [data, activeTab])
if (isPending || !data?.data) {
return <SupportSkeleton />
}
return (
<div className='mt-4'>
<Helmet>
<title>
داناک | {t('support.title')}
</title>
</Helmet>
<div className='font-bold'>
خدمات پشتیبانی داناک
</div>
<p className='mt-5 text-sm text-description'>
با استفاده از خدمات پشتیبانی داناک میتوانید در کمترین زمان ایرادهای فنی زیر ساخت های نرم افزاری خود را رفع نمایید.
</p>
<div className='xl:hidden mt-5'>
<Tabs
items={data?.data?.supportPlans?.map((plan: PlanItemType, index: number) => ({
icon: index === 0 ? <Component color={activeTab === plan.id ? 'black' : '#8C90A3'} size={22} /> : index === 1 ? <Crown color={activeTab === plan.id ? 'black' : '#8C90A3'} size={22} /> : <Building color={activeTab === plan.id ? 'black' : '#8C90A3'} size={22} />,
label: plan.name,
value: plan.id
}))}
active={activeTab}
onChange={setActiveTab}
/>
</div>
<div className='flex gap-6 xl:mt-8 mt-4'>
<div className='flex-1 bg-white py-8 xl:px-10 px-4 rounded-3xl'>
<div className='xl:flex hidden justify-between mt-10'>
<div className='flex-1 flex justify-center'>
<img src={SupportImage} alt='support' className='w-[160px]' />
</div>
{
data?.data?.supportPlans?.map((item: PlanItemType) => {
return (
<div key={item.id} className='flex-1 flex flex-col items-center'>
<div className='text-center flex flex-col flex-1 w-full'>
<div className='font-bold'>
{item.name}
</div>
<div className='text-sm text-[#595C67] mt-4'>
سالیانه
</div>
<div className='font-bold text-sm mt-1'>
{item.price === 0 ? 'رایگان' : NumberFormat(item.price)}
</div>
<div className='mt-1 text-sm'>
{item.price === 0 ? ' ' : 'تومان'}
</div>
{/* <div className='flex-1 flex items-end'>
<BuyPlan
id={item.id}
/>
</div> */}
</div>
</div>
)
})
}
</div>
<div className='xl:flex hidden flex-1 mt-5'>
<div className='flex-1 flex flex-col'>
{
data?.data?.supportPlans?.[0]?.features.map((row: featureItemType) => (
<div key={row.featureKey} className='flex h-16 px-4 plan items-center justify-between'>
<div className='flex-1 flex items-center gap-2'>
<div className='size-8 rounded-2.5 bg-[#EEF0F7] flex items-center justify-center'>
<SupportIcon keySupport={row.featureKey as SupportPlanFeatureKey} />
</div>
<div className='text-xs'>{t(`support.${row.featureKey}`)}</div>
</div>
</div>
))
}
</div>
{
data?.data?.supportPlans?.map((item: PlanItemType) => (
<div className='flex-1 flex flex-col'>
{
item.features.map((row) => (
<div className='flex h-16 px-4 plan items-center justify-center'>
{
row.featureType === 'boolean' ?
row.featureValue === 'true' ?
<TickCircle className='xl:size-8 size-6' color='#01A560' variant='Bold' />
:
<CloseCircle className='xl:size-8 size-6' color='#D50303' variant='Bold' />
:
<div className='text-xs'>
{row.featureValue}
{row.featureKey === 'ticket_limit' && ' (روزانه)'}
</div>
}
</div>
))
}
</div>
))
}
</div>
{/* Mobile View */}
<div className='xl:hidden block mt-5'>
{
data?.data?.supportPlans?.map((plan: PlanItemType) => (
activeTab === plan.id && (
<div key={plan.id}>
<div className='flex justify-center mb-6'>
<img src={SupportImage} alt='support' className='w-[120px]' />
</div>
<div className='text-center mb-6'>
<div className='font-bold text-lg'>{plan.name}</div>
<div className='text-sm text-[#595C67] mt-2'>سالیانه</div>
<div className='font-bold text-sm mt-1'>{plan.price === 0 ? 'رایگان' : NumberFormat(plan.price)}</div>
<div className='mt-1 text-sm'>{plan.price === 0 ? ' ' : 'تومان'}</div>
{/* <BuyPlan
id={plan.id}
/> */}
</div>
<div className='space-y-4'>
{
plan.features.map((row: featureItemType) => (
<div className='flex items-center justify-between p-4 bg-gray-50 rounded-xl'>
<div className='flex items-center gap-2'>
<div className='size-8 rounded-2.5 bg-[#EEF0F7] flex items-center justify-center'>
<SupportIcon keySupport={row.featureKey as SupportPlanFeatureKey} />
</div>
<div className='text-xs'>{t(`support.${row.featureKey}`)}</div>
</div>
{
row.featureType === 'boolean' ?
row.featureValue === 'true' ?
<TickCircle className='size-6' color='#01A560' variant='Bold' />
:
<CloseCircle className='size-6' color='#D50303' variant='Bold' />
:
<div className='text-sm'>
{row.featureValue}
{row.featureKey === 'ticket_limit' && ' (روزانه)'}
</div>
}
</div>
))
}
</div>
</div>
)
))
}
</div>
</div>
<SidebarHint />
</div>
<div className='flex flex-col gap-4 mt-10'>
<Accordion title='آیا امکان ارتقای بسته‌ی پشتیبانی به پلن‌های بالاتر وجود دارد؟' content='بله، شما می‌توانید با انتخاب بسته‌های بالاتر به طیف گسترده‌تری از خدمات پشتیبانی داناک مانند: پاسخ‌گویی در کم‌تر از ۲ ساعت، دسترسی به متخصصین فنی و … دسترسی داشته باشید.' />
<Accordion title='آیا امکان بازگشت به بسته‌های پایین‌تر وجود دارد؟' content='بسته‌های مختلف خدمات پشتیبانی به‌شکل سالیانه ارایه می شوند و شما از تاریخ خرید یا فعال‌سازی پلن خود، تا ابتدای سال بعد امکان بازگشت به بسته‌ی پایین‌تر را نخواهید داشت.' />
<Accordion title='آیا خدمات پشتیبانی منطبق با سازمان من ارایه می‌شود؟' content='بله، شما با استفاده از خدمات سازمانی داناک می‌توانید به طیف گسترده‌ای از خدمات پشتیبانی دسترسی داشته باشید و در کم‌ترین زمان ممکن مشکلات و چالش‌های نرم افزاری کسب‌وکار خود را برطرف کنید. ' />
</div>
</div>
)
}
export default SupportInfo
+2
View File
@@ -30,6 +30,7 @@ import MyDiscountList from '../pages/discounts/List'
import LearningDetail from '../pages/learning/Detail' import LearningDetail from '../pages/learning/Detail'
import BuyService from '../pages/service/BuyService' import BuyService from '../pages/service/BuyService'
import Support from '../pages/support/Support' import Support from '../pages/support/Support'
import SupportInfo from '../pages/support/SupportInfo'
const MainRouter: FC = () => { const MainRouter: FC = () => {
return ( return (
@@ -42,6 +43,7 @@ const MainRouter: FC = () => {
<Routes> <Routes>
<Route path={Pages.dashboard} element={<Home />} /> <Route path={Pages.dashboard} element={<Home />} />
<Route path={Pages.support.index} element={<Support />} /> <Route path={Pages.support.index} element={<Support />} />
<Route path={Pages.support.info} element={<SupportInfo />} />
<Route path={Pages.services.mine} element={<MyServices />} /> <Route path={Pages.services.mine} element={<MyServices />} />
<Route path={Pages.services.other} element={<OtherServices />} /> <Route path={Pages.services.other} element={<OtherServices />} />
<Route path={Pages.services.detail + ':id'} element={<DetailService />} /> <Route path={Pages.services.detail + ':id'} element={<DetailService />} />