Merge branch 'feature/remove_tel_number' into 'develop'

complete role page with show/store/update and delete actions and remove tel number from login page and add it to user page and add prettier to format the code as code formatter

See merge request witel-front-end/crm-app!45
This commit is contained in:
2025-07-29 12:30:26 +00:00
199 changed files with 16211 additions and 14778 deletions

2
.gitignore vendored
View File

@@ -31,7 +31,7 @@ yarn-error.log*
.pnpm-debug.log*
# env files (can opt-in for committing if needed)
.env*
.env
# vercel
.vercel

8
.idea/.gitignore generated vendored Normal file
View File

@@ -0,0 +1,8 @@
# Default ignored files
/shelf/
/workspace.xml
# Editor-based HTTP Client requests
/httpRequests/
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml

47
.idea/codeStyles/Project.xml generated Normal file
View File

@@ -0,0 +1,47 @@
<component name="ProjectCodeStyleConfiguration">
<code_scheme name="Project" version="173">
<option name="LINE_SEPARATOR" value="&#13;&#10;" />
<HTMLCodeStyleSettings>
<option name="HTML_SPACE_INSIDE_EMPTY_TAG" value="true" />
</HTMLCodeStyleSettings>
<JSCodeStyleSettings version="0">
<option name="FORCE_SEMICOLON_STYLE" value="true" />
<option name="SPACE_BEFORE_FUNCTION_LEFT_PARENTH" value="false" />
<option name="FORCE_QUOTE_STYlE" value="true" />
<option name="ENFORCE_TRAILING_COMMA" value="WhenMultiline" />
<option name="SPACES_WITHIN_OBJECT_LITERAL_BRACES" value="true" />
<option name="SPACES_WITHIN_IMPORTS" value="true" />
</JSCodeStyleSettings>
<TypeScriptCodeStyleSettings version="0">
<option name="FORCE_SEMICOLON_STYLE" value="true" />
<option name="SPACE_BEFORE_FUNCTION_LEFT_PARENTH" value="false" />
<option name="FORCE_QUOTE_STYlE" value="true" />
<option name="ENFORCE_TRAILING_COMMA" value="WhenMultiline" />
<option name="SPACES_WITHIN_OBJECT_LITERAL_BRACES" value="true" />
<option name="SPACES_WITHIN_IMPORTS" value="true" />
</TypeScriptCodeStyleSettings>
<VueCodeStyleSettings>
<option name="INTERPOLATION_NEW_LINE_AFTER_START_DELIMITER" value="false" />
<option name="INTERPOLATION_NEW_LINE_BEFORE_END_DELIMITER" value="false" />
</VueCodeStyleSettings>
<codeStyleSettings language="HTML">
<option name="SOFT_MARGINS" value="120" />
<indentOptions>
<option name="CONTINUATION_INDENT_SIZE" value="4" />
</indentOptions>
</codeStyleSettings>
<codeStyleSettings language="JavaScript">
<option name="SOFT_MARGINS" value="120" />
</codeStyleSettings>
<codeStyleSettings language="TypeScript">
<option name="SOFT_MARGINS" value="120" />
</codeStyleSettings>
<codeStyleSettings language="Vue">
<option name="SOFT_MARGINS" value="120" />
<indentOptions>
<option name="INDENT_SIZE" value="4" />
<option name="TAB_SIZE" value="4" />
</indentOptions>
</codeStyleSettings>
</code_scheme>
</component>

5
.idea/codeStyles/codeStyleConfig.xml generated Normal file
View File

@@ -0,0 +1,5 @@
<component name="ProjectCodeStyleConfiguration">
<state>
<option name="USE_PER_PROJECT_SETTINGS" value="true" />
</state>
</component>

12
.idea/crm-app.iml generated Normal file
View File

@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="WEB_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$">
<excludeFolder url="file://$MODULE_DIR$/.tmp" />
<excludeFolder url="file://$MODULE_DIR$/temp" />
<excludeFolder url="file://$MODULE_DIR$/tmp" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

View File

@@ -0,0 +1,7 @@
<component name="InspectionProjectProfileManager">
<profile version="1.0">
<option name="myName" value="Project Default" />
<inspection_tool class="Eslint" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="JSAnnotator" enabled="false" level="ERROR" enabled_by_default="false" />
</profile>
</component>

8
.idea/modules.xml generated Normal file
View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/crm-app.iml" filepath="$PROJECT_DIR$/.idea/crm-app.iml" />
</modules>
</component>
</project>

6
.idea/vcs.xml generated Normal file
View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="" vcs="Git" />
</component>
</project>

12
.prettierrc Normal file
View File

@@ -0,0 +1,12 @@
{
"printWidth": 120,
"tabWidth": 4,
"useTabs": false,
"semi": true,
"singleQuote": false,
"trailingComma": "es5",
"bracketSpacing": true,
"jsxBracketSameLine": false,
"arrowParens": "always",
"endOfLine": "crlf"
}

View File

@@ -1,4 +1,4 @@
version: '3.8'
version: "3.8"
services:
nextjs:
@@ -13,5 +13,5 @@ services:
ports:
- "3000:3000"
env_file:
- .env.local
- .env
restart: unless-stopped

View File

