Feature/migration

This commit is contained in:
AmirHossein Mahmoodi
2025-05-05 09:57:50 +00:00
parent 18af64b3f6
commit 9bcddb6610
381 changed files with 9465 additions and 12983 deletions

View File

@@ -0,0 +1,7 @@
"use client";
import PageLoading from "@/core/components/PageLoading";
const Loading = () => {
return <PageLoading />;
};
export default Loading;

View File

@@ -0,0 +1,9 @@
export const metadata = {
title: "پیشخوان",
};
const Page = () => {
return <></>;
};
export default Page;

View File

@@ -0,0 +1,19 @@
import HeaderWithSidebar from "@/components/layouts/dashboard/headerWithSidebar";
import CallWidget from "@/components/widget/call";
import WithWidgetMiddleware from "@/core/middlewares/withWidget";
import { SocketProvider } from "@/lib/contexts/socket";
import { Stack } from "@mui/material";
const Layout = ({ children }) => {
return (
<SocketProvider>
<Stack sx={{ width: "100%", height: "100%" }}>
<HeaderWithSidebar>{children}</HeaderWithSidebar>
</Stack>
<WithWidgetMiddleware enable={true}>
<CallWidget />
</WithWidgetMiddleware>
</SocketProvider>
);
};
export default Layout;

View File

@@ -0,0 +1,7 @@
import WithAuthMiddleware from "@/core/middlewares/withAuth";
const Layout = ({ children }) => {
return <WithAuthMiddleware>{children}</WithAuthMiddleware>;
};
export default Layout;

View File

@@ -0,0 +1,13 @@
"use client";
import WithoutAuthMiddleware from "@/core/middlewares/withoutAuth";
import { Suspense } from "react";
const Layout = ({ children }) => {
return (
<Suspense>
<WithoutAuthMiddleware>{children}</WithoutAuthMiddleware>
</Suspense>
);
};
export default Layout;

View File

@@ -0,0 +1,10 @@
import LoginPage from "@/components/Login";
export const metadata = {
title: "ورود",
};
const Page = () => {
return <LoginPage />;
};
export default Page;

3
src/app/default.js Normal file
View File

@@ -0,0 +1,3 @@
export default function Default() {
return null;
}

29
src/app/layout.js Normal file
View File

@@ -0,0 +1,29 @@
import { Rtl } from "@/core/utils/cacheRtl";
import { AuthProvider } from "@/lib/contexts/auth";
import { TableSettingProvider } from "@/lib/contexts/tableSetting";
import { AppRouterCacheProvider } from "@mui/material-nextjs/v15-appRouter";
export const metadata = {
title: {
template: "%s | سامانه CRM",
default: "سامانه CRM",
},
};
export default function RootLayout({ children }) {
return (
<html lang="fa" dir={"rtl"}>
<head></head>
<body style={{ height: "100vh", width: "100vw" }}>
<AppRouterCacheProvider
CacheProvider={Rtl}
options={{ enableCssLayer: true }}
>
<AuthProvider>
<TableSettingProvider>{children}</TableSettingProvider>
</AuthProvider>
</AppRouterCacheProvider>
</body>
</html>
);
}

21
src/app/not-found.js Normal file
View File

@@ -0,0 +1,21 @@
"use client";
import { Box, Stack, Typography } from "@mui/material";
import SvgNotFound from "@/core/components/svgs/SvgNotFound";
export default function NotFound() {
return (
<Stack
sx={{ height: "100%" }}
justifyContent={"center"}
alignItems={"center"}
spacing={2}
>
<Box>
<SvgNotFound width={200} height={200} />
</Box>
<Typography variant={"body1"} sx={{ color: "primary.main" }}>
صفحه موردنظر یافت نشد ...
</Typography>
</Stack>
);
}

8
src/app/page.js Normal file
View File

@@ -0,0 +1,8 @@
import { redirect } from "next/navigation";
function Page() {
redirect("/dashboard", "replace");
return null;
}
export default Page;

40
src/app/template.js Normal file
View File

@@ -0,0 +1,40 @@
"use client";
import "@/assets/scss/fontiran.scss";
import "@/assets/scss/global.scss";
import theme from "@/core/utils/theme";
import { CssBaseline, GlobalStyles, ThemeProvider } from "@mui/material";
import { ToastContainer } from "react-toastify";
const Template = ({ children }) => {
return (
<ThemeProvider theme={theme}>
<GlobalStyles
styles={{
"*": {
scrollbarWidth: "thin",
scrollbarColor: `#155175 transparent`,
},
"*&::-webkit-scrollbar": {
width: "4px",
},
"*&::-webkit-scrollbar-track": {
boxShadow: "inset 0 0 5px #fff",
borderRadius: "4px",
},
"*&::-webkit-scrollbar-thumb": {
background: "#155175",
borderRadius: "4px",
},
}}
/>
<CssBaseline />
{children}
<ToastContainer rtl containerId="filtering" closeButton={false} />
<ToastContainer rtl containerId="request_data" />
<ToastContainer rtl containerId="socket_connection" position="top-left" />
</ThemeProvider>
);
};
export default Template;

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" data-name="Layer 1" width="647.63626" height="632.17383" viewBox="0 0 647.63626 632.17383" xmlns:xlink="http://www.w3.org/1999/xlink"><path d="M687.3279,276.08691H512.81813a15.01828,15.01828,0,0,0-15,15v387.85l-2,.61005-42.81006,13.11a8.00676,8.00676,0,0,1-9.98974-5.31L315.678,271.39691a8.00313,8.00313,0,0,1,5.31006-9.99l65.97022-20.2,191.25-58.54,65.96972-20.2a7.98927,7.98927,0,0,1,9.99024,5.3l32.5498,106.32Z" transform="translate(-276.18187 -133.91309)" fill="#f2f2f2"/><path d="M725.408,274.08691l-39.23-128.14a16.99368,16.99368,0,0,0-21.23-11.28l-92.75,28.39L380.95827,221.60693l-92.75,28.4a17.0152,17.0152,0,0,0-11.28028,21.23l134.08008,437.93a17.02661,17.02661,0,0,0,16.26026,12.03,16.78926,16.78926,0,0,0,4.96972-.75l63.58008-19.46,2-.62v-2.09l-2,.61-64.16992,19.65a15.01489,15.01489,0,0,1-18.73-9.95l-134.06983-437.94a14.97935,14.97935,0,0,1,9.94971-18.73l92.75-28.4,191.24024-58.54,92.75-28.4a15.15551,15.15551,0,0,1,4.40966-.66,15.01461,15.01461,0,0,1,14.32032,10.61l39.0498,127.56.62012,2h2.08008Z" transform="translate(-276.18187 -133.91309)" fill="#3f3d56"/><path d="M398.86279,261.73389a9.0157,9.0157,0,0,1-8.61133-6.3667l-12.88037-42.07178a8.99884,8.99884,0,0,1,5.9712-11.24023l175.939-53.86377a9.00867,9.00867,0,0,1,11.24072,5.9707l12.88037,42.07227a9.01029,9.01029,0,0,1-5.9707,11.24072L401.49219,261.33887A8.976,8.976,0,0,1,398.86279,261.73389Z" transform="translate(-276.18187 -133.91309)" fill="#2070af"/><circle cx="190.15351" cy="24.95465" r="20" fill="#2070af"/><circle cx="190.15351" cy="24.95465" r="12.66462" fill="#fff"/><path d="M878.81836,716.08691h-338a8.50981,8.50981,0,0,1-8.5-8.5v-405a8.50951,8.50951,0,0,1,8.5-8.5h338a8.50982,8.50982,0,0,1,8.5,8.5v405A8.51013,8.51013,0,0,1,878.81836,716.08691Z" transform="translate(-276.18187 -133.91309)" fill="#e6e6e6"/><path d="M723.31813,274.08691h-210.5a17.02411,17.02411,0,0,0-17,17v407.8l2-.61v-407.19a15.01828,15.01828,0,0,1,15-15H723.93825Zm183.5,0h-394a17.02411,17.02411,0,0,0-17,17v458a17.0241,17.0241,0,0,0,17,17h394a17.0241,17.0241,0,0,0,17-17v-458A17.02411,17.02411,0,0,0,906.81813,274.08691Zm15,475a15.01828,15.01828,0,0,1-15,15h-394a15.01828,15.01828,0,0,1-15-15v-458a15.01828,15.01828,0,0,1,15-15h394a15.01828,15.01828,0,0,1,15,15Z" transform="translate(-276.18187 -133.91309)" fill="#3f3d56"/><path d="M801.81836,318.08691h-184a9.01015,9.01015,0,0,1-9-9v-44a9.01016,9.01016,0,0,1,9-9h184a9.01016,9.01016,0,0,1,9,9v44A9.01015,9.01015,0,0,1,801.81836,318.08691Z" transform="translate(-276.18187 -133.91309)" fill="#2070af"/><circle cx="433.63626" cy="105.17383" r="20" fill="#2070af"/><circle cx="433.63626" cy="105.17383" r="12.18187" fill="#fff"/></svg>

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@@ -0,0 +1,212 @@
@font-face {
font-family: IRANSansFaNum;
font-style: normal;
font-weight: 900;
src: url("../fonts/eot/IRANSansWeb(FaNum)_Black.eot");
src:
url("../fonts/eot/IRANSansWeb(FaNum)_Black.eot?#iefix")
format("embedded-opentype"),
/* IE6-8 */ url("../fonts/woff2/IRANSansWeb(FaNum)_Black.woff2")
format("woff2"),
/* FF39+,Chrome36+, Opera24+*/
url("../fonts/woff/IRANSansWeb(FaNum)_Black.woff") format("woff"),
/* FF3.6+, IE9, Chrome6+, Saf5.1+*/
url("../fonts/ttf/IRANSansWeb(FaNum)_Black.ttf") format("truetype");
}
@font-face {
font-family: IRANSansFaNum;
font-style: normal;
font-weight: bold;
src: url("../fonts/eot/IRANSansWeb(FaNum)_Bold.eot");
src:
url("../fonts/eot/IRANSansWeb(FaNum)_Bold.eot?#iefix")
format("embedded-opentype"),
/* IE6-8 */ url("../fonts/woff2/IRANSansWeb(FaNum)_Bold.woff2")
format("woff2"),
/* FF39+,Chrome36+, Opera24+*/
url("../fonts/woff/IRANSansWeb(FaNum)_Bold.woff") format("woff"),
/* FF3.6+, IE9, Chrome6+, Saf5.1+*/
url("../fonts/ttf/IRANSansWeb(FaNum)_Bold.ttf") format("truetype");
}
@font-face {
font-family: IRANSansFaNum;
font-style: normal;
font-weight: 500;
src: url("../fonts/eot/IRANSansWeb(FaNum)_Medium.eot");
src:
url("../fonts/eot/IRANSansWeb(FaNum)_Medium.eot?#iefix")
format("embedded-opentype"),
/* IE6-8 */ url("../fonts/woff2/IRANSansWeb(FaNum)_Medium.woff2")
format("woff2"),
/* FF39+,Chrome36+, Opera24+*/
url("../fonts/woff/IRANSansWeb(FaNum)_Medium.woff") format("woff"),
/* FF3.6+, IE9, Chrome6+, Saf5.1+*/
url("../fonts/ttf/IRANSansWeb(FaNum)_Medium.ttf") format("truetype");
}
@font-face {
font-family: IRANSansFaNum;
font-style: normal;
font-weight: 300;
src: url("../fonts/eot/IRANSansWeb(FaNum)_Light.eot");
src:
url("../fonts/eot/IRANSansWeb(FaNum)_Light.eot?#iefix")
format("embedded-opentype"),
/* IE6-8 */ url("../fonts/woff2/IRANSansWeb(FaNum)_Light.woff2")
format("woff2"),
/* FF39+,Chrome36+, Opera24+*/
url("../fonts/woff/IRANSansWeb(FaNum)_Light.woff") format("woff"),
/* FF3.6+, IE9, Chrome6+, Saf5.1+*/
url("../fonts/ttf/IRANSansWeb(FaNum)_Light.ttf") format("truetype");
}
@font-face {
font-family: IRANSansFaNum;
font-style: normal;
font-weight: 200;
src: url("../fonts/eot/IRANSansWeb(FaNum)_UltraLight.eot");
src:
url("../fonts/eot/IRANSansWeb(FaNum)_UltraLight.eot?#iefix")
format("embedded-opentype"),
/* IE6-8 */ url("../fonts/woff2/IRANSansWeb(FaNum)_UltraLight.woff2")
format("woff2"),
/* FF39+,Chrome36+, Opera24+*/
url("../fonts/woff/IRANSansWeb(FaNum)_UltraLight.woff") format("woff"),
/* FF3.6+, IE9, Chrome6+, Saf5.1+*/
url("../fonts/ttf/IRANSansWeb(FaNum)_UltraLight.ttf") format("truetype");
}
@font-face {
font-family: IRANSansFaNum;
font-style: normal;
font-weight: normal;
src: url("../fonts/eot/IRANSansWeb(FaNum).eot");
src:
url("../fonts/eot/IRANSansWeb(FaNum).eot?#iefix")
format("embedded-opentype"),
/* IE6-8 */ url("../fonts/woff2/IRANSansWeb(FaNum).woff2") format("woff2"),
/* FF39+,Chrome36+, Opera24+*/ url("../fonts/woff/IRANSansWeb(FaNum).woff")
format("woff"),
/* FF3.6+, IE9, Chrome6+, Saf5.1+*/
url("../fonts/ttf/IRANSansWeb(FaNum).ttf") format("truetype");
}
@font-face {
font-family: IRANSans;
font-style: normal;
font-weight: 900;
src: url("../fonts/eot/IRANSansWeb_Black.eot");
src:
url("../fonts/eot/IRANSansWeb_Black.eot?#iefix") format("embedded-opentype"),
/* IE6-8 */ url("../fonts/woff2/IRANSansWeb_Black.woff2") format("woff2"),
/* FF39+,Chrome36+, Opera24+*/ url("../fonts/woff/IRANSansWeb_Black.woff")
format("woff"),
/* FF3.6+, IE9, Chrome6+, Saf5.1+*/
url("../fonts/ttf/IRANSansWeb_Black.ttf") format("truetype");
}
@font-face {
font-family: IRANSans;
font-style: normal;
font-weight: bold;
src: url("../fonts/eot/IRANSansWeb_Bold.eot");
src:
url("../fonts/eot/IRANSansWeb_Bold.eot?#iefix") format("embedded-opentype"),
/* IE6-8 */ url("../fonts/woff2/IRANSansWeb_Bold.woff2") format("woff2"),
/* FF39+,Chrome36+, Opera24+*/ url("../fonts/woff/IRANSansWeb_Bold.woff")
format("woff"),
/* FF3.6+, IE9, Chrome6+, Saf5.1+*/ url("../fonts/ttf/IRANSansWeb_Bold.ttf")
format("truetype");
}
@font-face {
font-family: IRANSans;
font-style: normal;
font-weight: 500;
src: url("../fonts/eot/IRANSansWeb_Medium.eot");
src:
url("../fonts/eot/IRANSansWeb_Medium.eot?#iefix")
format("embedded-opentype"),
/* IE6-8 */ url("../fonts/woff2/IRANSansWeb_Medium.woff2") format("woff2"),
/* FF39+,Chrome36+, Opera24+*/ url("../fonts/woff/IRANSansWeb_Medium.woff")
format("woff"),
/* FF3.6+, IE9, Chrome6+, Saf5.1+*/
url("../fonts/ttf/IRANSansWeb_Medium.ttf") format("truetype");
}
@font-face {
font-family: IRANSans;
font-style: normal;
font-weight: 300;
src: url("../fonts/eot/IRANSansWeb_Light.eot");
src:
url("../fonts/eot/IRANSansWeb_Light.eot?#iefix") format("embedded-opentype"),
/* IE6-8 */ url("../fonts/woff2/IRANSansWeb_Light.woff2") format("woff2"),
/* FF39+,Chrome36+, Opera24+*/ url("../fonts/woff/IRANSansWeb_Light.woff")
format("woff"),
/* FF3.6+, IE9, Chrome6+, Saf5.1+*/
url("../fonts/ttf/IRANSansWeb_Light.ttf") format("truetype");
}
@font-face {
font-family: IRANSans;
font-style: normal;
font-weight: 200;
src: url("../fonts/eot/IRANSansWeb_UltraLight.eot");
src:
url("../fonts/eot/IRANSansWeb_UltraLight.eot?#iefix")
format("embedded-opentype"),
/* IE6-8 */ url("../fonts/woff2/IRANSansWeb_UltraLight.woff2")
format("woff2"),
/* FF39+,Chrome36+, Opera24+*/
url("../fonts/woff/IRANSansWeb_UltraLight.woff") format("woff"),
/* FF3.6+, IE9, Chrome6+, Saf5.1+*/
url("../fonts/ttf/IRANSansWeb_UltraLight.ttf") format("truetype");
}
@font-face {
font-family: IRANSans;
font-style: normal;
font-weight: normal;
src: url("../fonts/eot/IRANSansWeb.eot");
src:
url("../fonts/eot/IRANSansWeb.eot?#iefix") format("embedded-opentype"),
/* IE6-8 */ url("../fonts/woff2/IRANSansWeb.woff2") format("woff2"),
/* FF39+,Chrome36+, Opera24+*/ url("../fonts/woff/IRANSansWeb.woff")
format("woff"),
/* FF3.6+, IE9, Chrome6+, Saf5.1+*/ url("../fonts/ttf/IRANSansWeb.ttf")
format("truetype");
}
@font-face {
font-family: Parastoo;
font-style: normal;
font-weight: normal;
src: url("../fonts/eot/Parastoo.eot");
src:
url("../fonts/eot/Parastoo.eot?#iefix") format("embedded-opentype"),
/* IE6-8 */ url("../fonts/woff/Parastoo.woff") format("woff"),
/* FF3.6+, IE9, Chrome6+, Saf5.1+*/ url("../fonts/ttf/Parastoo.ttf")
format("truetype");
}
@font-face {
font-family: Parastoo;
font-style: normal;
font-weight: bold;
src: url("../fonts/eot/Parastoo-Bold.eot");
src:
url("../fonts/eot/Parastoo-Bold.eot?#iefix") format("embedded-opentype"),
/* IE6-8 */ url("../fonts/woff/Parastoo-Bold.woff") format("woff"),
/* FF3.6+, IE9, Chrome6+, Saf5.1+*/ url("../fonts/ttf/Parastoo-Bold.ttf")
format("truetype");
}
@font-face {
font-family: Bnazanin;
font-style: normal;
font-weight: normal;
src: url("../fonts/ttf/BNazanin.ttf") format("truetype");
}

