From 46e29c490903909234aceeb6e3f045fc67180242 Mon Sep 17 00:00:00 2001 From: hamid zarghami Date: Sun, 1 Jun 2025 15:18:42 +0330 Subject: [PATCH] edit my company --- src/components/UploadBox.tsx | 21 +- src/pages/company/Detail.tsx | 4 +- src/pages/company/MyCompany.tsx | 44 +- src/pages/home/Home.tsx | 2 +- src/pages/request/Request.tsx | 479 +++++++++++------- .../request/components/CompanyProducts.tsx | 6 +- .../request/components/CompanyServices.tsx | 4 +- src/pages/request/hooks/useRequestData.ts | 17 +- src/pages/request/service/Service.ts | 16 + src/router/Main.tsx | 1 + 10 files changed, 391 insertions(+), 203 deletions(-) diff --git a/src/components/UploadBox.tsx b/src/components/UploadBox.tsx index 0a3e71e..7120f89 100644 --- a/src/components/UploadBox.tsx +++ b/src/components/UploadBox.tsx @@ -9,6 +9,7 @@ type Props = { isMultiple?: boolean, onChange?: (file: File[]) => void; isReset?: boolean; + preview?: string; } const UploadBox: FC = (props: Props) => { @@ -44,15 +45,11 @@ const UploadBox: FC = (props: Props) => { } useEffect(() => { - if (props.isReset) { setFiles([]) } - }, [props.isReset]) - - return (
{props.label}
@@ -72,6 +69,14 @@ const UploadBox: FC = (props: Props) => {
)) } + { + files.length === 0 && props.preview && ( +
+
فایل موجود
+ preview +
+ ) + }
@@ -83,6 +88,14 @@ const UploadBox: FC = (props: Props) => {
)) } + { + files.length === 0 && props.preview && ( +
+
فایل موجود
+ preview +
+ ) + } ) diff --git a/src/pages/company/Detail.tsx b/src/pages/company/Detail.tsx index b11292e..760470e 100644 --- a/src/pages/company/Detail.tsx +++ b/src/pages/company/Detail.tsx @@ -65,7 +65,7 @@ const CompanyDetail: FC = () => { color='black' />
- شماره تماس : {data?.data?.company?.user?.phone} + شماره تماس : {data?.data?.company?.phone}
@@ -85,7 +85,7 @@ const CompanyDetail: FC = () => { color='black' />
- ایمیل : {data?.data?.company?.user?.email} + ایمیل : {data?.data?.company?.email}
diff --git a/src/pages/company/MyCompany.tsx b/src/pages/company/MyCompany.tsx index 676f334..9a5c311 100644 --- a/src/pages/company/MyCompany.tsx +++ b/src/pages/company/MyCompany.tsx @@ -1,6 +1,6 @@ -import { Add, Calendar, CallCalling, Location, Map1, MessageMinus, Profile, Setting2, Sms } from 'iconsax-react' +import { Add, Calendar, CallCalling, Edit, Location, Map1, MessageMinus, Profile, Setting2, Sms } from 'iconsax-react' import { FC } from 'react' -import { Link } from 'react-router-dom' +import { Link, useNavigate, useParams } from 'react-router-dom' import { useGetMyCompany } from '../home/hooks/useHomeData' import moment from 'moment-jalaali' import Button from '../../components/Button' @@ -9,7 +9,16 @@ import { Pages } from '../../config/Pages' import MyProduct from './components/MyProduct' const CompanyDetail: FC = () => { + const { slug } = useParams() const { data } = useGetMyCompany() + const navigate = useNavigate() + + const handleEditClick = () => { + if (data?.data?.company) { + console.log('Navigating to edit with company data:', data.data.company); + navigate(buildPath(`${Pages.request}/${data.data.company.id}`, slug)) + } + } if (data?.data?.company) { return ( @@ -22,24 +31,37 @@ const CompanyDetail: FC = () => {
-
+
{data?.data?.company?.name}
-
- +
- آدرس در نقشه + ویرایش
+
+ +
+ آدرس در نقشه +
+
+
@@ -48,7 +70,7 @@ const CompanyDetail: FC = () => { color='black' />
- مدیرعامل: {data?.data?.company?.user?.fullName} + مدیرعامل: {data?.data?.company?.chiefExecutiveOfficer}
@@ -68,7 +90,7 @@ const CompanyDetail: FC = () => { color='black' />
- شماره تماس : {data?.data?.company?.user?.phone} + شماره تماس : {data?.data?.company?.phone}
diff --git a/src/pages/home/Home.tsx b/src/pages/home/Home.tsx index 4e54efa..fa0c3f3 100644 --- a/src/pages/home/Home.tsx +++ b/src/pages/home/Home.tsx @@ -36,7 +36,7 @@ const Home: FC = () => { alt='banner' width={1920} height={1080} - className='w-full rounded-3xl object-cover xl:mt-14 mt-8 min-h-[210px] max-h-[500px]' + className='w-full rounded-3xl object-cover min-h-[210px] max-h-[500px]' />
diff --git a/src/pages/request/Request.tsx b/src/pages/request/Request.tsx index 553462a..ade15eb 100644 --- a/src/pages/request/Request.tsx +++ b/src/pages/request/Request.tsx @@ -1,4 +1,4 @@ -import { FC } from 'react' +import { FC, useEffect } from 'react' import withAuth from '../../hoc/withAuth' import Button from '../../components/Button' import { TickCircle } from 'iconsax-react' @@ -8,12 +8,11 @@ import { useFormik } from 'formik' import * as Yup from 'yup' import { useState } from 'react' import { toast } from '../../components/Toast' -import { ErrorType } from '../../helpers/types' import { Pages } from '../../config/Pages' import { useNavigate, useParams } from 'react-router-dom' import DatePickerComponent from '../../components/DatePicker' import moment from 'moment-jalaali' -import { useCreateCompany, useMultiUpload, useSingleUpload } from './hooks/useRequestData' +import { useCreateCompany, useMultiUpload, useSingleUpload, useUpdateCompany, useGetCompanyById } from './hooks/useRequestData' import { CreateCompanyType } from './types/Types' import UploadBox from '../../components/UploadBox' import CompanyServices from './components/CompanyServices' @@ -22,9 +21,11 @@ import { useGetIndustry } from '../home/hooks/useHomeData' import Select from '../../components/Select' import { IndustryItemType } from '../home/types/HomeTypes' import { buildPath } from '../../helpers/utils' + const Request: FC = () => { const createCompany = useCreateCompany() + const updateCompany = useUpdateCompany() const navigate = useNavigate() const { t } = useTranslation('global') const [profileImage, setProfileImage] = useState(null) @@ -32,10 +33,16 @@ const Request: FC = () => { const multiUpload = useMultiUpload() const singleUpload = useSingleUpload() const { data: industries } = useGetIndustry() - const { slug } = useParams() + const { slug, id } = useParams() + const isEdit = !!id + const { data: companyResponse, isLoading: isLoadingCompany } = useGetCompanyById(id) + const companyData = companyResponse?.data?.company || null + const [isSubmitting, setIsSubmitting] = useState(false) - const [services, setServices] = useState<{ title: string; image?: File }[]>([]) - const [products, setProducts] = useState<{ title: string; image?: File }[]>([]) + const [services, setServices] = useState<{ title: string; image?: File; imageUrl?: string; existingImageUrl?: string }[]>([]) + const [products, setProducts] = useState<{ title: string; image?: File; imageUrl?: string; existingImageUrl?: string }[]>([]) + const [profileImageUrl, setProfileImageUrl] = useState('') + const [coverImageUrl, setCoverImageUrl] = useState('') const formik = useFormik({ initialValues: { @@ -68,192 +75,306 @@ const Request: FC = () => { industryId: Yup.string().required(t('errors.required')), }), onSubmit: async (values) => { - if (!profileImage || !coverImage) { - toast('لطفا تصاویر را انتخاب کنید', 'error') - return - } - - let serviceImages: string[] = [] - if (services.length > 0) { - const formDataServices = new FormData() - services.forEach(s => s.image && formDataServices.append('files', s.image)) - const serviceUploadRes = await multiUpload.mutateAsync(formDataServices) - serviceImages = serviceUploadRes.data.map((item: { url: string }) => item?.url) - } - - // آپلود تصاویر محصولات - let productImages: string[] = [] - if (products.length > 0) { - const formDataProducts = new FormData() - products.forEach(p => p.image && formDataProducts.append('files', p.image)) - const productUploadRes = await multiUpload.mutateAsync(formDataProducts) - productImages = productUploadRes.data.map((item: { url: string }) => item?.url) - } - - // مقداردهی به values - values.services = services.map((s, idx) => ({ - title: s.title, - imageUrl: serviceImages[idx] ? serviceImages[idx] : '' - })) - values.products = products.map((p, idx) => ({ - title: p.title, - imageUrl: productImages[idx] ? productImages[idx] : '' - })) - - const formDataProfile = new FormData() - formDataProfile.append('file', profileImage) - const profileUploadRes = await singleUpload.mutateAsync(formDataProfile) - values.profileImageUrl = profileUploadRes.data.url - - const formDataCover = new FormData() - formDataCover.append('file', coverImage) - const coverUploadRes = await singleUpload.mutateAsync(formDataCover) - values.coverImageUrl = coverUploadRes.data.url - - createCompany.mutate(values, { - onSuccess: () => { - toast('درخواست با موفقیت ثبت شد', 'success') - navigate(buildPath(Pages.dashboard, slug)) - }, - onError: (error: ErrorType) => { - toast(error?.response?.data?.error?.message[0], 'error') + values.dateOfEstablishment = moment(values.dateOfEstablishment, 'jYYYY-jMM-jDD').format('YYYY-MM-DD') + try { + setIsSubmitting(true) + if (!isEdit && (!profileImage || !coverImage)) { + toast('لطفا تصاویر را انتخاب کنید', 'error') + setIsSubmitting(false) + return } - }) + + // بررسی مقادیر ضروری برای آپدیت + if (isEdit && !values.profileImageUrl && !profileImage) { + toast('لطفا تصویر پروفایل را انتخاب کنید', 'error') + setIsSubmitting(false) + return + } + + if (isEdit && !values.coverImageUrl && !coverImage) { + toast('لطفا تصویر کاور را انتخاب کنید', 'error') + setIsSubmitting(false) + return + } + + let serviceImages: string[] = [] + if (services.length > 0) { + const newServices = services.filter(s => s.image) + if (newServices.length > 0) { + const formDataServices = new FormData() + newServices.forEach(s => s.image && formDataServices.append('files', s.image)) + const serviceUploadRes = await multiUpload.mutateAsync(formDataServices) + serviceImages = serviceUploadRes.data.map((item: { url: string }) => item?.url) + } + } + + // آپلود تصاویر محصولات + let productImages: string[] = [] + if (products.length > 0) { + const newProducts = products.filter(p => p.image) + if (newProducts.length > 0) { + const formDataProducts = new FormData() + newProducts.forEach(p => p.image && formDataProducts.append('files', p.image)) + const productUploadRes = await multiUpload.mutateAsync(formDataProducts) + productImages = productUploadRes.data.map((item: { url: string }) => item?.url) + } + } + + // مقداردهی به values + values.services = services.map((s, idx) => { + const newImageIndex = services.filter((item, i) => item.image && i < idx).length + return { + title: s.title, + imageUrl: s.image ? (serviceImages[newImageIndex] || '') : (s.existingImageUrl || '') + } + }) + + values.products = products.map((p, idx) => { + const newImageIndex = products.filter((item, i) => item.image && i < idx).length + return { + title: p.title, + imageUrl: p.image ? (productImages[newImageIndex] || '') : (p.existingImageUrl || '') + } + }) + + if (profileImage) { + const formDataProfile = new FormData() + formDataProfile.append('file', profileImage) + const profileUploadRes = await singleUpload.mutateAsync(formDataProfile) + values.profileImageUrl = profileUploadRes.data.url + } else if (profileImageUrl) { + values.profileImageUrl = profileImageUrl + } + + if (coverImage) { + const formDataCover = new FormData() + formDataCover.append('file', coverImage) + const coverUploadRes = await singleUpload.mutateAsync(formDataCover) + values.coverImageUrl = coverUploadRes.data.url + } else if (coverImageUrl) { + values.coverImageUrl = coverImageUrl + } + + if (isEdit && companyData?.id) { + await handleUpdateCompany(companyData.id, values) + } else { + await handleCreateCompany(values) + } + } catch (error) { + setIsSubmitting(false) + toast('خطا در ثبت اطلاعات', 'error') + console.error('Submit error:', error) + } } }) + const handleUpdateCompany = async (companyId: string, values: CreateCompanyType) => { + try { + console.log('Updating company with ID:', companyId); + console.log('Update data:', values); + await updateCompany.mutateAsync( + { id: companyId, data: values } + ) + toast('اطلاعات شرکت با موفقیت ویرایش شد', 'success') + navigate(buildPath(Pages.company.my, slug), { replace: true }) + } catch (error: any) { + console.error('Update error:', error); + toast(error?.response?.data?.error?.message[0] || 'خطا در ویرایش اطلاعات', 'error') + } finally { + setIsSubmitting(false) + } + } + + const handleCreateCompany = async (values: CreateCompanyType) => { + try { + await createCompany.mutateAsync(values) + toast('درخواست با موفقیت ثبت شد', 'success') + navigate(buildPath(Pages.dashboard, slug), { replace: true }) + } catch (error: any) { + toast(error?.response?.data?.error?.message[0] || 'خطا در ثبت درخواست', 'error') + } finally { + setIsSubmitting(false) + } + } + + useEffect(() => { + if (isEdit && companyData) { + formik.setValues({ + phone: companyData.user?.phone || '', + name: companyData.name || '', + email: companyData?.email || '', + identificationNumber: companyData.identificationNumber || '', + dateOfEstablishment: moment(companyData.dateOfEstablishment, 'jYYYY-jMM-jDD').format('jYYYY-jMM-jDD') || '', + address: companyData.address || '', + mapAddressLink: companyData.mapAddressLink || '', + description: companyData.description || '', + websiteUrl: companyData.websiteUrl || '', + profileImageUrl: companyData.profileImageUrl || '', + coverImageUrl: companyData.coverImageUrl || '', + industryId: companyData.industry?.id || '', + chiefExecutiveOfficer: companyData.user?.fullName || '', + products: [], + services: [], + }) + + setProfileImageUrl(companyData.profileImageUrl || '') + setCoverImageUrl(companyData.coverImageUrl || '') + + if (companyData.services?.length) { + setServices(companyData.services.map((service: any) => ({ + title: service.title, + existingImageUrl: service.imageUrl + }))) + } + + if (companyData.products?.length) { + setProducts(companyData.products.map((product: any) => ({ + title: product.title, + existingImageUrl: product.imageUrl + }))) + } + } + }, [isEdit, companyData]) + return (
-
-
- ثبت درخواست + {isLoadingCompany && isEdit ? ( +
+
- -
- -
-
-
-
اطلاعات درخواست
- -
- - -
- +
+ +
+
+
{isEdit ? 'اطلاعات شرکت' : 'اطلاعات درخواست'}
-
- - +
+ + +
+ +
+ +
+ + +
+ +
+ + formik.setFieldValue('dateOfEstablishment', date)} + error_text={formik.touched.dateOfEstablishment && formik.errors.dateOfEstablishment ? formik.errors.dateOfEstablishment : ''} + defaulValue={formik.values.dateOfEstablishment} + /> +
+ + + + + + + + + + setProfileImage(file[0])} + /> + + setCoverImage(file[0])} + /> + + + +
- -
- - formik.setFieldValue('dateOfEstablishment', moment(date).format('YYYY-MM-DD'))} - error_text={formik.touched.dateOfEstablishment && formik.errors.dateOfEstablishment ? formik.errors.dateOfEstablishment : ''} - /> -
- - - - - - - - - - setProfileImage(file[0])} - /> - - setCoverImage(file[0])} - /> - - - - -
-
+ + )}
) } diff --git a/src/pages/request/components/CompanyProducts.tsx b/src/pages/request/components/CompanyProducts.tsx index 3cc05b7..3607988 100644 --- a/src/pages/request/components/CompanyProducts.tsx +++ b/src/pages/request/components/CompanyProducts.tsx @@ -65,7 +65,7 @@ const CompanyProducts: FC = ({ value, onChange }) => { >
-
افزودن خدمت
+
افزودن محصول
@@ -75,8 +75,8 @@ const CompanyProducts: FC = ({ value, onChange }) => { {value.map((prd, idx) => (
- {prd.image && } - {prd.existingImageUrl && !prd.image && } + {prd.image && } + {prd.existingImageUrl && !prd.image && }
{prd.title}