@@ -7,7 +7,7 @@
"build": "next build",
"start": "next start",
"lint": "next lint",
"format": "prettier --write \"src/**/*.{js,jsx,ts,tsx,html,css,scss}\""
"format": "npx prettier . --write"
},
"dependencies": {
"@emotion/cache": "^11.14.0",

4972
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,16 @@
import RolesPage from "@/components/dashboard/Roles";
import WithPermission from "@/core/middlewares/withPermission";
export const metadata = {
title: "نقش ها",
};
const Page = () => {
return (
<WithPermission permission_name={["manage_roles"]}>
<RolesPage />
</WithPermission>
);
};
export default Page;

View File

@@ -9,9 +9,7 @@ import { SWRConfig } from "swr";
const Layout = ({ children }) => {
const { data: permissions } = usePermissions();
const isCallWidgetEnabled = permissions?.some(
(permission) => permission === "manage_calls",
);
const isCallWidgetEnabled = permissions?.some((permission) => permission === "manage_calls");
return (
<SocketProvider>

View File

@@ -18,10 +18,7 @@ export default function RootLayout({ children }) {
<link rel="icon" href={favicon.src} type="image/png" sizes="any" />
</head>
<body style={{ height: "100vh", width: "100vw" }}>
<AppRouterCacheProvider
CacheProvider={Rtl}
options={{ enableCssLayer: true }}
>
<AppRouterCacheProvider CacheProvider={Rtl} options={{ enableCssLayer: true }}>
<AuthProvider>
<TableSettingProvider>{children}</TableSettingProvider>
</AuthProvider>

View File

@@ -4,12 +4,7 @@ import SvgNotFound from "@/core/components/svgs/SvgNotFound";
export default function NotFound() {
return (
<Stack
sx={{ height: "100%" }}
justifyContent={"center"}
alignItems={"center"}
spacing={2}
>
<Stack sx={{ height: "100%" }} justifyContent={"center"} alignItems={"center"} spacing={2}>
<Box>
<SvgNotFound width={200} height={200} />
</Box>

View File

@@ -4,14 +4,10 @@
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");
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 {
@@ -20,14 +16,10 @@
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");
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 {
@@ -36,14 +28,10 @@
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");
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 {
@@ -52,14 +40,10 @@
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");
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 {
@@ -68,14 +52,10 @@
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");
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 {
@@ -84,13 +64,10 @@
font-weight: normal;
src: url("../fonts/eot/IRANSansWeb(FaNum).eot");
src:
url("../fonts/eot/IRANSansWeb(FaNum).eot?#iefix")
format("embedded-opentype"),
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");
/* 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 {
@@ -101,10 +78,8 @@
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");
/* 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 {
@@ -115,10 +90,8 @@
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");
/* 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 {
@@ -127,13 +100,10 @@
font-weight: 500;
src: url("../fonts/eot/IRANSansWeb_Medium.eot");
src:
url("../fonts/eot/IRANSansWeb_Medium.eot?#iefix")
format("embedded-opentype"),
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");
/* 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 {
@@ -144,10 +114,8 @@
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");
/* 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 {
@@ -156,14 +124,10 @@
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");
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 {
@@ -174,10 +138,8 @@
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");
/* 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 {
@@ -188,8 +150,7 @@
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");
/* FF3.6+, IE9, Chrome6+, Saf5.1+*/ url("../fonts/ttf/Parastoo.ttf") format("truetype");
}
@font-face {
@@ -200,8 +161,7 @@
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");
/* FF3.6+, IE9, Chrome6+, Saf5.1+*/ url("../fonts/ttf/Parastoo-Bold.ttf") format("truetype");
}
@font-face {

View File

@@ -5,21 +5,8 @@ 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 {
Lock,
Person,
PhoneCallback,
Visibility,
VisibilityOff,
} from "@mui/icons-material";
import {
Button,
Container,
IconButton,
InputAdornment,
Stack,
Typography,
} from "@mui/material";
import { Lock, Person, PhoneCallback, Visibility, VisibilityOff } from "@mui/icons-material";
import { Button, Container, IconButton, InputAdornment, Stack, Typography } from "@mui/material";
import { useState } from "react";
import { Controller, useForm } from "react-hook-form";
import { object, string } from "yup";
@@ -31,13 +18,11 @@ const LoginForm = () => {
const defaultValues = {
username: "",
password: "",
telephone_id: "",
};
const validationSchema = object({
username: string().required("لطفا نام کاربری را وارد کنید!"),
password: string().required("لطفا رمز عبور را وارد کنید!"),
telephone_id: string().required("لطفا شماره تماس داخلی را وارد کنید!"),
});
const {
@@ -57,7 +42,6 @@ const LoginForm = () => {
const formData = new FormData();
formData.append("username", data.username);
formData.append("password", data.password);
formData.append("telephone_id", data.telephone_id);
await requestServer(GET_USER_LOGIN_ROUTE, "post", {
data: formData,
});
@@ -67,27 +51,10 @@ const LoginForm = () => {
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"
>
<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>
@@ -132,11 +99,7 @@ const LoginForm = () => {
startAdornment: (
<InputAdornment position="start">
<IconButton onClick={handleClickShowPassword}>
{showPassword ? (
<VisibilityOff />
) : (
<Visibility />
)}
{showPassword ? <VisibilityOff /> : <Visibility />}
</IconButton>
</InputAdornment>
),
@@ -155,32 +118,6 @@ const LoginForm = () => {
}}
name={"password"}
/>
<Controller
control={control}
render={({ field, fieldState: { error } }) => {
return (
<LtrTextField
{...field}
label="شماره تماس داخلی"
variant="outlined"
type="tel"
slotProps={{
input: {
endAdornment: (
<InputAdornment position="end">
<PhoneCallback />
</InputAdornment>
),
},
}}
fullWidth
error={!!error}
helperText={!!error && error.message}
/>
);
}}
name={"telephone_id"}
/>
</Stack>
<Stack>
<Button

View File

@@ -0,0 +1,90 @@
"use client";
import DataTableWithAuth from "@/core/components/DataTableWithAuth";
import { GET_ROLE_LIST } from "@/core/utils/routes";
import { Box, Typography } from "@mui/material";
import { useMemo } from "react";
import Toolbar from "./Toolbar";
import moment from "jalali-moment";
import RowActions from "./RowAcctions";
const DataTable = () => {
const columns = useMemo(
() => [
{
accessorKey: "id",
header: "کد یکتا",
id: "id",
enableColumnFilter: true,
datatype: "text",
filterMode: "equals",
sortDescFirst: false,
columnFilterModeOptions: ["equals", "contains"],
grow: false,
size: 100,
},
{
accessorKey: "name_fa",
header: "نام",
id: "name_fa",
enableColumnFilter: true,
datatype: "text",
filterMode: "equals",
sortDescFirst: false,
columnFilterModeOptions: ["equals", "contains"],
grow: false,
size: 100,
},
{
accessorKey: "created_at",
header: "تاریخ ساخت",
id: "created_at",
enableColumnFilter: false,
datatype: "date",
filterMode: "equals",
grow: false,
size: 100,
Cell: ({ renderedCellValue }) => (
<Typography variant="body2">
{renderedCellValue ? moment(renderedCellValue).locale("fa").format("HH:mm | YYYY/MM/DD") : "-"}
</Typography>
),
},
{
accessorKey: "updated_at",
header: "تاریخ آخرین بروزرسانی",
id: "updated_at",
enableColumnFilter: false,
datatype: "date",
filterMode: "equals",
grow: false,
size: 100,
Cell: ({ renderedCellValue }) => (
<Typography variant="body2">
{renderedCellValue ? moment(renderedCellValue).locale("fa").format("HH:mm | YYYY/MM/DD") : "-"}
</Typography>
),
},
],
[]
);
return (
<>
<Box sx={{ p: 1, border: 1, borderColor: "divider", borderRadius: 1 }}>
<DataTableWithAuth
need_filter={true}
columns={columns}
sorting={[{ id: "id", desc: true }]}
table_url={GET_ROLE_LIST}
page_name={"rolesPage"}
table_name={"rolesList"}
TableToolbar={Toolbar}
enableRowActions
positionActionsColumn={"last"}
RowActions={RowActions}
/>
</Box>
</>
);
};
export default DataTable;

View File

@@ -0,0 +1,39 @@
import { DELETE_ROLE } from "@/core/utils/routes";
import useRequest from "@/lib/hooks/useRequest";
import { Button, DialogActions, DialogContent, Stack, Typography } from "@mui/material";
import { useState } from "react";
const DeleteContent = ({ rowId, mutate, setOpenDeleteDialog }) => {
const [submitting, setSubmitting] = useState(false);
const requestServer = useRequest({ notificationSuccess: true });
const handleClick = async () => {
setSubmitting(true);
try {
await requestServer(`${DELETE_ROLE}/${rowId}`, "delete");
mutate();
setOpenDeleteDialog(false);
} catch (error) {
} finally {
setSubmitting(false);
}
};
return (
<>
<DialogContent>
<Stack alignItems="center" spacing={2}>
<Typography mt={2}>آیا از حذف کاربر اطمینان دارید؟</Typography>
</Stack>
</DialogContent>
<DialogActions sx={{ justifyContent: "center", paddingBottom: 2, width: "100%" }}>
<Button onClick={() => setOpenDeleteDialog(false)} variant="outlined" color="secondary">
خیر !
</Button>
<Button onClick={handleClick} variant="contained" color="error" disabled={submitting}>
{submitting ? "درحال حذف..." : "بله اطمینان دارم"}
</Button>
</DialogActions>
</>
);
};
export default DeleteContent;

View File

@@ -0,0 +1,32 @@
import DeleteIcon from "@mui/icons-material/Delete";
import { Dialog, DialogTitle, IconButton, Tooltip } from "@mui/material";
import { useState } from "react";
import DeleteContent from "./DeleteContent";
const Delete = ({ rowId, mutate }) => {
const [openDeleteDialog, setOpenDeleteDialog] = useState(false);
return (
<>
<Tooltip title="حذف">
<IconButton color="error" onClick={() => setOpenDeleteDialog(true)}>
<DeleteIcon />
</IconButton>
</Tooltip>
<Dialog
open={openDeleteDialog}
onClose={() => setOpenDeleteDialog(false)}
PaperProps={{
sx: {
boxShadow: "rgba(60, 64, 67, 0.3) 0px 1px 16px 0px, rgba(60, 64, 67, 0.15) 0px 1px 10px 0px",
},
}}
dir="rtl"
maxWidth={"md"}
>
<DialogTitle>حذف</DialogTitle>
<DeleteContent rowId={rowId} mutate={mutate} setOpenDeleteDialog={setOpenDeleteDialog} />
</Dialog>
</>
);
};
export default Delete;

View File

@@ -0,0 +1,186 @@
import LtrTextField from "@/core/components/LtrTextField";
import StyledForm from "@/core/components/StyledForm";
import { CREATE_ROLE } from "@/core/utils/routes";
import useRequest from "@/lib/hooks/useRequest";
import { yupResolver } from "@hookform/resolvers/yup";
import {
Box,
Button,
Checkbox,
Chip,
DialogActions,
DialogContent,
Divider,
FormControlLabel,
FormHelperText,
Grid,
Skeleton,
Stack,
} from "@mui/material";
import { Controller, useForm } from "react-hook-form";
import { array, object, string } from "yup";
import usePermissionsList from "@/lib/hooks/usePermissionsList";
const validationSchema = object().shape({
name: string().required("نام فارسی نقش را وارد کنید"),
name_fa: string().required("نام انگلیسی نقش را وارد کنید"),
permissions: array().min(1, "حداقل یک دسترسی را انتخاب نمایید")
});
const UpdateRoleForm = ({ values, setOpen, mutate }) => {
const requestServer = useRequest({ notificationSuccess: true });
const { permissions, loadingPermissions } = usePermissionsList();
const defaultValues = {
name: values.name,
name_fa: values.name_fa,
permissions: values.permissions?.map(p => p.id) || []
};
const {
control,
handleSubmit,
formState: { isSubmitting, errors },
} = useForm({ defaultValues, resolver: yupResolver(validationSchema) });
const onSubmit = async (data) => {
try {
await requestServer(`${CREATE_ROLE}/${values.id}`, "post", {
data: {
permissions: data.permissions,
name: data.name,
name_fa: data.name_fa,
},
});
setOpen(false);
mutate();
} catch (error) {}
};
return (
<>
<DialogContent dividers>
<Divider sx={{ mb: 3 }}>
<Chip color="primary" variant="outlined" label="کاربر جدید" />
</Divider>
<StyledForm
id="UpdateRoleForm"
onSubmit={handleSubmit(onSubmit)}
style={{ width: "100%", height: "100%" }}
>
<Stack spacing={2}>
<Grid container spacing={2}>
<Grid size={{ xs: 12, md: 6 }}>
<Controller
control={control}
render={({ field, fieldState: { error } }) => {
return (
<LtrTextField
{...field}
label="نام انگلیسی نقش"
variant="outlined"
fullWidth
error={!!error}
helperText={!!error && error.message}
/>
);
}}
name={"name"}
/>
</Grid>
<Grid size={{ xs: 12, md: 6 }}>
<Controller
control={control}
render={({ field, fieldState: { error } }) => {
return (
<LtrTextField
{...field}
label="نام فارسی نقش"
variant="outlined"
fullWidth
error={!!error}
helperText={!!error && error.message}
/>
);
}}
name={"name_fa"}
/>
</Grid>
<Box sx={{width: "100%"}}>
<Divider>
<Chip label="سطوح دسترسی" size="medium" />
</Divider>
</Box>
<Grid container spacing={1} sx={{width: "100%"}}>
{!loadingPermissions ? (
<Controller
control={control}
name="permissions"
render={({ field, fieldState: {error} }) => (
<>
{permissions.map((permission) => (
<Grid key={permission.id} size={{ xs: 12, md: 4 }}>
<FormControlLabel
control={
<Checkbox
value={permission.id}
checked={field.value.includes(permission.id)}
onChange={(e) => {
const value = parseInt(e.target.value, 10);
if (e.target.checked) {
field.onChange([...field.value, value]);
} else {
field.onChange(field.value.filter((id) => id !== value));
}
}}
/>
}
label={permission.name_fa}
/>
</Grid>
))}
<FormHelperText sx={{color: "error.main"}}>{!!error && error.message}</FormHelperText>
</>
)}
/>
) : (
<Grid container spacing={2} width="100%">
<Grid size={{ xs: 12, md: 4 }}><Skeleton animation="wave" /></Grid>
<Grid size={{ xs: 12, md: 4 }}><Skeleton animation="wave" /></Grid>
<Grid size={{ xs: 12, md: 4 }}><Skeleton animation="wave" /></Grid>
<Grid size={{ xs: 12, md: 4 }}><Skeleton animation="wave" /></Grid>
<Grid size={{ xs: 12, md: 4 }}><Skeleton animation="wave" /></Grid>
<Grid size={{ xs: 12, md: 4 }}><Skeleton animation="wave" /></Grid>
</Grid>
)}
</Grid>
</Grid>
</Stack>
</StyledForm>
</DialogContent>
<DialogActions>
<Button
disabled={isSubmitting}
variant="outlined"
color="secondary"
size="large"
onClick={() => setOpen(false)}
>
بستن
</Button>
<Button
type="submit"
disabled={isSubmitting}
form="UpdateRoleForm"
size="large"
autoFocus
variant="contained"
>
{isSubmitting ? "در حال ویرایش کاربر..." : "ویرایش کاربر"}
</Button>
</DialogActions>
</>
);
};
export default UpdateRoleForm;

View File

@@ -0,0 +1,27 @@
"use client";
import { Edit } from "@mui/icons-material";
import { Dialog, IconButton, Tooltip } from "@mui/material";
import { useState } from "react";
import UpdateUserForm from "./Form";
const UpdateUser = ({ values, mutate }) => {
const [open, setOpen] = useState(false);
const handleOpen = () => {
setOpen(true);
};
return (
<>
<Tooltip title="ویرایش">
<IconButton onClick={handleOpen}>
<Edit />
</IconButton>
</Tooltip>
<Dialog maxWidth="sm" fullWidth={true} open={open}>
<UpdateUserForm open={open} setOpen={setOpen} mutate={mutate} values={values} />
</Dialog>
</>
);
};
export default UpdateUser;

View File

@@ -0,0 +1,12 @@
import { Box } from "@mui/material";
import Delete from "./Delete";
import UpdateUser from "./Edit";
const RowActions = ({ row, mutate }) => {
return (
<Box sx={{ display: "flex", gap: 1, alignItems: "center" }}>
<Delete rowId={row.original.id} mutate={mutate} />
<UpdateUser values={row.original} mutate={mutate} />
</Box>
);
};
export default RowActions;

View File

@@ -0,0 +1,184 @@
import LtrTextField from "@/core/components/LtrTextField";
import StyledForm from "@/core/components/StyledForm";
import { yupResolver } from "@hookform/resolvers/yup";
import {
Box,
Button,
Checkbox,
Chip,
DialogActions,
DialogContent,
Divider,
FormControlLabel, FormHelperText,
Grid, Skeleton,
Stack,
} from "@mui/material";
import { Controller, useForm } from "react-hook-form";
import { array, object, string } from "yup";
import useRequest from "@/lib/hooks/useRequest";
import { CREATE_ROLE } from "@/core/utils/routes";
import usePermissionsList from "@/lib/hooks/usePermissionsList";
const defaultValues = {
name: "",
name_fa: "",
permissions: []
};
const validationSchema = object().shape({
name: string().required("نام فارسی نقش را وارد کنید"),
name_fa: string().required("نام انگلیسی نقش را وارد کنید"),
permissions: array().min(1, "حداقل یک دسترسی را انتخاب نمایید")
});
const CreateRoleForm = ({ setOpen, mutate }) => {
const requestServer = useRequest({ notificationSuccess: true });
const { permissions, loadingPermissions } = usePermissionsList();
const {
control,
handleSubmit,
formState: { isSubmitting, errors },
} = useForm({ defaultValues, resolver: yupResolver(validationSchema) });
const onSubmit = async (data) => {
try {
await requestServer(CREATE_ROLE, "post", {
data: {
permissions: data.permissions,
name: data.name,
name_fa: data.name_fa,
},
});
setOpen(false);
mutate();
} catch (error) {}
};
return (
<>
<DialogContent dividers>
<Divider sx={{ mb: 3 }}>
<Chip color="primary" variant="outlined" label="نقش جدید" />
</Divider>
<StyledForm
id="createRoleForm"
onSubmit={handleSubmit(onSubmit)}
style={{ width: "100%", height: "100%" }}
>
<Stack spacing={2}>
<Grid container spacing={2}>
<Grid size={{ xs: 12, md: 6 }}>
<Controller
control={control}
render={({ field, fieldState: { error } }) => {
return (
<LtrTextField
{...field}
label="نام انگلیسی نقش"
variant="outlined"
fullWidth
error={!!error}
helperText={!!error && error.message}
/>
);
}}
name={"name"}
/>
</Grid>
<Grid size={{ xs: 12, md: 6 }}>
<Controller
control={control}
render={({ field, fieldState: { error } }) => {
return (
<LtrTextField
{...field}
label="نام فارسی نقش"
variant="outlined"
fullWidth
error={!!error}
helperText={!!error && error.message}
/>
);
}}
name={"name_fa"}
/>
</Grid>
<Box sx={{width: "100%"}}>
<Divider>
<Chip label="سطوح دسترسی" size="medium" />
</Divider>
</Box>
<Grid container spacing={1} sx={{width: "100%"}}>
{!loadingPermissions ? (
<Controller
control={control}
name="permissions"
render={({ field, fieldState: {error} }) => (
<>
{permissions.map((permission) => (
<Grid key={permission.id} size={{ xs: 12, md: 4 }}>
<FormControlLabel
control={
<Checkbox
value={permission.id}
checked={field.value.includes(permission.id)}
onChange={(e) => {
const value = parseInt(e.target.value, 10);
if (e.target.checked) {
field.onChange([...field.value, value]);
} else {
field.onChange(field.value.filter((id) => id !== value));
}
}}
/>
}
label={permission.name_fa}
/>
</Grid>
))}
<FormHelperText sx={{color: "error.main"}}>{!!error && error.message}</FormHelperText>
</>
)}
/>
) : (
<Grid container spacing={2} width="100%">
<Grid size={{ xs: 12, md: 4 }}><Skeleton animation="wave" /></Grid>
<Grid size={{ xs: 12, md: 4 }}><Skeleton animation="wave" /></Grid>
<Grid size={{ xs: 12, md: 4 }}><Skeleton animation="wave" /></Grid>
<Grid size={{ xs: 12, md: 4 }}><Skeleton animation="wave" /></Grid>
<Grid size={{ xs: 12, md: 4 }}><Skeleton animation="wave" /></Grid>
<Grid size={{ xs: 12, md: 4 }}><Skeleton animation="wave" /></Grid>
</Grid>
)}
</Grid>
</Grid>
</Stack>
</StyledForm>
</DialogContent>
<DialogActions>
<Button
disabled={isSubmitting}
variant="outlined"
color="secondary"
size="large"
onClick={() => setOpen(false)}
>
بستن
</Button>
<Button
type="submit"
disabled={isSubmitting}
form="createRoleForm"
size="large"
autoFocus
variant="contained"
>
{isSubmitting ? "در حال ثبت نقش جدید..." : "ثبت نقش جدید"}
</Button>
</DialogActions>
</>
);
};
export default CreateRoleForm;

View File

@@ -0,0 +1,39 @@
"use client";
import { AddCircle } from "@mui/icons-material";
import { Button, Dialog, IconButton, useMediaQuery, useTheme } from "@mui/material";
import CreateRoleForm from "./Form";
import { useState } from "react";
const CreateRole = ({ mutate }) => {
const theme = useTheme();
const isMobile = useMediaQuery(theme.breakpoints.down("sm"));
const [open, setOpen] = useState(false);
const handleOpen = () => {
setOpen(true);
};
return (
<>
{isMobile ? (
<IconButton aria-label="نقش جدید" color="primary" onClick={handleOpen}>
<AddCircle sx={{ fontSize: "25px" }} />
</IconButton>
) : (
<Button
size={"small"}
variant="contained"
color="primary"
startIcon={<AddCircle />}
onClick={handleOpen}
>
نقش جدید
</Button>
)}
<Dialog maxWidth="sm" fullWidth={true} open={open}>
<CreateRoleForm open={open} setOpen={setOpen} mutate={mutate} />
</Dialog>
</>
);
};
export default CreateRole;

View File

@@ -0,0 +1,10 @@
import CreateRole from "./Create";
const Toolbar = ({ mutate }) => {
return (
<>
<CreateRole mutate={mutate} />
</>
);
};
export default Toolbar;

View File

@@ -0,0 +1,14 @@
import PageTitle from "@/core/components/PageTitle";
import { Stack } from "@mui/material";
import DataTable from "./DataTable";
const RolesPage = () => {
return (
<Stack spacing={1}>
<PageTitle title={"نقش ها"} />
<DataTable />
</Stack>
);
};
export default RolesPage;

View File

@@ -73,8 +73,7 @@ const DataTable = () => {
grow: false,
size: 130,
ColumnSelectComponent: (props) => {
const { provinces, errorProvinces, loadingProvinces } =
useProvinces();
const { provinces, errorProvinces, loadingProvinces } = useProvinces();
const getColumnSelectOptions = useMemo(() => {
if (loadingProvinces) {
return [{ value: "loading", label: "در حال بارگذاری..." }];
@@ -93,9 +92,7 @@ const DataTable = () => {
return (
<CustomSelectByDependency
{...props}
value={
loadingProvinces ? "loading" : props.filterParameters.value
}
value={loadingProvinces ? "loading" : props.filterParameters.value}
columnSelectOption={getColumnSelectOptions}
/>
);
@@ -187,12 +184,10 @@ const DataTable = () => {
enableColumnFilter: false,
grow: false,
size: 100,
Cell: ({ renderedCellValue }) => (
<>{renderedCellValue == "male" ? "آقا" : "خانم"}</>
),
Cell: ({ renderedCellValue }) => <>{renderedCellValue == "male" ? "آقا" : "خانم"}</>,
},
],
[],
[]
);
return (

View File

@@ -1,12 +1,6 @@
import { DELETE_USER } from "@/core/utils/routes";
import useRequest from "@/lib/hooks/useRequest";
import {
Button,
DialogActions,
DialogContent,
Stack,
Typography,
} from "@mui/material";
import { Button, DialogActions, DialogContent, Stack, Typography } from "@mui/material";
import { useState } from "react";
const DeleteContent = ({ rowId, mutate, setOpenDeleteDialog }) => {
@@ -30,22 +24,11 @@ const DeleteContent = ({ rowId, mutate, setOpenDeleteDialog }) => {
<Typography mt={2}>آیا از حذف کاربر اطمینان دارید؟</Typography>
</Stack>
</DialogContent>
<DialogActions
sx={{ justifyContent: "center", paddingBottom: 2, width: "100%" }}
>
<Button
onClick={() => setOpenDeleteDialog(false)}
variant="outlined"
color="secondary"
>
<DialogActions sx={{ justifyContent: "center", paddingBottom: 2, width: "100%" }}>
<Button onClick={() => setOpenDeleteDialog(false)} variant="outlined" color="secondary">
خیر !
</Button>
<Button
onClick={handleClick}
variant="contained"
color="error"
disabled={submitting}
>
<Button onClick={handleClick} variant="contained" color="error" disabled={submitting}>
{submitting ? "درحال حذف..." : "بله اطمینان دارم"}
</Button>
</DialogActions>

View File

@@ -17,19 +17,14 @@ const Delete = ({ rowId, mutate }) => {
onClose={() => setOpenDeleteDialog(false)}
PaperProps={{
sx: {
boxShadow:
"rgba(60, 64, 67, 0.3) 0px 1px 16px 0px, rgba(60, 64, 67, 0.15) 0px 1px 10px 0px",
boxShadow: "rgba(60, 64, 67, 0.3) 0px 1px 16px 0px, rgba(60, 64, 67, 0.15) 0px 1px 10px 0px",
},
}}
dir="rtl"
maxWidth={"md"}
>
<DialogTitle>حذف</DialogTitle>
<DeleteContent
rowId={rowId}
mutate={mutate}
setOpenDeleteDialog={setOpenDeleteDialog}
/>
<DeleteContent rowId={rowId} mutate={mutate} setOpenDeleteDialog={setOpenDeleteDialog} />
</Dialog>
</>
);

View File

@@ -27,25 +27,20 @@ import { Controller, useForm } from "react-hook-form";
import { object, string } from "yup";
const validationSchema = object().shape({
full_name: string().required("نام و نام خانوادگی خود را وارد کنید"),
username: string().required("نام کاربری خود را وارد کنید"),
full_name: string().required("نام و نام خانوادگی را وارد کنید"),
username: string().required("نام کاربری را وارد کنید"),
phone_number: string()
.matches(/^09\d{9}$/, "شماره همراه باید با 09 شروع شود و 11 رقم باشد.")
.required("شماره همراه خود را وارد کنید"),
gender: string().required("جنسیت خود را وارد کنید"),
.required("شماره همراه را وارد کنید"),
gender: string().required("جنسیت را وارد کنید"),
national_id: string()
.test(
"max",
"کد ملی باید شامل 10 رقم باشد",
(value) => value.toString().length === 10,
)
.test("validation", "کد ملی صحیح نمی باشد", (value) =>
validateNationalCode(value),
)
.required("کد ملی خود را وارد کنید"),
position: string().required("سمت خود را وارد کنید"),
province_id: string().required("استان خود را وارد کنید"),
role_id: string().required("نقش خود را وارد کنید"),
.test("max", "کد ملی باید شامل 10 رقم باشد", (value) => value.toString().length === 10)
.test("validation", "کد ملی صحیح نمی باشد", (value) => validateNationalCode(value))
.required("کد ملی را وارد کنید"),
position: string().required("سمت را وارد کنید"),
province_id: string().required("استان را وارد کنید"),
role_id: string().required("نقش را وارد کنید"),
telephone_id: string().required("شماره تماس داخلی را وارد کنید")
});
const UpdateUserForm = ({ values, setOpen, mutate }) => {
@@ -62,6 +57,7 @@ const UpdateUserForm = ({ values, setOpen, mutate }) => {
phone_number: values.phone_number,
province_id: values.province_id,
role_id: values.roles[0].id,
telephone_id: values.telephone_id
};
const provinceSelectOptions = useMemo(() => {
@@ -218,12 +214,12 @@ const UpdateUserForm = ({ values, setOpen, mutate }) => {
render={({ field, fieldState: { error } }) => {
return (
<FormControl fullWidth error={!!error}>
<InputLabel id={`label-phone-number`} shrink>
<InputLabel id={`label-gender`} shrink>
جنسیت
</InputLabel>
<Select
labelId={`label-phone-number`}
id={"phone-number"}
labelId={`label-gender`}
id={"gender"}
name={`gender`}
value={field.value}
input={<OutlinedInput label={"جنسیت"} />}
@@ -337,6 +333,25 @@ const UpdateUserForm = ({ values, setOpen, mutate }) => {
name={"role_id"}
/>
</Grid>
<Grid size={{ xs: 12, md: 6 }}>
<Controller
control={control}
render={({ field, fieldState: { error } }) => {
return (
<LtrTextField
{...field}
label="شماره تماس داخلی"
variant="outlined"
fullWidth
type="tel"
error={!!error}
helperText={!!error && error.message}
/>
);
}}
name={"telephone_id"}
/>
</Grid>
</Grid>
</Stack>
</StyledForm>

View File

@@ -19,12 +19,7 @@ const UpdateUser = ({ values, mutate }) => {
</IconButton>
</Tooltip>
<Dialog maxWidth="sm" fullWidth={true} open={open}>
<UpdateUserForm
open={open}
setOpen={setOpen}
mutate={mutate}
values={values}
/>
<UpdateUserForm open={open} setOpen={setOpen} mutate={mutate} values={values} />
</Dialog>
</>
);

View File

@@ -6,11 +6,7 @@ const OnlineCell = ({ user_id }) => {
const { clientsOnline } = useSocket();
return (
<Stack alignItems={"center"}>
{clientsOnline.some((co) => co.user_id == user_id) ? (
<Power color="success" />
) : (
<PowerOff color="error" />
)}
{clientsOnline.some((co) => co.user_id == user_id) ? <Power color="success" /> : <PowerOff color="error" />}
</Stack>
);
};

View File

@@ -3,9 +3,7 @@ import { Stack } from "@mui/material";
const TelephoneId = ({ user_id }) => {
const { clientsOnline } = useSocket();
const telephone_id = clientsOnline.find(
(co) => co.user_id == user_id,
)?.telephone_id;
const telephone_id = clientsOnline.find((co) => co.user_id == user_id)?.telephone_id;
return <Stack alignItems={"center"}>{telephone_id}</Stack>;
};
export default TelephoneId;

View File

@@ -39,34 +39,27 @@ const defaultValues = {
province_id: "",
password: "",
role_id: "",
telephone_id: "",
};
const validationSchema = object().shape({
full_name: string().required("نام و نام خانوادگی خود را وارد کنید"),
username: string().required("نام کاربری خود را وارد کنید"),
full_name: string().required("نام و نام خانوادگی را وارد کنید"),
username: string().required("نام کاربری را وارد کنید"),
phone_number: string()
.matches(/^09\d{9}$/, "شماره همراه باید با 09 شروع شود و 11 رقم باشد.")
.required("شماره همراه خود را وارد کنید"),
gender: string().required("جنسیت خود را وارد کنید"),
.required("شماره همراه را وارد کنید"),
gender: string().required("جنسیت را وارد کنید"),
national_id: string()
.test(
"max",
"کد ملی باید شامل 10 رقم باشد",
(value) => value.toString().length === 10,
)
.test("validation", "کد ملی صحیح نمی باشد", (value) =>
validateNationalCode(value),
)
.required("کد ملی خود را وارد کنید"),
.test("max", "کد ملی باید شامل 10 رقم باشد", (value) => value.toString().length === 10)
.test("validation", "کد ملی صحیح نمی باشد", (value) => validateNationalCode(value))
.required("کد ملی را وارد کنید"),
password: string()
.required("رمز عبور خود را وارد کنید")
.matches(
/^(?=.*[a-zA-Z])(?=.*\d).{8,}$/,
"رمز عبور باید حداقل 8 کاراکتر و متشکل از عدد، حرف یا سمبل باشد",
),
position: string().required("سمت خود را وارد کنید"),
province_id: string().required("استان خود را وارد کنید"),
role_id: string().required("نقش خود را وارد کنید"),
.required("رمز عبور را وارد کنید")
.matches(/^(?=.*[a-zA-Z])(?=.*\d).{8,}$/, "رمز عبور باید حداقل 8 کاراکتر و متشکل از عدد، حرف یا سمبل باشد"),
position: string().required("سمت را وارد کنید"),
province_id: string().required("استان را وارد کنید"),
role_id: string().required("نقش را وارد کنید"),
telephone_id: string().required("شماره تماس داخلی را وارد کنید"),
});
const CreateUserForm = ({ setOpen, mutate }) => {
@@ -175,11 +168,7 @@ const CreateUserForm = ({ setOpen, mutate }) => {
startAdornment: (
<InputAdornment position="start">
<IconButton onClick={handleClickShowPassword}>
{showPassword ? (
<VisibilityOff />
) : (
<Visibility />
)}
{showPassword ? <VisibilityOff /> : <Visibility />}
</IconButton>
</InputAdornment>
),
@@ -265,12 +254,12 @@ const CreateUserForm = ({ setOpen, mutate }) => {
render={({ field, fieldState: { error } }) => {
return (
<FormControl fullWidth error={!!error}>
<InputLabel id={`label-phone-number`} shrink>
<InputLabel id={`label-gender`} shrink>
جنسیت
</InputLabel>
<Select
labelId={`label-phone-number`}
id={"phone-number"}
labelId={`label-gender`}
id={"gender"}
name={`gender`}
value={field.value}
input={<OutlinedInput label={"جنسیت"} />}
@@ -384,6 +373,25 @@ const CreateUserForm = ({ setOpen, mutate }) => {
name={"role_id"}
/>
</Grid>
<Grid size={{ xs: 12, md: 6 }}>
<Controller
control={control}
render={({ field, fieldState: { error } }) => {
return (
<LtrTextField
{...field}
label="شماره تماس داخلی"
variant="outlined"
fullWidth
type="tel"
error={!!error}
helperText={!!error && error.message}
/>
);
}}
name={"telephone_id"}
/>
</Grid>
</Grid>
</Stack>
</StyledForm>

View File

@@ -1,12 +1,6 @@
"use client";
import { AddCircle } from "@mui/icons-material";
import {
Button,
Dialog,
IconButton,
useMediaQuery,
useTheme,
} from "@mui/material";
import { Button, Dialog, IconButton, useMediaQuery, useTheme } from "@mui/material";
import CreateUserForm from "./Form";
import { useState } from "react";
@@ -22,11 +16,7 @@ const CreateUser = ({ mutate }) => {
return (
<>
{isMobile ? (
<IconButton
aria-label="کاربر جدید"
color="primary"
onClick={handleOpen}
>
<IconButton aria-label="کاربر جدید" color="primary" onClick={handleOpen}>
<AddCircle sx={{ fontSize: "25px" }} />
</IconButton>
) : (

View File

@@ -3,10 +3,6 @@ import { Stack } from "@mui/material";
const OnlineUsersReport = () => {
const { clientsOnline } = useSocket();
return (
<Stack>
clientsOnline: {clientsOnline.length}
</Stack>
)
}
return <Stack>clientsOnline: {clientsOnline.length}</Stack>;
};
export default OnlineUsersReport;

View File

@@ -1,4 +1,4 @@
"use client"
"use client";
import { Stack } from "@mui/material";
import OnlineUsersReport from "./OnlineUsersReport";
@@ -7,6 +7,6 @@ const DashboardPage = () => {
<Stack>
<OnlineUsersReport />
</Stack>
)
}
);
};
export default DashboardPage;

View File

@@ -1,13 +1,5 @@
import { ExpandLess, ExpandMore, Link } from "@mui/icons-material";
import {
Button,
Divider,
ListItemIcon,
ListItemText,
Menu,
MenuItem,
Stack,
} from "@mui/material";
import { Button, Divider, ListItemIcon, ListItemText, Menu, MenuItem, Stack } from "@mui/material";
import NextLink from "next/link";
import { useState } from "react";
@@ -36,21 +28,14 @@ const HeaderMenu = ({ menu }) => {
<Menu anchorEl={anchorEl} open={open} onClose={handleClose}>
{menu.subMenu.flatMap((subMenu, index) => [
...subMenu.map((sub) => (
<MenuItem
component={NextLink}
href={sub.href}
key={sub.title}
onClick={handleClose}
>
<MenuItem component={NextLink} href={sub.href} key={sub.title} onClick={handleClose}>
<ListItemIcon>
<Link fontSize="small" />
</ListItemIcon>
<ListItemText>{sub.title}</ListItemText>
</MenuItem>
)),
index < menu.subMenu.length - 1 && (
<Divider key={`divider-${index}`} />
),
index < menu.subMenu.length - 1 && <Divider key={`divider-${index}`} />,
])}
</Menu>
</Stack>

View File

@@ -1,13 +1,5 @@
import { ExpandLess, ExpandMore } from "@mui/icons-material";
import {
Collapse,
List,
ListItem,
ListItemButton,
ListItemIcon,
ListItemText,
Stack,
} from "@mui/material";
import { Collapse, List, ListItem, ListItemButton, ListItemIcon, ListItemText, Stack } from "@mui/material";
import Link from "next/link";
import SidebarBadge from "./SidebarBadge";
import SidebarSubitems from "./SidebarSubitems";
@@ -51,21 +43,10 @@ const SidebarListItems = ({ menuItem, dispatch }) => {
))}
</Stack>
)}
{menuItem.hasSubitems ? (
menuItem.showSubitems ? (
<ExpandLess />
) : (
<ExpandMore />
)
) : null}
{menuItem.hasSubitems ? menuItem.showSubitems ? <ExpandLess /> : <ExpandMore /> : null}
</ListItemButton>
</ListItem>
<Collapse
in={menuItem.showSubitems}
timeout="auto"
mountOnEnter={true}
unmountOnExit={true}
>
<Collapse in={menuItem.showSubitems} timeout="auto" mountOnEnter={true} unmountOnExit={true}>
{menuItem.hasSubitems ? (
<List
disablePadding
@@ -75,13 +56,7 @@ const SidebarListItems = ({ menuItem, dispatch }) => {
}}
>
{menuItem.Subitems.map((subitem, index) => {
return (
<SidebarSubitems
key={index}
dispatch={dispatch}
subitem={subitem}
/>
);
return <SidebarSubitems key={index} dispatch={dispatch} subitem={subitem} />;
})}
</List>
) : null}

View File

@@ -16,15 +16,11 @@ function selectPage(item, route) {
showSubitems: item.route === route,
};
} else if (item.Subitems && Array.isArray(item.Subitems)) {
const updatedSubitems = item.Subitems.map((subitem) =>
selectPage(subitem, route),
);
const updatedSubitems = item.Subitems.map((subitem) => selectPage(subitem, route));
return {
...item,
Subitems: updatedSubitems,
showSubitems: updatedSubitems.some(
(subitem) => subitem.showSubitems || subitem.route === route,
),
showSubitems: updatedSubitems.some((subitem) => subitem.showSubitems || subitem.route === route),
};
}
return item;
@@ -32,9 +28,7 @@ function selectPage(item, route) {
function toggleSubitems(items, actionId) {
return items.map((item) =>
actionId === item.id
? { ...item, showSubitems: !item.showSubitems }
: { ...item, showSubitems: false },
actionId === item.id ? { ...item, showSubitems: !item.showSubitems } : { ...item, showSubitems: false }
);
}
@@ -52,9 +46,7 @@ function reducer(state, action) {
case "COLLAPSE_SUB_ITEMS":
return state.map((item) =>
item.hasSubitems
? { ...item, Subitems: toggleSubitems(item.Subitems, action.id) }
: item,
item.hasSubitems ? { ...item, Subitems: toggleSubitems(item.Subitems, action.id) } : item
);
case "COLLAPSE_SUB_SECOND_ITEMS":
@@ -68,10 +60,10 @@ function reducer(state, action) {
...subitem,
Subitems: toggleSubitems(subitem.Subitems, action.id),
}
: subitem,
: subitem
),
}
: item,
: item
);
case "SELECTED":
@@ -112,13 +104,7 @@ const SidebarMenu = () => {
{userPermissions && (
<List sx={{ overflow: "auto", flex: 1 }} disablePadding dense>
{menuItems.map((menuItem) => {
return (
<SidebarListItems
dispatch={dispatch}
key={menuItem.id}
menuItem={menuItem}
/>
);
return <SidebarListItems dispatch={dispatch} key={menuItem.id} menuItem={menuItem} />;
})}
</List>
)}

View File

@@ -1,14 +1,5 @@
import { ExpandLess, ExpandMore } from "@mui/icons-material";
import {
Box,
Collapse,
List,
ListItem,
ListItemButton,
ListItemIcon,
ListItemText,
Stack,
} from "@mui/material";
import { Box, Collapse, List, ListItem, ListItemButton, ListItemIcon, ListItemText, Stack } from "@mui/material";
import Link from "next/link";
import SidebarBadge from "./SidebarBadge";
@@ -64,12 +55,7 @@ const SidebarSubitems = ({ subitem, dispatch }) => {
)}
</ListItemButton>
</ListItem>
<Collapse
in={subitem.showSubitems}
timeout="auto"
mountOnEnter={true}
unmountOnExit={true}
>
<Collapse in={subitem.showSubitems} timeout="auto" mountOnEnter={true} unmountOnExit={true}>
{subitem.hasSubitems ? (
<List
disablePadding
@@ -79,13 +65,7 @@ const SidebarSubitems = ({ subitem, dispatch }) => {
}}
>
{subitem.Subitems.map((subSubitem, index) => {
return (
<SidebarSubitems
key={index}
dispatch={dispatch}
subitem={subSubitem}
/>
);
return <SidebarSubitems key={index} dispatch={dispatch} subitem={subSubitem} />;
})}
</List>
) : null}

View File

@@ -1,17 +1,7 @@
"use client";
import ChevronRightIcon from "@mui/icons-material/ChevronRight";
import MenuIcon from "@mui/icons-material/Menu";
import {
Box,
Drawer,
IconButton,
Stack,
styled,
Toolbar,
Typography,
useMediaQuery,
useTheme,
} from "@mui/material";
import { Box, Drawer, IconButton, Stack, styled, Toolbar, Typography, useMediaQuery, useTheme } from "@mui/material";
import MuiAppBar from "@mui/material/AppBar";
import { useState, useEffect } from "react";
import HeaderMenu from "./HeaderMenu";
@@ -21,8 +11,7 @@ import SidebarMenu from "./Sidebar/SidebarMenu";
const drawerWidth = 300;
const Main = styled(Stack, { shouldForwardProp: (prop) => prop !== "open" })(
({ theme, open }) => ({
const Main = styled(Stack, { shouldForwardProp: (prop) => prop !== "open" })(({ theme, open }) => ({
flexGrow: 1,
height: "100%",
transition: theme.transitions.create("margin", {
@@ -37,8 +26,7 @@ const Main = styled(Stack, { shouldForwardProp: (prop) => prop !== "open" })(
}),
marginLeft: 0,
}),
}),
);
}));
const AppBar = styled(MuiAppBar, {
shouldForwardProp: (prop) => prop !== "open",
@@ -92,11 +80,7 @@ const HeaderWithSidebar = ({ children }) => {
width: "100%",
}}
>
<AppBar
sx={{ position: "fixed", top: "unset" }}
elevation={0}
open={open}
>
<AppBar sx={{ position: "fixed", top: "unset" }} elevation={0} open={open}>
<Toolbar variant="dense" sx={{ minHeight: 40 }}>
<IconButton
color="inherit"
@@ -158,18 +142,11 @@ const HeaderWithSidebar = ({ children }) => {
</IconButton>
</DrawerHeader>
<SidebarMenu />
<Typography
textAlign={"center"}
variant="caption"
sx={{ py: 0.2, fontFamily: "sans-serif" }}
>
<Typography textAlign={"center"} variant="caption" sx={{ py: 0.2, fontFamily: "sans-serif" }}>
v{process.env.NEXT_PUBLIC_VERSION}
</Typography>
</Drawer>
<Main
open={open}
sx={{ height: "100%", width: "100%", overflow: "hidden" }}
>
<Main open={open} sx={{ height: "100%", width: "100%", overflow: "hidden" }}>
<DrawerHeader />
<Box
sx={{

View File

@@ -15,11 +15,7 @@ const ActionHeader = ({ tab }) => {
<Typography variant="subtitle1" sx={{ marginRight: 1, color: "#fff" }}>
.... عملیات های مربوط به تماس:
</Typography>
<Typography
data-testid="phone_number"
variant="subtitle1"
sx={{ color: "#fff" }}
>
<Typography data-testid="phone_number" variant="subtitle1" sx={{ color: "#fff" }}>
{tab.phone_number} ....
</Typography>
</Stack>

View File

@@ -9,9 +9,7 @@ const CallActionCategoriesButton = ({ category, control }) => {
<Button
sx={{ py: 1.5 }}
fullWidth
variant={
field.value === category.category_id ? "contained" : "outlined"
}
variant={field.value === category.category_id ? "contained" : "outlined"}
color={"primary"}
onClick={() => {
field.onChange(category.category_id);

View File

@@ -12,7 +12,7 @@ const CallActionSubcategoriesButton = ({ sub_category, control, onSubmit }) => {
onSubmit();
}, 0);
},
[sub_category.subcategory_id],
[sub_category.subcategory_id]
);
return (

View File

@@ -11,11 +11,7 @@ const CallActionsCategories = ({ control }) => {
</Divider>
<Stack sx={{ m: 1, p: 1 }} direction={"row"} spacing={3}>
{categoryLists.map((category) => (
<CallActionCategoriesButton
key={category.category_id}
category={category}
control={control}
/>
<CallActionCategoriesButton key={category.category_id} category={category} control={control} />
))}
</Stack>
</>

View File

@@ -39,8 +39,7 @@ function CallActions({ tab }) {
const onSubmit = handleSubmit(async (data) => {
try {
const formData = new FormData();
data.description != "" &&
formData.append("description", data.description);
data.description != "" && formData.append("description", data.description);
formData.append("category_id", data.category_id);
formData.append("subcategory_id", data.subcategory_id);
await requestServer(`${CALL_ACTION}/${tab.id}`, "post", {
@@ -71,12 +70,7 @@ function CallActions({ tab }) {
zIndex: 9999,
}}
>
<LoadingHardPage
width={80}
height={80}
loading={true}
sx={{ position: "absolute" }}
/>
<LoadingHardPage width={80} height={80} loading={true} sx={{ position: "absolute" }} />
</Box>
)}
</Stack>

View File

@@ -12,9 +12,7 @@ const PreviousOperatorData = ({ historyItem }) => {
</Box>
<Stack>
<Stack direction={"row"} sx={{ alignItems: "end" }}>
<Typography sx={{ mr: 1 }}>
{historyItem.operator_full_name}
</Typography>
<Typography sx={{ mr: 1 }}>{historyItem.operator_full_name}</Typography>
<Typography variant="caption" sx={{ color: "secondary.main" }}>
(کارشناس)
</Typography>

View File

@@ -13,9 +13,7 @@ const Topics = ({ historyItem }) => {
>
<Chip label={"موضوع"} size="small" variant="outlined" color="primary" />
<Divider sx={{ flex: 1 }} />
{historyItem.category_name && (
<Chip label={historyItem.category_name} />
)}
{historyItem.category_name && <Chip label={historyItem.category_name} />}
</Stack>
<Stack
sx={{
@@ -25,16 +23,9 @@ const Topics = ({ historyItem }) => {
spacing={1}
direction={"row"}
>
<Chip
label={"زیر موضوع"}
size="small"
variant="outlined"
color="primary"
/>
<Chip label={"زیر موضوع"} size="small" variant="outlined" color="primary" />
<Divider sx={{ flex: 1 }} />
{historyItem.subcategory_name && (
<Chip label={historyItem.subcategory_name} />
)}
{historyItem.subcategory_name && <Chip label={historyItem.subcategory_name} />}
</Stack>
<Stack
sx={{
@@ -44,12 +35,7 @@ const Topics = ({ historyItem }) => {
spacing={1}
direction={"row"}
>
<Chip
label={"توضیحات تماس"}
size="small"
variant="outlined"
color="primary"
/>
<Chip label={"توضیحات تماس"} size="small" variant="outlined" color="primary" />
<Divider sx={{ flex: 1 }} />
{historyItem.description && <Chip label={historyItem.description} />}
</Stack>

View File

@@ -1,11 +1,4 @@
import {
Box,
List,
ListItem,
ListItemAvatar,
ListItemText,
Skeleton,
} from "@mui/material";
import { Box, List, ListItem, ListItemAvatar, ListItemText, Skeleton } from "@mui/material";
const LoadingHistory = () => {
return (

View File

@@ -9,12 +9,11 @@ import { Headphones } from "@mui/icons-material";
const max_size = 10;
const CallHistory = ({ tab }) => {
const {
firstItemOfHistory,
historyList,
isLoadingHistoryList,
errorHistoryList,
} = useCallerHistory(tab.id, tab.phone_number, max_size);
const { firstItemOfHistory, historyList, isLoadingHistoryList, errorHistoryList } = useCallerHistory(
tab.id,
tab.phone_number,
max_size
);
const [showRestOfHistory, setShowRestOfHistory] = useState(false);
return (

View File

@@ -4,12 +4,7 @@ import CallTabTime from "./CallTabTime";
const CallTabDetails = ({ tab }) => {
return (
<Stack
direction="row"
justifyContent="center"
alignItems="center"
spacing={3}
>
<Stack direction="row" justifyContent="center" alignItems="center" spacing={3}>
<Call />
<Stack alignItems={"start"}>
<Typography>{tab.phone_number}</Typography>

View File

@@ -14,8 +14,7 @@ const CallTabLabel = ({ tab, index }) => {
sx={{
width: "100%",
px: 1,
borderRight:
activeCall === index ? 0 : activeCall - 1 === index ? 0 : 1,
borderRight: activeCall === index ? 0 : activeCall - 1 === index ? 0 : 1,
borderRightColor: "divider",
}}
direction={"row"}

View File

@@ -35,11 +35,7 @@ const CallWidgetDialog = () => {
}, [calls.length]);
return (
<Dialog
fullScreen
open={openCallDialog}
slots={{ transition: DialogTransition }}
>
<Dialog fullScreen open={openCallDialog} slots={{ transition: DialogTransition }}>
<CallTabs />
</Dialog>
);

View File

@@ -5,12 +5,7 @@ import { LocalizationProvider, MobileDatePicker } from "@mui/x-date-pickers";
import { IconButton, InputAdornment } from "@mui/material";
import ClearIcon from "@mui/icons-material/Clear";
const CustomDatePicker = ({
dateValue,
setDateValue,
placeholder = "انتخاب تاریخ",
size = "small",
}) => {
const CustomDatePicker = ({ dateValue, setDateValue, placeholder = "انتخاب تاریخ", size = "small" }) => {
const handleDateChange = (newValue) => {
setDateValue(newValue);
};
@@ -18,9 +13,7 @@ const CustomDatePicker = ({
return (
<LocalizationProvider
dateAdapter={AdapterDateFnsJalali}
localeText={
faIR.components.MuiLocalizationProvider.defaultProps.localeText
}
localeText={faIR.components.MuiLocalizationProvider.defaultProps.localeText}
>
<MobileDatePicker
value={dateValue || null}

View File

@@ -23,10 +23,7 @@ const rowSelectionReducer = (state, action) => {
const DataTable_Main = (props) => {
const request = useRequest();
const [rowSelection, dispatchRowSelection] = useReducer(
rowSelectionReducer,
{},
);
const [rowSelection, dispatchRowSelection] = useReducer(rowSelectionReducer, {});
const { filterData, sortData, setSortData, hideData } = useDataTable();
const {
need_filter,
@@ -56,20 +53,12 @@ const DataTable_Main = (props) => {
params.set("size", pagination.pageSize);
if (specialFilter) {
const filteredSpecialFilterData = Object.values(specialFilter).filter(
(filter) => !isArrayEmpty(filter.value),
(filter) => !isArrayEmpty(filter.value)
);
params.set("filters", JSON.stringify(filteredSpecialFilterData || []));
} else {
const filteredFilterData = DataTableFilterDataStructure(
filterData,
isArrayEmpty,
);
params.set(
"filters",
JSON.stringify(
filteredFilterData.length === 0 ? [] : filteredFilterData,
),
);
const filteredFilterData = DataTableFilterDataStructure(filterData, isArrayEmpty);
params.set("filters", JSON.stringify(filteredFilterData.length === 0 ? [] : filteredFilterData));
}
params.set(
"sorting",
@@ -77,8 +66,8 @@ const DataTable_Main = (props) => {
Object.values(sortData).map(({ id, ...rest }) => ({
...rest,
id: id.replace(/__/g, "."),
})),
),
}))
)
);
return `${table_url}?${params}`;
}, [table_url, filterData, pagination, sortData, specialFilter]);
@@ -97,16 +86,12 @@ const DataTable_Main = (props) => {
}
};
const { data, isValidating, mutate } = useSWR(
props.data ? "" : fetchUrl(),
fetcher,
{
const { data, isValidating, mutate } = useSWR(props.data ? "" : fetchUrl(), fetcher, {
revalidateIfStale: true,
revalidateOnFocus: false,
revalidateOnReconnect: true,
keepPreviousData: true,
},
);
});
useEffect(() => {
if (!isValidating) return;
@@ -118,8 +103,7 @@ const DataTable_Main = (props) => {
columns,
data: data ?? [],
muiTableBodyRowProps: ({ row }) => ({
onClick: () =>
dispatchRowSelection({ type: "TOGGLE_ROW", payload: row.id }),
onClick: () => dispatchRowSelection({ type: "TOGGLE_ROW", payload: row.id }),
selected: !!rowSelection[row.id],
}),
initialState: {
@@ -167,11 +151,7 @@ const DataTable_Main = (props) => {
renderTopToolbarCustomActions: ({ table }) => (
<>
{TableToolbar && (
<TableToolbar
table={table}
mutate={mutate}
filterData={specialFilter || filterData}
/>
<TableToolbar table={table} mutate={mutate} filterData={specialFilter || filterData} />
)}
</>
),

View File

@@ -2,9 +2,7 @@ import { parseFromValuesOrFunc } from "@/core/utils/utils";
import { TableBody, Typography } from "@mui/material";
import { useMRT_RowVirtualizer, useMRT_Rows } from "material-react-table";
import { memo, useMemo } from "react";
import DataTable_TableBodyRow, {
Memo_DataTable_TableBodyRow,
} from "./TableBodyRow";
import DataTable_TableBodyRow, { Memo_DataTable_TableBodyRow } from "./TableBodyRow";
const DataTable_TableBody = ({ columnVirtualizer, table, ...rest }) => {
const {
@@ -33,12 +31,8 @@ const DataTable_TableBody = ({ columnVirtualizer, table, ...rest }) => {
...rest,
};
const tableHeadHeight =
((enableStickyHeader || isFullScreen) &&
tableHeadRef.current?.clientHeight) ||
0;
const tableFooterHeight =
(enableStickyFooter && tableFooterRef.current?.clientHeight) || 0;
const tableHeadHeight = ((enableStickyHeader || isFullScreen) && tableHeadRef.current?.clientHeight) || 0;
const tableFooterHeight = (enableStickyFooter && tableFooterRef.current?.clientHeight) || 0;
const pinnedRowIds = useMemo(() => {
if (!rowPinning.bottom?.length && !rowPinning.top?.length) return [];
@@ -61,8 +55,7 @@ const DataTable_TableBody = ({ columnVirtualizer, table, ...rest }) => {
return (
<>
{!rowPinningDisplayMode?.includes("sticky") &&
getIsSomeRowsPinned("top") && (
{!rowPinningDisplayMode?.includes("sticky") && getIsSomeRowsPinned("top") && (
<TableBody
{...tableBodyProps}
sx={(theme) => ({
@@ -91,9 +84,7 @@ const DataTable_TableBody = ({ columnVirtualizer, table, ...rest }) => {
{...tableBodyProps}
sx={(theme) => ({
display: layoutMode?.startsWith("grid") ? "grid" : undefined,
height: rowVirtualizer
? `${rowVirtualizer.getTotalSize()}px`
: undefined,
height: rowVirtualizer ? `${rowVirtualizer.getTotalSize()}px` : undefined,
minHeight: !rows.length ? "100px" : undefined,
position: "relative",
...parseFromValuesOrFunc(tableBodyProps?.sx, theme),
@@ -164,8 +155,7 @@ const DataTable_TableBody = ({ columnVirtualizer, table, ...rest }) => {
</>
))}
</TableBody>
{!rowPinningDisplayMode?.includes("sticky") &&
getIsSomeRowsPinned("bottom") && (
{!rowPinningDisplayMode?.includes("sticky") && getIsSomeRowsPinned("bottom") && (
<TableBody
{...tableBodyProps}
sx={(theme) => ({
@@ -197,5 +187,5 @@ export default DataTable_TableBody;
export const Memo_DataTable_TableBody = memo(
DataTable_TableBody,
(prev, next) => prev.table.options.data === next.table.options.data,
(prev, next) => prev.table.options.data === next.table.options.data
);

View File

@@ -1,7 +1,4 @@
import {
getCommonMRTCellStyles,
parseFromValuesOrFunc,
} from "@/core/utils/utils";
import { getCommonMRTCellStyles, parseFromValuesOrFunc } from "@/core/utils/utils";
import { useTheme } from "@emotion/react";
import { Skeleton, TableCell } from "@mui/material";
import { isCellEditable, openEditingCell } from "material-react-table";
@@ -9,15 +6,7 @@ import { memo, useEffect, useMemo, useState } from "react";
import DataTable_CopyButton from "../buttons/CopyButton";
import DataTable_TableBodyCellValue from "./TableBodyCellValue";
const DataTable_TableBodyCell = ({
cell,
numRows,
rowRef,
staticColumnIndex,
staticRowIndex,
table,
...rest
}) => {
const DataTable_TableBodyCell = ({ cell, numRows, rowRef, staticColumnIndex, staticRowIndex, table, ...rest }) => {
const theme = useTheme();
const {
getState,
@@ -75,9 +64,7 @@ const DataTable_TableBodyCell = ({
if ((!isLoading && !showSkeletons) || skeletonWidth !== 100) return;
const size = column.getSize();
setSkeletonWidth(
columnDefType === "display"
? size / 2
: Math.round(Math.random() * (size - size / 3) + size / 3),
columnDefType === "display" ? size / 2 : Math.round(Math.random() * (size - size / 3) + size / 3)
);
}, [isLoading, showSkeletons]);
@@ -90,8 +77,7 @@ const DataTable_TableBodyCell = ({
const isLastColumn = column.getIsLastColumn();
const isLastRow = numRows && staticRowIndex === numRows - 1;
const isResizingColumn = columnSizingInfo.isResizingColumn === column.id;
const showResizeBorder =
isResizingColumn && columnResizeMode === "onChange";
const showResizeBorder = isResizingColumn && columnResizeMode === "onChange";
const borderStyle = showResizeBorder
? `2px solid ${draggingBorderColor} !important`
@@ -102,65 +88,44 @@ const DataTable_TableBodyCell = ({
: undefined;
if (showResizeBorder) {
return columnResizeDirection === "ltr"
? { borderRight: borderStyle }
: { borderLeft: borderStyle };
return columnResizeDirection === "ltr" ? { borderRight: borderStyle } : { borderLeft: borderStyle };
}
return borderStyle
? {
borderBottom:
isDraggingRow || isHoveredRow || (isLastRow && !isResizingColumn)
? borderStyle
: undefined,
isDraggingRow || isHoveredRow || (isLastRow && !isResizingColumn) ? borderStyle : undefined,
borderLeft:
isDraggingColumn ||
isHoveredColumn ||
((isDraggingRow || isHoveredRow) && isFirstColumn)
isDraggingColumn || isHoveredColumn || ((isDraggingRow || isHoveredRow) && isFirstColumn)
? borderStyle
: undefined,
borderRight:
isDraggingColumn ||
isHoveredColumn ||
((isDraggingRow || isHoveredRow) && isLastColumn)
isDraggingColumn || isHoveredColumn || ((isDraggingRow || isHoveredRow) && isLastColumn)
? borderStyle
: undefined,
borderTop: isDraggingRow || isHoveredRow ? borderStyle : undefined,
}
: undefined;
}, [
columnSizingInfo.isResizingColumn,
draggingColumn,
draggingRow,
hoveredColumn,
hoveredRow,
staticRowIndex,
]);
}, [columnSizingInfo.isResizingColumn, draggingColumn, draggingRow, hoveredColumn, hoveredRow, staticRowIndex]);
const isColumnPinned =
enableColumnPinning &&
columnDef.columnDefType !== "group" &&
column.getIsPinned();
const isColumnPinned = enableColumnPinning && columnDef.columnDefType !== "group" && column.getIsPinned();
const isEditable = isCellEditable({ cell, table });
const isEditing =
isEditable &&
!["custom", "modal"].includes(editDisplayMode) &&
(editDisplayMode === "table" ||
editingRow?.id === row.id ||
editingCell?.id === cell.id) &&
(editDisplayMode === "table" || editingRow?.id === row.id || editingCell?.id === cell.id) &&
!row.getIsGrouped();
const isCreating =
isEditable && createDisplayMode === "row" && creatingRow?.id === row.id;
const isCreating = isEditable && createDisplayMode === "row" && creatingRow?.id === row.id;
const showClickToCopyButton =
(parseFromValuesOrFunc(enableClickToCopy, cell) === true ||
parseFromValuesOrFunc(columnDef.enableClickToCopy, cell) === true) &&
!["context-menu", false].includes(
// @ts-ignore
parseFromValuesOrFunc(columnDef.enableClickToCopy, cell),
parseFromValuesOrFunc(columnDef.enableClickToCopy, cell)
);
const isRightClickable = parseFromValuesOrFunc(enableCellActions, cell);
@@ -181,9 +146,7 @@ const DataTable_TableBodyCell = ({
setHoveredColumn(null);
}
if (enableColumnOrdering && draggingColumn) {
setHoveredColumn(
columnDef.enableColumnOrdering !== false ? column : null,
);
setHoveredColumn(columnDef.enableColumnOrdering !== false ? column : null);
}
};
@@ -227,10 +190,7 @@ const DataTable_TableBodyCell = ({
: isEditable && editDisplayMode === "cell"
? "pointer"
: "inherit",
outline:
actionCell?.id === cell.id
? `1px solid ${theme.palette.grey[500]}`
: undefined,
outline: actionCell?.id === cell.id ? `1px solid ${theme.palette.grey[500]}` : undefined,
outlineOffset: "-1px",
overflow: "hidden",
p:
@@ -247,8 +207,7 @@ const DataTable_TableBodyCell = ({
: "1.5rem",
textOverflow: columnDefType !== "display" ? "ellipsis" : undefined,
whiteSpace:
row.getIsPinned() || density === "compact" ? "nowrap" : "normal",
whiteSpace: row.getIsPinned() || density === "compact" ? "nowrap" : "normal",
...getCommonMRTCellStyles({
column,
table,
@@ -264,16 +223,9 @@ const DataTable_TableBodyCell = ({
{cell.getIsPlaceholder() ? (
(columnDef.PlaceholderCell?.({ cell, column, row, table }) ?? null)
) : showSkeletons !== false && (isLoading || showSkeletons) ? (
<Skeleton
animation="wave"
height={20}
width={skeletonWidth}
{...skeletonProps}
/>
<Skeleton animation="wave" height={20} width={skeletonWidth} {...skeletonProps} />
) : columnDefType === "display" &&
(["mrt-row-expand", "mrt-row-numbers", "mrt-row-select"].includes(
column.id,
) ||
(["mrt-row-expand", "mrt-row-numbers", "mrt-row-select"].includes(column.id) ||
!row.getIsGrouped()) ? (
columnDef.Cell?.({
cell,
@@ -292,9 +244,7 @@ const DataTable_TableBodyCell = ({
) : (
<DataTable_TableBodyCellValue {...cellValueProps} />
)}
{cell.getIsGrouped() && !columnDef.GroupedCell && (
<> ({row.subRows?.length})</>
)}
{cell.getIsGrouped() && !columnDef.GroupedCell && <> ({row.subRows?.length})</>}
</>
)}
</TableCell>
@@ -302,7 +252,4 @@ const DataTable_TableBodyCell = ({
};
export default DataTable_TableBodyCell;
export const Memo_DataTable_TableBodyCell = memo(
DataTable_TableBodyCell,
(prev, next) => next.cell === prev.cell,
);
export const Memo_DataTable_TableBodyCell = memo(DataTable_TableBodyCell, (prev, next) => next.cell === prev.cell);

View File

@@ -2,13 +2,7 @@ import { Box } from "@mui/material";
const allowedTypes = ["string", "number"];
const DataTable_TableBodyCellValue = ({
cell,
rowRef,
staticColumnIndex,
staticRowIndex,
table,
}) => {
const DataTable_TableBodyCellValue = ({ cell, rowRef, staticColumnIndex, staticRowIndex, table }) => {
const {
getState,
options: {
@@ -54,13 +48,10 @@ const DataTable_TableBodyCellValue = ({
((filterValue &&
allowedTypes.includes(typeof filterValue) &&
["autocomplete", "text"].includes(columnDef.filterVariant)) ||
(globalFilter &&
allowedTypes.includes(typeof globalFilter) &&
column.getCanGlobalFilter()))
(globalFilter && allowedTypes.includes(typeof globalFilter) && column.getCanGlobalFilter()))
) {
const chunks = highlightWords?.({
matchExactly:
(filterValue ? columnDef._filterFn : globalFilterFn) !== "fuzzy",
matchExactly: (filterValue ? columnDef._filterFn : globalFilterFn) !== "fuzzy",
query: (filterValue ?? globalFilter ?? "").toString(),
text: renderedCellValue?.toString(),
});

View File

@@ -1,15 +1,9 @@
import {
commonCellBeforeAfterStyles,
getCommonPinnedCellStyles,
parseFromValuesOrFunc,
} from "@/core/utils/utils";
import { commonCellBeforeAfterStyles, getCommonPinnedCellStyles, parseFromValuesOrFunc } from "@/core/utils/utils";
import { useTheme } from "@emotion/react";
import { TableRow, alpha, darken, lighten } from "@mui/material";
import { getIsRowSelected } from "material-react-table";
import { memo, useMemo, useRef } from "react";
import DataTable_TableBodyCell, {
Memo_DataTable_TableBodyCell,
} from "./TableBodyCell";
import DataTable_TableBodyCell, { Memo_DataTable_TableBodyCell } from "./TableBodyCell";
import DataTable_TableDetailPanel from "./TableDetailPanel";
const DataTable_TableBodyRow = ({
@@ -34,11 +28,7 @@ const DataTable_TableBodyRow = ({
enableStickyHeader,
layoutMode,
memoMode,
mrtTheme: {
baseBackgroundColor,
pinnedRowBackgroundColor,
selectedRowBackgroundColor,
},
mrtTheme: { baseBackgroundColor, pinnedRowBackgroundColor, selectedRowBackgroundColor },
muiTableBodyRowProps,
renderDetailPanel,
rowPinningDisplayMode,
@@ -46,21 +36,12 @@ const DataTable_TableBodyRow = ({
refs: { tableFooterRef, tableHeadRef },
setHoveredRow,
} = table;
const {
density,
draggingColumn,
draggingRow,
editingCell,
editingRow,
hoveredRow,
isFullScreen,
rowPinning,
} = getState();
const { density, draggingColumn, draggingRow, editingCell, editingRow, hoveredRow, isFullScreen, rowPinning } =
getState();
const visibleCells = row.getVisibleCells();
const { virtualColumns, virtualPaddingLeft, virtualPaddingRight } =
columnVirtualizer ?? {};
const { virtualColumns, virtualPaddingLeft, virtualPaddingRight } = columnVirtualizer ?? {};
const isRowSelected = getIsRowSelected({ row, table });
const isRowPinned = enableRowPinning && row.getIsPinned();
@@ -77,30 +58,17 @@ const DataTable_TableBodyRow = ({
};
const [bottomPinnedIndex, topPinnedIndex] = useMemo(() => {
if (
!enableRowPinning ||
!rowPinningDisplayMode?.includes("sticky") ||
!pinnedRowIds ||
!row.getIsPinned()
)
if (!enableRowPinning || !rowPinningDisplayMode?.includes("sticky") || !pinnedRowIds || !row.getIsPinned())
return [];
return [
[...pinnedRowIds].reverse().indexOf(row.id),
pinnedRowIds.indexOf(row.id),
];
return [[...pinnedRowIds].reverse().indexOf(row.id), pinnedRowIds.indexOf(row.id)];
}, [pinnedRowIds, rowPinning]);
const tableHeadHeight =
((enableStickyHeader || isFullScreen) &&
tableHeadRef.current?.clientHeight) ||
0;
const tableFooterHeight =
(enableStickyFooter && tableFooterRef.current?.clientHeight) || 0;
const tableHeadHeight = ((enableStickyHeader || isFullScreen) && tableHeadRef.current?.clientHeight) || 0;
const tableFooterHeight = (enableStickyFooter && tableFooterRef.current?.clientHeight) || 0;
const sx = parseFromValuesOrFunc(tableRowProps?.sx, theme);
const defaultRowHeight =
density === "compact" ? 37 : density === "comfortable" ? 53 : 69;
const defaultRowHeight = density === "compact" ? 37 : density === "comfortable" ? 53 : 69;
const customRowHeight =
// @ts-ignore
@@ -152,9 +120,7 @@ const DataTable_TableBodyRow = ({
selected={isRowSelected}
{...tableRowProps}
style={{
transform: virtualRow
? `translateY(${virtualRow.start}px)`
: undefined,
transform: virtualRow ? `translateY(${virtualRow.start}px)` : undefined,
...tableRowProps?.style,
}}
sx={(theme) => ({
@@ -195,16 +161,12 @@ const DataTable_TableBodyRow = ({
: undefined,
transition: virtualRow ? "none" : "all 150ms ease-in-out",
width: "100%",
zIndex:
rowPinningDisplayMode?.includes("sticky") && isRowPinned ? 2 : 0,
zIndex: rowPinningDisplayMode?.includes("sticky") && isRowPinned ? 2 : 0,
...sx,
})}
>
{virtualPaddingLeft ? (
<td style={{ display: "flex", width: virtualPaddingLeft }} />
) : null}
{(virtualColumns ?? visibleCells).map(
(cellOrVirtualCell, staticColumnIndex) => {
{virtualPaddingLeft ? <td style={{ display: "flex", width: virtualPaddingLeft }} /> : null}
{(virtualColumns ?? visibleCells).map((cellOrVirtualCell, staticColumnIndex) => {
let cell = cellOrVirtualCell;
if (columnVirtualizer) {
staticColumnIndex = cellOrVirtualCell.index;
@@ -230,11 +192,8 @@ const DataTable_TableBodyRow = ({
<DataTable_TableBodyCell key={cell.id} {...props} />
)
) : null;
},
)}
{virtualPaddingRight ? (
<td style={{ display: "flex", width: virtualPaddingRight }} />
) : null}
})}
{virtualPaddingRight ? <td style={{ display: "flex", width: virtualPaddingRight }} /> : null}
</TableRow>
{renderDetailPanel && !row.getIsGrouped() && (
<DataTable_TableDetailPanel
@@ -253,6 +212,5 @@ export default DataTable_TableBodyRow;
export const Memo_DataTable_TableBodyRow = memo(
DataTable_TableBodyRow,
(prev, next) =>
prev.row === next.row && prev.staticRowIndex === next.staticRowIndex,
(prev, next) => prev.row === next.row && prev.staticRowIndex === next.staticRowIndex
);

View File

@@ -53,12 +53,8 @@ const DataTable_TableDetailPanel = ({
sx={(theme) => ({
display: layoutMode?.startsWith("grid") ? "flex" : undefined,
position: virtualRow ? "absolute" : undefined,
top: virtualRow
? `${parentRowRef.current?.getBoundingClientRect()?.height}px`
: undefined,
transform: virtualRow
? `translateY(${virtualRow?.start}px)`
: undefined,
top: virtualRow ? `${parentRowRef.current?.getBoundingClientRect()?.height}px` : undefined,
transform: virtualRow ? `translateY(${virtualRow?.start}px)` : undefined,
width: "100%",
...parseFromValuesOrFunc(tableRowProps?.sx, theme),
})}

View File

@@ -1,7 +1,4 @@
import {
getCommonTooltipProps,
parseFromValuesOrFunc,
} from "@/core/utils/utils";
import { getCommonTooltipProps, parseFromValuesOrFunc } from "@/core/utils/utils";
import { Button, Tooltip } from "@mui/material";
import { useState } from "react";
@@ -40,10 +37,7 @@ const DataTable_CopyButton = ({ cell, table, ...rest }) => {
return (
<Tooltip
{...getCommonTooltipProps("top")}
title={
buttonProps?.title ??
(copied ? localization.copiedToClipboard : localization.clickToCopy)
}
title={buttonProps?.title ?? (copied ? localization.copiedToClipboard : localization.clickToCopy)}
>
<Button
onClick={(e) => handleCopy(e, cell.getValue())}

View File

@@ -1,7 +1,4 @@
import {
getCommonTooltipProps,
parseFromValuesOrFunc,
} from "@/core/utils/utils";
import { getCommonTooltipProps, parseFromValuesOrFunc } from "@/core/utils/utils";
import { IconButton, Tooltip } from "@mui/material";
const DataTable_GrabHandleButton = ({ location, table, ...rest }) => {
@@ -13,10 +10,7 @@ const DataTable_GrabHandleButton = ({ location, table, ...rest }) => {
} = table;
return (
<Tooltip
{...getCommonTooltipProps("top")}
title={rest?.title ?? localization.move}
>
<Tooltip {...getCommonTooltipProps("top")} title={rest?.title ?? localization.move}>
<IconButton
aria-label={rest.title ?? localization.move}
disableRipple

View File

@@ -46,7 +46,7 @@ function FilterBody({ columns, drawerState, setDrawerState }) {
});
}
return acc;
}, {}),
}, {})
);
setValidationSchema(schema);
@@ -94,7 +94,7 @@ function FilterBody({ columns, drawerState, setDrawerState }) {
reset={reset}
/>
)
) : null,
) : null
)}
</Box>
<Box
@@ -112,8 +112,7 @@ function FilterBody({ columns, drawerState, setDrawerState }) {
disabled={!isDirty || !isValid}
sx={{
px: 8,
boxShadow:
"rgba(0, 0, 0, 0.23) 0px 6px 6px, rgba(0, 0, 0, 0.19) 10px 0px 20px",
boxShadow: "rgba(0, 0, 0, 0.23) 0px 6px 6px, rgba(0, 0, 0, 0.19) 10px 0px 20px",
backgroundColor: "primary2",
":hover": {
backgroundColor: "primary2",

View File

@@ -1,12 +1,7 @@
import { Controller, useWatch } from "react-hook-form";
import FilterBodyField from "./FilterBodyField";
const FilterBodyControllerWithDependency = ({
column,
control,
reset,
errors,
}) => {
const FilterBodyControllerWithDependency = ({ column, control, reset, errors }) => {
const dependencyField = useWatch({ control, name: column.dependencyId });
return (

View File

@@ -29,8 +29,7 @@ function FilterBodyField({
}) {
const [anchorEl, setAnchorEl] = useState(null);
const defaultFilterTranslation =
columnFilterModeOptionFa[filterParameters.filterMode] ||
filterParameters.filterMode;
columnFilterModeOptionFa[filterParameters.filterMode] || filterParameters.filterMode;
const handleOpenFilterBox = (event) => {
setAnchorEl(event.currentTarget);

View File

@@ -11,9 +11,7 @@ function FilterButton({ drawerState, setDrawerState }) {
}
return value === "" || value === null || value === undefined;
};
const filteredFilterData = Object.values(filterData).filter(
(filter) => !isValueEmpty(filter.value),
);
const filteredFilterData = Object.values(filterData).filter((filter) => !isValueEmpty(filter.value));
return (
<Tooltip title="فیلتر">
<IconButton

View File

@@ -14,8 +14,7 @@ function FilterHeader({ setDrawerState }) {
px: 2,
py: 1,
backgroundColor: (theme) => theme.palette.primary.main,
boxShadow:
"rgba(0, 0, 0, 0.19) 0px 10px 20px, rgba(0, 0, 0, 0.23) 0px 6px 6px",
boxShadow: "rgba(0, 0, 0, 0.19) 0px 10px 20px, rgba(0, 0, 0, 0.23) 0px 6px 6px",
maxWidth: "450px",
}}
>

View File

@@ -29,13 +29,7 @@ function FilterOptionList({
};
return (
<Menu
id="simple-menu"
anchorEl={anchorEl}
keepMounted
open={Boolean(anchorEl)}
onClose={handleCloseFilterBox}
>
<Menu id="simple-menu" anchorEl={anchorEl} keepMounted open={Boolean(anchorEl)} onClose={handleCloseFilterBox}>
{filterOption.map((option, index) => (
<ListItem
key={index}

View File

@@ -2,12 +2,7 @@ import React from "react";
import MuiDatePicker from "@/core/components/DataTable/filter/fieldsType/CustomDate/MuiDatePicker";
import { Typography } from "@mui/material";
function CustomDatePicker({
column,
filterParameters,
defaultFilterTranslation,
handleChange,
}) {
function CustomDatePicker({ column, filterParameters, defaultFilterTranslation, handleChange }) {
return (
<MuiDatePicker
name={`${column.id}.value`}
@@ -17,10 +12,7 @@ function CustomDatePicker({
}}
placeholder={column.header}
helperText={
<Typography
variant="button"
sx={{ color: (theme) => theme.palette.primary.main }}
>
<Typography variant="button" sx={{ color: (theme) => theme.palette.primary.main }}>
نوع فیلتر: {defaultFilterTranslation} (تاریخ)
</Typography>
}

View File

@@ -4,13 +4,7 @@ import React from "react";
import { Box, Typography } from "@mui/material";
import MuiDatePicker from "@/core/components/DataTable/filter/fieldsType/CustomDate/MuiDatePicker";
function CustomDatePickerRange({
column,
filterParameters,
defaultFilterTranslation,
handleChange,
errors,
}) {
function CustomDatePickerRange({ column, filterParameters, defaultFilterTranslation, handleChange, errors }) {
return (
<Box sx={{ display: "flex", gap: 1 }}>
<MuiDatePicker
@@ -26,10 +20,7 @@ function CustomDatePickerRange({
maxDate={filterParameters.value[1]}
placeholder={`از تاریخ`}
helperText={
<Typography
variant="button"
sx={{ color: (theme) => theme.palette.primary.main }}
>
<Typography variant="button" sx={{ color: (theme) => theme.palette.primary.main }}>
نوع فیلتر: {defaultFilterTranslation} (تاریخ)
</Typography>
}
@@ -46,11 +37,7 @@ function CustomDatePickerRange({
}}
minDate={filterParameters.value[0]}
placeholder={`تا تاریخ`}
helperText={
errors?.[`${column.id}`]?.value
? errors?.[`${column.id}`]?.value.message
: null
}
helperText={errors?.[`${column.id}`]?.value ? errors?.[`${column.id}`]?.value.message : null}
error={Boolean(errors?.[`${column.id}`]?.value)}
/>
</Box>

View File

@@ -6,24 +6,12 @@ import { Box, FormHelperText, IconButton, InputAdornment } from "@mui/material";
import ClearIcon from "@mui/icons-material/Clear";
import moment from "jalali-moment";
function MuiDatePicker({
label,
value,
setFieldValue,
name,
minDate,
maxDate,
helperText,
placeholder,
error,
}) {
function MuiDatePicker({ label, value, setFieldValue, name, minDate, maxDate, helperText, placeholder, error }) {
return (
<Box sx={{ display: "flex", flexDirection: "column", my: 1 }}>
<LocalizationProvider
dateAdapter={AdapterDateFnsJalali}
localeText={
faIR.components.MuiLocalizationProvider.defaultProps.localeText
}
localeText={faIR.components.MuiLocalizationProvider.defaultProps.localeText}
>
<MobileDatePicker
value={value ? new Date(value) : null}
@@ -35,9 +23,7 @@ function MuiDatePicker({
aria-describedby="component-helper-text"
onChange={(value) => {
const date = new Date(value);
const formattedDate = moment(date)
.locale("en")
.format("YYYY-MM-DD");
const formattedDate = moment(date).locale("en").format("YYYY-MM-DD");
setFieldValue(name, formattedDate);
}}
minDate={minDate ? new Date(minDate) : null}

View File

@@ -1,12 +1,6 @@
"use client";
import {
FormControl,
InputLabel,
MenuItem,
OutlinedInput,
Select,
} from "@mui/material";
import { FormControl, InputLabel, MenuItem, OutlinedInput, Select } from "@mui/material";
function CustomSelect({ column, filterParameters, handleChange }) {
return (
<FormControl fullWidth sx={{ marginY: 1 }} size="small">
@@ -20,9 +14,7 @@ function CustomSelect({ column, filterParameters, handleChange }) {
value={filterParameters.value}
input={<OutlinedInput label={column.header} />}
size="small"
onChange={(e) =>
handleChange({ ...filterParameters, value: e.target.value })
}
onChange={(e) => handleChange({ ...filterParameters, value: e.target.value })}
displayEmpty
>
{column.columnSelectOption().map((option) => (

View File

@@ -1,14 +1,6 @@
"use client";
import {
FormControl,
FormHelperText,
InputLabel,
MenuItem,
OutlinedInput,
Select,
Typography,
} from "@mui/material";
import { FormControl, FormHelperText, InputLabel, MenuItem, OutlinedInput, Select, Typography } from "@mui/material";
import { useCallback, useEffect } from "react";
function CustomSelectByDependency({
@@ -31,9 +23,7 @@ function CustomSelectByDependency({
value={value}
size="small"
input={<OutlinedInput label={column.header} />}
onChange={(e) =>
handleChange({ ...filterParameters, value: e.target.value })
}
onChange={(e) => handleChange({ ...filterParameters, value: e.target.value })}
displayEmpty
>
{columnSelectOption.map((option) => (

View File

@@ -12,12 +12,7 @@ import {
Typography,
} from "@mui/material";
function CustomSelectMultiple({
column,
filterParameters,
defaultFilterTranslation,
handleChange,
}) {
function CustomSelectMultiple({ column, filterParameters, defaultFilterTranslation, handleChange }) {
const columnSelectOption = column.columnSelectOption;
const getLabelForValue = (value) => {
@@ -36,9 +31,7 @@ function CustomSelectMultiple({
value={filterParameters.value}
multiple
size="small"
onChange={(e) =>
handleChange({ ...filterParameters, value: e.target.value })
}
onChange={(e) => handleChange({ ...filterParameters, value: e.target.value })}
renderValue={(selected) => (
<Box sx={{ display: "flex", flexWrap: "wrap", gap: 0.5 }}>
{selected.map((value) => (

View File

@@ -15,9 +15,7 @@ function CustomTextField({
name={column.id}
label={column.header}
value={filterParameters.value}
onChange={(e) =>
handleChange({ ...filterParameters, value: e.target.value })
}
onChange={(e) => handleChange({ ...filterParameters, value: e.target.value })}
onBlur={handleBlur}
fullWidth
variant="outlined"
@@ -25,11 +23,7 @@ function CustomTextField({
sx={{ my: 1 }}
InputProps={{
endAdornment: (
<InputAdornment
position="end"
sx={{ cursor: "pointer" }}
onClick={handleOpenFilterBox}
>
<InputAdornment position="end" sx={{ cursor: "pointer" }} onClick={handleOpenFilterBox}>
<FilterListIcon />
</InputAdornment>
),

View File

@@ -25,10 +25,7 @@ function CustomTextFieldRange({
label={<Typography>از {column.header}</Typography>}
value={filterParameters.value[0]}
fullWidth
error={
touched?.[`${column.id}`]?.value &&
Boolean(errors?.[`${column.id}`]?.value)
}
error={touched?.[`${column.id}`]?.value && Boolean(errors?.[`${column.id}`]?.value)}
helperText={
<Typography
variant="caption"
@@ -55,11 +52,7 @@ function CustomTextFieldRange({
}
onBlur={handleBlur}
error={Boolean(errors?.[`${column.id}`]?.value)}
helperText={
errors?.[`${column.id}`]?.value
? errors?.[`${column.id}`]?.value.message
: null
}
helperText={errors?.[`${column.id}`]?.value ? errors?.[`${column.id}`]?.value.message : null}
label={<Typography>تا {column.header}</Typography>}
value={filterParameters.value[1]}
fullWidth
@@ -68,11 +61,7 @@ function CustomTextFieldRange({
sx={{ my: 1 }}
InputProps={{
endAdornment: (
<InputAdornment
position="end"
sx={{ cursor: "pointer" }}
onClick={handleOpenFilterBox}
>
<InputAdornment position="end" sx={{ cursor: "pointer" }} onClick={handleOpenFilterBox}>
<FilterListIcon />
</InputAdornment>
),

View File

@@ -5,12 +5,7 @@ import DataTable_TableHeadRow from "./TableHeadRow";
const DataTable_TableHead = ({ columnVirtualizer, table, ...rest }) => {
const {
getState,
options: {
enableStickyHeader,
layoutMode,
muiTableHeadProps,
positionToolbarAlertBanner,
},
options: { enableStickyHeader, layoutMode, muiTableHeadProps, positionToolbarAlertBanner },
refs: { tableHeadRef },
} = table;
const { isFullScreen, showAlertBanner } = getState();

View File

@@ -1,20 +1,10 @@
import {
getCommonMRTCellStyles,
parseFromValuesOrFunc,
} from "@/core/utils/utils";
import { getCommonMRTCellStyles, parseFromValuesOrFunc } from "@/core/utils/utils";
import { useTheme } from "@emotion/react";
import { Box, TableCell } from "@mui/material";
import { MRT_TableHeadCellSortLabel } from "material-react-table";
import { useMemo } from "react";
const DataTable_TableHeadCell = ({
columnVirtualizer,
header,
staticColumnIndex,
backgroundColor,
table,
...rest
}) => {
const DataTable_TableHeadCell = ({ columnVirtualizer, header, staticColumnIndex, backgroundColor, table, ...rest }) => {
const theme = useTheme();
const {
getState,
@@ -34,14 +24,7 @@ const DataTable_TableHeadCell = ({
refs: { tableHeadCellRefs },
setHoveredColumn,
} = table;
const {
columnSizingInfo,
density,
draggingColumn,
grouping,
hoveredColumn,
showColumnFilters,
} = getState();
const { columnSizingInfo, density, draggingColumn, grouping, hoveredColumn, showColumnFilters } = getState();
const { column } = header;
const { columnDef } = column;
const { columnDefType } = columnDef;
@@ -55,23 +38,17 @@ const DataTable_TableHeadCell = ({
...rest,
};
const isColumnPinned =
enableColumnPinning &&
columnDef.columnDefType !== "group" &&
column.getIsPinned();
const isColumnPinned = enableColumnPinning && columnDef.columnDefType !== "group" && column.getIsPinned();
const showColumnActions =
(enableColumnActions || columnDef.enableColumnActions) &&
columnDef.enableColumnActions !== false;
(enableColumnActions || columnDef.enableColumnActions) && columnDef.enableColumnActions !== false;
const showDragHandle =
enableColumnDragging !== false &&
columnDef.enableColumnDragging !== false &&
(enableColumnDragging ||
(enableColumnOrdering && columnDef.enableColumnOrdering !== false) ||
(enableGrouping &&
columnDef.enableGrouping !== false &&
!grouping.includes(column.id)));
(enableGrouping && columnDef.enableGrouping !== false && !grouping.includes(column.id)));
const headerPL = useMemo(() => {
let pl = 0;
@@ -96,9 +73,7 @@ const DataTable_TableHeadCell = ({
: undefined;
if (showResizeBorder) {
return columnResizeDirection === "ltr"
? { borderRight: borderStyle }
: { borderLeft: borderStyle };
return columnResizeDirection === "ltr" ? { borderRight: borderStyle } : { borderLeft: borderStyle };
}
const draggingBorders = borderStyle
? {
@@ -116,9 +91,7 @@ const DataTable_TableHeadCell = ({
setHoveredColumn(null);
}
if (enableColumnOrdering && draggingColumn && columnDefType !== "group") {
setHoveredColumn(
columnDef.enableColumnOrdering !== false ? column : null,
);
setHoveredColumn(columnDef.enableColumnOrdering !== false ? column : null);
}
};
@@ -149,13 +122,7 @@ const DataTable_TableHeadCell = ({
return (
<TableCell
align={
columnDefType === "group"
? "center"
: theme.direction === "rtl"
? "right"
: "left"
}
align={columnDefType === "group" ? "center" : theme.direction === "rtl" ? "right" : "left"}
colSpan={header.colSpan}
rowSpan={rowSpan}
data-index={staticColumnIndex}
@@ -190,12 +157,7 @@ const DataTable_TableHeadCell = ({
: columnDefType === "display"
? "1rem 1.25rem"
: "1.5rem",
pb:
columnDefType === "display"
? 0
: showColumnFilters || density === "compact"
? "0.4rem"
: "0.6rem",
pb: columnDefType === "display" ? 0 : showColumnFilters || density === "compact" ? "0.4rem" : "0.6rem",
pt:
columnDefType === "group" || density === "compact"
? "0.25rem"
@@ -221,8 +183,7 @@ const DataTable_TableHeadCell = ({
sx={{
alignItems: "center",
display: "flex",
flexDirection:
tableCellProps?.align === "right" ? "row-reverse" : "row",
flexDirection: tableCellProps?.align === "right" ? "row-reverse" : "row",
justifyContent:
columnDefType === "group" || tableCellProps?.align === "center"
? "center"
@@ -238,18 +199,11 @@ const DataTable_TableHeadCell = ({
onClick={column.getToggleSortingHandler()}
sx={{
alignItems: "center",
cursor:
column.getCanSort() && columnDefType !== "group"
? "pointer"
: undefined,
cursor: column.getCanSort() && columnDefType !== "group" ? "pointer" : undefined,
display: "flex",
flexDirection:
tableCellProps?.align === "right" ? "row-reverse" : "row",
flexDirection: tableCellProps?.align === "right" ? "row-reverse" : "row",
overflow: columnDefType === "data" ? "hidden" : undefined,
pl:
tableCellProps?.align === "center"
? `${headerPL}rem`
: undefined,
pl: tableCellProps?.align === "center" ? `${headerPL}rem` : undefined,
}}
>
<Box

View File

@@ -14,11 +14,9 @@ const DataTable_TableHeadRow = ({
const {
options: { enableStickyHeader, layoutMode, muiTableHeadRowProps },
} = table;
const { virtualColumns, virtualPaddingLeft, virtualPaddingRight } =
columnVirtualizer ?? {};
const { virtualColumns, virtualPaddingLeft, virtualPaddingRight } = columnVirtualizer ?? {};
const backgroundColor =
index % 2 === 0 ? palette.primary.main : palette.secondary.main;
const backgroundColor = index % 2 === 0 ? palette.primary.main : palette.secondary.main;
const tableRowProps = {
...parseFromValuesOrFunc(muiTableHeadRowProps, {
@@ -30,19 +28,15 @@ const DataTable_TableHeadRow = ({
// Access theme from the sx function
...(parseFromValuesOrFunc(muiTableHeadRowProps?.sx, theme) || {}),
display: layoutMode?.startsWith("grid") ? "flex" : undefined,
position:
enableStickyHeader && layoutMode === "semantic" ? "sticky" : "relative",
position: enableStickyHeader && layoutMode === "semantic" ? "sticky" : "relative",
top: 0,
}),
};
return (
<TableRow {...tableRowProps}>
{virtualPaddingLeft && (
<th style={{ display: "flex", width: virtualPaddingLeft }} />
)}
{(virtualColumns ?? headerGroup.headers).map(
(headerOrVirtualHeader, staticColumnIndex) => {
{virtualPaddingLeft && <th style={{ display: "flex", width: virtualPaddingLeft }} />}
{(virtualColumns ?? headerGroup.headers).map((headerOrVirtualHeader, staticColumnIndex) => {
const header = columnVirtualizer
? headerGroup.headers[headerOrVirtualHeader.index]
: headerOrVirtualHeader;
@@ -57,11 +51,8 @@ const DataTable_TableHeadRow = ({
table={table}
/>
) : null;
},
)}
{virtualPaddingRight && (
<th style={{ display: "flex", width: virtualPaddingRight }} />
)}
})}
{virtualPaddingRight && <th style={{ display: "flex", width: virtualPaddingRight }} />}
</TableRow>
);
};

View File

@@ -27,12 +27,7 @@ function HideBody({ columns, drawerState, setDrawerState }) {
<ScrollBox>
<Box sx={{ px: 1, py: 2, display: "flex", flexDirection: "column" }}>
{columns.map((column) => (
<HideBodyField
key={column.id}
column={column}
hideData={hideData}
setHideData={setHideData}
/>
<HideBodyField key={column.id} column={column} hideData={hideData} setHideData={setHideData} />
))}
</Box>
</ScrollBox>

View File

@@ -44,11 +44,7 @@ function HideBodyField({ column, hideData, setHideData }) {
if (typeof hideData[column.id] === "boolean") {
return (
<Box sx={{ display: "flex", alignItems: "center" }}>
<Checkbox
checked={hideData[column.id]}
onChange={handleCheckboxChange}
name={column.id}
/>
<Checkbox checked={hideData[column.id]} onChange={handleCheckboxChange} name={column.id} />
<Typography variant="subtitle1">{column.header}</Typography>
</Box>
);

View File

@@ -7,9 +7,7 @@ import { flattenObjectOfObjects } from "@/core/utils/flattenObjectOfObjects";
function HideButton({ drawerState, setDrawerState }) {
const { hideData } = useDataTable();
const flattenHideData = flattenObjectOfObjects(hideData);
const falseCount = Object.values(flattenHideData).filter(
(value) => value === false,
).length;
const falseCount = Object.values(flattenHideData).filter((value) => value === false).length;
return (
<Tooltip title="نمایش/مخفی کردن ستون ها">

View File

@@ -14,8 +14,7 @@ function FilterHeader({ setDrawerState }) {
px: 2,
py: 1,
backgroundColor: "#155175",
boxShadow:
"rgba(0, 0, 0, 0.19) 0px 10px 20px, rgba(0, 0, 0, 0.23) 0px 6px 6px",
boxShadow: "rgba(0, 0, 0, 0.19) 0px 10px 20px, rgba(0, 0, 0, 0.23) 0px 6px 6px",
maxWidth: "450px",
}}
>

View File

@@ -67,8 +67,7 @@ export const FA_DATATABLE_LOCALIZATION = {
rowsPerPage: "ردیف در هر صفحه",
save: "ذخیره",
search: "جستجو",
selectedCountOfRowCountRowsSelected:
"{selectedCount} از {rowCount} ردیف انتخاب شده",
selectedCountOfRowCountRowsSelected: "{selectedCount} از {rowCount} ردیف انتخاب شده",
select: "انتخاب",
showAll: "نمایش همه",
showAllColumns: "نمایش همه ستون‌ها",

View File

@@ -1,12 +1,6 @@
import { Box, IconButton, ListItemIcon, MenuItem } from "@mui/material";
const DataTable_ActionMenuItem = ({
icon,
label,
onOpenSubMenu,
table,
...rest
}) => {
const DataTable_ActionMenuItem = ({ icon, label, onOpenSubMenu, table, ...rest }) => {
const {
options: {
icons: { ArrowRightIcon },
@@ -34,12 +28,7 @@ const DataTable_ActionMenuItem = ({
{label}
</Box>
{onOpenSubMenu && (
<IconButton
onClick={onOpenSubMenu}
onMouseEnter={onOpenSubMenu}
size="small"
sx={{ p: 0 }}
>
<IconButton onClick={onOpenSubMenu} onMouseEnter={onOpenSubMenu} size="small" sx={{ p: 0 }}>
<ArrowRightIcon />
</IconButton>
)}

View File

@@ -30,8 +30,7 @@ const DataTable_CellActionMenu = ({ table, ...rest }) => {
const internalMenuItems = [
(parseFromValuesOrFunc(enableClickToCopy, cell) === "context-menu" ||
parseFromValuesOrFunc(columnDef.enableClickToCopy, cell) ===
"context-menu") && (
parseFromValuesOrFunc(columnDef.enableClickToCopy, cell) === "context-menu") && (
<DataTable_ActionMenuItem
icon={<ContentCopy />}
key={"mrt-copy"}
@@ -68,8 +67,7 @@ const DataTable_CellActionMenu = ({ table, ...rest }) => {
};
const menuItems =
columnDef.renderCellActionMenuItems?.(renderActionProps) ??
renderCellActionMenuItems?.(renderActionProps);
columnDef.renderCellActionMenuItems?.(renderActionProps) ?? renderCellActionMenuItems?.(renderActionProps);
return (
(!!menuItems?.length || !!internalMenuItems?.length) && (

View File

@@ -93,9 +93,7 @@ const DataTable_Paper = ({
))}
<DataTable_TableContainer table={table} />
{enableBottomToolbar &&
(parseFromValuesOrFunc(renderBottomToolbar, { table }) ?? (
<DataTable_BottomToolbar table={table} />
))}
(parseFromValuesOrFunc(renderBottomToolbar, { table }) ?? <DataTable_BottomToolbar table={table} />)}
</Paper>
);
};

View File

@@ -2,9 +2,7 @@ import { parseCSSVarId, parseFromValuesOrFunc } from "@/core/utils/utils";
import { Table } from "@mui/material";
import { useMRT_ColumnVirtualizer } from "material-react-table";
import { useMemo } from "react";
import DataTable_TableBody, {
Memo_DataTable_TableBody,
} from "../body/TableBody";
import DataTable_TableBody, { Memo_DataTable_TableBody } from "../body/TableBody";
import DataTable_TableHead from "../head/TableHead";
const DataTable_Table = ({ table, ...rest }) => {
@@ -22,8 +20,7 @@ const DataTable_Table = ({ table, ...rest }) => {
renderCaption,
},
} = table;
const { columnSizing, columnSizingInfo, columnVisibility, isFullScreen } =
getState();
const { columnSizing, columnSizingInfo, columnVisibility, isFullScreen } = getState();
const tableProps = {
...parseFromValuesOrFunc(muiTableProps, { table }),

View File

@@ -5,8 +5,7 @@ import DataTable_CellActionMenu from "../menus/CellActionMenu";
import DataTable_Table from "./Table";
import DataTable_TableLoadingOverlay from "./TableLoadingOverlay";
const useIsomorphicLayoutEffect =
typeof window !== "undefined" ? useLayoutEffect : useEffect;
const useIsomorphicLayoutEffect = typeof window !== "undefined" ? useLayoutEffect : useEffect;
const DataTable_TableContainer = ({ table, ...rest }) => {
const {
@@ -14,11 +13,9 @@ const DataTable_TableContainer = ({ table, ...rest }) => {
options: { enableCellActions, enableStickyHeader, muiTableContainerProps },
refs: { bottomToolbarRef, tableContainerRef, topToolbarRef },
} = table;
const { actionCell, isFullScreen, isLoading, showLoadingOverlay } =
getState();
const { actionCell, isFullScreen, isLoading, showLoadingOverlay } = getState();
const loading =
showLoadingOverlay !== false && (isLoading || showLoadingOverlay);
const loading = showLoadingOverlay !== false && (isLoading || showLoadingOverlay);
const [totalToolbarHeight, setTotalToolbarHeight] = useState(0);
@@ -30,15 +27,10 @@ const DataTable_TableContainer = ({ table, ...rest }) => {
};
useIsomorphicLayoutEffect(() => {
const topToolbarHeight =
typeof document !== "undefined"
? (topToolbarRef.current?.offsetHeight ?? 0)
: 0;
const topToolbarHeight = typeof document !== "undefined" ? (topToolbarRef.current?.offsetHeight ?? 0) : 0;
const bottomToolbarHeight =
typeof document !== "undefined"
? (bottomToolbarRef?.current?.offsetHeight ?? 0)
: 0;
typeof document !== "undefined" ? (bottomToolbarRef?.current?.offsetHeight ?? 0) : 0;
setTotalToolbarHeight(topToolbarHeight + bottomToolbarHeight);
});
@@ -58,9 +50,7 @@ const DataTable_TableContainer = ({ table, ...rest }) => {
}
}}
style={{
maxHeight: isFullScreen
? `calc(100vh - ${totalToolbarHeight}px)`
: undefined,
maxHeight: isFullScreen ? `calc(100vh - ${totalToolbarHeight}px)` : undefined,
...tableContainerProps?.style,
}}
sx={(theme) => ({
@@ -75,9 +65,7 @@ const DataTable_TableContainer = ({ table, ...rest }) => {
>
{loading ? <DataTable_TableLoadingOverlay table={table} /> : null}
<DataTable_Table table={table} />
{enableCellActions && actionCell && (
<DataTable_CellActionMenu table={table} />
)}
{enableCellActions && actionCell && <DataTable_CellActionMenu table={table} />}
</TableContainer>
);
};

View File

@@ -1,7 +1,4 @@
import {
getCommonToolbarStyles,
parseFromValuesOrFunc,
} from "@/core/utils/utils";
import { getCommonToolbarStyles, parseFromValuesOrFunc } from "@/core/utils/utils";
import { Box, alpha, useMediaQuery } from "@mui/material";
import DataTable_LinearProgressBar from "./LinearProgressBar";
import DataTable_TablePagination from "./TablePagination";
@@ -9,12 +6,7 @@ import DataTable_TablePagination from "./TablePagination";
const DataTable_BottomToolbar = ({ table, ...rest }) => {
const {
getState,
options: {
enablePagination,
muiBottomToolbarProps,
positionPagination,
renderBottomToolbarCustomActions,
},
options: { enablePagination, muiBottomToolbarProps, positionPagination, renderBottomToolbarCustomActions },
refs: { bottomToolbarRef },
} = table;
const { isFullScreen } = getState();
@@ -59,11 +51,7 @@ const DataTable_BottomToolbar = ({ table, ...rest }) => {
width: "100%",
}}
>
{renderBottomToolbarCustomActions ? (
renderBottomToolbarCustomActions({ table })
) : (
<span />
)}
{renderBottomToolbarCustomActions ? renderBottomToolbarCustomActions({ table }) : <span />}
<Box
sx={{
display: "flex",
@@ -73,8 +61,7 @@ const DataTable_BottomToolbar = ({ table, ...rest }) => {
top: 0,
}}
>
{enablePagination &&
["both", "bottom"].includes(positionPagination ?? "") && (
{enablePagination && ["both", "bottom"].includes(positionPagination ?? "") && (
<DataTable_TablePagination position="bottom" table={table} />
)}
</Box>

View File

@@ -1,8 +1,4 @@
import {
flipIconStyles,
getCommonTooltipProps,
parseFromValuesOrFunc,
} from "@/core/utils/utils";
import { flipIconStyles, getCommonTooltipProps, parseFromValuesOrFunc } from "@/core/utils/utils";
import { useTheme } from "@emotion/react";
import {
Box,
@@ -81,12 +77,7 @@ const DataTable_TablePagination = ({ position = "bottom", table, ...rest }) => {
gap: "8px",
justifyContent: { md: "space-between", sm: "center" },
justifySelf: "flex-end",
mt:
position === "top" &&
enableToolbarInternalActions &&
!showGlobalFilter
? "3rem"
: undefined,
mt: position === "top" && enableToolbarInternalActions && !showGlobalFilter ? "3rem" : undefined,
position: "relative",
px: "8px",
py: "12px",
@@ -115,8 +106,7 @@ const DataTable_TablePagination = ({ position = "bottom", table, ...rest }) => {
>
{rowsPerPageOptions.map((option) => {
const value = typeof option !== "number" ? option.value : option;
const label =
typeof option !== "number" ? option.label : `${option}`;
const label = typeof option !== "number" ? option.label : `${option}`;
return (
SelectProps?.children ??
(SelectProps?.native ? (

View File

@@ -1,7 +1,4 @@
import {
getCommonToolbarStyles,
parseFromValuesOrFunc,
} from "@/core/utils/utils";
import { getCommonToolbarStyles, parseFromValuesOrFunc } from "@/core/utils/utils";
import { Box, Typography, useMediaQuery } from "@mui/material";
import DataTable_LinearProgressBar from "./LinearProgressBar";
import DataTable_TablePagination from "./TablePagination";
@@ -43,10 +40,7 @@ const DataTable_TopToolbar = ({
const toolbarProps = parseFromValuesOrFunc(muiTopToolbarProps, { table });
const stackAlertBanner =
isMobile ||
!!renderTopToolbarCustomActions ||
(showGlobalFilter && isTablet);
const stackAlertBanner = isMobile || !!renderTopToolbarCustomActions || (showGlobalFilter && isTablet);
return (
<Box
@@ -112,11 +106,7 @@ const DataTable_TopToolbar = ({
>
{!special_data && (
<>
<ResetStorage
user_id={user_id}
page_name={page_name}
table_name={table_name}
/>
<ResetStorage user_id={user_id} page_name={page_name} table_name={table_name} />
<UpdateTable mutate={mutate} />
</>
)}
@@ -136,16 +126,12 @@ const DataTable_TopToolbar = ({
/>
)}
{special_filter && setFilterData && (
<FilterCustom
filterData={special_filter}
setFilterData={setFilterData}
/>
<FilterCustom filterData={special_filter} setFilterData={setFilterData} />
)}
</Box>
)}
</Box>
{enablePagination &&
["both", "top"].includes(positionPagination ?? "") && (
{enablePagination && ["both", "top"].includes(positionPagination ?? "") && (
<DataTable_TablePagination position="top" table={table} />
)}
<DataTable_LinearProgressBar isTopToolbar table={table} />

View File

@@ -1,8 +1,6 @@
import { forwardRef } from "react";
import { Slide } from "@mui/material";
export const DialogTransition = forwardRef(
function DialogTransition(props, ref) {
export const DialogTransition = forwardRef(function DialogTransition(props, ref) {
return <Slide direction="up" ref={ref} {...props} />;
},
);
});

View File

@@ -28,9 +28,7 @@ function FilterField({
errors,
}) {
const [anchorEl, setAnchorEl] = useState(null);
const defaultFilterTranslation =
filterModeOptionFa[filterParameters.filterMode] ||
filterParameters.filterMode;
const defaultFilterTranslation = filterModeOptionFa[filterParameters.filterMode] || filterParameters.filterMode;
const handleOpenFilterBox = (event) => {
setAnchorEl(event.currentTarget);

View File

@@ -29,13 +29,7 @@ function FilterOptionList({
};
return (
<Menu
id="simple-menu"
anchorEl={anchorEl}
keepMounted
open={Boolean(anchorEl)}
onClose={handleCloseFilterBox}
>
<Menu id="simple-menu" anchorEl={anchorEl} keepMounted open={Boolean(anchorEl)} onClose={handleCloseFilterBox}>
{filterOption.map((option, index) => (
<ListItem
key={index}

View File

@@ -2,12 +2,7 @@ import React from "react";
import MuiDatePicker from "@/core/components/DataTable/filter/fieldsType/CustomDate/MuiDatePicker";
import { Typography } from "@mui/material";
function CustomDatePicker({
column,
filterParameters,
defaultFilterTranslation,
handleChange,
}) {
function CustomDatePicker({ column, filterParameters, defaultFilterTranslation, handleChange }) {
return (
<MuiDatePicker
name={`${column.id}.value`}
@@ -17,10 +12,7 @@ function CustomDatePicker({
}}
placeholder={column.header}
helperText={
<Typography
variant="button"
sx={{ color: (theme) => theme.palette.primary.main }}
>
<Typography variant="button" sx={{ color: (theme) => theme.palette.primary.main }}>
نوع فیلتر: {defaultFilterTranslation} (تاریخ)
</Typography>
}

View File

@@ -4,13 +4,7 @@ import React from "react";
import { Box, Typography } from "@mui/material";
import MuiDatePicker from "@/core/components/DataTable/filter/fieldsType/CustomDate/MuiDatePicker";
function CustomDatePickerRange({
item,
filterParameters,
defaultFilterTranslation,
handleChange,
errors,
}) {
function CustomDatePickerRange({ item, filterParameters, defaultFilterTranslation, handleChange, errors }) {
return (
<Box sx={{ display: "flex", gap: 1 }}>
<MuiDatePicker
@@ -26,10 +20,7 @@ function CustomDatePickerRange({
maxDate={filterParameters.value[1]}
placeholder={`از تاریخ`}
helperText={
<Typography
variant="button"
sx={{ color: (theme) => theme.palette.primary.main }}
>
<Typography variant="button" sx={{ color: (theme) => theme.palette.primary.main }}>
نوع فیلتر: {defaultFilterTranslation} (تاریخ)
</Typography>
}
@@ -46,11 +37,7 @@ function CustomDatePickerRange({
}}
minDate={filterParameters.value[0]}
placeholder={`تا تاریخ`}
helperText={
errors?.[`${item.id}`]?.value
? errors?.[`${item.id}`]?.value.message
: null
}
helperText={errors?.[`${item.id}`]?.value ? errors?.[`${item.id}`]?.value.message : null}
error={Boolean(errors?.[`${item.id}`]?.value)}
/>
</Box>

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