View File

@@ -0,0 +1,6 @@
.filter-toast {
box-shadow:
rgba(50, 50, 93, 0.25) 0px 13px 27px -5px,
rgba(0, 0, 0, 0.3) 0px 8px 16px -8px;
background-color: #d0dfe8;
}

View File

@@ -0,0 +1,128 @@
"use client";
import LtrTextField from "@/core/components/LtrTextField";
import StyledForm from "@/core/components/StyledForm";
import { GET_USER_LOGIN_ROUTE } from "@/core/utils/routes";
import { useAuth } from "@/lib/contexts/auth";
import useRequest from "@/lib/hooks/useRequest";
import { yupResolver } from "@hookform/resolvers/yup";
import { Button, Container, Stack, Typography } from "@mui/material";
import { Controller, useForm } from "react-hook-form";
import { object, string } from "yup";
const LoginForm = () => {
const requestServer = useRequest();
const { getUser } = useAuth();
const defaultValues = {
username: "",
password: "",
};
const validationSchema = object({
username: string().required("لطفا نام کاربری را وارد کنید!"),
password: string().required("لطفا رمز عبور را وارد کنید!"),
});
const {
control,
handleSubmit,
formState: { isSubmitting },
} = useForm({
defaultValues,
resolver: yupResolver(validationSchema),
mode: "all",
});
const onSubmit = async (data) => {
try {
const formData = new FormData();
formData.append("username", data.username);
formData.append("password", data.password);
await requestServer(GET_USER_LOGIN_ROUTE, "post", {
data: formData,
});
getUser();
} catch (error) {
console.error("Login error:", error);
}
};
return (
<Container maxWidth="xs" sx={{ flex: 1 }}>
<StyledForm
onSubmit={handleSubmit(onSubmit)}
style={{ width: "100%", height: "100%" }}
>
<Stack
sx={{ width: "100%", height: "100%" }}
justifyContent="center"
alignItems="center"
spacing={6}
>
<Stack
sx={{ width: "100%", mb: 2 }}
justifyContent="center"
alignItems="center"
>
<Typography
variant="h4"
color="primary"
fontWeight={600}
textAlign="center"
>
ورود به سامانه CRM
</Typography>
</Stack>
<Stack sx={{ width: "100%", p: 2 }} spacing={4}>
<Stack spacing={2}>
<Controller
control={control}
render={({ field, fieldState: { error } }) => {
return (
<LtrTextField
{...field}
label="نام کاربری"
variant="outlined"
fullWidth
error={!!error}
helperText={!!error && error.message}
/>
);
}}
name={"username"}
/>
<Controller
control={control}
render={({ field, fieldState: { error } }) => {
return (
<LtrTextField
{...field}
label="رمزعبور"
variant="outlined"
type="password"
fullWidth
error={!!error}
helperText={!!error && error.message}
/>
);
}}
name={"password"}
/>
</Stack>
<Stack>
<Button
variant="contained"
color="primary"
size="large"
type={"submit"}
disabled={isSubmitting}
>
{isSubmitting ? "درحال ورود..." : "ورود"}
</Button>
</Stack>
</Stack>
</Stack>
</StyledForm>
</Container>
);
};
export default LoginForm;

View File

@@ -0,0 +1,25 @@
"use client";
import { Button, Stack } from "@mui/material";
import Link from "next/link";
import { useSearchParams } from "next/navigation";
const LoginLinkRouting = () => {
const searchParams = useSearchParams();
const redirect = searchParams.get("redirect");
return (
<Stack direction="row" alignItems="center" justifyContent="center">
<Button
component={Link}
data-testid="link_routing"
sx={{ margin: 2 }}
color="secondary"
href={redirect ? decodeURIComponent(redirect) : "/"}
>
{`بازگشت به ${redirect ? "صفحه قبلی" : "صفحه اصلی"}`}
</Button>
</Stack>
);
};
export default LoginLinkRouting;

View File

@@ -0,0 +1,19 @@
"use client";
import { Fade, Stack } from "@mui/material";
import LoginForm from "./Form";
import LoginLinkRouting from "./LoginLinkRouting";
import { Suspense } from "react";
const LoginPage = () => {
return (
<Suspense>
<Fade in={true}>
<Stack sx={{ width: "100%", height: "100vh" }}>
<LoginForm />
<LoginLinkRouting />
</Stack>
</Fade>
</Suspense>
);
};
export default LoginPage;

View File

