CFE-4 Merge branch 'develop' into 'feature/CFE-4_role_management_page'
This commit is contained in:
@@ -5,7 +5,10 @@ export const handler = [
|
|||||||
rest.get(GET_USER_ROUTE, (req, res, ctx) => {
|
rest.get(GET_USER_ROUTE, (req, res, ctx) => {
|
||||||
return res(ctx.json({
|
return res(ctx.json({
|
||||||
data:{
|
data:{
|
||||||
id: 10
|
id: 10,
|
||||||
|
permissions:[
|
||||||
|
"manage_users"
|
||||||
|
],
|
||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
}),
|
}),
|
||||||
|
|||||||
@@ -64,7 +64,7 @@
|
|||||||
"jest": "^29.7.0",
|
"jest": "^29.7.0",
|
||||||
"jest-environment-jsdom": "^29.7.0",
|
"jest-environment-jsdom": "^29.7.0",
|
||||||
"msw": "^1.3.1",
|
"msw": "^1.3.1",
|
||||||
"next-router-mock": "^0.9.9",
|
"next-router-mock": "^0.9.10",
|
||||||
"run-script-os": "^1.1.6"
|
"run-script-os": "^1.1.6"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,7 +43,7 @@
|
|||||||
"typography_your_login_is_valid_and_you_do_not_need_to_login_again": "شما دسترسی لازم به این صفحه را دارید نیاز به ورود مجدد نیست.",
|
"typography_your_login_is_valid_and_you_do_not_need_to_login_again": "شما دسترسی لازم به این صفحه را دارید نیاز به ورود مجدد نیست.",
|
||||||
"typography_your_access_to_this_page_has_expired_Please_login_again": "دسترسی شما منقضی شده است لطفا دوباره ورود نمایید.",
|
"typography_your_access_to_this_page_has_expired_Please_login_again": "دسترسی شما منقضی شده است لطفا دوباره ورود نمایید.",
|
||||||
"typography_redirect_to": "درحال رفتن به صفحه",
|
"typography_redirect_to": "درحال رفتن به صفحه",
|
||||||
"typography_routing_previuos_page": "صفحه قبل...",
|
"typography_routing_previuos_page": " قبل...",
|
||||||
"typography_routing_dashbaord_page": "داشبورد..."
|
"typography_routing_dashbaord_page": "داشبورد..."
|
||||||
},
|
},
|
||||||
"Permission": {
|
"Permission": {
|
||||||
|
|||||||
@@ -9,56 +9,45 @@ import useRequest from "@/lib/app/hooks/useRequest";
|
|||||||
|
|
||||||
function DataTable(props) {
|
function DataTable(props) {
|
||||||
const requestServer = useRequest({auth: true})
|
const requestServer = useRequest({auth: true})
|
||||||
const fetcher = (...args) => {
|
|
||||||
return requestServer(args, 'get', {
|
|
||||||
pending: false,
|
|
||||||
success: {notification: {show: false}}
|
|
||||||
}).then((response) => {
|
|
||||||
setRowCount(response.data.meta.totalRowCount);
|
|
||||||
return response.data.data;
|
|
||||||
}).catch(() => {
|
|
||||||
})
|
|
||||||
};
|
|
||||||
const t = useTranslations();
|
const t = useTranslations();
|
||||||
const {languageApp, languageList} = useLanguage();
|
const {languageApp, languageList} = useLanguage();
|
||||||
const [columnFilters, setColumnFilters] = useState([]);
|
const [columnFilters, setColumnFilters] = useState([]);
|
||||||
const [sorting, setSorting] = useState([]);
|
const [sorting, setSorting] = useState([]);
|
||||||
const [pagination, setPagination] = useState({pageIndex: 0, pageSize: 10});
|
const [pagination, setPagination] = useState({pageIndex: 0, pageSize: 10});
|
||||||
const [rowCount, setRowCount] = useState(0);
|
|
||||||
const [columnFilterFns, setColumnFilterFns] = useState(() => {
|
const [columnFilterFns, setColumnFilterFns] = useState(() => {
|
||||||
let output = {};
|
let output = {};
|
||||||
const list = props.columns.map((item) =>
|
const list = props.columns.map((item) =>
|
||||||
item.enableColumnFilter ? {[item.id]: item.filterFn} : {[item.id]: ""}
|
item.enableColumnFilter ? {[item.id]: item.filterFn} : {[item.id]: ""}
|
||||||
);
|
);
|
||||||
for (var key in list) {
|
for (const key in list) {
|
||||||
var nestedObj = list[key];
|
const nestedObj = list[key];
|
||||||
for (var nestedKey in nestedObj) {
|
for (const nestedKey in nestedObj) {
|
||||||
output[nestedKey] = nestedObj[nestedKey];
|
output[nestedKey] = nestedObj[nestedKey];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return output;
|
return output;
|
||||||
});
|
});
|
||||||
|
|
||||||
const [updateTime, setupdateTime] = useState(
|
const [updateTime, setUpdateTime] = useState(
|
||||||
moment().format("HH:mm | jYYYY/jM/jD")
|
moment().format("HH:mm | jYYYY/jM/jD")
|
||||||
);
|
);
|
||||||
|
|
||||||
const tableLocalization = useMemo(
|
const tableLocalization = useMemo(
|
||||||
() =>
|
() =>
|
||||||
languageList.find((item) => item.key == languageApp).tableLocalization,
|
languageList.find((item) => item.key === languageApp).tableLocalization,
|
||||||
[languageApp, languageList]
|
[languageApp, languageList]
|
||||||
);
|
);
|
||||||
|
|
||||||
const fetchUrl = useMemo(() => {
|
const fetchUrl = useMemo(() => {
|
||||||
const url = new URL(props.tableUrl);
|
const params = new URLSearchParams();
|
||||||
url.searchParams.set(
|
params.set(
|
||||||
"start",
|
"start",
|
||||||
`${pagination.pageIndex * pagination.pageSize}`
|
`${pagination.pageIndex * pagination.pageSize}`
|
||||||
);
|
);
|
||||||
const filters = columnFilters.map((filter) => {
|
const filters = columnFilters.map((filter) => {
|
||||||
let datatype;
|
let datatype;
|
||||||
for (const i in props.columns) {
|
for (const i in props.columns) {
|
||||||
if (props.columns[i].id == filter.id) {
|
if (props.columns[i].id === filter.id) {
|
||||||
datatype = props.columns[i].datatype;
|
datatype = props.columns[i].datatype;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -68,10 +57,10 @@ function DataTable(props) {
|
|||||||
datatype: datatype,
|
datatype: datatype,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
url.searchParams.set("size", pagination.pageSize);
|
params.set("size", pagination.pageSize);
|
||||||
url.searchParams.set("filters", JSON.stringify(filters ?? []));
|
params.set("filters", JSON.stringify(filters ?? []));
|
||||||
url.searchParams.set("sorting", JSON.stringify(sorting ?? []));
|
params.set("sorting", JSON.stringify(sorting ?? []));
|
||||||
return url;
|
return `${props.tableUrl}?${params}`;
|
||||||
}, [
|
}, [
|
||||||
props.tableUrl,
|
props.tableUrl,
|
||||||
columnFilters,
|
columnFilters,
|
||||||
@@ -81,20 +70,27 @@ function DataTable(props) {
|
|||||||
props.columns,
|
props.columns,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const {data, isValidating, mutate} = useSWR(fetchUrl, fetcher, {
|
const {data, isValidating, mutate} = useSWR(fetchUrl, (...args) =>
|
||||||
revalidateIfStale: false,
|
requestServer(args, 'get', {
|
||||||
revalidateOnFocus: false,
|
pending: false,
|
||||||
revalidateOnReconnect: false,
|
success: {notification: {show: false}}
|
||||||
});
|
}).then((response) => response.data).catch(() => {
|
||||||
|
})
|
||||||
|
, {
|
||||||
|
revalidateIfStale: false,
|
||||||
|
revalidateOnFocus: false,
|
||||||
|
revalidateOnReconnect: true,
|
||||||
|
keepPreviousData: true
|
||||||
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setupdateTime(moment().format("HH:mm | jYYYY/jM/jD"));
|
setUpdateTime(moment().format("HH:mm | jYYYY/jM/jD"));
|
||||||
}, [isValidating, languageApp]);
|
}, [isValidating, languageApp]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<MaterialReactTable
|
<MaterialReactTable
|
||||||
localization={tableLocalization}
|
localization={tableLocalization}
|
||||||
data={data ?? []}
|
data={data?.data ?? []}
|
||||||
manualFiltering
|
manualFiltering
|
||||||
manualPagination
|
manualPagination
|
||||||
manualSorting
|
manualSorting
|
||||||
@@ -125,7 +121,7 @@ function DataTable(props) {
|
|||||||
}}
|
}}
|
||||||
enableColumnFilterModes
|
enableColumnFilterModes
|
||||||
muiTablePaperProps={{elevation: 0}}
|
muiTablePaperProps={{elevation: 0}}
|
||||||
rowCount={rowCount}
|
rowCount={data?.meta.totalRowCount}
|
||||||
onColumnFilterFnsChange={setColumnFilterFns}
|
onColumnFilterFnsChange={setColumnFilterFns}
|
||||||
onColumnFiltersChange={setColumnFilters}
|
onColumnFiltersChange={setColumnFilters}
|
||||||
onPaginationChange={setPagination}
|
onPaginationChange={setPagination}
|
||||||
@@ -134,7 +130,7 @@ function DataTable(props) {
|
|||||||
renderTopToolbarCustomActions={({table}) => (
|
renderTopToolbarCustomActions={({table}) => (
|
||||||
<>
|
<>
|
||||||
{props.enableCustomToolbar /* send condition */
|
{props.enableCustomToolbar /* send condition */
|
||||||
? <props.CustomToolbar fetchUrl={fetchUrl} mutate={mutate} /> /* send component */
|
? <props.CustomToolbar fetchUrl={fetchUrl} mutate={mutate}/> /* send component */
|
||||||
: "<span></span>"}
|
: "<span></span>"}
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
@@ -159,6 +155,7 @@ function DataTable(props) {
|
|||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
state={{
|
state={{
|
||||||
|
showProgressBars: isValidating,
|
||||||
columnFilters,
|
columnFilters,
|
||||||
columnFilterFns,
|
columnFilterFns,
|
||||||
pagination,
|
pagination,
|
||||||
|
|||||||
33
src/core/components/Middleware/RolePermissionComponent.jsx
Normal file
33
src/core/components/Middleware/RolePermissionComponent.jsx
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
import { Button, Typography } from "@mui/material";
|
||||||
|
import { useTranslations } from "next-intl";
|
||||||
|
import { NextLinkComposed } from "@/core/components/LinkRouting";
|
||||||
|
import Message from "@/core/components/Messages";
|
||||||
|
|
||||||
|
const RolePermissionComponent = () => {
|
||||||
|
const t = useTranslations();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Message
|
||||||
|
text={
|
||||||
|
<Typography sx={{ textAlign: "center" }}>
|
||||||
|
{t("Permission.typography_you_dont_have_access")}
|
||||||
|
</Typography>
|
||||||
|
}
|
||||||
|
actions={
|
||||||
|
<>
|
||||||
|
<Button
|
||||||
|
variant="contained"
|
||||||
|
component={NextLinkComposed}
|
||||||
|
to={{
|
||||||
|
pathname: "/dashboard",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{t("Permission.button_back_dashboard")}
|
||||||
|
</Button>
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default RolePermissionComponent;
|
||||||
36
src/core/components/Middleware/WithAuthComponent.jsx
Normal file
36
src/core/components/Middleware/WithAuthComponent.jsx
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
import { Button, Typography } from "@mui/material";
|
||||||
|
import { useRouter } from "next/router";
|
||||||
|
import Message from "@/core/components/Messages";
|
||||||
|
import { NextLinkComposed } from "@/core/components/LinkRouting";
|
||||||
|
import {useTranslations} from "next-intl";
|
||||||
|
|
||||||
|
const WithAuthComponent = () => {
|
||||||
|
const router = useRouter();
|
||||||
|
const t = useTranslations();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Message
|
||||||
|
text={
|
||||||
|
<Typography sx={{ textAlign: "center" }}>
|
||||||
|
{t("Authorization.typography_your_access_to_this_page_has_expired_Please_login_again")}
|
||||||
|
</Typography>
|
||||||
|
}
|
||||||
|
actions={
|
||||||
|
<>
|
||||||
|
<Button
|
||||||
|
variant="contained"
|
||||||
|
component={NextLinkComposed}
|
||||||
|
to={{
|
||||||
|
pathname: "/login-expert",
|
||||||
|
query: {back_url: encodeURIComponent(router.asPath)},
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{t("login")}
|
||||||
|
</Button>
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default WithAuthComponent;
|
||||||
25
src/core/components/Middleware/WithoutAuthComponent.jsx
Normal file
25
src/core/components/Middleware/WithoutAuthComponent.jsx
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
import {Button, Stack, Typography} from "@mui/material";
|
||||||
|
import Message from "@/core/components/Messages";
|
||||||
|
import {useTranslations} from "next-intl";
|
||||||
|
const WithoutAuthComponent = ({ backUrlDecodedPath }) => {
|
||||||
|
const t = useTranslations();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Message
|
||||||
|
text={
|
||||||
|
<Stack alignItems="center" spacing={2}>
|
||||||
|
<Typography sx={{ textAlign: "center" }}>
|
||||||
|
{t("Authorization.typography_your_login_is_valid_and_you_do_not_need_to_login_again")}
|
||||||
|
</Typography>
|
||||||
|
<Typography>
|
||||||
|
{t("Authorization.typography_redirect_to")}{" "}
|
||||||
|
{backUrlDecodedPath
|
||||||
|
? t("Authorization.typography_routing_previuos_page")
|
||||||
|
: t("Authorization.typography_routing_dashbaord_page")}
|
||||||
|
</Typography>
|
||||||
|
</Stack>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
export default WithoutAuthComponent;
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
import { render, screen } from '@testing-library/react';
|
||||||
|
import MockAppWithProviders from "../../../../../mocks/AppWithProvider";
|
||||||
|
import RolePermissionComponent from "@/core/components/Middleware/RolePermissionComponent";
|
||||||
|
|
||||||
|
describe('RolePermissionComponent From RolePermissionComponent page', () => {
|
||||||
|
describe('Rendering', () => {
|
||||||
|
it('should render the error message when user dont have permission', () => {
|
||||||
|
render(<MockAppWithProviders><RolePermissionComponent /></MockAppWithProviders>);
|
||||||
|
|
||||||
|
expect(screen.queryByText('شما دسترسی لازم برای مشاهده این صفحه را ندارید!')).toBeInTheDocument();
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render the back dashboard button when user dont have permission', () => {
|
||||||
|
render(<MockAppWithProviders><RolePermissionComponent /></MockAppWithProviders>);
|
||||||
|
|
||||||
|
const backButton = screen.queryByText('بازگشت به صفحه اصلی');
|
||||||
|
|
||||||
|
expect(backButton).toBeInTheDocument();
|
||||||
|
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
import { render, screen, fireEvent, waitFor } from '@testing-library/react';
|
||||||
|
import MockAppWithProviders from "../../../../../mocks/AppWithProvider";
|
||||||
|
import WithAuthComponent from "@/core/components/Middleware/WithAuthComponent";
|
||||||
|
import mockRouter from 'next-router-mock';
|
||||||
|
|
||||||
|
describe('WithAuthComponent From WithAuthMiddleware', () => {
|
||||||
|
describe('Rendering', () => {
|
||||||
|
it('should see expired text in render component', () => {
|
||||||
|
render(<MockAppWithProviders><WithAuthComponent /></MockAppWithProviders>);
|
||||||
|
|
||||||
|
const authText = screen.queryByText('دسترسی شما منقضی شده است لطفا دوباره ورود نمایید.');
|
||||||
|
|
||||||
|
expect(authText).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should see login button in render component', () => {
|
||||||
|
render(<MockAppWithProviders><WithAuthComponent /></MockAppWithProviders>);
|
||||||
|
|
||||||
|
const loginButton = screen.queryByText('ورود');
|
||||||
|
|
||||||
|
expect(loginButton).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
describe('behavior', () => {
|
||||||
|
it('should see if router updated in login button', () => {
|
||||||
|
|
||||||
|
mockRouter.query.back_url = 'back_url'
|
||||||
|
render(<MockAppWithProviders><WithAuthComponent /></MockAppWithProviders>);
|
||||||
|
|
||||||
|
const loginButton = screen.queryByText('ورود');
|
||||||
|
|
||||||
|
fireEvent.click(loginButton);
|
||||||
|
|
||||||
|
expect(mockRouter).toMatchObject({
|
||||||
|
query: { back_url: "back_url" },
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
import {render, screen, waitFor} from '@testing-library/react';
|
||||||
|
import WithoutAuthComponent from "@/core/components/Middleware/WithoutAuthComponent";
|
||||||
|
import MockAppWithProviders from "../../../../../mocks/AppWithProvider";
|
||||||
|
import WithoutAuthMiddleware from "@/middlewares/WithoutAuth";
|
||||||
|
|
||||||
|
describe('WithoutAuthComponent From WithoutAuthMiddleware', () => {
|
||||||
|
describe('Rendering', () => {
|
||||||
|
it('should render the message with correct text when backUrlDecodedPath is not provided', async () => {
|
||||||
|
|
||||||
|
localStorage.setItem("_token", 'token');
|
||||||
|
|
||||||
|
render(<MockAppWithProviders><WithoutAuthMiddleware /></MockAppWithProviders>);
|
||||||
|
|
||||||
|
await waitFor(()=>{
|
||||||
|
expect(screen.queryByText('شما دسترسی لازم به این صفحه را دارید نیاز به ورود مجدد نیست.')).toBeInTheDocument();
|
||||||
|
|
||||||
|
expect(screen.queryByText('درحال رفتن به صفحه داشبورد...')).toBeInTheDocument();
|
||||||
|
})
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render the message with a different text when backUrlDecodedPath is provided', async() => {
|
||||||
|
render(<MockAppWithProviders><WithoutAuthComponent backUrlDecodedPath="/dashboard/change-password" /></MockAppWithProviders>);
|
||||||
|
|
||||||
|
localStorage.setItem("_token", 'token');
|
||||||
|
|
||||||
|
render(<MockAppWithProviders><WithoutAuthMiddleware /></MockAppWithProviders>);
|
||||||
|
|
||||||
|
await waitFor(()=>{
|
||||||
|
|
||||||
|
expect(screen.queryByText('درحال رفتن به صفحه قبل...')).toBeInTheDocument();
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -1,43 +1,14 @@
|
|||||||
import {NextLinkComposed} from "@/core/components/LinkRouting";
|
|
||||||
import Message from "@/core/components/Messages";
|
|
||||||
import useUser from "@/lib/app/hooks/useUser";
|
import useUser from "@/lib/app/hooks/useUser";
|
||||||
import {Button, Typography} from "@mui/material";
|
import RolePermissionComponent from "@/core/components/Middleware/RolePermissionComponent";
|
||||||
import {useTranslations} from "next-intl";
|
|
||||||
|
|
||||||
const RolePermissionMiddleware = ({children, requiredPermissions}) => {
|
const RolePermissionMiddleware = ({children, requiredPermissions}) => {
|
||||||
const {user} = useUser();
|
const {user} = useUser();
|
||||||
const t = useTranslations();
|
|
||||||
|
|
||||||
const hasPermission = requiredPermissions.some((permission) =>
|
const hasPermission = requiredPermissions.some((permission) =>
|
||||||
user?.permissions?.includes(permission)
|
user?.permissions?.includes(permission)
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!hasPermission) {
|
return !hasPermission ? <RolePermissionComponent /> : <>{children}</>;
|
||||||
return (
|
|
||||||
<Message
|
|
||||||
text={
|
|
||||||
<Typography sx={{textAlign: "center"}}>
|
|
||||||
{t("Permission.typography_you_dont_have_access")}
|
|
||||||
</Typography>
|
|
||||||
}
|
|
||||||
actions={
|
|
||||||
<>
|
|
||||||
<Button
|
|
||||||
variant="contained"
|
|
||||||
component={NextLinkComposed}
|
|
||||||
to={{
|
|
||||||
pathname: "/dashboard",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{t("Permission.button_back_dashboard")}
|
|
||||||
</Button>
|
|
||||||
</>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return <>{children}</>;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default RolePermissionMiddleware;
|
export default RolePermissionMiddleware;
|
||||||
|
|||||||
@@ -1,42 +1,11 @@
|
|||||||
import {NextLinkComposed} from "@/core/components/LinkRouting";
|
|
||||||
import Message from "@/core/components/Messages";
|
|
||||||
import useUser from "@/lib/app/hooks/useUser";
|
import useUser from "@/lib/app/hooks/useUser";
|
||||||
import {Button, Typography} from "@mui/material";
|
import WithAuthComponent from "@/core/components/Middleware/WithAuthComponent";
|
||||||
import {useTranslations} from "next-intl";
|
|
||||||
import {useRouter} from "next/router";
|
|
||||||
|
|
||||||
const WithAuthMiddleware = ({children}) => {
|
const WithAuthMiddleware = ({children}) => {
|
||||||
const {isAuth} = useUser();
|
const {isAuth} = useUser();
|
||||||
const t = useTranslations();
|
|
||||||
const router = useRouter();
|
|
||||||
|
|
||||||
if (!isAuth)
|
return isAuth ? <>{children}</> : <WithAuthComponent />;
|
||||||
return (
|
|
||||||
<Message
|
|
||||||
text={
|
|
||||||
<Typography sx={{textAlign: "center"}}>
|
|
||||||
{t(
|
|
||||||
"Authorization.typography_your_access_to_this_page_has_expired_Please_login_again"
|
|
||||||
)}
|
|
||||||
</Typography>
|
|
||||||
}
|
|
||||||
actions={
|
|
||||||
<>
|
|
||||||
<Button
|
|
||||||
variant="contained"
|
|
||||||
component={NextLinkComposed}
|
|
||||||
to={{
|
|
||||||
pathname: "/login-expert",
|
|
||||||
query: {back_url: encodeURIComponent(router.asPath)},
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{t("login")}
|
|
||||||
</Button>
|
|
||||||
</>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
return <>{children}</>;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default WithAuthMiddleware;
|
export default WithAuthMiddleware;
|
||||||
|
|||||||
@@ -1,19 +1,13 @@
|
|||||||
import Message from "@/core/components/Messages";
|
|
||||||
import useUser from "@/lib/app/hooks/useUser";
|
import useUser from "@/lib/app/hooks/useUser";
|
||||||
import {Stack, Typography} from "@mui/material";
|
|
||||||
import {useTranslations} from "next-intl";
|
|
||||||
import {useSearchParams} from "next/navigation";
|
|
||||||
import {useRouter} from "next/router";
|
import {useRouter} from "next/router";
|
||||||
import {useEffect} from "react";
|
import {useEffect} from "react";
|
||||||
|
import WithoutAuthComponent from "@/core/components/Middleware/WithoutAuthComponent";
|
||||||
|
|
||||||
const WithoutAuthMiddleware = ({children}) => {
|
const WithoutAuthMiddleware = ({children}) => {
|
||||||
const {isAuth} = useUser();
|
const {isAuth} = useUser();
|
||||||
const t = useTranslations();
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
// gettin url query
|
const backUrlDecodedPath = router.query?.back_url;
|
||||||
const searchParams = useSearchParams();
|
|
||||||
const backUrlDecodedPath = searchParams.get("back_url");
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!isAuth) return;
|
if (!isAuth) return;
|
||||||
@@ -30,27 +24,11 @@ const WithoutAuthMiddleware = ({children}) => {
|
|||||||
};
|
};
|
||||||
}, [isAuth]);
|
}, [isAuth]);
|
||||||
|
|
||||||
if (isAuth)
|
return isAuth ? (
|
||||||
return (
|
<WithoutAuthComponent backUrlDecodedPath={backUrlDecodedPath} />
|
||||||
<Message
|
) : (
|
||||||
text={
|
<>{children}</>
|
||||||
<Stack alignItems="center" spacing={2}>
|
);
|
||||||
<Typography sx={{textAlign: "center"}}>
|
|
||||||
{t(
|
|
||||||
"Authorization.typography_your_login_is_valid_and_you_do_not_need_to_login_again"
|
|
||||||
)}
|
|
||||||
</Typography>
|
|
||||||
<Typography>
|
|
||||||
{t("Authorization.typography_redirect_to")}{" "}
|
|
||||||
{backUrlDecodedPath
|
|
||||||
? t("Authorization.typography_routing_previuos_page")
|
|
||||||
: t("Authorization.typography_routing_dashbaord_page")}
|
|
||||||
</Typography>
|
|
||||||
</Stack>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
return <>{children}</>;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default WithoutAuthMiddleware;
|
export default WithoutAuthMiddleware;
|
||||||
|
|||||||
34
src/middlewares/__test__/RolePermission.test.js
Normal file
34
src/middlewares/__test__/RolePermission.test.js
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
import {render, screen, waitFor} from '@testing-library/react';
|
||||||
|
import MockAppWithProviders from "../../../mocks/AppWithProvider";
|
||||||
|
import RolePermissionMiddleware from "@/middlewares/RolePermission";
|
||||||
|
|
||||||
|
|
||||||
|
describe('RolePermissionMiddleware From RolePermissionMiddleware', () => {
|
||||||
|
describe('Behavior', () => {
|
||||||
|
it('show related child if permission exist', async () => {
|
||||||
|
|
||||||
|
const requiredPermissions = ["manage_users"];
|
||||||
|
render(<MockAppWithProviders><RolePermissionMiddleware requiredPermissions={requiredPermissions}/>{'children'}</MockAppWithProviders>);
|
||||||
|
|
||||||
|
await waitFor(()=>{
|
||||||
|
expect(screen.queryByText('children')).toBeInTheDocument();
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
});
|
||||||
|
it('show related error if permission not exist', async () => {
|
||||||
|
|
||||||
|
const requiredPermissions = ["other-permission"];
|
||||||
|
|
||||||
|
render(<MockAppWithProviders><RolePermissionMiddleware requiredPermissions={requiredPermissions}/></MockAppWithProviders>);
|
||||||
|
|
||||||
|
await waitFor(()=>{
|
||||||
|
|
||||||
|
expect(screen.queryByText('شما دسترسی لازم برای مشاهده این صفحه را ندارید!')).toBeInTheDocument();
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user