diff --git a/mocks/handler.js b/mocks/handler.js
index 3a8f75d..45183f9 100644
--- a/mocks/handler.js
+++ b/mocks/handler.js
@@ -1,10 +1,42 @@
-import {GET_USER_ROUTE} from "@/core/data/apiRoutes";
+import {GET_PROVINCE_LIST, GET_ROLE_LIST, GET_USER_ROUTE} from "@/core/data/apiRoutes";
import {rest} from "msw";
-export const handler = [rest.get(GET_USER_ROUTE, (req, res, ctx) => {
- return res(ctx.json({
- data: {
- id: 10
- }
- }))
-})]
\ No newline at end of file
+export const handler = [
+ rest.get(GET_USER_ROUTE, (req, res, ctx) => {
+ return res(ctx.json({
+ data: {
+ id: 10
+ }
+ }))
+ }),
+ rest.get(GET_PROVINCE_LIST, (req, res, ctx) => {
+ return res(ctx.json({
+ data: [
+ {
+ id: 1,
+ name: "آذربایجان شرقی"
+ },
+ {
+ id: 3,
+ name: "اردبیل"
+ }
+ ]
+ }))
+ }),
+ rest.get(GET_ROLE_LIST, (req, res, ctx) => {
+ return res(ctx.json({
+ data: [
+ {
+ id: 1,
+ name: "passenger_office_chief",
+ name_fa: "رئیس اداره مسافری استان"
+ },
+ {
+ id: 4,
+ name: "province_manager",
+ name_fa: "مدیر کل استانی"
+ }
+ ]
+ }))
+ })
+]
\ No newline at end of file
diff --git a/public/locales/fa/app.json b/public/locales/fa/app.json
index 06b811d..4f7eef8 100644
--- a/public/locales/fa/app.json
+++ b/public/locales/fa/app.json
@@ -133,6 +133,40 @@
"city_name": "شهر",
"role_name": "نقش",
"updated_at": "آخرین بروزرسانی",
- "create": "افزودن کارشناس"
+ "create": "افزودن کارشناس",
+ "personal_info": "مشخصات کارشناس",
+ "user_info": "اطلاعات کاربری",
+ "rest_info": "اطلاعات تکمیلی",
+ "text_field_name": "نام",
+ "text_field_username": "نام کاربری",
+ "text_field_email": "پست الکترونیک",
+ "text_field_phone_number": "شماره همراه",
+ "text_field_national_id": "کد ملی",
+ "text_field_password": "رمز عبور",
+ "text_field_position": "سمت",
+ "text_field_province_id": "استان",
+ "text_field_city_id": "شهر",
+ "text_field_role_id": "نقش",
+ "text_field_loading_provinces_list": "درحال دریافت شهر ها",
+ "text_field_error_fetching_provinces": "خطا در دریافت شهر ها",
+ "text_field_loading_roles_list": "درحال دریافت نقش ها",
+ "text_field_error_fetching_roles": "خطا در دریافت نقش ها",
+ "text_field_please_select_province": "ابتدا استان خود را انتخاب کنید",
+ "text_field_loading_cities_list": "درحال دریافت شهر ها",
+ "text_field_error_fetching_cities": "خطا در دریافت شهر ها",
+ "text_field_new_password": "رمز عبور جدید",
+ "error_message_name": "نام خود را وارد کنید",
+ "error_message_username": "نام کاربری خود را وارد کنید",
+ "error_message_email": "پست الکترونیک خود را وارد کنید",
+ "error_message_phone_number": "شماره همراه خود را وارد کنید",
+ "error_message_national_id": "کد ملی خود را وارد کنید",
+ "error_message_password": "رمز عبور خود را وارد کنید",
+ "error_message_password_regex": "رمز عبور باید حداقل 8 کاراکتر و متشکل از عدد، حرف یا سمبل باشد",
+ "error_message_position": "سمت خود را وارد کنید",
+ "error_message_province_id": "استان خود را وارد کنید",
+ "error_message_city_id": "شهر خود را وارد کنید",
+ "error_message_role_id": "نقش خود را وارد کنید",
+ "error_message_new_password": "رمز عبور جدید را وارد کنید",
+ "error_message_new_password_regex": "رمز عبور باید حداقل 8 کاراکتر و متشکل از عدد، حرف یا سمبل باشد"
}
}
diff --git a/src/components/dashboard/expert-management/Form/CreateForm/CreateContent/__tests__/index.test.js b/src/components/dashboard/expert-management/Form/CreateForm/CreateContent/__tests__/index.test.js
index e69de29..cf93005 100644
--- a/src/components/dashboard/expert-management/Form/CreateForm/CreateContent/__tests__/index.test.js
+++ b/src/components/dashboard/expert-management/Form/CreateForm/CreateContent/__tests__/index.test.js
@@ -0,0 +1,83 @@
+import {act, render, screen, waitFor} from "@testing-library/react";
+import React from 'react';
+import CreateContent from "../../CreateContent";
+import MockAppWithProviders from "../../../../../../../../mocks/AppWithProvider";
+
+describe("CreateContent Component From Expert Management", () => {
+ describe("Rendering", () => {
+ it("Name TextField Rendered", async () => {
+ render();
+ await waitFor(() => {
+ const nameTextField = screen.queryByLabelText('نام');
+ expect(nameTextField).toBeInTheDocument();
+ });
+ });
+ it("UserName TextField Rendered", async () => {
+ render();
+ await waitFor(() => {
+ const nameTextField = screen.queryByLabelText('نام کاربری');
+ expect(nameTextField).toBeInTheDocument();
+ });
+ });
+ it("Email TextField Rendered", async () => {
+ render();
+ await waitFor(() => {
+ const nameTextField = screen.queryByLabelText('پست الکترونیک');
+ expect(nameTextField).toBeInTheDocument();
+ });
+ });
+ it("Phone Number TextField Rendered", async () => {
+ render();
+ await waitFor(() => {
+ const nameTextField = screen.queryByLabelText('شماره همراه');
+ expect(nameTextField).toBeInTheDocument();
+ });
+ });
+ it("National Id TextField Rendered", async () => {
+ render();
+ await waitFor(() => {
+ const nameTextField = screen.queryByLabelText('کد ملی');
+ expect(nameTextField).toBeInTheDocument();
+ });
+ });
+ it("Password TextField Rendered", async () => {
+ render();
+ await waitFor(() => {
+ const nameTextField = screen.queryByLabelText('رمز عبور');
+ expect(nameTextField).toBeInTheDocument();
+ });
+
+ });
+ it("Position TextField Rendered", async () => {
+ render();
+ await waitFor(() => {
+ const nameTextField = screen.queryByLabelText('سمت');
+ expect(nameTextField).toBeInTheDocument();
+ });
+ });
+ it("Province TextField Rendered", async () => {
+ render();
+ await waitFor(() => {
+ const nameTextField = screen.getByTestId('province-select');
+ expect(nameTextField).toBeInTheDocument();
+ });
+ });
+ it("City TextField Rendered", async () => {
+ render();
+ await waitFor(() => {
+ const nameTextField = screen.getByTestId('city-select');
+ expect(nameTextField).toBeInTheDocument();
+ });
+ });
+ it("Role TextField Rendered", async () => {
+ render();
+ await waitFor(() => {
+ const nameTextField = screen.getByTestId('role-select');
+ expect(nameTextField).toBeInTheDocument();
+ });
+ });
+ });
+ describe("Behavioral", () => {
+
+ });
+});
\ No newline at end of file
diff --git a/src/components/dashboard/expert-management/Form/CreateForm/CreateContent/index.jsx b/src/components/dashboard/expert-management/Form/CreateForm/CreateContent/index.jsx
index 7ce4fcf..8f24ef4 100644
--- a/src/components/dashboard/expert-management/Form/CreateForm/CreateContent/index.jsx
+++ b/src/components/dashboard/expert-management/Form/CreateForm/CreateContent/index.jsx
@@ -1,7 +1,377 @@
-const CreateContent = () => {
+import {
+ Box,
+ Button,
+ Chip,
+ DialogActions,
+ DialogContent,
+ Divider,
+ FormControl,
+ FormHelperText,
+ Grid,
+ IconButton,
+ InputAdornment,
+ InputLabel,
+ MenuItem,
+ Select,
+ TextField,
+} from "@mui/material";
+import * as Yup from "yup";
+import {useTranslations} from "next-intl";
+import {useFormik} from "formik";
+import {useState} from "react";
+import useRequest from "@/lib/app/hooks/useRequest";
+import {CREATE_EXPERT_MANAGEMENT, GET_CITY_LIST} from "@/core/data/apiRoutes";
+import useRole from "@/lib/app/hooks/useRole";
+import {Visibility, VisibilityOff} from "@mui/icons-material";
+import useProvince from "@/lib/app/hooks/useProvince";
+
+const CreateContent = ({setOpenCreateDialog, mutate, fetchUrl}) => {
+ const t = useTranslations();
+ const requestServer = useRequest()
+ const [cityList, setCityList] = useState([]);
+ const [cityTextField, setCityTextField] = useState(t("ExpertMangement.text_field_please_select_province"));
+ const {provinceList, isLoadingProvinceList, errorProvinceList} = useProvince();
+ const {roleList, isLoadingRoleList, errorRoleList} = useRole();
+ const [showPassword, setShowPassword] = useState(false);
+
+ const handleClickShowPassword = () => {
+ setShowPassword(!showPassword);
+ };
+
+ function getCities(province_id) {
+ formik.setFieldTouched("city_id", false, false);
+ formik.setFieldValue("city_id", "")
+ setCityTextField(t("ExpertMangement.text_field_loading_cities_list"))
+ requestServer(`${GET_CITY_LIST}?province_id=${province_id}`, "get", {auth: true, notification: false})
+ .then(({data}) => {
+ const result = data.data;
+ const formattedData = result.map((city, index) => ({
+ id: index,
+ name: city.name,
+ value: city.id,
+ }));
+ setCityList(formattedData);
+ setCityTextField(t("ExpertMangement.text_field_city_id"))
+ }).catch(() => {
+ setCityTextField(t("ExpertMangement.text_field_error_fetching_cities"))
+ });
+ }
+
+ const validationSchema = Yup.object().shape({
+ name: Yup.string().required(t("ExpertMangement.error_message_name")),
+ username: Yup.string().required(t("ExpertMangement.error_message_username")),
+ email: Yup.string().required(t("ExpertMangement.error_message_email")),
+ phone_number: Yup.string().required(t("ExpertMangement.error_message_phone_number")),
+ national_id: Yup.string().required(t("ExpertMangement.error_message_national_id")),
+ password: Yup.string()
+ .required(t("ExpertMangement.error_message_password"))
+ .matches(
+ /^(?=.*[a-zA-Z])(?=.*\d).{8,}$/,
+ t("ExpertMangement.error_message_password_regex")
+ ),
+ position: Yup.string().required(t("ExpertMangement.error_message_position")),
+ province_id: Yup.string().required(t("ExpertMangement.error_message_province_id")),
+ city_id: Yup.string().required(t("ExpertMangement.error_message_city_id")),
+ role_id: Yup.string().required(t("ExpertMangement.error_message_role_id"))
+ });
+
+ const formik = useFormik({
+ initialValues: {
+ name: "",
+ username: "",
+ email: "",
+ phone_number: "",
+ national_id: "",
+ password: "",
+ position: "",
+ province_id: "",
+ city_id: "",
+ role_id: ""
+ },
+ validationSchema,
+ onSubmit: (values, {setSubmitting}) => {
+ const formData = new FormData();
+ formData.append("name", values.name);
+ formData.append("national_id", values.national_id);
+ formData.append("phone_number", values.phone_number);
+ formData.append("email", values.email);
+ formData.append("username", values.username);
+ formData.append("password", values.password);
+ formData.append("province_id", values.province_id);
+ formData.append("city_id", values.city_id);
+ formData.append("position", values.position);
+ formData.append("role_id", values.role_id);
+
+ requestServer(`${CREATE_EXPERT_MANAGEMENT}`, 'post', {auth: true, data: formData})
+ .then((response) => {
+ mutate(fetchUrl)
+ setOpenCreateDialog(false)
+ }).catch(() => {
+ }).finally(() => {
+ setSubmitting(false);
+ });
+ },
+ });
+
return (
<>
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {showPassword ? : }
+
+
+ ),
+ }}
+ sx={{width: "100%"}}
+ />
+
+
+
+
+
+
+
+
+
+
+ {t("ExpertMangement.text_field_province_id")}
+
+
+ {formik.touched.province_id && formik.errors.province_id ? formik.errors.province_id : ""}
+
+
+
+
+
+ {cityTextField}
+
+
+ {formik.touched.city_id && formik.errors.city_id ? formik.errors.city_id : ""}
+
+
+
+
+
+
+
+
+
+
+ {t("ExpertMangement.text_field_role_id")}
+
+
+ {formik.touched.role_id && formik.errors.role_id ? formik.errors.role_id : ""}
+
+
+
+
+
+
+
>
)
}
diff --git a/src/core/data/apiRoutes.js b/src/core/data/apiRoutes.js
index 543e9a4..6e604c1 100644
--- a/src/core/data/apiRoutes.js
+++ b/src/core/data/apiRoutes.js
@@ -1,5 +1,14 @@
const BASE_URL = process.env.NEXT_PUBLIC_BASE_URL;
+// role list
+export const GET_ROLE_LIST = BASE_URL + "/dashboard/roles/list";
+// role list
+
+// province/city list
+export const GET_PROVINCE_LIST = BASE_URL + "/api/provinces";
+export const GET_CITY_LIST = BASE_URL + "/api/cities";
+// province/city list
+
//login
export const GET_USER_TOKEN = BASE_URL + "/api/auth/login";
//end login
@@ -14,4 +23,5 @@ export const GET_USER_ROUTE = BASE_URL + "/api/profile/info";
//expert management
export const GET_EXPERT_MANAGEMENT_LIST = BASE_URL + "/dashboard/experts/show";
+export const CREATE_EXPERT_MANAGEMENT = BASE_URL + "/dashboard/experts/store";
//expert management
\ No newline at end of file
diff --git a/src/lib/app/hooks/useProvince.jsx b/src/lib/app/hooks/useProvince.jsx
new file mode 100644
index 0000000..359eff4
--- /dev/null
+++ b/src/lib/app/hooks/useProvince.jsx
@@ -0,0 +1,29 @@
+import {GET_PROVINCE_LIST} from "@/core/data/apiRoutes";
+import useRequest from "@/lib/app/hooks/useRequest";
+import useSWR from "swr";
+
+const useProvince = () => {
+ const requestServer = useRequest({auth: true, notification: false})
+
+ //swr config
+ const fetcher = (...args) => {
+ return requestServer(args, 'get').then(({data}) => {
+ return data.data;
+ }).catch(() => {
+ })
+ };
+
+ const {data, isLoading} = useSWR(GET_PROVINCE_LIST, fetcher, {
+ revalidateIfStale: false,
+ revalidateOnFocus: false,
+ revalidateOnReconnect: false
+ });
+
+ return {
+ provinceList: data,
+ isLoadingProvinceList: isLoading,
+ errorProvinceList: !data
+ }
+};
+
+export default useProvince;
\ No newline at end of file
diff --git a/src/lib/app/hooks/useRole.jsx b/src/lib/app/hooks/useRole.jsx
new file mode 100644
index 0000000..fc3dd18
--- /dev/null
+++ b/src/lib/app/hooks/useRole.jsx
@@ -0,0 +1,29 @@
+import {GET_ROLE_LIST} from "@/core/data/apiRoutes";
+import useRequest from "@/lib/app/hooks/useRequest";
+import useSWR from "swr";
+
+const useRole = () => {
+ const requestServer = useRequest({auth: true, notification: false})
+
+ //swr config
+ const fetcher = (...args) => {
+ return requestServer(args, 'get').then(({data}) => {
+ return data.data;
+ }).catch(() => {
+ })
+ };
+
+ const {data, isLoading} = useSWR(GET_ROLE_LIST, fetcher, {
+ revalidateIfStale: false,
+ revalidateOnFocus: false,
+ revalidateOnReconnect: false
+ });
+
+ return {
+ roleList: data,
+ isLoadingRoleList: isLoading,
+ errorRoleList: !data
+ }
+};
+
+export default useRole;
\ No newline at end of file