@@ -1,305 +0,0 @@
import { render, screen, waitFor, fireEvent , act } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import MockAppWithProviders from "../../../../../../mocks/AppWithProvider";
import ChangePasswordForm from "@/components/dashboard/change-password/change-password-form";
import {SET_USER_PASSWORD} from "@/core/data/apiRoutes";
import {server} from "../../../../../../mocks/server";
import {rest} from "msw";
describe('Change Password Form Component From Change Password Page', () => {
describe('Rendering', () => {
it('Should see change password heading',() => {
render(<MockAppWithProviders><ChangePasswordForm /></MockAppWithProviders>);
const changePasswordElement = screen.getByRole('heading', { level: 4 });
expect(changePasswordElement).toHaveTextContent('تغییر رمز عبور');
});
it('Should see the label for current password field', () => {
render(<MockAppWithProviders><ChangePasswordForm /></MockAppWithProviders>);
const currentPasswordLabel = screen.queryByLabelText('رمز عبور فعلی');
expect(currentPasswordLabel).toBeInTheDocument();
});
it('Should see the label for new password field', () => {
render(<MockAppWithProviders><ChangePasswordForm /></MockAppWithProviders>);
const newPasswordLabel = screen.queryByLabelText('رمز عبور جدید');
expect(newPasswordLabel).toBeInTheDocument();
});
it('Should see the label for confirm password field', () => {
render(<MockAppWithProviders><ChangePasswordForm /></MockAppWithProviders>);
const confirmPasswordLabel = screen.queryByLabelText('تکرار رمز عبور جدید');
expect(confirmPasswordLabel).toBeInTheDocument();
});
it('Should see the submit button with the submit label and should be disable', () => {
render(<MockAppWithProviders><ChangePasswordForm /></MockAppWithProviders>);
const submitButton = screen.getByRole('button', { name: 'ثبت' });
expect(submitButton).toBeInTheDocument();
expect(submitButton).toBeDisabled();
});
it('Should have empty input fields and not see any validation error for current password, new password, and confirm password', () => {
render(<MockAppWithProviders><ChangePasswordForm /></MockAppWithProviders>);
const currentPasswordInput = screen.queryByLabelText('رمز عبور فعلی');
const newPasswordInput = screen.queryByLabelText('رمز عبور جدید');
const confirmPasswordInput = screen.queryByLabelText('تکرار رمز عبور جدید');
expect(currentPasswordInput).toHaveValue('');
expect(newPasswordInput).toHaveValue('');
expect(confirmPasswordInput).toHaveValue('');
expect(screen.queryByText("وارد کردن رمز عبور فعلی الزامیست!")).not.toBeInTheDocument();
expect(screen.queryByText("وارد کردن رمز عبور جدید الزامیست!")).not.toBeInTheDocument();
expect(screen.queryByText("وارد کردن تکرار رمز عبور جدید الزامیست!")).not.toBeInTheDocument();
});
});
describe("Behavior", ()=>{
it('Should fill the current password field and not see any error while its not empty', async () => {
render(<MockAppWithProviders><ChangePasswordForm /></MockAppWithProviders>);
const currentPasswordInput = screen.queryByLabelText('رمز عبور فعلی');
// Simulate typing something in the current password input
fireEvent.change(currentPasswordInput, { target: { value: 'witel@fani0' } });
await waitFor(() => {
expect(screen.queryByText("وارد کردن رمز عبور فعلی الزامیست!")).not.toBeInTheDocument();
expect(currentPasswordInput).toHaveValue('witel@fani0');
});
});
it('Should fill the new password field and not see any error while its not empty', async () => {
render(<MockAppWithProviders><ChangePasswordForm /></MockAppWithProviders>);
const newPasswordInput = screen.queryByLabelText('رمز عبور جدید');
// Simulate typing something in the new password input
fireEvent.change(newPasswordInput, { target: { value: 'witel@fani1' } });
await waitFor(() => {
expect(screen.queryByText("وارد کردن رمز عبور جدید الزامیست!")).not.toBeInTheDocument();
expect(newPasswordInput).toHaveValue('witel@fani1');
});
});
it('Should fill the confirm new password field and not see any error while its not empty', async () => {
render(<MockAppWithProviders><ChangePasswordForm /></MockAppWithProviders>);
const confirmPasswordInput = screen.queryByLabelText('تکرار رمز عبور جدید');
// Simulate typing something in the confirmation new password input
fireEvent.change(confirmPasswordInput, { target: { value: 'witel@fani1' } });
await waitFor(() => {
expect(screen.queryByText("وارد کردن تکرار رمز عبور جدید الزامیست!")).not.toBeInTheDocument();
expect(confirmPasswordInput).toHaveValue('witel@fani1');
});
});
});
describe("Validation", ()=>{
it('Should see error while current password is empty on blur event', async () => {
render(<MockAppWithProviders><ChangePasswordForm /></MockAppWithProviders>);
// Simulate blur event on the current password input
const currentPasswordInput = screen.queryByLabelText('رمز عبور فعلی');
// Clear the input field
fireEvent.change(currentPasswordInput, { target: { value: '' } });
fireEvent.blur(currentPasswordInput);
await waitFor(()=>{
expect(screen.queryByText("وارد کردن رمز عبور فعلی الزامیست!")).toBeInTheDocument()
});
});
it('Should see error while new password is empty on blur event', async () => {
render(<MockAppWithProviders><ChangePasswordForm /></MockAppWithProviders>);
// Simulate blur event on the new password input
const newPasswordInput = screen.queryByLabelText('رمز عبور جدید');
// Clear the input field
fireEvent.change(newPasswordInput, { target: { value: '' } });
fireEvent.blur(newPasswordInput);
await waitFor(()=>{
expect(screen.queryByText("وارد کردن رمز عبور جدید الزامیست!")).toBeInTheDocument()
});
});
it('Should see error while confirm new password is empty on blur event', async () => {
render(<MockAppWithProviders><ChangePasswordForm /></MockAppWithProviders>);
// Simulate blur event on the new password input
const confirmPasswordInput = screen.queryByLabelText('تکرار رمز عبور جدید');
// Clear the input field
fireEvent.change(confirmPasswordInput, { target: { value: '' } });
fireEvent.blur(confirmPasswordInput);
await waitFor(()=>{
expect(screen.queryByText("وارد کردن تکرار رمز عبور جدید الزامیست!")).toBeInTheDocument()
});
});
it('Should see error when new password is less than 8 characters', async () => {
render(<MockAppWithProviders><ChangePasswordForm /></MockAppWithProviders>);
const newPasswordInput = screen.queryByLabelText('رمز عبور جدید');
const submitButton = screen.getByRole('button', { name: 'ثبت' });
// Simulate entering a short new password
fireEvent.change(newPasswordInput, { target: { value: 'test' } });
fireEvent.blur(newPasswordInput);
await waitFor(() => {
expect(screen.queryByText("رمز عبور باید حداقل 8 کاراکتر باشد.")).toBeInTheDocument();
});
// Simulate clicking the submit button
fireEvent.click(submitButton);
await waitFor(() => {
expect(screen.queryByText("رمز عبور باید حداقل 8 کاراکتر باشد.")).toBeInTheDocument();
});
});
it('Should not see error when new password are 8 or more characters', async () => {
render(<MockAppWithProviders><ChangePasswordForm /></MockAppWithProviders>);
const newPasswordInput = screen.queryByLabelText('رمز عبور جدید');
const submitButton = screen.getByRole('button', { name: 'ثبت' });
// Simulate entering a valid new password
fireEvent.change(newPasswordInput, { target: { value: 'Witel@fani1' } });
fireEvent.blur(newPasswordInput);
await waitFor(() => {
expect(screen.queryByText("رمز عبور باید حداقل 8 کاراکتر باشد.")).not.toBeInTheDocument();
});
// Simulate clicking the submit button
fireEvent.click(submitButton);
await waitFor(() => {
expect(screen.queryByText("رمز عبور باید حداقل 8 کاراکتر باشد.")).not.toBeInTheDocument();
});
});
it('Should see error when new password and confirm password do not match on blur event and submit click', async () => {
render(<MockAppWithProviders><ChangePasswordForm /></MockAppWithProviders>);
const newPasswordInput = screen.queryByLabelText('رمز عبور جدید');
const confirmPasswordInput = screen.queryByLabelText('تکرار رمز عبور جدید');
const submitButton = screen.getByRole('button', { name: 'ثبت' });
// Simulate entering a valid new password
fireEvent.change(newPasswordInput, { target: { value: 'Witel@fani1' } });
fireEvent.blur(newPasswordInput);
// Simulate entering a different value in the confirm password field
fireEvent.change(confirmPasswordInput, { target: { value: 'MismatchedPassword' } });
fireEvent.blur(confirmPasswordInput);
await waitFor(() => {
expect(screen.queryByText("پسورد و تکرار رمز عبور باید یکسان باشد")).toBeInTheDocument();
});
// Simulate clicking the submit button
fireEvent.click(submitButton);
await waitFor(() => {
expect(screen.queryByText("پسورد و تکرار رمز عبور باید یکسان باشد")).toBeInTheDocument();
});
});
it('Should not see error when new password and confirm password match on blur event and submit click', async () => {
render(<MockAppWithProviders><ChangePasswordForm /></MockAppWithProviders>);
const newPasswordInput = screen.queryByLabelText('رمز عبور جدید');
const confirmPasswordInput = screen.queryByLabelText('تکرار رمز عبور جدید');
const submitButton = screen.getByRole('button', { name: 'ثبت' });
// Simulate entering a valid new password
fireEvent.change(newPasswordInput, { target: { value: 'Witel@fani1' } });
fireEvent.blur(newPasswordInput);
// Simulate entering the same value in the confirmation password field
fireEvent.change(confirmPasswordInput, { target: { value: 'Witel@fani1' } });
fireEvent.blur(confirmPasswordInput);
await waitFor(() => {
expect(screen.queryByText("پسورد و تکرار رمز عبور باید یکسان باشد")).not.toBeInTheDocument();
});
// Simulate clicking the submit button
fireEvent.click(submitButton);
await waitFor(() => {
expect(screen.queryByText("پسورد و تکرار رمز عبور باید یکسان باشد")).not.toBeInTheDocument();
});
});
});
describe("Form Submission", () => {
it('Should enable the submit button when the inputs are valid', async () => {
render(<MockAppWithProviders><ChangePasswordForm /></MockAppWithProviders>);
const submitButton = screen.getByRole('button', { name: 'ثبت' });
// Simulate entering valid values in the form fields
const currentPasswordInput = screen.queryByLabelText('رمز عبور فعلی');
const newPasswordInput = screen.queryByLabelText('رمز عبور جدید');
const confirmPasswordInput = screen.queryByLabelText('تکرار رمز عبور جدید');
fireEvent.change(currentPasswordInput, { target: { value: 'Witel@fani0' } });
fireEvent.change(newPasswordInput, { target: { value: 'Witel@fani1' } });
fireEvent.change(confirmPasswordInput, { target: { value: 'Witel@fani1' } });
// Check if the submit button is enabled
await waitFor(() => {
expect(submitButton).not.toBeDisabled();
});
});
it('Should request to api and resetform in success response', async () => {
// Render the component
render(<MockAppWithProviders><ChangePasswordForm /></MockAppWithProviders>);
// Fill in the form fields
const currentPasswordInput = screen.queryByLabelText('رمز عبور فعلی');
const newPasswordInput = screen.queryByLabelText('رمز عبور جدید');
const confirmPasswordInput = screen.queryByLabelText('تکرار رمز عبور جدید');
fireEvent.change(currentPasswordInput, { target: { value: 'Witel@fani0' } });
fireEvent.change(newPasswordInput, { target: { value: 'Witel@fani1' } });
fireEvent.change(confirmPasswordInput, { target: { value: 'Witel@fani1' } });
// Submit the form
const submitButton = screen.getByRole('button', { name: 'ثبت' });
await userEvent.click(submitButton);
await waitFor(() => {
expect(currentPasswordInput).toHaveValue('');
expect(newPasswordInput).toHaveValue('');
expect(confirmPasswordInput).toHaveValue('');
});
});
it('Should request to api and not resetform in error response', async () => {
// Render the component
render(<MockAppWithProviders><ChangePasswordForm /></MockAppWithProviders>);
server.use([rest.get(SET_USER_PASSWORD, (req, res, ctx) => {
return res(ctx.status(422))
})])
// Fill in the form fields wrong
const currentPasswordInput = screen.queryByLabelText('رمز عبور فعلی');
const newPasswordInput = screen.queryByLabelText('رمز عبور جدید');
const confirmPasswordInput = screen.queryByLabelText('تکرار رمز عبور جدید');
fireEvent.change(currentPasswordInput, { target: { value: 'incorrect' } });
fireEvent.change(newPasswordInput, { target: { value: 'Witel@fani1' } });
fireEvent.change(confirmPasswordInput, { target: { value: 'Witel@fani1' } });
// Submit the form
const submitButton = screen.getByRole('button', { name: 'ثبت' });
await userEvent.click(submitButton);
await waitFor(() => {
expect(currentPasswordInput.value).toBe('incorrect');
expect(newPasswordInput.value).toBe('Witel@fani1');
expect(confirmPasswordInput.value).toBe('Witel@fani1');
});
});
});
})

View File

@@ -1,137 +0,0 @@
import {Formik, Form} from "formik";
import * as Yup from "yup";
import {useTranslations} from "next-intl";
import {Button, Paper, Stack, Typography} from "@mui/material";
import PasswordField from "@/core/components/PasswordField";
import StyledForm from "@/core/components/StyledForm";
import useRequest from "@/lib/app/hooks/useRequest";
import {SET_USER_PASSWORD} from "@/core/data/apiRoutes";
const ChangePasswordForm = ({onSubmit}) => {
const t = useTranslations();
const requestServer = useRequest({auth: true})
const handleSubmit = (values, {setSubmitting, resetForm}) => {
requestServer(SET_USER_PASSWORD, 'post', {
data: {
current_password: values.current_password,
new_password: values.new_password,
new_password_confirmation: values.new_password_confirmation,
},
}).then((response) => {
resetForm();
}).catch(() => {
}).finally(() => {
setSubmitting(false);
});
};
const initialValues = {
current_password: "",
new_password: "",
new_password_confirmation: "",
};
const validationSchema = Yup.object().shape({
current_password: Yup.string().required(
t("ChangePassword.error_message_current_password_required")
),
new_password: Yup.string()
.min(8, t("ChangePassword.error_message_password_length"))
.required(t("ChangePassword.error_message_new_password_required")),
new_password_confirmation: Yup.string()
.required(t("ChangePassword.error_message_confirm_password_required"))
.test(
t("ChangePassword.error_message_password_match"),
t("ChangePassword.error_message_password_not_match"), // Use the correct error message here
function (value) {
return this.parent.new_password === value;
}
),
});
return (
<Formik
initialValues={initialValues}
onSubmit={handleSubmit}
validationSchema={validationSchema}
>
{(props) => (
<StyledForm
onSubmit={(e) => {
e.preventDefault();
props.handleSubmit();
}}
>
<Paper elevation={0}>
<Stack spacing={3} sx={{p: 5}} component="div">
<Typography margin={2} variant="h4" textAlign="center">
{t("ChangePassword.typography_change_password")}
</Typography>
<Stack spacing={1} component="div">
<PasswordField
name="current_password"
label={t("ChangePassword.label_current_password")}
error={
props.touched.current_password &&
props.errors.current_password
? true
: false
}
helperText={
props.touched.current_password
? props.errors.current_password
: null
}
/>
</Stack>
<Stack spacing={1} component="div">
<PasswordField
name="new_password"
label={t("ChangePassword.label_new_password")}
error={
props.touched.new_password && props.errors.new_password
? true
: false
}
helperText={
props.touched.new_password ? props.errors.new_password : null
}
/>
</Stack>
<Stack spacing={1} component="div">
<PasswordField
name="new_password_confirmation"
label={t("ChangePassword.label_confirm_password")}
error={
props.touched.new_password_confirmation &&
props.errors.new_password_confirmation
? true
: false
}
helperText={
props.touched.new_password_confirmation
? props.errors.new_password_confirmation
: null
}
/>
</Stack>
<Button
type="submit"
fullWidth
variant="contained"
color="primary"
size="large"
disabled={props.isSubmitting || !(props.values.current_password && props.values.new_password && props.values.new_password_confirmation)}
>
{props.isSubmitting
? t("SubmitButton.button_while_submit")
: t("SubmitButton.button_submit")}
</Button>
</Stack>
</Paper>
</StyledForm>
)}
</Formik>
);
};
export default ChangePasswordForm;

View File

@@ -1,15 +0,0 @@
import CenterLayout from "@/layouts/CenterLayout";
import {Container} from "@mui/material";
import ChangePasswordForm from "@/components/dashboard/change-password/change-password-form";
const DashboardChangePasswordComponent = () => {
return (
<CenterLayout>
<Container maxWidth="sm">
<ChangePasswordForm/>
</Container>
</CenterLayout>
);
};
export default DashboardChangePasswordComponent;

View File

@@ -1,195 +0,0 @@
import StyledForm from "@/core/components/StyledForm";
import CenterLayout from "@/layouts/CenterLayout";
import useUser from "@/lib/app/hooks/useUser";
import {Box, Container, Grid, Paper, Stack, TextField, Typography,} from "@mui/material";
import * as Yup from "yup";
import {Field, Formik} from "formik";
import {useTranslations} from "next-intl";
import AvatarUpload from "@/core/components/AvatarUpload";
import {UPDATE_AVATAR} from "@/core/data/apiRoutes";
import useDirection from "@/lib/app/hooks/useDirection";
import ImageResizer from "@/core/components/ImageConvertor";
import useRequest from "@/lib/app/hooks/useRequest";
const DashboardEditProfile = () => {
const t = useTranslations();
const requestServer = useRequest({auth: true})
const {user, token, getUser, changeUser} = useUser();
const {directionApp} = useDirection();
const editAvatar = async (avatar) => {
try {
const formData = new FormData();
if (avatar != null) {
var resizedAvatar;
resizedAvatar = await ImageResizer(avatar);
formData.append("avatar", resizedAvatar);
}
await requestServer(UPDATE_AVATAR, 'post', {formData}).then((response) => {
})
.catch(() => {
}).finally(() => {
});
} catch (error) {
throw error;
}
};
const handleSubmit = (values, {setSubmitting}) => {
};
const initialValues = {
expert_avatar: null,
username: user.username,
name: user.name,
email: user.email,
province_name: user.province_name,
position: user.position,
};
const validationSchema = Yup.object().shape({});
return (
<CenterLayout>
<Container maxWidth="sm">
<Formik
initialValues={initialValues}
onSubmit={handleSubmit}
validationSchema={validationSchema}
>
{(props) => (
<StyledForm
onSubmit={(e) => {
e.preventDefault();
props.handleSubmit();
}}
>
<Paper elevation={0}>
<Stack spacing={3} sx={{p: 5}} component="div">
<Typography margin={2} variant="h4" textAlign="center">
{t("UpdateProfile.typography_edit_profile")}
</Typography>
<Box
sx={{
display: "flex",
flexDirection: "column",
alignItems: "center",
justifyContent: "center",
}}
>
<AvatarUpload
user={user}
setFieldValue={props.setFieldValue}
valueAvatar="expert_avatar"
changeFlag="change_avatar"
/>
</Box>
<Grid container spacing={2} sx={{pb: 2}}>
<Grid item xs={12} sm={6}>
<Field
as={TextField}
name="username"
label={t("UpdateProfile.text_field_username")}
variant="outlined"
margin="normal"
size="small"
disabled={true}
error={!!(props.touched.username && props.errors.username)}
helperText={
props.touched.username
? props.errors.username
: null
}
sx={{
width: "100%",
}}
/>
</Grid>
<Grid item xs={12} sm={6}>
<Field
as={TextField}
name="name"
label={t("UpdateProfile.text_field_name")}
variant="outlined"
margin="normal"
size="small"
disabled={true}
error={!!(props.touched.name && props.errors.name)}
helperText={
props.touched.name ? props.errors.name : null
}
sx={{
width: "100%",
}}
/>
</Grid>
<Grid item xs={12} sm={6}>
<Field
as={TextField}
name="email"
label={t("UpdateProfile.text_field_email")}
variant="outlined"
margin="normal"
size="small"
disabled={true}
error={!!(props.touched.email && props.errors.email)}
helperText={
props.touched.email ? props.errors.email : null
}
sx={{
width: "100%",
}}
/>
</Grid>
<Grid item xs={12} sm={6}>
<Field
as={TextField}
name="province_name"
label={t("UpdateProfile.text_field_province_name")}
variant="outlined"
margin="normal"
size="small"
disabled={true}
error={!!(props.touched.province_name && props.errors.province_name)}
helperText={
props.touched.province_name
? props.errors.province_name
: null
}
sx={{
width: "100%",
}}
/>
</Grid>
<Grid item xs={12} sm={6}>
<Field
as={TextField}
name="position"
label={t("UpdateProfile.text_field_position")}
variant="outlined"
margin="normal"
size="small"
disabled={true}
error={!!(props.touched.position && props.errors.position)}
helperText={
props.touched.position
? props.errors.position
: null
}
sx={{
width: "100%",
}}
/>
</Grid>
</Grid>
</Stack>
</Paper>
</StyledForm>
)}
</Formik>
</Container>
</CenterLayout>
);
};
export default DashboardEditProfile;

