short description + edit first name last name + ...
This commit is contained in:
@@ -256,3 +256,12 @@ body {
|
|||||||
.plan:nth-child(even) {
|
.plan:nth-child(even) {
|
||||||
background-color: #f5f5f5;
|
background-color: #f5f5f5;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@layer utilities {
|
||||||
|
.line-clamp-4 {
|
||||||
|
display: -webkit-box;
|
||||||
|
-webkit-line-clamp: 4;
|
||||||
|
-webkit-box-orient: vertical;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
+3
-1
@@ -54,7 +54,7 @@
|
|||||||
"menu": "منو",
|
"menu": "منو",
|
||||||
"mainpage": "صفحه اصلی",
|
"mainpage": "صفحه اصلی",
|
||||||
"myservice": "سرویس های من",
|
"myservice": "سرویس های من",
|
||||||
"other_service": "سایر سرویس ها",
|
"other_service": "سرویس های داناک",
|
||||||
"receipt_list": "لیست صورتحساب",
|
"receipt_list": "لیست صورتحساب",
|
||||||
"transactions": "تراکنش ها",
|
"transactions": "تراکنش ها",
|
||||||
"other": "سایر",
|
"other": "سایر",
|
||||||
@@ -397,6 +397,8 @@
|
|||||||
"enter_carefully_your_information": "اطلاعت شخصی خود را با دقت وارد کنید.",
|
"enter_carefully_your_information": "اطلاعت شخصی خود را با دقت وارد کنید.",
|
||||||
"date_of_birth": "تاریخ تولد",
|
"date_of_birth": "تاریخ تولد",
|
||||||
"national_code": "کد ملی",
|
"national_code": "کد ملی",
|
||||||
|
"first_name": "نام",
|
||||||
|
"last_name": "نام خانوادگی",
|
||||||
"address": "آدرس",
|
"address": "آدرس",
|
||||||
"address_live": "آدرس محل سکونت خود را با دقت وارد کنید",
|
"address_live": "آدرس محل سکونت خود را با دقت وارد کنید",
|
||||||
"province": "استان",
|
"province": "استان",
|
||||||
|
|||||||
@@ -18,6 +18,8 @@ import { useFormik } from 'formik'
|
|||||||
import * as Yup from 'yup'
|
import * as Yup from 'yup'
|
||||||
import Email from './components/Email'
|
import Email from './components/Email'
|
||||||
import Phone from './components/Phone'
|
import Phone from './components/Phone'
|
||||||
|
import FirstName from './components/FirstName.tsx'
|
||||||
|
import LastName from './components/LastName.tsx'
|
||||||
|
|
||||||
const Profile: FC = () => {
|
const Profile: FC = () => {
|
||||||
|
|
||||||
@@ -34,6 +36,8 @@ const Profile: FC = () => {
|
|||||||
cityId: '',
|
cityId: '',
|
||||||
userAddress: '',
|
userAddress: '',
|
||||||
postalCode: '',
|
postalCode: '',
|
||||||
|
firstName: '',
|
||||||
|
lastName: '',
|
||||||
},
|
},
|
||||||
validationSchema: Yup.object({
|
validationSchema: Yup.object({
|
||||||
cityId: Yup.string().required(t('errors.required')),
|
cityId: Yup.string().required(t('errors.required')),
|
||||||
@@ -59,6 +63,8 @@ const Profile: FC = () => {
|
|||||||
cityId: getProfile.data.data.user.city?.id || '',
|
cityId: getProfile.data.data.user.city?.id || '',
|
||||||
userAddress: getProfile.data.data.user.userAddress || '',
|
userAddress: getProfile.data.data.user.userAddress || '',
|
||||||
postalCode: getProfile.data.data.user.postalCode || '',
|
postalCode: getProfile.data.data.user.postalCode || '',
|
||||||
|
firstName: getProfile.data.data.user.firstName || '',
|
||||||
|
lastName: getProfile.data.data.user.lastName || '',
|
||||||
})
|
})
|
||||||
if (getProfile.data.data.user.city) {
|
if (getProfile.data.data.user.city) {
|
||||||
}
|
}
|
||||||
@@ -190,6 +196,10 @@ const Profile: FC = () => {
|
|||||||
value={getProfile.data?.data?.user?.nationalCode}
|
value={getProfile.data?.data?.user?.nationalCode}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<FirstName firstName={getProfile.data?.data?.user?.firstName} />
|
||||||
|
|
||||||
|
<LastName lastName={getProfile.data?.data?.user?.lastName} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,71 @@
|
|||||||
|
import { FC, useEffect, useState } from 'react'
|
||||||
|
import Input from '../../../components/Input'
|
||||||
|
import Button from '../../../components/Button'
|
||||||
|
import { Edit } from 'iconsax-react'
|
||||||
|
import { useTranslation } from 'react-i18next'
|
||||||
|
import { useUpdateProfile } from '../hooks/useProfileData'
|
||||||
|
import { UpdateProfileType } from '../types/ProfileTypes'
|
||||||
|
import { toast } from '../../../components/Toast'
|
||||||
|
import { ErrorType } from '../../../helpers/types'
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
firstName: string | null | undefined
|
||||||
|
}
|
||||||
|
|
||||||
|
const FirstName: FC<Props> = (props: Props) => {
|
||||||
|
|
||||||
|
const { t } = useTranslation('global')
|
||||||
|
const [value, setValue] = useState<string>(props.firstName || '')
|
||||||
|
const [isReadOnly, setIsReadOnly] = useState<boolean>(true)
|
||||||
|
const updateProfile = useUpdateProfile()
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setValue(props.firstName || '')
|
||||||
|
}, [props.firstName])
|
||||||
|
|
||||||
|
const handleSave = () => {
|
||||||
|
const params: UpdateProfileType = { firstName: value }
|
||||||
|
updateProfile.mutate(params, {
|
||||||
|
onSuccess: () => {
|
||||||
|
toast(t('success'), 'success')
|
||||||
|
setIsReadOnly(true)
|
||||||
|
},
|
||||||
|
onError: (error: ErrorType) => {
|
||||||
|
toast(error.response?.data?.error?.message[0], 'error')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const isDisabled = value.trim().length === 0 || value === (props.firstName || '')
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className='flex items-end xl:gap-6 gap-3 xl:mt-7 mt-4'>
|
||||||
|
<Input
|
||||||
|
label={t('profile.first_name')}
|
||||||
|
value={value}
|
||||||
|
readOnly={isReadOnly}
|
||||||
|
onChange={(e) => setValue(e.target.value)}
|
||||||
|
/>
|
||||||
|
{
|
||||||
|
isReadOnly ? (
|
||||||
|
<div onClick={() => setIsReadOnly(false)} className='flex cursor-pointer relative -top-3 gap-1 text-[#0047FF] text-xs items-center'>
|
||||||
|
<Edit className='xl:size-[18px] size-4' color='#0047FF' />
|
||||||
|
<div>{t('edit')}</div>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<Button
|
||||||
|
label={t('save')}
|
||||||
|
className='px-4 w-fit'
|
||||||
|
disabled={isDisabled}
|
||||||
|
onClick={handleSave}
|
||||||
|
isLoading={updateProfile.isPending}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default FirstName
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
import { FC, useEffect, useState } from 'react'
|
||||||
|
import Input from '../../../components/Input'
|
||||||
|
import Button from '../../../components/Button'
|
||||||
|
import { Edit } from 'iconsax-react'
|
||||||
|
import { useTranslation } from 'react-i18next'
|
||||||
|
import { useUpdateProfile } from '../hooks/useProfileData'
|
||||||
|
import { UpdateProfileType } from '../types/ProfileTypes'
|
||||||
|
import { toast } from '../../../components/Toast'
|
||||||
|
import { ErrorType } from '../../../helpers/types'
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
lastName: string | null | undefined
|
||||||
|
}
|
||||||
|
|
||||||
|
const LastName: FC<Props> = (props: Props) => {
|
||||||
|
|
||||||
|
const { t } = useTranslation('global')
|
||||||
|
const [value, setValue] = useState<string>(props.lastName || '')
|
||||||
|
const [isReadOnly, setIsReadOnly] = useState<boolean>(true)
|
||||||
|
const updateProfile = useUpdateProfile()
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setValue(props.lastName || '')
|
||||||
|
}, [props.lastName])
|
||||||
|
|
||||||
|
const handleSave = () => {
|
||||||
|
const params: UpdateProfileType = { lastName: value }
|
||||||
|
updateProfile.mutate(params, {
|
||||||
|
onSuccess: () => {
|
||||||
|
toast(t('success'), 'success')
|
||||||
|
setIsReadOnly(true)
|
||||||
|
},
|
||||||
|
onError: (error: ErrorType) => {
|
||||||
|
toast(error.response?.data?.error?.message[0], 'error')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const isDisabled = value.trim().length === 0 || value === (props.lastName || '')
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className='flex items-end xl:gap-6 gap-3 xl:mt-7 mt-4'>
|
||||||
|
<Input
|
||||||
|
label={t('profile.last_name')}
|
||||||
|
value={value}
|
||||||
|
readOnly={isReadOnly}
|
||||||
|
onChange={(e) => setValue(e.target.value)}
|
||||||
|
/>
|
||||||
|
{
|
||||||
|
isReadOnly ? (
|
||||||
|
<div onClick={() => setIsReadOnly(false)} className='flex cursor-pointer relative -top-3 gap-1 text-[#0047FF] text-xs items-center'>
|
||||||
|
<Edit className='xl:size-[18px] size-4' color='#0047FF' />
|
||||||
|
<div>{t('edit')}</div>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<Button
|
||||||
|
label={t('save')}
|
||||||
|
className='px-4 w-fit'
|
||||||
|
disabled={isDisabled}
|
||||||
|
onClick={handleSave}
|
||||||
|
isLoading={updateProfile.isPending}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default LastName
|
||||||
|
|
||||||
|
|
||||||
@@ -33,11 +33,15 @@ const BuyService: FC = () => {
|
|||||||
},
|
},
|
||||||
validationSchema: Yup.object({
|
validationSchema: Yup.object({
|
||||||
businessName: Yup.string().required(t('errors.required')),
|
businessName: Yup.string().required(t('errors.required')),
|
||||||
businessPhone: Yup.string().required(t('errors.required')),
|
|
||||||
description: Yup.string().required(t('errors.required')),
|
|
||||||
planId: Yup.string().required(t('errors.required'))
|
planId: Yup.string().required(t('errors.required'))
|
||||||
}),
|
}),
|
||||||
onSubmit: (values) => {
|
onSubmit: (values) => {
|
||||||
|
if (!values.businessPhone) {
|
||||||
|
values.businessPhone = undefined
|
||||||
|
}
|
||||||
|
if (!values.description) {
|
||||||
|
values.description = undefined
|
||||||
|
}
|
||||||
buyService.mutate(values, {
|
buyService.mutate(values, {
|
||||||
onSuccess: (data) => {
|
onSuccess: (data) => {
|
||||||
toast(t('success'), 'success')
|
toast(t('success'), 'success')
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { FC, Fragment } from 'react'
|
import { FC, Fragment, useState } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import Rate from 'rc-rate'
|
import Rate from 'rc-rate'
|
||||||
import ServiceImages from './components/ServiceImages'
|
import ServiceImages from './components/ServiceImages'
|
||||||
@@ -20,6 +20,7 @@ const DetailService: FC = () => {
|
|||||||
const getAdsLeft = useGetAds(AdsDisplayLocation.SINGLE_SERVICE_PAGE)
|
const getAdsLeft = useGetAds(AdsDisplayLocation.SINGLE_SERVICE_PAGE)
|
||||||
|
|
||||||
const getDetailService = useGetServiceBySlug(id ? id : '')
|
const getDetailService = useGetServiceBySlug(id ? id : '')
|
||||||
|
const [isExpanded, setIsExpanded] = useState(false)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='w-full flex gap-6 mt-4'>
|
<div className='w-full flex gap-6 mt-4'>
|
||||||
@@ -87,8 +88,23 @@ const DetailService: FC = () => {
|
|||||||
<div>
|
<div>
|
||||||
{t('service.compelete_description')}
|
{t('service.compelete_description')}
|
||||||
</div>
|
</div>
|
||||||
<p dangerouslySetInnerHTML={{ __html: getDetailService.data?.data?.danakService?.metaDescription }} className='text-[13px] mt-4 leading-6'>
|
<p
|
||||||
|
dangerouslySetInnerHTML={{ __html: getDetailService.data?.data?.danakService?.metaDescription }}
|
||||||
|
className={`text-[13px] mt-4 leading-6 ${!isExpanded ? 'line-clamp-4' : ''}`}
|
||||||
|
>
|
||||||
</p>
|
</p>
|
||||||
|
{
|
||||||
|
(getDetailService.data?.data?.danakService?.metaDescription?.length || 0) > 0 && (
|
||||||
|
<div className='mt-3'>
|
||||||
|
<button
|
||||||
|
onClick={() => setIsExpanded(prev => !prev)}
|
||||||
|
className='text-xs text-blue-600'
|
||||||
|
>
|
||||||
|
{isExpanded ? 'کمتر' : 'دیدن بیشتر'}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className='mt-8 flex xl:flex-row flex-col gap-8 items-start'>
|
<div className='mt-8 flex xl:flex-row flex-col gap-8 items-start'>
|
||||||
|
|||||||
@@ -120,8 +120,8 @@ export type MyServicesItem = {
|
|||||||
export type BuyServiceType = {
|
export type BuyServiceType = {
|
||||||
planId: string;
|
planId: string;
|
||||||
businessName: string;
|
businessName: string;
|
||||||
businessPhone: string;
|
businessPhone?: string;
|
||||||
description: string;
|
description?: string;
|
||||||
serviceId: string;
|
serviceId: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user