call back and service item skeleton

This commit is contained in:
hamid zarghami
2025-02-27 09:12:27 +03:30
parent 550d825e3a
commit e8c26de5e1
11 changed files with 164 additions and 102 deletions
+1 -1
View File
@@ -1,4 +1,4 @@
VITE_TOKEN_NAME = 'dsc_token' VITE_TOKEN_NAME = 'dsc_token'
VITE_REFRESH_TOKEN_NAME = 'dsc_refresh_token' VITE_REFRESH_TOKEN_NAME = 'dsc_refresh_token'
VITE_BASE_URL = 'https://api.danakcorp.com' VITE_BASE_URL = 'https://api.danakcorp.com'
# VITE_BASE_URL = 'http://192.168.0.223:3500' # VITE_BASE_URL = 'http://192.168.1.124:4000'
+1 -1
View File
@@ -32,7 +32,7 @@ export const Pages = {
}, },
setting: "/setting", setting: "/setting",
wallet: "/wallet", wallet: "/wallet",
callback: "/wallet/callback/", callback: "/payment",
profile: "/profile", profile: "/profile",
discounts: "/discounts", discounts: "/discounts",
financial: "/financial", financial: "/financial",
+7 -2
View File
@@ -382,7 +382,8 @@
"username_save_success": "نام کاربری با موفقیت ذخیره شد", "username_save_success": "نام کاربری با موفقیت ذخیره شد",
"image_uploaded_successfully": "تصویر با موفقیت آپلود شد", "image_uploaded_successfully": "تصویر با موفقیت آپلود شد",
"confrim_email": "تایید ایمیل", "confrim_email": "تایید ایمیل",
"confrim": "تایید صورتحساب " "confrim": "تایید صورتحساب ",
"link_email": "یک لینک برای تایید ایمیل برای شما ارسال شد."
}, },
"email": "ایمیل", "email": "ایمیل",
"save": "ذخیره", "save": "ذخیره",
@@ -428,7 +429,11 @@
"order_number": "شماره سفارش", "order_number": "شماره سفارش",
"amount": "مبلغ پرداختی", "amount": "مبلغ پرداختی",
"date": "تاریخ", "date": "تاریخ",
"back": "بازگشت" "back": "بازگشت",
"failed": "پرداخت ناموفق!",
"desc_failed": "متأسفیم! پرداخت شما انجام نشد. لطفاً دوباره تلاش کنید یا روش پرداخت دیگری انتخاب کنید.",
"pending": "وضعیت پرداخت نامشخص است!",
"desc_pending": "اگر مبلغی از حساب شما کسر شده ولی سفارش شما بعد از ۷۲ ساعت تأیید نشد، لطفاً با پشتیبانی تماس بگیرید."
}, },
"discount": { "discount": {
"number": "شماره", "number": "شماره",
+102
View File
@@ -0,0 +1,102 @@
import { CloseCircle, InfoCircle, TickCircle } from 'iconsax-react'
import { FC } from 'react'
import { useTranslation } from 'react-i18next'
import { NumberFormat } from '../../config/func'
import Button from '../../components/Button'
import { useSearchParams } from "react-router-dom";
import moment from 'moment-jalaali'
const CallBack: FC = () => {
const [searchParams] = useSearchParams();
const { t } = useTranslation('global')
const params = {
status: searchParams.get('status') as 'PENDING' | 'FAILED' | 'COMPLETED',
id: searchParams.get('id'),
date: searchParams.get('date'),
amount: searchParams.get('amount'),
}
return (
<div className='flex mt-10 flex-col justify-center items-center flex-1 h-full'>
{
params.status === 'COMPLETED' ?
<TickCircle
size={64}
color={'#00712D'}
/>
:
params.status === 'FAILED' ?
<CloseCircle
size={64}
color='#D52903'
/>
:
<InfoCircle
size={64}
color='#FFA800'
/>
}
<div className='mt-7 text-xl'>
{
params.status === 'COMPLETED' ?
t('callback.title_success')
:
params.status === 'FAILED' ?
t('callback.failed')
:
t('callback.pending')
}
</div>
<div className='mt-7'>
{
params.status === 'COMPLETED' ?
t('callback.desc_success')
:
params.status === 'FAILED' ?
t('callback.desc_failed')
:
t('callback.desc_pending')
}
</div>
<div className='mt-16 xl:min-w-[560px] bg-[#FBFBFD] p-8 text-sm'>
<div className='flex justify-between'>
<div>
{t('callback.order_number')}
</div>
<div>
{params.id}
</div>
</div>
<div className='flex justify-between mt-6'>
<div>
{t('callback.amount')}
</div>
<div>
{NumberFormat(Number(params.amount)) + ' ' + t('toman')}
</div>
</div>
<div className='flex justify-between mt-6'>
<div>
{t('callback.date')}
</div>
<div>
{moment(params.date).format('jYYYY/jMM/jDD')}
</div>
</div>
</div>
<Button
label={t('callback.back')}
className='xl:max-w-[560px] mt-8'
/>
</div>
)
}
export default CallBack
+1 -1
View File
@@ -26,7 +26,7 @@ const Email: FC<Props> = (props: Props) => {
const handleShowModal = () => { const handleShowModal = () => {
updateEmail.mutate({ email: email }, { updateEmail.mutate({ email: email }, {
onSuccess: () => { onSuccess: () => {
setShowModal(true) toast.success(t('profile.link_email'))
}, },
onError: (error: ErrorType) => { onError: (error: ErrorType) => {
toast.error(error.response?.data?.error.message[0]) toast.error(error.response?.data?.error.message[0])
+2 -2
View File
@@ -23,12 +23,12 @@ export const updateProfile = async (params: UpdateProfileType) => {
}; };
export const updateEmail = async (params: UpdateEmailType) => { export const updateEmail = async (params: UpdateEmailType) => {
const { data } = await axios.patch(`/users/update-email`, params); const { data } = await axios.patch(`/users/change-email`, params);
return data; return data;
}; };
export const updatePhone = async (params: UpdatePhoneType) => { export const updatePhone = async (params: UpdatePhoneType) => {
const { data } = await axios.patch(`/users/update-phone`, params); const { data } = await axios.patch(`/users/change-phone`, params);
return data; return data;
}; };
+34 -31
View File
@@ -10,6 +10,7 @@ import { MyServicesItem } from './types/ServiecTypes'
import { useGetAds } from '../ads/hooks/useAdsData' import { useGetAds } from '../ads/hooks/useAdsData'
import { AdsDisplayLocation } from '../ads/types/AdsTypes' import { AdsDisplayLocation } from '../ads/types/AdsTypes'
import { Helmet } from 'react-helmet-async' import { Helmet } from 'react-helmet-async'
import ServiceItemSkeleton from './components/ServiceItemSkeleton'
const MyServices: FC = () => { const MyServices: FC = () => {
@@ -53,40 +54,42 @@ const MyServices: FC = () => {
</div> </div>
<div className='flex items-stretch flex-wrap xl:gap-6 gap-4 xl:items-center mt-8'> <div className='flex items-stretch flex-wrap xl:gap-6 gap-4 xl:items-center mt-8'>
{ {
getServices.data?.data?.subscriptions?.map((item: MyServicesItem) => { getServices.isPending ?
return ( Array.from({ length: 4 }).map((_, index) => <ServiceItemSkeleton key={index} />)
<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 getServices.data?.data?.subscriptions?.map((item: MyServicesItem) => {
item={{ return (
author: item.plan.service.author, <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'>
createDate: item.plan?.service?.createDate, <ServiceSection
createdAt: item.createdAt, item={{
description: item.plan?.service?.title, author: item.plan.service.author,
icon: item.plan?.service.icon, createDate: item.plan?.service?.createDate,
id: item.plan.service.id, createdAt: item.createdAt,
isActive: item.plan.isActive, description: item.plan?.service?.title,
isDanakSuggest: item.plan.service.isDanakSuggest, icon: item.plan?.service.icon,
link: item.plan.service.link, id: item.plan.service.id,
metaDescription: item.plan.service.metaDescription, isActive: item.plan.isActive,
name: item.plan.service.name, isDanakSuggest: item.plan.service.isDanakSuggest,
serviceLanguage: item.plan.service.serviceLanguage, link: item.plan.service.link,
softwareLanguage: item.plan.service.softwareLanguage, metaDescription: item.plan.service.metaDescription,
updatedAt: item.plan.service.updatedAt, name: item.plan.service.name,
userCount: item.plan.service?.userCount serviceLanguage: item.plan.service.serviceLanguage,
}} softwareLanguage: item.plan.service.softwareLanguage,
/> updatedAt: item.plan.service.updatedAt,
<div className='mt-6 flex gap-1 items-center'> userCount: item.plan.service?.userCount
<StatusCircle }}
color='#00BA4B'
/> />
<div className='text-xs text-description'>1 {t('service.active_menu')}</div> <div className='mt-6 flex gap-1 items-center'>
</div> <StatusCircle
color='#00BA4B'
/>
<div className='text-xs text-description'>1 {t('service.active_menu')}</div>
</div>
</Link> </Link>
) )
}) })
} }
@@ -0,0 +1,13 @@
import { FC } from 'react'
import Skeleton from 'react-loading-skeleton'
const ServiceItemSkeleton: FC = () => {
return (
<Skeleton
containerClassName='flex-1 min-w-[40%] xl:min-w-[20%]'
className='min-h-[128px] !rounded-3xl '
/>
)
}
export default ServiceItemSkeleton
+1 -1
View File
@@ -11,5 +11,5 @@ export const updateSettings = async (params: UpdateSettingType) => {
}; };
export const changePassword = async (params: ChangePasswordType) => { export const changePassword = async (params: ChangePasswordType) => {
await axios.patch(`/auth/password`, params); await axios.patch(`/auth/change-password`, params);
}; };
-61
View File
@@ -1,61 +0,0 @@
import { TickCircle } from 'iconsax-react'
import { FC } from 'react'
import { useTranslation } from 'react-i18next'
import { NumberFormat } from '../../config/func'
import Button from '../../components/Button'
const CallBack: FC = () => {
const { t } = useTranslation('global')
return (
<div className='flex mt-10 flex-col justify-center items-center flex-1 h-full'>
<TickCircle
size={64}
color='#00712D'
/>
<div className='mt-7 text-xl'>
{t('callback.title_success')}
</div>
<div className='mt-7'>
{t('callback.desc_success')}
</div>
<div className='mt-16 xl:min-w-[560px] bg-[#FBFBFD] p-8 text-sm'>
<div className='flex justify-between'>
<div>
{t('callback.order_number')}
</div>
<div>
#1234
</div>
</div>
<div className='flex justify-between mt-6'>
<div>
{t('callback.amount')}
</div>
<div>
{NumberFormat(200000) + ' ' + t('toman')}
</div>
</div>
<div className='flex justify-between mt-6'>
<div>
{t('callback.date')}
</div>
<div>
۲۹ بهمن ۱۴۰۳
</div>
</div>
</div>
<Button
label={t('callback.back')}
className='xl:max-w-[560px] mt-8'
/>
</div>
)
}
export default CallBack
+2 -2
View File
@@ -25,7 +25,7 @@ import TicketList from '../pages/ticket/TicketList'
import CreateTicket from '../pages/ticket/CreateTicket' import CreateTicket from '../pages/ticket/CreateTicket'
import TicketDetail from '../pages/ticket/Detail' import TicketDetail from '../pages/ticket/Detail'
import Financial from '../pages/financial/Financial' import Financial from '../pages/financial/Financial'
import CallBack from '../pages/wallet/CallBack' import CallBack from '../pages/payment/CallBack'
import MyDiscountList from '../pages/discounts/List' 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'
@@ -57,7 +57,7 @@ const MainRouter: FC = () => {
<Route path={Pages.learning.detail + ':id'} element={<LearningDetail />} /> <Route path={Pages.learning.detail + ':id'} element={<LearningDetail />} />
<Route path={Pages.setting} element={<Setting />} /> <Route path={Pages.setting} element={<Setting />} />
<Route path={Pages.wallet} element={<Wallet />} /> <Route path={Pages.wallet} element={<Wallet />} />
<Route path={Pages.callback + ':id'} element={<CallBack />} /> <Route path={Pages.callback} element={<CallBack />} />
<Route path={Pages.profile} element={<Profile />} /> <Route path={Pages.profile} element={<Profile />} />
<Route path={Pages.financial} element={<Financial />} /> <Route path={Pages.financial} element={<Financial />} />
<Route path={Pages.discounts} element={<MyDiscountList />} /> <Route path={Pages.discounts} element={<MyDiscountList />} />