View File

@@ -1,35 +0,0 @@
import {render, screen} from "@testing-library/react";
import MockAppWithProviders from "../../../../../../mocks/AppWithProvider";
import ExpertManagementDataTable from "@/components/dashboard/expert-management/DataTable";
describe("ExpertManagementDatatable Component From Expert Management", () => {
describe("Rendering", () => {
it("Table Headers Rendered", () => {
render(<MockAppWithProviders><ExpertManagementDataTable/></MockAppWithProviders>);
const idHeader = screen.queryByText("کد یکتا");
const nameHeader = screen.queryByText("نام کامل");
const usernameHeader = screen.queryByText("نام کاربری");
const emailHeader = screen.queryByText("پست الکترونیک");
const telephone_idHeader = screen.queryByText("کد تلفن");
const phone_numberHeader = screen.queryByText("شماره همراه");
const national_idHeader = screen.queryByText("کد ملی");
const positionHeader = screen.queryByText("سمت");
const province_nameHeader = screen.queryByText("استان");
const role_nameHeader = screen.queryByText("نقش");
const genderHeader = screen.queryByText("جنسیت");
const updated_atHeader = screen.queryByText("آخرین بروزرسانی");
expect(idHeader).toBeInTheDocument();
expect(nameHeader).toBeInTheDocument();
expect(usernameHeader).toBeInTheDocument();
expect(emailHeader).toBeInTheDocument();
expect(telephone_idHeader).toBeInTheDocument();
expect(phone_numberHeader).toBeInTheDocument();
expect(national_idHeader).toBeInTheDocument();
expect(positionHeader).toBeInTheDocument();
expect(province_nameHeader).toBeInTheDocument();
expect(role_nameHeader).toBeInTheDocument();
expect(genderHeader).toBeInTheDocument();
expect(updated_atHeader).toBeInTheDocument();
});
});
});

View File

@@ -1,202 +0,0 @@
import DataTable from "@/core/components/DataTable";
import MuiDatePicker from "@/core/components/MuiDatePicker";
import {GET_EXPERTS} from "@/core/data/apiRoutes";
import TableToolbar from "../TableToolbar";
import TableRowActions from "../TableRowActions";
import {Box, Typography} from "@mui/material";
import {useTranslations} from "next-intl";
import {useMemo} from "react";
import moment from "jalali-moment";
function ExpertManagementDataTable() {
const t = useTranslations();
const columns = useMemo(
() => [
{
accessorFn: (row) => row.id,
id: "id",
header: t("ExpertMangement.id"),
enableColumnFilter: true,
datatype: "numeric",
filterFn: "equals",
columnFilterModeOptions: [
"equals",
"notEquals",
"contains",
"lessThan",
"greaterThan",
"between",
],
Cell: ({renderedCellValue}) => (
<Typography variant="body2">{renderedCellValue}</Typography>
),
},
{
accessorFn: (row) => row.full_name,
id: "full_name",
header: t("ExpertMangement.name"),
enableColumnFilter: true,
datatype: "text",
filterFn: "contains",
columnFilterModeOptions: ["contains", "equals", "notEquals"],
Cell: ({renderedCellValue}) => (
<Typography variant="body2">{renderedCellValue}</Typography>
),
},
{
accessorFn: (row) => row.username,
id: "username",
header: t("ExpertMangement.username"),
enableColumnFilter: true,
datatype: "text",
filterFn: "contains",
columnFilterModeOptions: ["contains", "equals", "notEquals"],
Cell: ({renderedCellValue}) => (
<Typography variant="body2">{renderedCellValue}</Typography>
),
},
{
accessorFn: (row) => row.email,
id: "email",
header: t("ExpertMangement.email"),
enableColumnFilter: true,
datatype: "text",
filterFn: "contains",
columnFilterModeOptions: ["contains", "equals", "notEquals"],
Cell: ({renderedCellValue}) => (
<Typography variant="body2">{renderedCellValue}</Typography>
),
},
{
accessorFn: (row) => row.telephone_id,
id: "telephone_id",
header: t("ExpertMangement.telephone_id"),
enableColumnFilter: true,
datatype: "numeric",
filterFn: "equals",
columnFilterModeOptions: ["contains", "equals", "notEquals"],
Cell: ({renderedCellValue}) => (
<Typography variant="body2">{renderedCellValue}</Typography>
),
},
{
accessorFn: (row) => row.phone_number,
id: "phone_number",
header: t("ExpertMangement.phone_number"),
enableColumnFilter: true,
datatype: "numeric",
filterFn: "equals",
columnFilterModeOptions: ["contains", "equals", "notEquals"],
Cell: ({renderedCellValue}) => (
<Typography variant="body2">{renderedCellValue}</Typography>
),
},
{
accessorFn: (row) => row.national_id,
id: "national_id",
header: t("ExpertMangement.national_id"),
enableColumnFilter: true,
datatype: "numeric",
filterFn: "equals",
columnFilterModeOptions: ["contains", "equals", "notEquals"],
Cell: ({renderedCellValue}) => (
<Typography variant="body2">{renderedCellValue}</Typography>
),
},
{
accessorFn: (row) => row.position,
id: "position",
header: t("ExpertMangement.position"),
enableColumnFilter: true,
datatype: "text",
filterFn: "contains",
columnFilterModeOptions: ["contains", "equals", "notEquals"],
Cell: ({renderedCellValue}) => (
<Typography variant="body2">{renderedCellValue}</Typography>
),
},
{
accessorFn: (row) => row.province_fa,
id: "province_id",
header: t("ExpertMangement.province_fa"),
enableColumnFilter: false,
datatype: "text",
filterFn: "contains",
columnFilterModeOptions: ["contains", "equals", "notEquals"],
Cell: ({renderedCellValue}) => (
<Typography variant="body2">{renderedCellValue}</Typography>
),
},
{
accessorFn: (row) => row.roles[0]?.name_fa,
id: "roles[0].name_fa",
header: t("ExpertMangement.role_name"),
enableColumnFilter: false,
enableSorting: false,
datatype: "text",
filterFn: "contains",
columnFilterModeOptions: ["contains", "equals", "notEquals"],
Cell: ({renderedCellValue}) => (
<Typography variant="body2">{renderedCellValue}</Typography>
),
},
{
accessorFn: (row) => row.gender,
id: "gender",
header: t("ExpertMangement.gender"),
enableColumnFilter: false,
datatype: "text",
filterFn: "contains",
columnFilterModeOptions: ["contains", "equals", "notEquals"],
Cell: ({renderedCellValue}) => (
<Typography
variant="body2">{renderedCellValue === "male" ? t("ExpertMangement.male") : t("ExpertMangement.female")}</Typography>
),
},
{
accessorFn: (row) =>
moment(row.updated_at).locale("fa").format("HH:mm | yyyy/MM/DD"),
id: "updated_at",
header: t("ExpertMangement.updated_at"),
enableColumnFilter: true,
datatype: "date",
filterFn: "lessThan",
columnFilterModeOptions: ["lessThan", "greaterThan"],
Cell: ({renderedCellValue}) => {
return <Typography variant="body2">{renderedCellValue}</Typography>;
},
Header: ({column}) => <>{column.columnDef.header}</>,
Filter: ({column}) => {
return (
<MuiDatePicker column={column}/>
);
},
},
],
[]
);
return (
<Box sx={{px: 3}}>
<DataTable
tableUrl={GET_EXPERTS}
columns={columns}
selectableRow={false}
CustomToolbar={TableToolbar}
enableCustomToolbar={true}
enableLastUpdate={true}
enablePinning={true}
enableDensityToggle={false}
initialState={{density: 'compact'}} //compact (small) //comfortable (medium) //spacious (large)
enableColumnFilters={true}
enableHiding={true}
enableFullScreenToggle={false}
enableGlobalFilter={false}
enableColumnResizing={false} // if you want true this you should change renderRowActions props ** see https://www.material-react-table.com/docs/guides/row-actions
enableRowActions={true}
TableRowAction={TableRowActions}
/>
</Box>
);
}
export default ExpertManagementDataTable;

View File

@@ -1,7 +0,0 @@
const ChangePassword = () => {
return (
<></>
)
}
export default ChangePassword

View File

@@ -1,219 +0,0 @@
import {act, fireEvent, render, screen, waitFor} from "@testing-library/react";
import React from 'react';
import MockAppWithProviders from "../../../../../../../../../mocks/AppWithProvider";
import * as Yup from "yup";
import {Formik} from "formik";
import PersonalInfo from "@/components/dashboard/expert-management/Form/CreateForm/CreateContent/PersonalInfo";
import {useTranslations} from "next-intl";
import Province from "@/components/dashboard/expert-management/Form/CreateForm/CreateContent/RestInfo/Province";
const CreateFormMock = ({Component}) => {
const t = useTranslations();
const validationSchema = Yup.object().shape({
full_name: Yup.string().required(t("ExpertMangement.error_message_full_name")),
email: Yup.string().required(t("ExpertMangement.error_message_email")),
phone_number: Yup.string().required(t("ExpertMangement.error_message_phone_number")),
telephone_id: Yup.string().required(t("ExpertMangement.error_message_telephone_id")),
national_id: Yup.string().required(t("ExpertMangement.error_message_national_id")),
gender: Yup.string().required(t("ExpertMangement.error_message_gender"))
});
return (
<Formik
initialValues={{
full_name: "",
email: "",
phone_number: "",
telephone_id: "",
national_id: "",
gender: ""
}}
validationSchema={validationSchema}
onSubmit={(values, {}) => {
}}
>
{formikProps => (<Component formik={formikProps}></Component>)}
</Formik>
);
};
describe("PersonalInfo Component From Expert Management (create)", () => {
describe("Rendering", () => {
it("full_name TextField Rendered", async () => {
render(<MockAppWithProviders><CreateFormMock Component={PersonalInfo}/></MockAppWithProviders>);
await waitFor(() => {
const fullNameTextField = screen.queryByLabelText('نام کامل');
expect(fullNameTextField).toBeInTheDocument();
});
});
it("Email TextField Rendered", async () => {
render(<MockAppWithProviders><CreateFormMock Component={PersonalInfo}/></MockAppWithProviders>);
await waitFor(() => {
const emailTextField = screen.queryByLabelText('پست الکترونیک');
expect(emailTextField).toBeInTheDocument();
});
});
it("Phone Number TextField Rendered", async () => {
render(<MockAppWithProviders><CreateFormMock Component={PersonalInfo}/></MockAppWithProviders>);
await waitFor(() => {
const phoneNumberTextField = screen.queryByLabelText('شماره همراه');
expect(phoneNumberTextField).toBeInTheDocument();
});
});
it("telephone id TextField Rendered", async () => {
render(<MockAppWithProviders><CreateFormMock Component={PersonalInfo}/></MockAppWithProviders>);
await waitFor(() => {
const telephoneIdTextField = screen.queryByLabelText('کد تلفن');
expect(telephoneIdTextField).toBeInTheDocument();
});
});
it("National Id TextField Rendered", async () => {
render(<MockAppWithProviders><CreateFormMock Component={PersonalInfo}/></MockAppWithProviders>);
await waitFor(() => {
const nationalIdTextField = screen.queryByLabelText('کد ملی');
expect(nationalIdTextField).toBeInTheDocument();
});
});
it("Gender Select Box Rendered", async () => {
render(<MockAppWithProviders><CreateFormMock Component={PersonalInfo}/></MockAppWithProviders>);
await waitFor(() => {
const genderSelectBox = screen.getByTestId('select-box');
expect(genderSelectBox).toBeInTheDocument();
});
});
});
describe("Behavioral", () => {
it("Name TextField Work Correctly", async () => {
render(<MockAppWithProviders><CreateFormMock Component={PersonalInfo}/></MockAppWithProviders>);
const nameTextField = screen.queryByLabelText('نام کامل');
fireEvent.change(nameTextField, {target: {value: 'exampleName'}});
await act(() => {
expect(nameTextField).toHaveValue('exampleName');
})
});
it("Email TextField Work Correctly", async () => {
render(<MockAppWithProviders><CreateFormMock Component={PersonalInfo}/></MockAppWithProviders>);
const emailTextField = screen.queryByLabelText('پست الکترونیک');
fireEvent.change(emailTextField, {target: {value: 'exampleEmail'}});
await act(() => {
expect(emailTextField).toHaveValue('exampleEmail');
})
});
it("Phone Number TextField Work Correctly", async () => {
render(<MockAppWithProviders><CreateFormMock Component={PersonalInfo}/></MockAppWithProviders>);
const phoneNumberTextField = screen.queryByLabelText('شماره همراه');
fireEvent.change(phoneNumberTextField, {target: {value: 'examplePhoneNumber'}});
await act(() => {
expect(phoneNumberTextField).toHaveValue('examplePhoneNumber');
})
});
it("Telephone Id TextField Work Correctly", async () => {
render(<MockAppWithProviders><CreateFormMock Component={PersonalInfo}/></MockAppWithProviders>);
const telephoneIdTextField = screen.queryByLabelText('کد تلفن');
fireEvent.change(telephoneIdTextField, {target: {value: 'exampleTelephoneId'}});
await act(() => {
expect(telephoneIdTextField).toHaveValue('exampleTelephoneId');
})
});
it("National Id TextField Work Correctly", async () => {
render(<MockAppWithProviders><CreateFormMock Component={PersonalInfo}/></MockAppWithProviders>);
const nationalIdTextField = screen.queryByLabelText('کد ملی');
fireEvent.change(nationalIdTextField, {target: {value: 'exampleNationalId'}});
await act(() => {
expect(nationalIdTextField).toHaveValue('exampleNationalId');
})
});
it("Gender Select Box Work Correctly", async () => {
render(<MockAppWithProviders><CreateFormMock Component={PersonalInfo}/></MockAppWithProviders>);
const genderSelectBox = screen.getByTestId('select-box');
const genderSelectOpener = await waitFor(() => screen.getByTestId("option-opener-gender"));
await waitFor(() => {
expect(genderSelectBox).toBeInTheDocument();
});
fireEvent.mouseDown(genderSelectOpener);
await waitFor(() => {
const selectItem = screen.queryByText("مرد");
expect(selectItem).toBeInTheDocument();
});
});
});
describe("validation", () => {
it('Should See Error When Name Input Is Empty', async () => {
render(<MockAppWithProviders><CreateFormMock Component={PersonalInfo}/></MockAppWithProviders>);
const nameInput = screen.queryByLabelText('نام کامل');
fireEvent.change(nameInput, {target: {value: ''}});
fireEvent.blur(nameInput);
await waitFor(() => {
expect(screen.queryByText("نام کامل خود را وارد کنید")).toBeInTheDocument()
});
});
it('Should See Error When Email Input Is Empty', async () => {
render(<MockAppWithProviders><CreateFormMock Component={PersonalInfo}/></MockAppWithProviders>);
const emailInput = screen.queryByLabelText('پست الکترونیک');
fireEvent.change(emailInput, {target: {value: ''}});
fireEvent.blur(emailInput);
await waitFor(() => {
expect(screen.queryByText("پست الکترونیک خود را وارد کنید")).toBeInTheDocument()
});
});
it('Should See Error When Phone Number Input Is Empty', async () => {
render(<MockAppWithProviders><CreateFormMock Component={PersonalInfo}/></MockAppWithProviders>);
const phoneNumberInput = screen.queryByLabelText('شماره همراه');
fireEvent.change(phoneNumberInput, {target: {value: ''}});
fireEvent.blur(phoneNumberInput);
await waitFor(() => {
expect(screen.queryByText("شماره همراه خود را وارد کنید")).toBeInTheDocument()
});
});
it('Should See Error When telephone Id Input Is Empty', async () => {
render(<MockAppWithProviders><CreateFormMock Component={PersonalInfo}/></MockAppWithProviders>);
const telephoneIdTextField = screen.queryByLabelText('کد تلفن');
fireEvent.change(telephoneIdTextField, {target: {value: ''}});
fireEvent.blur(telephoneIdTextField);
await waitFor(() => {
expect(screen.queryByText("کد تلفن خود را وارد کنید")).toBeInTheDocument()
});
});
it('Should See Error When National Id Input Is Empty', async () => {
render(<MockAppWithProviders><CreateFormMock Component={PersonalInfo}/></MockAppWithProviders>);
const nationalIdInput = screen.queryByLabelText('کد ملی');
fireEvent.change(nationalIdInput, {target: {value: ''}});
fireEvent.blur(nationalIdInput);
await waitFor(() => {
expect(screen.queryByText("کد ملی خود را وارد کنید")).toBeInTheDocument()
});
});
it('Should Select An Item With Valid Value of gender', async () => {
render(<MockAppWithProviders><CreateFormMock Component={PersonalInfo}/></MockAppWithProviders>);
const genderInput = screen.getByTestId("input-gender")
const genderSelectOpener = await waitFor(() => screen.getByTestId("option-opener-gender"));
fireEvent.mouseDown(genderSelectOpener);
const selectItem = await waitFor(() => screen.queryByText("مرد"));
expect(selectItem).toBeInTheDocument();
fireEvent.click(selectItem);
await waitFor(() => {
expect(genderInput.value).toBe('male')
});
});
})
});

