customers
This commit is contained in:
+6
-1
@@ -601,7 +601,12 @@
|
||||
"state": "استان",
|
||||
"city": "شهر",
|
||||
"password": "رمز عبور",
|
||||
"reapeat_password": "تکرار رمز عبور"
|
||||
"reapeat_password": "تکرار رمز عبور",
|
||||
"copany_name": "نام شرکت",
|
||||
"enter_company_name": "نام ثبتی شرکت را وارد کنید",
|
||||
"postal_code": "کد پستی",
|
||||
"enter_postal_code": "کد پستی را وارد کنید",
|
||||
"address": "آدرس"
|
||||
},
|
||||
"messages": {
|
||||
"messages_list": "لیست پیام ها",
|
||||
|
||||
+255
-107
@@ -1,4 +1,4 @@
|
||||
import { FC } from 'react'
|
||||
import { FC, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import Input from '../../components/Input'
|
||||
import UploadBoxDraggble from '../../components/UploadBoxDraggble';
|
||||
@@ -6,10 +6,100 @@ import Button from '../../components/Button';
|
||||
import { TickCircle } from 'iconsax-react';
|
||||
import DatePickerComponent from '../../components/DatePicker';
|
||||
import Select from '../../components/Select';
|
||||
import * as Yup from 'yup'
|
||||
import { useFormik } from 'formik';
|
||||
import { CreateCustomerType, ProvinesItemType } from './types/CustomerTypes';
|
||||
import { useCreateCustomer, useGetCities, useGetProvines } from './hooks/useCustomerData';
|
||||
import PageLoading from '../../components/PageLoading';
|
||||
import { toast } from 'react-toastify';
|
||||
import { ErrorType } from '../../helpers/types';
|
||||
import { useSingleUpload } from '../service/hooks/useServiceData';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { Pages } from '../../config/Pages';
|
||||
import Textarea from '../../components/Textarea';
|
||||
|
||||
const AddCustomer: FC = () => {
|
||||
|
||||
const { t } = useTranslation('global')
|
||||
const navigate = useNavigate()
|
||||
const [provinesId, setProvinesId] = useState<string>('')
|
||||
const [file, setFile] = useState<File>()
|
||||
const getProvines = useGetProvines()
|
||||
const getCities = useGetCities(provinesId)
|
||||
const singleUpload = useSingleUpload()
|
||||
const createCustomer = useCreateCustomer()
|
||||
|
||||
const handleCreateCustomer = (values: CreateCustomerType) => {
|
||||
createCustomer.mutate(values, {
|
||||
onSuccess: () => {
|
||||
toast.success(t('success'))
|
||||
navigate(Pages.customer.list)
|
||||
},
|
||||
onError: (error: ErrorType) => {
|
||||
toast.error(error.response?.data?.error.message[0])
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
const formik = useFormik<CreateCustomerType>({
|
||||
initialValues: {
|
||||
phone: '',
|
||||
firstName: '',
|
||||
lastName: '',
|
||||
email: '',
|
||||
birthDate: '',
|
||||
nationalCode: '',
|
||||
password: '',
|
||||
economicCode: '',
|
||||
companyRegisteredName: '',
|
||||
registrationId: '',
|
||||
nationalId: '',
|
||||
number: '',
|
||||
postalCode: '',
|
||||
address: '',
|
||||
cityId: '',
|
||||
profilePic: ''
|
||||
},
|
||||
validationSchema: Yup.object({
|
||||
phone: Yup.string().required(t('errors.required')),
|
||||
firstName: Yup.string().required(t('errors.required')),
|
||||
lastName: Yup.string().required(t('errors.required')),
|
||||
email: Yup.string().email(t('errors.email')).required(t('errors.required')),
|
||||
birthDate: Yup.string().required(t('errors.required')),
|
||||
nationalCode: Yup.string().required(t('errors.required')),
|
||||
password: Yup.string().required(t('errors.required')),
|
||||
economicCode: Yup.string().required(t('errors.required')),
|
||||
companyRegisteredName: Yup.string().required(t('errors.required')),
|
||||
registrationId: Yup.string().required(t('errors.required')),
|
||||
nationalId: Yup.string().required(t('errors.required')),
|
||||
number: Yup.string().required(t('errors.required')),
|
||||
postalCode: Yup.string().required(t('errors.required')),
|
||||
address: Yup.string().required(t('errors.required')),
|
||||
cityId: Yup.string().required(t('errors.required')),
|
||||
}),
|
||||
onSubmit: async (values) => {
|
||||
if (file) {
|
||||
const formData = new FormData()
|
||||
formData.append('file', file)
|
||||
await singleUpload.mutateAsync(formData, {
|
||||
onSuccess: (data) => {
|
||||
values.profilePic = data?.data?.url
|
||||
},
|
||||
onError: (error: ErrorType) => {
|
||||
toast.error(error.response?.data?.error?.message[0])
|
||||
}
|
||||
})
|
||||
|
||||
handleCreateCustomer(values)
|
||||
} else {
|
||||
values.profilePic = undefined
|
||||
handleCreateCustomer(values)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
return (
|
||||
<div className='w-full mt-4'>
|
||||
@@ -20,6 +110,8 @@ const AddCustomer: FC = () => {
|
||||
<div>
|
||||
<Button
|
||||
className='px-5'
|
||||
onClick={() => formik.handleSubmit()}
|
||||
isLoading={createCustomer.isPending || singleUpload.isPending}
|
||||
>
|
||||
<div className='flex gap-2'>
|
||||
<TickCircle
|
||||
@@ -31,121 +123,177 @@ const AddCustomer: FC = () => {
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
<div className='flex gap-6'>
|
||||
<div className='flex-1'>
|
||||
{
|
||||
getProvines.isPending ?
|
||||
<PageLoading />
|
||||
:
|
||||
<div className='flex gap-6'>
|
||||
<div className='flex-1'>
|
||||
|
||||
<div className='flex-1 mt-10 bg-white py-8 xl:px-10 px-4 rounded-3xl'>
|
||||
<div className='rowTwoInput'>
|
||||
<Input
|
||||
label={t('customer.name')}
|
||||
/>
|
||||
<div className='flex-1 mt-10 bg-white py-8 xl:px-10 px-4 rounded-3xl'>
|
||||
<div className='rowTwoInput'>
|
||||
<Input
|
||||
label={t('customer.name')}
|
||||
{...formik.getFieldProps('firstName')}
|
||||
error_text={formik.touched.firstName && formik.errors.firstName ? formik.errors.firstName : ''}
|
||||
/>
|
||||
|
||||
<Input
|
||||
label={t('customer.family')}
|
||||
/>
|
||||
<Input
|
||||
label={t('customer.family')}
|
||||
{...formik.getFieldProps('lastName')}
|
||||
error_text={formik.touched.lastName && formik.errors.lastName ? formik.errors.lastName : ''}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className='mt-8 rowTwoInput'>
|
||||
<DatePickerComponent
|
||||
label={t('customer.dateofbirth')}
|
||||
onChange={(value) => formik.setFieldValue('birthDate', value)}
|
||||
error_text={formik.touched.birthDate && formik.errors.birthDate ? formik.errors.birthDate : ''}
|
||||
placeholder=''
|
||||
/>
|
||||
<Input
|
||||
label={t('customer.national_code')}
|
||||
placeholder={t('customer.enter_nation_code')}
|
||||
{...formik.getFieldProps('nationalCode')}
|
||||
error_text={formik.touched.nationalCode && formik.errors.nationalCode ? formik.errors.nationalCode : ''}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className='mt-8 rowTwoInput'>
|
||||
<Input
|
||||
label={t('customer.email')}
|
||||
placeholder={t('customer.enter_email')}
|
||||
{...formik.getFieldProps('email')}
|
||||
error_text={formik.touched.email && formik.errors.email ? formik.errors.email : ''}
|
||||
/>
|
||||
|
||||
<Input
|
||||
label={t('customer.phone_number')}
|
||||
placeholder={t('customer.enter_phone_number')}
|
||||
{...formik.getFieldProps('phone')}
|
||||
error_text={formik.touched.phone && formik.errors.phone ? formik.errors.phone : ''}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className='mt-8'>
|
||||
{t('customer.information_legal')}
|
||||
</div>
|
||||
|
||||
<div className='mt-8 rowTwoInput'>
|
||||
|
||||
<Input
|
||||
label={t('customer.copany_name')}
|
||||
placeholder={t('customer.enter_company_name')}
|
||||
{...formik.getFieldProps('companyRegisteredName')}
|
||||
error_text={formik.touched.companyRegisteredName && formik.errors.companyRegisteredName ? formik.errors.companyRegisteredName : ''}
|
||||
/>
|
||||
|
||||
<Input
|
||||
label={t('customer.id_national')}
|
||||
placeholder={t('customer.enter_id_nation')}
|
||||
{...formik.getFieldProps('nationalId')}
|
||||
error_text={formik.touched.nationalId && formik.errors.nationalId ? formik.errors.nationalId : ''}
|
||||
/>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
<div className='mt-8 rowTwoInput'>
|
||||
|
||||
<Input
|
||||
label={t('customer.economic_code')}
|
||||
placeholder={t('customer.enter_economic_code')}
|
||||
{...formik.getFieldProps('economicCode')}
|
||||
error_text={formik.touched.economicCode && formik.errors.economicCode ? formik.errors.economicCode : ''}
|
||||
/>
|
||||
|
||||
<Input
|
||||
label={t('customer.postal_code')}
|
||||
placeholder={t('customer.enter_postal_code')}
|
||||
{...formik.getFieldProps('postalCode')}
|
||||
error_text={formik.touched.postalCode && formik.errors.postalCode ? formik.errors.postalCode : ''}
|
||||
/>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
<div className='mt-8 rowTwoInput'>
|
||||
<Input
|
||||
label={t('customer.registeration_id')}
|
||||
placeholder={t('customer.enter_registeration_id')}
|
||||
{...formik.getFieldProps('registrationId')}
|
||||
error_text={formik.touched.registrationId && formik.errors.registrationId ? formik.errors.registrationId : ''}
|
||||
/>
|
||||
|
||||
<Input
|
||||
label={t('customer.your_phone_fixed')}
|
||||
placeholder={t('customer.enter_phone_fixed')}
|
||||
{...formik.getFieldProps('number')}
|
||||
error_text={formik.touched.number && formik.errors.number ? formik.errors.number : ''}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className='mt-8 rowTwoInput'>
|
||||
<Select
|
||||
label={t('customer.state')}
|
||||
items={getProvines.data?.data?.provinces.map((item: ProvinesItemType) => ({ label: item.name, value: item.id }))}
|
||||
onChange={(e) => setProvinesId(e.target.value)}
|
||||
placeholder={t('select')}
|
||||
|
||||
/>
|
||||
|
||||
<Select
|
||||
label={t('customer.city')}
|
||||
items={getCities.data?.data?.cities ? getCities.data?.data?.cities.map((item: ProvinesItemType) => ({ label: item.name, value: item.id })) : []}
|
||||
placeholder={t('select')}
|
||||
{...formik.getFieldProps('cityId')}
|
||||
error_text={formik.touched.cityId && formik.errors.cityId ? formik.errors.cityId : ''}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className='mt-8 rowTwoInput'>
|
||||
<Textarea
|
||||
{...formik.getFieldProps('address')}
|
||||
placeholder={t('customer.address')}
|
||||
error_text={formik.touched.address && formik.errors.address ? formik.errors.address : ''}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className='mt-8 rowTwoInput'>
|
||||
<DatePickerComponent
|
||||
label={t('customer.dateofbirth')}
|
||||
onChange={() => null}
|
||||
placeholder=''
|
||||
/>
|
||||
<Input
|
||||
label={t('customer.national_code')}
|
||||
placeholder={t('customer.enter_nation_code')}
|
||||
/>
|
||||
</div>
|
||||
<div className='bg-white mt-10 w-sidebar text-xs hidden 2xl:block h-fit px-5 py-7 rounded-3xl'>
|
||||
|
||||
<div className='mt-8 rowTwoInput'>
|
||||
<Input
|
||||
label={t('customer.email')}
|
||||
placeholder={t('customer.enter_email')}
|
||||
/>
|
||||
<div>
|
||||
<Input
|
||||
label={t('customer.password')}
|
||||
type='password'
|
||||
{...formik.getFieldProps('password')}
|
||||
error_text={formik.touched.password && formik.errors.password ? formik.errors.password : ''}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<Input
|
||||
label={t('customer.phone_number')}
|
||||
placeholder={t('customer.enter_phone_number')}
|
||||
/>
|
||||
</div>
|
||||
{/* <div className='mt-5'>
|
||||
<Input
|
||||
label={t('customer.reapeat_password')}
|
||||
type='password'
|
||||
{...formik.getFieldProps('password')}
|
||||
error_text={formik.touched.password && formik.errors.password ? formik.errors.password : ''}
|
||||
/>
|
||||
</div> */}
|
||||
|
||||
<div className='mt-8'>
|
||||
{t('customer.information_legal')}
|
||||
</div>
|
||||
|
||||
<div className='mt-8 rowTwoInput'>
|
||||
<Input
|
||||
label={t('customer.economic_code')}
|
||||
placeholder={t('customer.enter_economic_code')}
|
||||
/>
|
||||
|
||||
<Input
|
||||
label={t('customer.id_national')}
|
||||
placeholder={t('customer.enter_id_nation')}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className='mt-8 rowTwoInput'>
|
||||
<Input
|
||||
label={t('customer.registeration_id')}
|
||||
placeholder={t('customer.enter_registeration_id')}
|
||||
/>
|
||||
|
||||
<Input
|
||||
label={t('customer.your_phone_fixed')}
|
||||
placeholder={t('customer.enter_phone_fixed')}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className='mt-8 rowTwoInput'>
|
||||
<Select
|
||||
label={t('customer.state')}
|
||||
items={[
|
||||
{ value: '1', label: '1' },
|
||||
{ value: '2', label: '2' },
|
||||
{ value: '3', label: '3' },
|
||||
]}
|
||||
placeholder={t('select')}
|
||||
/>
|
||||
|
||||
<Select
|
||||
label={t('customer.city')}
|
||||
items={[
|
||||
{ value: '1', label: '1' },
|
||||
{ value: '2', label: '2' },
|
||||
{ value: '3', label: '3' },
|
||||
]}
|
||||
placeholder={t('select')}
|
||||
/>
|
||||
<div className='mt-8'>
|
||||
<div>{t('service.service_icon')}</div>
|
||||
<div className='mt-2'>
|
||||
<UploadBoxDraggble
|
||||
label={t('service.upload_icon_service')}
|
||||
onChange={(files) => setFile(files[0])}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className='bg-white mt-10 w-sidebar text-xs hidden 2xl:block h-fit px-5 py-7 rounded-3xl'>
|
||||
|
||||
<div>
|
||||
<Input
|
||||
label={t('customer.password')}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className='mt-5'>
|
||||
<Input
|
||||
label={t('customer.reapeat_password')}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className='mt-8'>
|
||||
<div>{t('service.service_icon')}</div>
|
||||
<div className='mt-2'>
|
||||
<UploadBoxDraggble
|
||||
label={t('service.upload_icon_service')}
|
||||
onChange={() => null}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ const CustomerList: FC = () => {
|
||||
<div>
|
||||
{t('customer.customer_list')}
|
||||
</div>
|
||||
<div>
|
||||
<Link to={Pages.customer.create}>
|
||||
<Button
|
||||
className='px-5'
|
||||
>
|
||||
@@ -34,7 +34,7 @@ const CustomerList: FC = () => {
|
||||
<div>{t('customer.add_cutomer')}</div>
|
||||
</div>
|
||||
</Button>
|
||||
</div>
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
<div className='flex justify-between items-center mt-12'>
|
||||
|
||||
@@ -1,9 +1,38 @@
|
||||
import * as api from "../service/CustomerService";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
||||
import { CreateCustomerType } from "../types/CustomerTypes";
|
||||
|
||||
export const useGetCustomers = () => {
|
||||
return useQuery({
|
||||
queryKey: ["invoices"],
|
||||
queryKey: ["customers"],
|
||||
queryFn: () => api.getCustomers(),
|
||||
});
|
||||
};
|
||||
|
||||
export const useGetProvines = () => {
|
||||
return useQuery({
|
||||
queryKey: ["provines"],
|
||||
queryFn: () => api.getProvines(),
|
||||
});
|
||||
};
|
||||
|
||||
export const useGetCities = (provincesId: string) => {
|
||||
return useQuery({
|
||||
queryKey: ["cities", provincesId],
|
||||
queryFn: () => api.getCities(provincesId),
|
||||
enabled: !!provincesId,
|
||||
});
|
||||
};
|
||||
|
||||
export const useCreateCustomer = () => {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation({
|
||||
mutationFn: (variables: CreateCustomerType) =>
|
||||
api.createCustomer(variables),
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: ["customers"],
|
||||
});
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
@@ -1,6 +1,22 @@
|
||||
import axios from "../../../config/axios";
|
||||
import { CreateCustomerType } from "../types/CustomerTypes";
|
||||
|
||||
export const getCustomers = async () => {
|
||||
const { data } = await axios.get(`/users/customers`);
|
||||
return data;
|
||||
};
|
||||
|
||||
export const getProvines = async () => {
|
||||
const { data } = await axios.get(`/address/provinces/list?limit=50`);
|
||||
return data;
|
||||
};
|
||||
|
||||
export const getCities = async (id: string) => {
|
||||
const { data } = await axios.get(`/address/provinces/${id}/cities`);
|
||||
return data;
|
||||
};
|
||||
|
||||
export const createCustomer = async (params: CreateCustomerType) => {
|
||||
const { data } = await axios.post(`/users/customer`, params);
|
||||
return data;
|
||||
};
|
||||
|
||||
@@ -21,3 +21,27 @@ export type CustomerItemType = {
|
||||
ticketsCount: string;
|
||||
invoicesCount: string;
|
||||
};
|
||||
|
||||
export type CreateCustomerType = {
|
||||
phone: string;
|
||||
firstName: string;
|
||||
lastName: string;
|
||||
email: string | null;
|
||||
birthDate: string;
|
||||
nationalCode: string;
|
||||
password: string;
|
||||
economicCode: string;
|
||||
companyRegisteredName: string;
|
||||
registrationId: string;
|
||||
nationalId: string;
|
||||
number: string;
|
||||
postalCode: string;
|
||||
address: string;
|
||||
cityId: string;
|
||||
profilePic?: string;
|
||||
};
|
||||
|
||||
export type ProvinesItemType = {
|
||||
id: string;
|
||||
name: string;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user