diff --git a/.gitignore b/.gitignore index e72b4d6..f6e1a1c 100644 --- a/.gitignore +++ b/.gitignore @@ -39,3 +39,4 @@ yarn-error.log* # typescript *.tsbuildinfo next-env.d.ts +/.idea diff --git a/.idea/.gitignore b/.idea/.gitignore deleted file mode 100644 index 13566b8..0000000 --- a/.idea/.gitignore +++ /dev/null @@ -1,8 +0,0 @@ -# Default ignored files -/shelf/ -/workspace.xml -# Editor-based HTTP Client requests -/httpRequests/ -# Datasource local storage ignored files -/dataSources/ -/dataSources.local.xml diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml deleted file mode 100644 index 1113612..0000000 --- a/.idea/codeStyles/Project.xml +++ /dev/null @@ -1,47 +0,0 @@ - - - - \ No newline at end of file diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml deleted file mode 100644 index 79ee123..0000000 --- a/.idea/codeStyles/codeStyleConfig.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - - \ No newline at end of file diff --git a/.idea/crm-app.iml b/.idea/crm-app.iml deleted file mode 100644 index 24643cc..0000000 --- a/.idea/crm-app.iml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml deleted file mode 100644 index c63ea15..0000000 --- a/.idea/inspectionProfiles/Project_Default.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml deleted file mode 100644 index f13d54d..0000000 --- a/.idea/modules.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/.idea/prettier.xml b/.idea/prettier.xml deleted file mode 100644 index b0c1c68..0000000 --- a/.idea/prettier.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml deleted file mode 100644 index 35eb1dd..0000000 --- a/.idea/vcs.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/src/app/(withoutAuth)/teleport/page.js b/src/app/(withoutAuth)/teleport/page.js new file mode 100644 index 0000000..eef64f3 --- /dev/null +++ b/src/app/(withoutAuth)/teleport/page.js @@ -0,0 +1,10 @@ +import TeleportPage from "@/components/Teleport"; + +export const metadata = { + title: "درحال انتقال به استان مورد نظر", +}; + +const Page = () => { + return ; +}; +export default Page; diff --git a/src/components/Login/Form/index.jsx b/src/components/Login/Form/index.jsx index e3ae06b..41444fb 100644 --- a/src/components/Login/Form/index.jsx +++ b/src/components/Login/Form/index.jsx @@ -46,7 +46,7 @@ const LoginForm = () => { data: formData, }); setToken(response.data.data.token); - } catch (error) {} + } catch (error) { } }; return ( diff --git a/src/components/Teleport/index.jsx b/src/components/Teleport/index.jsx new file mode 100644 index 0000000..cc7b9b7 --- /dev/null +++ b/src/components/Teleport/index.jsx @@ -0,0 +1,51 @@ +'use client' +import LoadingHardPage from "@/core/components/LoadingHardPage"; +import { TELEPORT_USER_ROUTE } from "@/core/utils/routes"; +import { useAuth } from "@/lib/contexts/auth"; +import useRequest from "@/lib/hooks/useRequest"; +import { Stack, Typography } from "@mui/material"; +import { useSearchParams } from "next/navigation"; +import { useEffect, useState } from "react"; + +const TelePortPage = () => { + const { setToken } = useAuth() + const searchParams = useSearchParams(); + const token = searchParams.get("token"); + const user_id = searchParams.get("user_id"); + + const [error, setError] = useState(false) + const requestServer = useRequest({ notificationShow: false }); + + useEffect(() => { + const login = async () => { + try { + const response = await requestServer(TELEPORT_USER_ROUTE, "post", { + data: { + token: decodeURIComponent(token), + user_id: decodeURIComponent(user_id) + } + }); + setToken(response.data.data.token); + } catch (error) { setError(true) } + } + + login() + }, []) + + return ( + + مشکلی در انتقال پیش آمده است! + + ) : ( + درحال انتقال به مرکز مورد نظر... + ) + } + loading={true} + /> + ) +} +export default TelePortPage \ No newline at end of file diff --git a/src/components/dashboard/Roles/DataTable.jsx b/src/components/dashboard/Roles/DataTable.jsx index 3b6cab7..8acce6a 100644 --- a/src/components/dashboard/Roles/DataTable.jsx +++ b/src/components/dashboard/Roles/DataTable.jsx @@ -34,6 +34,18 @@ const DataTable = () => { grow: false, size: 100, }, + { + accessorKey: "name", + header: "نام انگلیسی", + id: "name", + enableColumnFilter: true, + datatype: "text", + filterMode: "equals", + sortDescFirst: false, + columnFilterModeOptions: ["equals", "contains"], + grow: false, + size: 100, + }, { accessorKey: "created_at", header: "تاریخ ساخت", diff --git a/src/components/dashboard/Users/DataTable.jsx b/src/components/dashboard/Users/DataTable.jsx index 31d2a6b..7988782 100644 --- a/src/components/dashboard/Users/DataTable.jsx +++ b/src/components/dashboard/Users/DataTable.jsx @@ -39,6 +39,7 @@ const DataTable = () => { size: 100, }, { + accessorKey: "telephone_id", header: "شماره تماس داخلی", id: "telephone_id", enableColumnFilter: true, @@ -48,7 +49,6 @@ const DataTable = () => { columnFilterModeOptions: ["equals", "contains"], grow: false, size: 100, - Cell: ({ row }) => , }, { accessorKey: "is_online", diff --git a/src/components/dashboard/dashboard/index.jsx b/src/components/dashboard/dashboard/index.jsx index 29faec3..eb996a7 100644 --- a/src/components/dashboard/dashboard/index.jsx +++ b/src/components/dashboard/dashboard/index.jsx @@ -5,7 +5,7 @@ import OnlineUsersReport from "./OnlineUsersReport"; const DashboardPage = () => { return ( - + {/* */} ); }; diff --git a/src/components/layouts/dashboard/headerWithSidebar/Sidebar/SidebarMenu.jsx b/src/components/layouts/dashboard/headerWithSidebar/Sidebar/SidebarMenu.jsx index 1bfb012..defa771 100644 --- a/src/components/layouts/dashboard/headerWithSidebar/Sidebar/SidebarMenu.jsx +++ b/src/components/layouts/dashboard/headerWithSidebar/Sidebar/SidebarMenu.jsx @@ -1,12 +1,12 @@ "use client"; +import Profile from "@/core/components/Profile"; +import { filterMenuItems } from "@/core/utils/filterMenuItems"; +import { pageMenu } from "@/core/utils/pageMenu"; import { usePermissions } from "@/lib/hooks/usePermissions"; import { List } from "@mui/material"; import { usePathname } from "next/navigation"; import { useEffect, useReducer, useState } from "react"; -import { filterMenuItems } from "@/core/utils/filterMenuItems"; -import { pageMenu } from "@/core/utils/pageMenu"; import SidebarListItems from "./SidebarListItems"; -import Profile from "@/core/components/Profile"; function selectPage(item, route) { if (item.type === "page") { @@ -53,16 +53,16 @@ function reducer(state, action) { return state.map((item) => item.hasSubitems ? { - ...item, - Subitems: item.Subitems.map((subitem) => - subitem.hasSubitems - ? { - ...subitem, - Subitems: toggleSubitems(subitem.Subitems, action.id), - } - : subitem - ), - } + ...item, + Subitems: item.Subitems.map((subitem) => + subitem.hasSubitems + ? { + ...subitem, + Subitems: toggleSubitems(subitem.Subitems, action.id), + } + : subitem + ), + } : item ); diff --git a/src/components/layouts/dashboard/headerWithSidebar/index.jsx b/src/components/layouts/dashboard/headerWithSidebar/index.jsx index 4b58b78..bb6c33e 100644 --- a/src/components/layouts/dashboard/headerWithSidebar/index.jsx +++ b/src/components/layouts/dashboard/headerWithSidebar/index.jsx @@ -8,8 +8,11 @@ import HeaderMenu from "./HeaderMenu"; import moment from "jalali-moment"; import { headerMenu } from "@/core/utils/headerMenu"; import SidebarMenu from "./Sidebar/SidebarMenu"; +import Teleporting from "@/core/components/Teleporting"; +import { usePermissions } from "@/lib/hooks/usePermissions"; +import WithWidgetMiddleware from "@/core/middlewares/withWidget"; -const drawerWidth = 300; +const drawerWidth = 270; const Main = styled(Stack, { shouldForwardProp: (prop) => prop !== "open" })(({ theme, open }) => ({ flexGrow: 1, @@ -50,11 +53,13 @@ const DrawerHeader = styled("div")(({ theme }) => ({ alignItems: "center", padding: theme.spacing(0, 1), ...theme.mixins.toolbar, - minHeight: "40px !important", + minHeight: "43px !important", justifyContent: "flex-end", })); const HeaderWithSidebar = ({ children }) => { + const { data: permissions } = usePermissions(); + const isTeleportToProvince = permissions?.some((permission) => permission === "teleport_to_province"); const theme = useTheme(); const isMobile = useMediaQuery(theme.breakpoints.down("md")); // Detect mobile/tablet screen const [open, setOpen] = useState(!isMobile); // Initial state based on screen size @@ -103,9 +108,16 @@ const HeaderWithSidebar = ({ children }) => { }, }} > - {headerMenu.map((menu) => ( - - ))} + + + {headerMenu.map((menu) => ( + + ))} + + + + + diff --git a/src/core/components/Teleporting/index.jsx b/src/core/components/Teleporting/index.jsx new file mode 100644 index 0000000..2713547 --- /dev/null +++ b/src/core/components/Teleporting/index.jsx @@ -0,0 +1,102 @@ +import { GET_TOKEN_TELEPORT_USER_ROUTE } from "@/core/utils/routes"; +import { useAuth } from "@/lib/contexts/auth"; +import useProvinces from "@/lib/hooks/useProvince"; +import useRequest from "@/lib/hooks/useRequest"; +import { Apartment } from "@mui/icons-material"; +import { Box, CircularProgress, FormControl, InputLabel, MenuItem, Select, Stack, Typography, Zoom } from "@mui/material"; +import { useMemo, useState } from "react"; + +const Teleporting = () => { + const { user } = useAuth() + const { provinces, errorProvinces, loadingProvinces } = useProvinces() + const getColumnSelectOptions = useMemo(() => { + if (loadingProvinces) { + return [{ value: "loading", label: "در حال بارگذاری..." }]; + } + if (errorProvinces) { + return [{ value: "error", label: "خطا در بارگذاری" }]; + } + return [ + ...provinces.map((province) => ({ + value: province.id, + label: province.name, + })), + ]; + }, [provinces, errorProvinces, loadingProvinces]); + const requestServer = useRequest(); + const [loading, setLoading] = useState(false); + const [province, setProvince] = useState(user.server_province_id); + + const handleChange = async ({ target: { value } }) => { + setLoading(true); + setProvince(value) + try { + const { data } = await requestServer(GET_TOKEN_TELEPORT_USER_ROUTE, "post", { + data: { + province_id: value + }, + }); + + const url = `http://${data.data.ip}/teleport` + const params = `?token=${encodeURIComponent(data.data.token)}&user_id=${encodeURIComponent(data.data.user_id)}`; + window.location.href = url + params + } catch (error) { + setLoading(false); + setProvince(user.server_province_id) + } + }; + + if (loading) { + return ( + + + + در حال انتقال به {provinces.find(p => p.id == province).name} + + + ); + } + + return ( + + + مرکز + + + + ); +}; + +export default Teleporting; \ No newline at end of file diff --git a/src/core/utils/routes.js b/src/core/utils/routes.js index ba43bad..c92a570 100644 --- a/src/core/utils/routes.js +++ b/src/core/utils/routes.js @@ -1,5 +1,8 @@ const api = process.env.NEXT_PUBLIC_API_URL; +export const TELEPORT_USER_ROUTE = api + "/verify_authentication"; +export const GET_TOKEN_TELEPORT_USER_ROUTE = api + "/login_to_province"; + export const GET_USER_ROUTE = api + "/profile/info"; export const CHANGE_USER_PASSWORD = api + "/profile/change_password"; export const GET_USER_LOGIN_ROUTE = api + "/auth/login"; diff --git a/src/lib/contexts/auth.js b/src/lib/contexts/auth.js index 90e97e3..eae28e0 100644 --- a/src/lib/contexts/auth.js +++ b/src/lib/contexts/auth.js @@ -36,6 +36,7 @@ const AuthContext = createContext(); export const AuthProvider = ({ children }) => { const [errorState, setErrorState] = useState({ status: null, message: "" }); const [state, dispatch] = useReducer(authReducer, initAuth); + const [tokenChecked, setTokenChecked] = useState(false); const clearUser = useCallback(() => { dispatch({ type: "CLEAR_USER" }); @@ -95,9 +96,12 @@ export const AuthProvider = ({ children }) => { useEffect(() => { const localToken = localStorage.getItem("_token"); if (localToken) dispatch({ type: "SET_TOKEN", token: localToken }); + setTokenChecked(true); }, []); useEffect(() => { + if (!tokenChecked) return; + if (!state.token) { clearUser(); changeAuthState(false); @@ -105,7 +109,7 @@ export const AuthProvider = ({ children }) => { return; } getUser(); - }, [state.token]); + }, [tokenChecked, state.token]); return (