View File

@@ -1,128 +0,0 @@
import {FormControl, FormHelperText, Grid, InputLabel, MenuItem, Select, TextField} from "@mui/material";
import {useTranslations} from "next-intl";
const PersonalInfo = ({formik}) => {
const t = useTranslations();
const genderList = [
{id: 1, name_en: "male", name_fa: "مرد"},
{id: 2, name_en: "female", name_fa: "زن"}
]
return (
<Grid container justifyContent="space-around" spacing={2} sx={{pb: 2}}>
<Grid item xs={12} sm={6} md={4}>
<TextField
name="full_name"
label={t("ExpertMangement.text_field_full_name")}
variant="outlined"
margin="normal"
size="small"
value={formik.values.full_name}
onChange={formik.handleChange}
onBlur={formik.handleBlur}
error={formik.touched.full_name && !!formik.errors.full_name}
helperText={formik.touched.full_name && formik.errors.full_name ? formik.errors.full_name : null}
sx={{width: "100%"}}
/>
</Grid>
<Grid item xs={12} sm={6} md={4}>
<TextField
name="national_id"
label={t("ExpertMangement.text_field_national_id")}
variant="outlined"
margin="normal"
size="small"
value={formik.values.national_id}
onChange={formik.handleChange}
onBlur={formik.handleBlur}
error={formik.touched.national_id && !!formik.errors.national_id}
helperText={formik.touched.national_id && formik.errors.national_id ? formik.errors.national_id : null}
sx={{width: "100%"}}
/>
</Grid>
<Grid item xs={12} sm={6} md={4}>
<TextField
name="phone_number"
label={t("ExpertMangement.text_field_phone_number")}
variant="outlined"
margin="normal"
size="small"
value={formik.values.phone_number}
onChange={formik.handleChange}
onBlur={formik.handleBlur}
error={formik.touched.phone_number && !!formik.errors.phone_number}
helperText={formik.touched.phone_number && formik.errors.phone_number ? formik.errors.phone_number : null}
sx={{width: "100%"}}
/>
</Grid>
<Grid item xs={12} sm={6} md={4}>
<TextField
name="email"
label={t("ExpertMangement.text_field_email")}
variant="outlined"
margin="normal"
size="small"
value={formik.values.email}
onChange={formik.handleChange}
onBlur={formik.handleBlur}
error={formik.touched.email && !!formik.errors.email}
helperText={formik.touched.email && formik.errors.email ? formik.errors.email : null}
sx={{width: "100%"}}
/>
</Grid>
<Grid item xs={12} sm={6} md={4}>
<TextField
name="telephone_id"
label={t("ExpertMangement.text_field_telephone_id")}
variant="outlined"
margin="normal"
size="small"
value={formik.values.telephone_id}
onChange={formik.handleChange}
onBlur={formik.handleBlur}
error={formik.touched.telephone_id && !!formik.errors.telephone_id}
helperText={formik.touched.telephone_id && formik.errors.telephone_id ? formik.errors.telephone_id : null}
sx={{width: "100%"}}
/>
</Grid>
<Grid item xs={12} sm={6} md={4}>
<FormControl
error={formik.touched.gender && !!formik.errors.gender}
sx={{width: "100%", mt: 2}}
size="small"
>
<InputLabel>{t("ExpertMangement.text_field_gender")}</InputLabel>
<Select
name="gender"
label={t("ExpertMangement.text_field_gender")}
value={formik.values.gender}
onChange={(e) => {
formik.setFieldValue("gender", e.target.value);
}}
inputProps={{
"data-testid": "input-gender"
}}
data-testid="select-box"
SelectDisplayProps={{"data-testid": 'option-opener-gender'}}
onBlur={formik.handleBlur}
fullWidth
variant="outlined"
>
{(
genderList.map((item) => (
<MenuItem key={item.id} value={item.name_en}>
{item.name_fa}
</MenuItem>
))
)}
</Select>
<FormHelperText>
{formik.touched.gender && formik.errors.gender ? formik.errors.gender : ""}
</FormHelperText>
</FormControl>
</Grid>
</Grid>
)
}
export default PersonalInfo

View File

@@ -1,96 +0,0 @@
import {fireEvent, render, screen, waitFor} from "@testing-library/react";
import React from 'react';
import {useTranslations} from "next-intl";
import * as Yup from "yup";
import {Formik} from "formik";
import MockAppWithProviders from "../../../../../../../../../../mocks/AppWithProvider";
import PositionAndRole from "../../PositionAndRole";
const CreateFormMock = ({Component}) => {
const t = useTranslations();
const validationSchema = Yup.object().shape({
position: Yup.string().required(t("ExpertMangement.error_message_position")),
roles: Yup.string().required(t("ExpertMangement.error_message_roles"))
});
return (
<Formik
initialValues={{
position: "",
roles: ""
}}
validationSchema={validationSchema}
onSubmit={(values, {}) => {
}}
>
{formikProps => (<Component formik={formikProps}></Component>)}
</Formik>
);
};
describe("PositionAndRole Component From Expert Management (create)", () => {
describe("Rendering", () => {
it("Position TextField Rendered", async () => {
render(<MockAppWithProviders><CreateFormMock Component={PositionAndRole}/></MockAppWithProviders>);
await waitFor(() => {
const positionTextField = screen.queryByLabelText('سمت');
expect(positionTextField).toBeInTheDocument();
});
});
it("Role Select Box Rendered", async () => {
render(<MockAppWithProviders><CreateFormMock Component={PositionAndRole}/></MockAppWithProviders>);
const roleSelect = screen.getByTestId('select-box');
await waitFor(() => {
expect(roleSelect).toBeInTheDocument();
});
});
});
describe("Behavioral", () => {
it("Position TextField Work Correctly", async () => {
render(<MockAppWithProviders><CreateFormMock Component={PositionAndRole}/></MockAppWithProviders>);
const positionTextField = screen.queryByLabelText('سمت');
fireEvent.change(positionTextField, {target: {value: 'examplePosition'}});
await waitFor(() => {
expect(positionTextField).toHaveValue('examplePosition');
})
});
it("Role Select Box Work Correctly", async () => {
render(<MockAppWithProviders><CreateFormMock Component={PositionAndRole}/></MockAppWithProviders>);
const roleSelect = screen.getByTestId("option-opener-role");
await waitFor(() => {
expect(roleSelect).toBeInTheDocument();
});
fireEvent.mouseDown(roleSelect);
await waitFor(() => {
const selectItem = screen.queryByText("ادمین");
expect(selectItem).toBeInTheDocument();
});
});
});
describe("validation", () => {
it('Should See Error When Position Input Is Empty', async () => {
render(<MockAppWithProviders><CreateFormMock Component={PositionAndRole}/></MockAppWithProviders>);
const positionInput = screen.queryByLabelText('سمت');
fireEvent.change(positionInput, {target: {value: ''}});
fireEvent.blur(positionInput);
await waitFor(() => {
expect(screen.queryByText("سمت خود را وارد کنید")).toBeInTheDocument()
});
});
it('Should Select An Item With Valid Value of role', async () => {
render(<MockAppWithProviders><CreateFormMock Component={PositionAndRole}/></MockAppWithProviders>);
const roleInput = await waitFor(() => screen.getByTestId("input-role-id"));
const roleSelectOpener = await waitFor(() => screen.getByTestId("option-opener-role"));
fireEvent.mouseDown(roleSelectOpener);
const selectItem = await waitFor(() => screen.queryByText("ادمین"));
expect(selectItem).toBeInTheDocument();
fireEvent.click(selectItem);
await waitFor(() => {
expect(roleInput.value).toBe('1')
});
});
})
});

View File

@@ -1,74 +0,0 @@
import {FormControl, FormHelperText, Grid, InputLabel, MenuItem, Select, TextField} from "@mui/material";
import {useTranslations} from "next-intl";
import useRequest from "@/lib/app/hooks/useRequest";
import useRole from "@/lib/app/hooks/useRole";
import {log} from "next/dist/server/typescript/utils";
const PositionAndRole = ({formik}) => {
const t = useTranslations();
const requestServer = useRequest()
const {roleList, isLoadingRoleList, errorRoleList} = useRole();
return (
<Grid container justifyContent="space-around" spacing={2} sx={{pb: 2}}>
<Grid item xs={12} sm={6}>
<TextField
name="position"
label={t("ExpertMangement.text_field_position")}
variant="outlined"
margin="normal"
size="small"
value={formik.values.position}
onChange={formik.handleChange}
onBlur={formik.handleBlur}
error={formik.touched.position && !!formik.errors.position}
helperText={formik.touched.position && formik.errors.position ? formik.errors.position : null}
sx={{width: "100%"}}
/>
</Grid>
<Grid item xs={12} sm={6}>
<FormControl
error={formik.touched.roles && !!formik.errors.roles}
sx={{width: "100%", mt: 2}}
size="small"
>
<InputLabel>{t("ExpertMangement.text_field_roles")}</InputLabel>
<Select
name="roles"
label={t("ExpertMangement.text_field_roles")}
value={formik.values.roles}
onChange={formik.handleChange}
onBlur={formik.handleBlur}
fullWidth
inputProps={{
"data-testid": "input-role-id"
}}
data-testid="select-box"
SelectDisplayProps={{"data-testid": 'option-opener-role'}}
variant="outlined"
>
{isLoadingRoleList ? (
<MenuItem>
{t("ExpertMangement.text_field_loading_roles_list")}
</MenuItem>
) : errorRoleList ? (
<MenuItem>
{t("ExpertMangement.text_field_error_fetching_roles")}
</MenuItem>
) : (
roleList.map((item) => (
<MenuItem key={item.id} value={item.id}>
{item.name_fa}
</MenuItem>
))
)}
</Select>
<FormHelperText>
{formik.touched.roles && formik.errors.roles ? formik.errors.roles : ""}
</FormHelperText>
</FormControl>
</Grid>
</Grid>
)
}
export default PositionAndRole

View File

@@ -1,71 +0,0 @@
import {fireEvent, render, screen, waitFor} from "@testing-library/react";
import React from 'react';
import {useTranslations} from "next-intl";
import * as Yup from "yup";
import {Formik} from "formik";
import Province from "../../Province";
import MockAppWithProviders from "../../../../../../../../../../mocks/AppWithProvider";
const CreateFormMock = ({Component}) => {
const t = useTranslations();
const validationSchema = Yup.object().shape({
province_id: Yup.string().required(t("ExpertMangement.error_message_province_id")),
});
return (
<Formik
initialValues={{
province_id: "",
}}
validationSchema={validationSchema}
onSubmit={(values, {}) => {
}}
>
{formikProps => (<Component formik={formikProps}></Component>)}
</Formik>
);
};
describe("Province Component From Expert Management (create)", () => {
describe("Rendering", () => {
it("Province Select Box Rendered", async () => {
render(<MockAppWithProviders><CreateFormMock Component={Province}/></MockAppWithProviders>);
await waitFor(() => {
const provinceSelectBox = screen.getByTestId('select-box');
expect(provinceSelectBox).toBeInTheDocument();
});
});
});
describe("Behavioral", () => {
it("Province Select Box Work Correctly", async () => {
render(<MockAppWithProviders><CreateFormMock Component={Province}/></MockAppWithProviders>);
const provinceSelectBox = screen.getByTestId('select-box');
const provinceSelectOpener = await waitFor(() => screen.getByTestId("option-opener-province"));
await waitFor(() => {
expect(provinceSelectBox).toBeInTheDocument();
});
fireEvent.mouseDown(provinceSelectOpener);
await waitFor(() => {
const selectItem = screen.queryByText("آذربایجان شرقی");
expect(selectItem).toBeInTheDocument();
});
});
});
describe("validation", () => {
it('Should Select An Item With Valid Value of province', async () => {
render(<MockAppWithProviders><CreateFormMock Component={Province}/></MockAppWithProviders>);
const provinceInput = screen.getByTestId("input-province-id")
const provinceSelectOpener = await waitFor(() => screen.getByTestId("option-opener-province"));
fireEvent.mouseDown(provinceSelectOpener);
const selectItem = await waitFor(() => screen.queryByText("آذربایجان شرقی"));
expect(selectItem).toBeInTheDocument();
fireEvent.click(selectItem);
await waitFor(() => {
expect(provinceInput.value).toBe('1')
});
});
})
});

View File

@@ -1,61 +0,0 @@
import {FormControl, FormHelperText, Grid, InputLabel, MenuItem, Select} from "@mui/material";
import {useTranslations} from "next-intl";
import useProvince from "@/lib/app/hooks/useProvince";
import useRequest from "@/lib/app/hooks/useRequest";
const Province = ({formik}) => {
const t = useTranslations();
const requestServer = useRequest()
const {provinceList, isLoadingProvinceList, errorProvinceList} = useProvince();
return (
<Grid container justifyContent="space-around" spacing={2} sx={{pb: 2}}>
<Grid item xs={12} sm={6}>
<FormControl
error={formik.touched.province_id && !!formik.errors.province_id}
sx={{width: "100%", mt: 2}}
size="small"
>
<InputLabel>{t("ExpertMangement.text_field_province_id")}</InputLabel>
<Select
name="province_id"
disabled={isLoadingProvinceList || errorProvinceList}
label={t("ExpertMangement.text_field_province_id")}
value={formik.values.province_id}
onChange={(e) => {
formik.setFieldValue("province_id", e.target.value);
}}
inputProps={{
"data-testid": "input-province-id"
}}
data-testid="select-box"
SelectDisplayProps={{"data-testid": 'option-opener-province'}}
onBlur={formik.handleBlur}
fullWidth
variant="outlined"
>
{isLoadingProvinceList ? (
<MenuItem>
{t("ExpertMangement.text_field_loading_provinces_list")}
</MenuItem>
) : errorProvinceList ? (
<MenuItem>
{t("ExpertMangement.text_field_error_fetching_provinces")}
</MenuItem>
) : (
provinceList.map((item) => (
<MenuItem key={item.id} value={item.id}>
{item.name}
</MenuItem>
))
)}
</Select>
<FormHelperText>
{formik.touched.province_id && formik.errors.province_id ? formik.errors.province_id : ""}
</FormHelperText>
</FormControl>
</Grid>
</Grid>
)
}
export default Province

View File

@@ -1,12 +0,0 @@
import Province from "./Province";
import PositionAndRole from "./PositionAndRole";
const RestInfo = ({formik}) => {
return (
<>
<Province formik={formik}/>
<PositionAndRole formik={formik}/>
</>
)
}
export default RestInfo

View File

@@ -1,123 +0,0 @@
import {act, fireEvent, render, screen, waitFor} from "@testing-library/react";
import React from 'react';
import MockAppWithProviders from "../../../../../../../../../mocks/AppWithProvider";
import {useTranslations} from "next-intl";
import * as Yup from "yup";
import {Formik} from "formik";
import UserInfo from "../../UserInfo";
const CreateFormMock = ({Component}) => {
const t = useTranslations();
const validationSchema = Yup.object().shape({
username: Yup.string().required(t("ExpertMangement.error_message_username")),
password: Yup.string()
.required(t("ExpertMangement.error_message_password"))
.matches(
/^(?=.*[a-zA-Z])(?=.*\d).{8,}$/,
t("ExpertMangement.error_message_password_regex")
),
});
return (
<Formik
initialValues={{
username: "",
password: "",
}}
validationSchema={validationSchema}
onSubmit={(values, {}) => {
}}
>
{formikProps => (<Component formik={formikProps}></Component>)}
</Formik>
);
};
describe("UserInfo Component From Expert Management (create)", () => {
describe("Rendering", () => {
it("UserName TextField Rendered", async () => {
render(<MockAppWithProviders><CreateFormMock Component={UserInfo}/></MockAppWithProviders>);
await waitFor(() => {
const usernameTextField = screen.queryByLabelText('نام کاربری');
expect(usernameTextField).toBeInTheDocument();
});
});
it("Password TextField Rendered", async () => {
render(<MockAppWithProviders><CreateFormMock Component={UserInfo}/></MockAppWithProviders>);
await waitFor(() => {
const passwordTextField = screen.queryByLabelText('رمز عبور');
expect(passwordTextField).toBeInTheDocument();
});
});
});
describe("Behavioral", () => {
it("Username TextField Work Correctly", async () => {
render(<MockAppWithProviders><CreateFormMock Component={UserInfo}/></MockAppWithProviders>);
const usernameTextField = screen.queryByLabelText('نام کاربری');
fireEvent.change(usernameTextField, {target: {value: 'exampleUsername'}});
await act(() => {
expect(usernameTextField).toHaveValue('exampleUsername');
})
});
it("Password TextField Work Correctly", async () => {
render(<MockAppWithProviders><CreateFormMock Component={UserInfo}/></MockAppWithProviders>);
const passwordTextField = screen.queryByLabelText('رمز عبور');
fireEvent.change(passwordTextField, {target: {value: 'examplePassword'}});
await act(() => {
expect(passwordTextField).toHaveValue('examplePassword');
})
});
});
describe("validation", () => {
it('Should See Error When Username Input Is Empty', async () => {
render(<MockAppWithProviders><CreateFormMock Component={UserInfo}/></MockAppWithProviders>);
const usernameInput = screen.queryByLabelText('نام کاربری');
fireEvent.change(usernameInput, {target: {value: ''}});
fireEvent.blur(usernameInput);
await waitFor(() => {
expect(screen.queryByText("نام کاربری خود را وارد کنید")).toBeInTheDocument()
});
});
it('Should See Error When Password Input Is Empty', async () => {
render(<MockAppWithProviders><CreateFormMock Component={UserInfo}/></MockAppWithProviders>);
const passwordInput = screen.queryByLabelText('رمز عبور');
fireEvent.change(passwordInput, {target: {value: ''}});
fireEvent.blur(passwordInput);
await waitFor(() => {
expect(screen.queryByText("رمز عبور خود را وارد کنید")).toBeInTheDocument()
});
});
it('Should See Error When Password Field Is Not On Correct Format', async () => {
render(<MockAppWithProviders><CreateFormMock Component={UserInfo}/></MockAppWithProviders>);
const passwordInput = screen.queryByLabelText('رمز عبور');
// check without text or symbol
fireEvent.change(passwordInput, {target: {value: '12345678'}});
fireEvent.blur(passwordInput);
await waitFor(() => {
expect(screen.queryByText("رمز عبور باید حداقل 8 کاراکتر و متشکل از عدد، حرف یا سمبل باشد")).toBeInTheDocument()
});
// check without number
fireEvent.change(passwordInput, {target: {value: 'abcdefgh'}});
fireEvent.blur(passwordInput);
await waitFor(() => {
expect(screen.queryByText("رمز عبور باید حداقل 8 کاراکتر و متشکل از عدد، حرف یا سمبل باشد")).toBeInTheDocument()
});
// check under 8 character
fireEvent.change(passwordInput, {target: {value: '11Sa'}});
fireEvent.blur(passwordInput);
await waitFor(() => {
expect(screen.queryByText("رمز عبور باید حداقل 8 کاراکتر و متشکل از عدد، حرف یا سمبل باشد")).toBeInTheDocument()
});
});
})
});

View File

@@ -1,61 +0,0 @@
import {Grid, IconButton, InputAdornment, TextField} from "@mui/material";
import {useTranslations} from "next-intl";
import {Visibility, VisibilityOff} from "@mui/icons-material";
import {useState} from "react";
const UserInfo = ({formik}) => {
const t = useTranslations();
const [showPassword, setShowPassword] = useState(false);
const handleClickShowPassword = () => {
setShowPassword(!showPassword);
};
return (
<>
<Grid container justifyContent="space-around" spacing={2} sx={{pb: 2}}>
<Grid item xs={12} sm={6}>
<TextField
name="username"
label={t("ExpertMangement.text_field_username")}
variant="outlined"
margin="normal"
size="small"
value={formik.values.username}
onChange={formik.handleChange}
onBlur={formik.handleBlur}
error={formik.touched.username && !!formik.errors.username}
helperText={formik.touched.username && formik.errors.username ? formik.errors.username : null}
sx={{width: "100%"}}
/>
</Grid>
<Grid item xs={12} sm={6}>
<TextField
name="password"
label={t("ExpertMangement.text_field_password")}
variant="outlined"
margin="normal"
size="small"
value={formik.values.password}
onChange={formik.handleChange}
onBlur={formik.handleBlur}
error={formik.touched.password && !!formik.errors.password}
helperText={formik.touched.password && formik.errors.password ? formik.errors.password : null}
type={showPassword ? "text" : "password"}
InputProps={{
endAdornment: (
<InputAdornment position="end">
<IconButton onClick={handleClickShowPassword}>
{showPassword ? <Visibility/> : <VisibilityOff/>}
</IconButton>
</InputAdornment>
),
}}
sx={{width: "100%"}}
/>
</Grid>
</Grid>
</>
)
}
export default UserInfo

View File

@@ -1,67 +0,0 @@
import {fireEvent, render, screen, waitFor} from "@testing-library/react";
import React from 'react';
import CreateContent from "../../CreateContent";
import MockAppWithProviders from "../../../../../../../../mocks/AppWithProvider";
function selectDropdownItem(screen, openerTestId, itemText) {
const opener = screen.getByTestId(openerTestId);
fireEvent.mouseDown(opener);
const selectItem = screen.queryByText(itemText);
fireEvent.click(selectItem);
}
function setInputValue(screen, inputElement, value) {
fireEvent.change(inputElement, {target: {value}});
}
describe("CreateContent Component From Expert Management (create)", () => {
describe("Rendering", () => {
it("close button Rendered", async () => {
render(<MockAppWithProviders><CreateContent/></MockAppWithProviders>);
await waitFor(() => {
const cancelBtn = screen.queryByText('بستن');
expect(cancelBtn).toBeInTheDocument();
});
});
it("confirm button Rendered", async () => {
render(<MockAppWithProviders><CreateContent/></MockAppWithProviders>);
await waitFor(() => {
const cancelBtn = screen.queryByText('ثبت');
expect(cancelBtn).toBeInTheDocument();
});
});
});
describe("Form Submission", () => {
it('Should enable the submit button when the inputs are valid', async () => {
render(<MockAppWithProviders><CreateContent/></MockAppWithProviders>);
const submitButton = screen.queryByText('ثبت');
const nameInput = screen.queryByLabelText('نام کامل');
const usernameInput = screen.queryByLabelText('نام کاربری');
const emailInput = screen.queryByLabelText('پست الکترونیک');
const phoneNumberInput = screen.queryByLabelText('شماره همراه');
const telephoneIdInput = screen.queryByLabelText('کد تلفن');
const nationalIdInput = screen.queryByLabelText('کد ملی');
const passwordInput = screen.queryByLabelText('رمز عبور');
const positionInput = screen.queryByLabelText('سمت');
selectDropdownItem(screen, "option-opener-province", "آذربایجان شرقی");
selectDropdownItem(screen, "option-opener-role", "ادمین");
selectDropdownItem(screen, "option-opener-gender", "مرد");
setInputValue(screen, nameInput, 'nameTest');
setInputValue(screen, usernameInput, 'usernameTest');
setInputValue(screen, emailInput, 'emailTest');
setInputValue(screen, phoneNumberInput, 'phoneNumberTest');
setInputValue(screen, telephoneIdInput, 'telephoneIdTest');
setInputValue(screen, nationalIdInput, 'nationalIdTest');
setInputValue(screen, passwordInput, 'passwordTest');
setInputValue(screen, positionInput, 'positionTest');
await waitFor(() => {
expect(submitButton).not.toBeDisabled();
});
});
})
});

View File

@@ -1,116 +0,0 @@
import {Box, Button, Chip, DialogActions, DialogContent, Divider,} from "@mui/material";
import * as Yup from "yup";
import {useTranslations} from "next-intl";
import {useFormik} from "formik";
import useRequest from "@/lib/app/hooks/useRequest";
import {ADD_EXPERT} from "@/core/data/apiRoutes";
import PersonalInfo from "@/components/dashboard/expert-management/Form/CreateForm/CreateContent/PersonalInfo";
import UserInfo from "@/components/dashboard/expert-management/Form/CreateForm/CreateContent/UserInfo";
import RestInfo from "@/components/dashboard/expert-management/Form/CreateForm/CreateContent/RestInfo";
const CreateContent = ({setOpenCreateDialog, mutate}) => {
const t = useTranslations();
const requestServer = useRequest()
const validationSchema = Yup.object().shape({
full_name: Yup.string().required(t("ExpertMangement.error_message_full_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")),
telephone_id: Yup.string().required(t("ExpertMangement.error_message_telephone_id")),
gender: Yup.string().required(t("ExpertMangement.error_message_gender")),
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")),
roles: Yup.string().required(t("ExpertMangement.error_message_roles"))
});
const formik = useFormik({
initialValues: {
full_name: "",
username: "",
email: "",
phone_number: "",
telephone_id: "",
gender: "",
national_id: "",
password: "",
position: "",
province_id: "",
roles: ""
},
validationSchema,
onSubmit: (values, {setSubmitting}) => {
const formData = new FormData();
formData.append("full_name", values.full_name);
formData.append("national_id", values.national_id);
formData.append("phone_number", values.phone_number);
formData.append("telephone_id", values.telephone_id);
formData.append("gender", values.gender);
formData.append("email", values.email);
formData.append("username", values.username);
formData.append("password", values.password);
formData.append("province_id", values.province_id);
formData.append("position", values.position);
formData.append("roles", values.roles);
requestServer(`${ADD_EXPERT}`, 'post', {auth: true, data: formData})
.then((response) => {
setOpenCreateDialog(false)
mutate()
}).catch(() => {
}).finally(() => {
setSubmitting(false);
});
},
});
return (
<>
<DialogContent>
<Box sx={{my: 1}}>
<Divider>
<Chip
label={t("ExpertMangement.personal_info")}
/>
</Divider>
</Box>
<PersonalInfo formik={formik}/>
<Box sx={{my: 1}}>
<Divider>
<Chip
label={t("ExpertMangement.user_info")}
/>
</Divider>
</Box>
<UserInfo formik={formik}/>
<Box sx={{my: 1}}>
<Divider>
<Chip
label={t("ExpertMangement.rest_info")}
/>
</Divider>
</Box>
<RestInfo formik={formik}/>
</DialogContent>
<DialogActions>
<Button onClick={() => setOpenCreateDialog(false)} variant="outlined" color="secondary"
disabled={formik.isSubmitting} autoFocus>
{t("ExpertMangement.button_cancel")}
</Button>
<Button onClick={formik.handleSubmit} variant="contained" color="primary"
disabled={formik.isSubmitting || !formik.isValid || !formik.dirty}>
{t("ExpertMangement.button_confirm")}
</Button>
</DialogActions>
</>
)
}
export default CreateContent

View File

@@ -1,131 +0,0 @@
import {act, fireEvent, render, screen, waitFor} from "@testing-library/react";
import React from 'react';
import MockAppWithProviders from "../../../../../../../mocks/AppWithProvider";
import CreateForm from "../../CreateForm";
function selectDropdownItem(screen, openerTestId, itemText) {
const opener = screen.getByTestId(openerTestId);
fireEvent.mouseDown(opener);
const selectItem = screen.queryByText(itemText);
fireEvent.click(selectItem);
}
function setInputValue(screen, inputElement, value) {
fireEvent.change(inputElement, {target: {value}});
}
describe("CreateForm Component From Expert Management", () => {
describe("Rendering", () => {
it("Create Button Rendered", () => {
render(<MockAppWithProviders><CreateForm/></MockAppWithProviders>);
const CreateButton = screen.getByRole('button', {name: "افزودن"});
expect(CreateButton).toBeInTheDocument();
});
it("Dialog Header Rendered", () => {
render(<MockAppWithProviders><CreateForm/></MockAppWithProviders>);
const CreateDialogHeader = screen.queryByText("افزودن");
expect(CreateDialogHeader).toBeInTheDocument();
});
});
describe("Behavioral", () => {
it("by Clicking Create Button Dialog Should Append To Document", async () => {
render(<MockAppWithProviders><CreateForm/></MockAppWithProviders>);
const CreateButton = screen.getByRole('button', {name: "افزودن"});
fireEvent.click(CreateButton);
await act(() => {
const CreateDialog = screen.getByRole('dialog', {name: "افزودن"})
expect(CreateDialog).toBeInTheDocument();
});
});
});
describe("Form Submission", () => {
it('Should request to api and if get success close dialog', async () => {
render(<MockAppWithProviders><CreateForm/></MockAppWithProviders>);
const CreateButton = screen.getByRole('button', {name: "افزودن"});
fireEvent.click(CreateButton);
const submitButton = screen.queryByText('ثبت');
const nameInput = screen.queryByLabelText('نام کامل');
const usernameInput = screen.queryByLabelText('نام کاربری');
const emailInput = screen.queryByLabelText('پست الکترونیک');
const phoneNumberInput = screen.queryByLabelText('شماره همراه');
const telephoneIdInput = screen.queryByLabelText('کد تلفن');
const nationalIdInput = screen.queryByLabelText('کد ملی');
const passwordInput = screen.queryByLabelText('رمز عبور');
const positionInput = screen.queryByLabelText('سمت');
selectDropdownItem(screen, "option-opener-province", "آذربایجان شرقی");
selectDropdownItem(screen, "option-opener-role", "ادمین");
selectDropdownItem(screen, "option-opener-gender", "مرد");
setInputValue(screen, nameInput, 'nameTest');
setInputValue(screen, usernameInput, 'usernameTest');
setInputValue(screen, emailInput, 'emailTest@gmail.com');
setInputValue(screen, phoneNumberInput, '0914577458');
setInputValue(screen, telephoneIdInput, '091');
setInputValue(screen, nationalIdInput, 'nationalIdTest');
setInputValue(screen, passwordInput, 'passwordTest12');
setInputValue(screen, positionInput, 'positionTest');
expect(submitButton).not.toBeDisabled();
fireEvent.click(submitButton);
await waitFor(() => {
const dialogContent = screen.queryByTestId('create-dialog-content');
expect(dialogContent).not.toBeInTheDocument();
});
});
it('Should request to api and if get error keep previous data', async () => {
render(<MockAppWithProviders><CreateForm/></MockAppWithProviders>);
const CreateButton = screen.getByRole('button', {name: "افزودن"});
fireEvent.click(CreateButton);
const submitButton = screen.queryByText('ثبت');
const nameInput = screen.queryByLabelText('نام کامل');
const usernameInput = screen.queryByLabelText('نام کاربری');
const emailInput = screen.queryByLabelText('پست الکترونیک');
const phoneNumberInput = screen.queryByLabelText('شماره همراه');
const telephoneIdInput = screen.queryByLabelText('کد تلفن');
const nationalIdInput = screen.queryByLabelText('کد ملی');
const passwordInput = screen.queryByLabelText('رمز عبور');
const positionInput = screen.queryByLabelText('سمت');
const provinceInput = screen.getByTestId("input-province-id")
const roleInput = screen.getByTestId("input-role-id")
const genderInput = screen.getByTestId("input-gender")
selectDropdownItem(screen, "option-opener-province", "آذربایجان شرقی");
selectDropdownItem(screen, "option-opener-role", "ادمین");
selectDropdownItem(screen, "option-opener-gender", "مرد");
setInputValue(screen, nameInput, 'nameTest');
setInputValue(screen, usernameInput, 'usernameTest');
setInputValue(screen, emailInput, 'emailTest@gmail.com');
setInputValue(screen, phoneNumberInput, '0914577458');
setInputValue(screen, telephoneIdInput, '091');
setInputValue(screen, nationalIdInput, 'nationalIdTest');
setInputValue(screen, passwordInput, 'passwordTest12');
setInputValue(screen, positionInput, 'positionTest');
expect(submitButton).not.toBeDisabled();
await fireEvent.click(submitButton);
await waitFor(() => {
expect(nameInput).toHaveValue('nameTest');
expect(usernameInput).toHaveValue('usernameTest');
expect(emailInput).toHaveValue('emailTest@gmail.com');
expect(phoneNumberInput).toHaveValue('0914577458');
expect(telephoneIdInput).toHaveValue('091');
expect(nationalIdInput).toHaveValue('nationalIdTest');
expect(passwordInput).toHaveValue('passwordTest12');
expect(positionInput).toHaveValue('positionTest');
expect(provinceInput).toHaveValue('1');
expect(roleInput).toHaveValue('1');
expect(genderInput).toHaveValue('male');
});
});
})
});

View File

@@ -1,39 +0,0 @@
import {Button, Dialog, DialogTitle, Stack, Tooltip} from "@mui/material";
import {useTranslations} from "next-intl";
import DataSaverOnIcon from "@mui/icons-material/DataSaverOn";
import {useState} from "react";
import CreateContent from "./CreateContent";
const Create = ({mutate}) => {
const t = useTranslations();
const [openCreateDialog, setOpenCreateDialog] = useState(false);
return (
<>
<Stack direction={"row"} spacing={2}>
<Tooltip title={t("ExpertMangement.create")} arrow placement="right">
<Button
color="primary"
variant="contained"
size="small"
sx={{textTransform: "unset", alignSelf: "center"}}
startIcon={<DataSaverOnIcon/>}
onClick={() => {
setOpenCreateDialog(true)
}}
>
{t("ExpertMangement.create")}
</Button>
</Tooltip>
</Stack>
<Dialog data-testid="create-dialog-content" fullWidth maxWidth={'lg'} open={openCreateDialog}
TransitionProps={{unmountOnExit: true}}
PaperProps={{sx: {boxShadow: 'rgba(60, 64, 67, 0.3) 0px 1px 16px 0px, rgba(60, 64, 67, 0.15) 0px 1px 10px 0px'}}}>
<DialogTitle>{t("ExpertMangement.create")}</DialogTitle>
<CreateContent setOpenCreateDialog={setOpenCreateDialog} mutate={mutate}/>
</Dialog>
</>
)
}
export default Create

View File

@@ -1,66 +0,0 @@
import {fireEvent, render, screen, waitFor} from "@testing-library/react";
import MockAppWithProviders from "../../../../../../../mocks/AppWithProvider";
import React from "react";
import DeleteForm from "@/components/dashboard/expert-management/Form/DeleteForm";
describe("CreateForm Component From Expert Management", () => {
describe("Rendering", () => {
it("Delete Expert Button And Tooltip Rendered", () => {
render(<MockAppWithProviders><DeleteForm/></MockAppWithProviders>);
const DeleteButton = screen.getByTestId('delete-button');
expect(DeleteButton).toBeInTheDocument();
});
it("Delete Dialog Rendered", () => {
render(<MockAppWithProviders><DeleteForm/></MockAppWithProviders>);
const DeleteButton = screen.getByTestId('delete-button');
fireEvent.click(DeleteButton);
const DeleteDialogHeader = screen.queryByText("حذف کارشناس");
expect(DeleteDialogHeader).toBeInTheDocument();
});
it("Delete Dialog Text Rendered", () => {
render(<MockAppWithProviders><DeleteForm/></MockAppWithProviders>);
const DeleteButton = screen.getByTestId('delete-button');
fireEvent.click(DeleteButton);
const DeleteDialogText = screen.queryByText("آیا از انجام این عملیات اطمینان دارید؟");
expect(DeleteDialogText).toBeInTheDocument();
});
it("Delete Dialog Delete Button Rendered", () => {
render(<MockAppWithProviders><DeleteForm/></MockAppWithProviders>);
const DeleteButton = screen.getByTestId('delete-button');
fireEvent.click(DeleteButton);
const DeleteButtonDialog = screen.getByRole('button', {name: "حذف"});
expect(DeleteButtonDialog).toBeInTheDocument();
});
it("Delete Dialog Cancel Button Rendered", () => {
render(<MockAppWithProviders><DeleteForm/></MockAppWithProviders>);
const DeleteButton = screen.getByTestId('delete-button');
fireEvent.click(DeleteButton);
const CancelButtonDialog = screen.getByRole('button', {name: "بستن"});
expect(CancelButtonDialog).toBeInTheDocument();
});
});
describe("Behavioral", () => {
it("By Clicking Delete Button Dialog Should Append To Document", async () => {
render(<MockAppWithProviders><DeleteForm/></MockAppWithProviders>);
const DeleteButton = screen.getByTestId('delete-button');
fireEvent.click(DeleteButton);
await waitFor(() => {
const DeleteDialog = screen.getByRole('dialog', {name: "حذف کارشناس"})
expect(DeleteDialog).toBeInTheDocument();
});
});
});
describe("Form Submission", () => {
it("By Clicking Delete Button Request To Api And Delete Item", async () => {
render(<MockAppWithProviders><DeleteForm rowId={1}/></MockAppWithProviders>);
const DeleteButton = screen.getByTestId('delete-button');
fireEvent.click(DeleteButton);
const DeleteButtonDialog = screen.getByRole('button', {name: "حذف"});
fireEvent.click(DeleteButtonDialog);
await waitFor(() => {
const DeleteDialog = screen.queryByRole('dialog', {name: "حذف کارشناس"});
expect(DeleteDialog).not.toBeInTheDocument();
});
});
});
});

View File

@@ -1,74 +0,0 @@
import {
Button,
Dialog,
DialogActions,
DialogContent,
DialogContentText,
DialogTitle,
IconButton,
Tooltip
} from "@mui/material";
import DeleteIcon from '@mui/icons-material/Delete';
import {useState} from "react";
import {DELETE_EXPERT} from "@/core/data/apiRoutes";
import useRequest from "@/lib/app/hooks/useRequest";
import {useTranslations} from "next-intl";
const Delete = ({rowId, mutate}) => {
const t = useTranslations();
const requestServer = useRequest({auth: true});
const [openDeleteDialog, setOpenDeleteDialog] = useState(false);
const [isSubmitting, setIsSubmitting] = useState(false);
const handleDelete = () => {
setIsSubmitting(true)
requestServer(`${DELETE_EXPERT}/${rowId}`, 'DELETE')
.then((response) => {
setOpenDeleteDialog(false);
mutate()
})
.catch(() => {
})
.finally(() => {
setIsSubmitting(false)
});
};
return (
<>
<Tooltip title={t("ExpertMangement.delete_tooltip")}>
<IconButton
color="primary"
data-testid="delete-button"
onClick={() => {
setOpenDeleteDialog(true);
}}
>
<DeleteIcon/>
</IconButton>
</Tooltip>
<Dialog
open={openDeleteDialog}
PaperProps={{
sx: {
boxShadow: 'rgba(60, 64, 67, 0.3) 0px 1px 16px 0px, rgba(60, 64, 67, 0.15) 0px 1px 10px 0px'
}
}}
>
<DialogTitle>{t("ExpertMangement.delete_expert")}</DialogTitle>
<DialogContent>
<DialogContentText>{t("ExpertMangement.are_you_sure_text")}</DialogContentText>
</DialogContent>
<DialogActions>
<Button onClick={() => setOpenDeleteDialog(false)} color="secondary" autoFocus>
{t("ExpertMangement.button_cancel")}
</Button>
<Button onClick={handleDelete} variant="contained" color="primary" disabled={isSubmitting}>
{t("ExpertMangement.button_delete")}
</Button>
</DialogActions>
</Dialog>
</>
);
};
export default Delete;

View File

@@ -1,219 +0,0 @@
import {act, fireEvent, render, screen, waitFor} from "@testing-library/react";
import React from 'react';
import MockAppWithProviders from "../../../../../../../../../mocks/AppWithProvider";
import * as Yup from "yup";
import {Formik} from "formik";
import PersonalInfo from "@/components/dashboard/expert-management/Form/CreateForm/CreateContent/PersonalInfo";
import {useTranslations} from "next-intl";
import Province from "@/components/dashboard/expert-management/Form/CreateForm/CreateContent/RestInfo/Province";
const CreateFormMock = ({Component}) => {
const t = useTranslations();
const validationSchema = Yup.object().shape({
full_name: Yup.string().required(t("ExpertMangement.error_message_full_name")),
email: Yup.string().required(t("ExpertMangement.error_message_email")),
phone_number: Yup.string().required(t("ExpertMangement.error_message_phone_number")),
telephone_id: Yup.string().required(t("ExpertMangement.error_message_telephone_id")),
national_id: Yup.string().required(t("ExpertMangement.error_message_national_id")),
gender: Yup.string().required(t("ExpertMangement.error_message_gender"))
});
return (
<Formik
initialValues={{
full_name: "",
email: "",
phone_number: "",
telephone_id: "",
national_id: "",
gender: ""
}}
validationSchema={validationSchema}
onSubmit={(values, {}) => {
}}
>
{formikProps => (<Component formik={formikProps}></Component>)}
</Formik>
);
};
describe("PersonalInfo Component From Expert Management (update)", () => {
describe("Rendering", () => {
it("full_name TextField Rendered", async () => {
render(<MockAppWithProviders><CreateFormMock Component={PersonalInfo}/></MockAppWithProviders>);
await waitFor(() => {
const fullNameTextField = screen.queryByLabelText('نام کامل');
expect(fullNameTextField).toBeInTheDocument();
});
});
it("Email TextField Rendered", async () => {
render(<MockAppWithProviders><CreateFormMock Component={PersonalInfo}/></MockAppWithProviders>);
await waitFor(() => {
const emailTextField = screen.queryByLabelText('پست الکترونیک');
expect(emailTextField).toBeInTheDocument();
});
});
it("Phone Number TextField Rendered", async () => {
render(<MockAppWithProviders><CreateFormMock Component={PersonalInfo}/></MockAppWithProviders>);
await waitFor(() => {
const phoneNumberTextField = screen.queryByLabelText('شماره همراه');
expect(phoneNumberTextField).toBeInTheDocument();
});
});
it("telephone id TextField Rendered", async () => {
render(<MockAppWithProviders><CreateFormMock Component={PersonalInfo}/></MockAppWithProviders>);
await waitFor(() => {
const telephoneIdTextField = screen.queryByLabelText('کد تلفن');
expect(telephoneIdTextField).toBeInTheDocument();
});
});
it("National Id TextField Rendered", async () => {
render(<MockAppWithProviders><CreateFormMock Component={PersonalInfo}/></MockAppWithProviders>);
await waitFor(() => {
const nationalIdTextField = screen.queryByLabelText('کد ملی');
expect(nationalIdTextField).toBeInTheDocument();
});
});
it("Gender Select Box Rendered", async () => {
render(<MockAppWithProviders><CreateFormMock Component={PersonalInfo}/></MockAppWithProviders>);
await waitFor(() => {
const genderSelectBox = screen.getByTestId('select-box');
expect(genderSelectBox).toBeInTheDocument();
});
});
});
describe("Behavioral", () => {
it("Name TextField Work Correctly", async () => {
render(<MockAppWithProviders><CreateFormMock Component={PersonalInfo}/></MockAppWithProviders>);
const nameTextField = screen.queryByLabelText('نام کامل');
fireEvent.change(nameTextField, {target: {value: 'exampleName'}});
await act(() => {
expect(nameTextField).toHaveValue('exampleName');
})
});
it("Email TextField Work Correctly", async () => {
render(<MockAppWithProviders><CreateFormMock Component={PersonalInfo}/></MockAppWithProviders>);
const emailTextField = screen.queryByLabelText('پست الکترونیک');
fireEvent.change(emailTextField, {target: {value: 'exampleEmail'}});
await act(() => {
expect(emailTextField).toHaveValue('exampleEmail');
})
});
it("Phone Number TextField Work Correctly", async () => {
render(<MockAppWithProviders><CreateFormMock Component={PersonalInfo}/></MockAppWithProviders>);
const phoneNumberTextField = screen.queryByLabelText('شماره همراه');
fireEvent.change(phoneNumberTextField, {target: {value: 'examplePhoneNumber'}});
await act(() => {
expect(phoneNumberTextField).toHaveValue('examplePhoneNumber');
})
});
it("Telephone Id TextField Work Correctly", async () => {
render(<MockAppWithProviders><CreateFormMock Component={PersonalInfo}/></MockAppWithProviders>);
const telephoneIdTextField = screen.queryByLabelText('کد تلفن');
fireEvent.change(telephoneIdTextField, {target: {value: 'exampleTelephoneId'}});
await act(() => {
expect(telephoneIdTextField).toHaveValue('exampleTelephoneId');
})
});
it("National Id TextField Work Correctly", async () => {
render(<MockAppWithProviders><CreateFormMock Component={PersonalInfo}/></MockAppWithProviders>);
const nationalIdTextField = screen.queryByLabelText('کد ملی');
fireEvent.change(nationalIdTextField, {target: {value: 'exampleNationalId'}});
await act(() => {
expect(nationalIdTextField).toHaveValue('exampleNationalId');
})
});
it("Gender Select Box Work Correctly", async () => {
render(<MockAppWithProviders><CreateFormMock Component={PersonalInfo}/></MockAppWithProviders>);
const genderSelectBox = screen.getByTestId('select-box');
const genderSelectOpener = await waitFor(() => screen.getByTestId("option-opener-gender"));
await waitFor(() => {
expect(genderSelectBox).toBeInTheDocument();
});
fireEvent.mouseDown(genderSelectOpener);
await waitFor(() => {
const selectItem = screen.queryByText("مرد");
expect(selectItem).toBeInTheDocument();
});
});
});
describe("validation", () => {
it('Should See Error When Name Input Is Empty', async () => {
render(<MockAppWithProviders><CreateFormMock Component={PersonalInfo}/></MockAppWithProviders>);
const nameInput = screen.queryByLabelText('نام کامل');
fireEvent.change(nameInput, {target: {value: ''}});
fireEvent.blur(nameInput);
await waitFor(() => {
expect(screen.queryByText("نام کامل خود را وارد کنید")).toBeInTheDocument()
});
});
it('Should See Error When Email Input Is Empty', async () => {
render(<MockAppWithProviders><CreateFormMock Component={PersonalInfo}/></MockAppWithProviders>);
const emailInput = screen.queryByLabelText('پست الکترونیک');
fireEvent.change(emailInput, {target: {value: ''}});
fireEvent.blur(emailInput);
await waitFor(() => {
expect(screen.queryByText("پست الکترونیک خود را وارد کنید")).toBeInTheDocument()
});
});
it('Should See Error When Phone Number Input Is Empty', async () => {
render(<MockAppWithProviders><CreateFormMock Component={PersonalInfo}/></MockAppWithProviders>);
const phoneNumberInput = screen.queryByLabelText('شماره همراه');
fireEvent.change(phoneNumberInput, {target: {value: ''}});
fireEvent.blur(phoneNumberInput);
await waitFor(() => {
expect(screen.queryByText("شماره همراه خود را وارد کنید")).toBeInTheDocument()
});
});
it('Should See Error When telephone Id Input Is Empty', async () => {
render(<MockAppWithProviders><CreateFormMock Component={PersonalInfo}/></MockAppWithProviders>);
const telephoneIdTextField = screen.queryByLabelText('کد تلفن');
fireEvent.change(telephoneIdTextField, {target: {value: ''}});
fireEvent.blur(telephoneIdTextField);
await waitFor(() => {
expect(screen.queryByText("کد تلفن خود را وارد کنید")).toBeInTheDocument()
});
});
it('Should See Error When National Id Input Is Empty', async () => {
render(<MockAppWithProviders><CreateFormMock Component={PersonalInfo}/></MockAppWithProviders>);
const nationalIdInput = screen.queryByLabelText('کد ملی');
fireEvent.change(nationalIdInput, {target: {value: ''}});
fireEvent.blur(nationalIdInput);
await waitFor(() => {
expect(screen.queryByText("کد ملی خود را وارد کنید")).toBeInTheDocument()
});
});
it('Should Select An Item With Valid Value of gender', async () => {
render(<MockAppWithProviders><CreateFormMock Component={PersonalInfo}/></MockAppWithProviders>);
const genderInput = screen.getByTestId("input-gender")
const genderSelectOpener = await waitFor(() => screen.getByTestId("option-opener-gender"));
fireEvent.mouseDown(genderSelectOpener);
const selectItem = await waitFor(() => screen.queryByText("مرد"));
expect(selectItem).toBeInTheDocument();
fireEvent.click(selectItem);
await waitFor(() => {
expect(genderInput.value).toBe('male')
});
});
})
});

View File

@@ -1,128 +0,0 @@
import {FormControl, FormHelperText, Grid, InputLabel, MenuItem, Select, TextField} from "@mui/material";
import {useTranslations} from "next-intl";
const PersonalInfo = ({formik}) => {
const t = useTranslations();
const genderList = [
{id: 1, name_en: "male", name_fa: "مرد"},
{id: 2, name_en: "female", name_fa: "زن"}
]
return (
<Grid container justifyContent="space-around" spacing={2} sx={{pb: 2}}>
<Grid item xs={12} sm={6} md={4}>
<TextField
name="full_name"
label={t("ExpertMangement.text_field_full_name")}
variant="outlined"
margin="normal"
size="small"
value={formik.values.full_name}
onChange={formik.handleChange}
onBlur={formik.handleBlur}
error={formik.touched.full_name && !!formik.errors.full_name}
helperText={formik.touched.full_name && formik.errors.full_name ? formik.errors.full_name : null}
sx={{width: "100%"}}
/>
</Grid>
<Grid item xs={12} sm={6} md={4}>
<TextField
name="national_id"
label={t("ExpertMangement.text_field_national_id")}
variant="outlined"
margin="normal"
size="small"
value={formik.values.national_id}
onChange={formik.handleChange}
onBlur={formik.handleBlur}
error={formik.touched.national_id && !!formik.errors.national_id}
helperText={formik.touched.national_id && formik.errors.national_id ? formik.errors.national_id : null}
sx={{width: "100%"}}
/>
</Grid>
<Grid item xs={12} sm={6} md={4}>
<TextField
name="phone_number"
label={t("ExpertMangement.text_field_phone_number")}
variant="outlined"
margin="normal"
size="small"
value={formik.values.phone_number}
onChange={formik.handleChange}
onBlur={formik.handleBlur}
error={formik.touched.phone_number && !!formik.errors.phone_number}
helperText={formik.touched.phone_number && formik.errors.phone_number ? formik.errors.phone_number : null}
sx={{width: "100%"}}
/>
</Grid>
<Grid item xs={12} sm={6} md={4}>
<TextField
name="email"
label={t("ExpertMangement.text_field_email")}
variant="outlined"
margin="normal"
size="small"
value={formik.values.email}
onChange={formik.handleChange}
onBlur={formik.handleBlur}
error={formik.touched.email && !!formik.errors.email}
helperText={formik.touched.email && formik.errors.email ? formik.errors.email : null}
sx={{width: "100%"}}
/>
</Grid>
<Grid item xs={12} sm={6} md={4}>
<TextField
name="telephone_id"
label={t("ExpertMangement.text_field_telephone_id")}
variant="outlined"
margin="normal"
size="small"
value={formik.values.telephone_id}
onChange={formik.handleChange}
onBlur={formik.handleBlur}
error={formik.touched.telephone_id && !!formik.errors.telephone_id}
helperText={formik.touched.telephone_id && formik.errors.telephone_id ? formik.errors.telephone_id : null}
sx={{width: "100%"}}
/>
</Grid>
<Grid item xs={12} sm={6} md={4}>
<FormControl
error={formik.touched.gender && !!formik.errors.gender}
sx={{width: "100%", mt: 2}}
size="small"
>
<InputLabel>{t("ExpertMangement.text_field_gender")}</InputLabel>
<Select
name="gender"
label={t("ExpertMangement.text_field_gender")}
value={formik.values.gender}
onChange={(e) => {
formik.setFieldValue("gender", e.target.value);
}}
inputProps={{
"data-testid": "input-gender"
}}
data-testid="select-box"
SelectDisplayProps={{"data-testid": 'option-opener-gender'}}
onBlur={formik.handleBlur}
fullWidth
variant="outlined"
>
{(
genderList.map((item) => (
<MenuItem key={item.id} value={item.name_en}>
{item.name_fa}
</MenuItem>
))
)}
</Select>
<FormHelperText>
{formik.touched.gender && formik.errors.gender ? formik.errors.gender : ""}
</FormHelperText>
</FormControl>
</Grid>
</Grid>
)
}
export default PersonalInfo

View File

@@ -1,96 +0,0 @@
import {fireEvent, render, screen, waitFor} from "@testing-library/react";
import React from 'react';
import {useTranslations} from "next-intl";
import * as Yup from "yup";
import {Formik} from "formik";
import MockAppWithProviders from "../../../../../../../../../../mocks/AppWithProvider";
import PositionAndRole from "../../PositionAndRole";
const CreateFormMock = ({Component}) => {
const t = useTranslations();
const validationSchema = Yup.object().shape({
position: Yup.string().required(t("ExpertMangement.error_message_position")),
roles: Yup.string().required(t("ExpertMangement.error_message_roles"))
});
return (
<Formik
initialValues={{
position: "",
roles: ""
}}
validationSchema={validationSchema}
onSubmit={(values, {}) => {
}}
>
{formikProps => (<Component formik={formikProps}></Component>)}
</Formik>
);
};
describe("PositionAndRole Component From Expert Management (update)", () => {
describe("Rendering", () => {
it("Position TextField Rendered", async () => {
render(<MockAppWithProviders><CreateFormMock Component={PositionAndRole}/></MockAppWithProviders>);
await waitFor(() => {
const positionTextField = screen.queryByLabelText('سمت');
expect(positionTextField).toBeInTheDocument();
});
});
it("Role Select Box Rendered", async () => {
render(<MockAppWithProviders><CreateFormMock Component={PositionAndRole}/></MockAppWithProviders>);
const roleSelect = screen.getByTestId('select-box');
await waitFor(() => {
expect(roleSelect).toBeInTheDocument();
});
});
});
describe("Behavioral", () => {
it("Position TextField Work Correctly", async () => {
render(<MockAppWithProviders><CreateFormMock Component={PositionAndRole}/></MockAppWithProviders>);
const positionTextField = screen.queryByLabelText('سمت');
fireEvent.change(positionTextField, {target: {value: 'examplePosition'}});
await waitFor(() => {
expect(positionTextField).toHaveValue('examplePosition');
})
});
it("Role Select Box Work Correctly", async () => {
render(<MockAppWithProviders><CreateFormMock Component={PositionAndRole}/></MockAppWithProviders>);
const roleSelect = screen.getByTestId("option-opener-role");
await waitFor(() => {
expect(roleSelect).toBeInTheDocument();
});
fireEvent.mouseDown(roleSelect);
await waitFor(() => {
const selectItem = screen.queryByText("ادمین");
expect(selectItem).toBeInTheDocument();
});
});
});
describe("validation", () => {
it('Should See Error When Position Input Is Empty', async () => {
render(<MockAppWithProviders><CreateFormMock Component={PositionAndRole}/></MockAppWithProviders>);
const positionInput = screen.queryByLabelText('سمت');
fireEvent.change(positionInput, {target: {value: ''}});
fireEvent.blur(positionInput);
await waitFor(() => {
expect(screen.queryByText("سمت خود را وارد کنید")).toBeInTheDocument()
});
});
it('Should Select An Item With Valid Value of role', async () => {
render(<MockAppWithProviders><CreateFormMock Component={PositionAndRole}/></MockAppWithProviders>);
const roleInput = await waitFor(() => screen.getByTestId("input-role-id"));
const roleSelectOpener = await waitFor(() => screen.getByTestId("option-opener-role"));
fireEvent.mouseDown(roleSelectOpener);
const selectItem = await waitFor(() => screen.queryByText("ادمین"));
expect(selectItem).toBeInTheDocument();
fireEvent.click(selectItem);
await waitFor(() => {
expect(roleInput.value).toBe('1')
});
});
})
});

Some files were not shown because too many files have changed in this diff Show More