complete system message
This commit is contained in:
6
.idea/prettier.xml
generated
Normal file
6
.idea/prettier.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="PrettierConfiguration">
|
||||
<option name="myConfigurationMode" value="AUTOMATIC" />
|
||||
</component>
|
||||
</project>
|
||||
@@ -19,6 +19,7 @@
|
||||
"@mui/material-nextjs": "^7.0.2",
|
||||
"@mui/x-date-pickers": "^8.2.0",
|
||||
"@mui/x-tree-view": "^8.2.0",
|
||||
"@wavesurfer/react": "^1.0.11",
|
||||
"axios": "^1.9.0",
|
||||
"date-fns-jalali": "4.1.0-0",
|
||||
"jalali-moment": "^3.3.11",
|
||||
@@ -34,6 +35,7 @@
|
||||
"stylis": "^4.3.6",
|
||||
"stylis-plugin-rtl": "^2.1.1",
|
||||
"swr": "^2.3.3",
|
||||
"wavesurfer.js": "^7.10.1",
|
||||
"yup": "^1.6.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
4994
pnpm-lock.yaml
generated
4994
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
BIN
public/audio/file_example_WAV_1MG.wav
Normal file
BIN
public/audio/file_example_WAV_1MG.wav
Normal file
Binary file not shown.
@@ -0,0 +1,16 @@
|
||||
import WithPermission from "@/core/middlewares/withPermission";
|
||||
import SystemMessagesPage from "@/components/dashboard/monitoring/SystemMessages";
|
||||
|
||||
export const metadata = {
|
||||
title: "پیام های سیستمی",
|
||||
};
|
||||
|
||||
const Page = () => {
|
||||
return (
|
||||
<WithPermission permission_name={["all"]}>
|
||||
<SystemMessagesPage />
|
||||
</WithPermission>
|
||||
);
|
||||
};
|
||||
|
||||
export default Page;
|
||||
@@ -0,0 +1,16 @@
|
||||
import WithPermission from "@/core/middlewares/withPermission";
|
||||
import CountryCallsReportPage from "@/components/dashboard/reports/CountryCallsReport";
|
||||
|
||||
export const metadata = {
|
||||
title: "گزارشات",
|
||||
};
|
||||
|
||||
const Page = () => {
|
||||
return (
|
||||
<WithPermission permission_name={["all"]}>
|
||||
<CountryCallsReportPage />
|
||||
</WithPermission>
|
||||
);
|
||||
};
|
||||
|
||||
export default Page;
|
||||
@@ -0,0 +1,16 @@
|
||||
import WithPermission from "@/core/middlewares/withPermission";
|
||||
import CountryKeyPressReportPage from "@/components/dashboard/reports/CountryKeyPressReport";
|
||||
|
||||
export const metadata = {
|
||||
title: "گزارشات",
|
||||
};
|
||||
|
||||
const Page = () => {
|
||||
return (
|
||||
<WithPermission permission_name={["all"]}>
|
||||
<CountryKeyPressReportPage />
|
||||
</WithPermission>
|
||||
);
|
||||
};
|
||||
|
||||
export default Page;
|
||||
@@ -0,0 +1,16 @@
|
||||
import WithPermission from "@/core/middlewares/withPermission";
|
||||
import CountryMessageRatingReportPage from "@/components/dashboard/reports/CountryMessageRatingReport";
|
||||
|
||||
export const metadata = {
|
||||
title: "گزارشات",
|
||||
};
|
||||
|
||||
const Page = () => {
|
||||
return (
|
||||
<WithPermission permission_name={["all"]}>
|
||||
<CountryMessageRatingReportPage />
|
||||
</WithPermission>
|
||||
);
|
||||
};
|
||||
|
||||
export default Page;
|
||||
@@ -0,0 +1,16 @@
|
||||
import WithPermission from "@/core/middlewares/withPermission";
|
||||
import CountryVoiceRatingReportPage from "@/components/dashboard/reports/CountryVoiceRatingReport";
|
||||
|
||||
export const metadata = {
|
||||
title: "گزارشات",
|
||||
};
|
||||
|
||||
const Page = () => {
|
||||
return (
|
||||
<WithPermission permission_name={["all"]}>
|
||||
<CountryVoiceRatingReportPage />
|
||||
</WithPermission>
|
||||
);
|
||||
};
|
||||
|
||||
export default Page;
|
||||
@@ -1,4 +1,5 @@
|
||||
"use client";
|
||||
|
||||
import WithoutAuthMiddleware from "@/core/middlewares/withoutAuth";
|
||||
import { Suspense } from "react";
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
"use client";
|
||||
import DataTableWithAuth from "@/core/components/DataTableWithAuth";
|
||||
import { GET_ROLE_LIST } from "@/core/utils/routes";
|
||||
import { ROLE_SERVICE } from "@/core/utils/routes";
|
||||
import { Box, Typography } from "@mui/material";
|
||||
import { useMemo } from "react";
|
||||
import Toolbar from "./Toolbar";
|
||||
@@ -75,7 +75,7 @@ const DataTable = () => {
|
||||
need_filter={true}
|
||||
columns={columns}
|
||||
sorting={[{ id: "id", desc: true }]}
|
||||
table_url={GET_ROLE_LIST}
|
||||
table_url={ROLE_SERVICE}
|
||||
page_name={"rolesPage"}
|
||||
table_name={"rolesList"}
|
||||
TableToolbar={Toolbar}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { DELETE_ROLE } from "@/core/utils/routes";
|
||||
import { ROLE_SERVICE } from "@/core/utils/routes";
|
||||
import useRequest from "@/lib/hooks/useRequest";
|
||||
import { Button, DialogActions, DialogContent, Stack, Typography } from "@mui/material";
|
||||
import { useState } from "react";
|
||||
@@ -9,7 +9,7 @@ const DeleteContent = ({ rowId, mutate, setOpenDeleteDialog }) => {
|
||||
const handleClick = async () => {
|
||||
setSubmitting(true);
|
||||
try {
|
||||
await requestServer(`${DELETE_ROLE}/${rowId}`, "delete");
|
||||
await requestServer(`${ROLE_SERVICE}/${rowId}`, "delete");
|
||||
mutate();
|
||||
setOpenDeleteDialog(false);
|
||||
} catch (error) {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import LtrTextField from "@/core/components/LtrTextField";
|
||||
import StyledForm from "@/core/components/StyledForm";
|
||||
import { CREATE_ROLE } from "@/core/utils/routes";
|
||||
import { ROLE_SERVICE } from "@/core/utils/routes";
|
||||
import useRequest from "@/lib/hooks/useRequest";
|
||||
import { yupResolver } from "@hookform/resolvers/yup";
|
||||
import {
|
||||
@@ -24,7 +24,7 @@ import usePermissionsList from "@/lib/hooks/usePermissionsList";
|
||||
const validationSchema = object().shape({
|
||||
name: string().required("نام فارسی نقش را وارد کنید"),
|
||||
name_fa: string().required("نام انگلیسی نقش را وارد کنید"),
|
||||
permissions: array().min(1, "حداقل یک دسترسی را انتخاب نمایید")
|
||||
permissions: array().min(1, "حداقل یک دسترسی را انتخاب نمایید"),
|
||||
});
|
||||
|
||||
const UpdateRoleForm = ({ values, setOpen, mutate }) => {
|
||||
@@ -34,7 +34,7 @@ const UpdateRoleForm = ({ values, setOpen, mutate }) => {
|
||||
const defaultValues = {
|
||||
name: values.name,
|
||||
name_fa: values.name_fa,
|
||||
permissions: values.permissions?.map(p => p.id) || []
|
||||
permissions: values.permissions?.map((p) => p.id) || [],
|
||||
};
|
||||
|
||||
const {
|
||||
@@ -45,7 +45,7 @@ const UpdateRoleForm = ({ values, setOpen, mutate }) => {
|
||||
|
||||
const onSubmit = async (data) => {
|
||||
try {
|
||||
await requestServer(`${CREATE_ROLE}/${values.id}`, "post", {
|
||||
await requestServer(`${ROLE_SERVICE}/${values.id}`, "post", {
|
||||
data: {
|
||||
permissions: data.permissions,
|
||||
name: data.name,
|
||||
@@ -106,17 +106,17 @@ const UpdateRoleForm = ({ values, setOpen, mutate }) => {
|
||||
name={"name_fa"}
|
||||
/>
|
||||
</Grid>
|
||||
<Box sx={{width: "100%"}}>
|
||||
<Box sx={{ width: "100%" }}>
|
||||
<Divider>
|
||||
<Chip label="سطوح دسترسی" size="medium" />
|
||||
</Divider>
|
||||
</Box>
|
||||
<Grid container spacing={1} sx={{width: "100%"}}>
|
||||
<Grid container spacing={1} sx={{ width: "100%" }}>
|
||||
{!loadingPermissions ? (
|
||||
<Controller
|
||||
control={control}
|
||||
name="permissions"
|
||||
render={({ field, fieldState: {error} }) => (
|
||||
render={({ field, fieldState: { error } }) => (
|
||||
<>
|
||||
{permissions.map((permission) => (
|
||||
<Grid key={permission.id} size={{ xs: 12, md: 4 }}>
|
||||
@@ -130,7 +130,9 @@ const UpdateRoleForm = ({ values, setOpen, mutate }) => {
|
||||
if (e.target.checked) {
|
||||
field.onChange([...field.value, value]);
|
||||
} else {
|
||||
field.onChange(field.value.filter((id) => id !== value));
|
||||
field.onChange(
|
||||
field.value.filter((id) => id !== value)
|
||||
);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
@@ -139,18 +141,32 @@ const UpdateRoleForm = ({ values, setOpen, mutate }) => {
|
||||
/>
|
||||
</Grid>
|
||||
))}
|
||||
<FormHelperText sx={{color: "error.main"}}>{!!error && error.message}</FormHelperText>
|
||||
<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 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>
|
||||
|
||||
@@ -9,26 +9,28 @@ import {
|
||||
DialogActions,
|
||||
DialogContent,
|
||||
Divider,
|
||||
FormControlLabel, FormHelperText,
|
||||
Grid, Skeleton,
|
||||
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 { ROLE_SERVICE } from "@/core/utils/routes";
|
||||
import usePermissionsList from "@/lib/hooks/usePermissionsList";
|
||||
|
||||
const defaultValues = {
|
||||
name: "",
|
||||
name_fa: "",
|
||||
permissions: []
|
||||
permissions: [],
|
||||
};
|
||||
|
||||
const validationSchema = object().shape({
|
||||
name: string().required("نام فارسی نقش را وارد کنید"),
|
||||
name_fa: string().required("نام انگلیسی نقش را وارد کنید"),
|
||||
permissions: array().min(1, "حداقل یک دسترسی را انتخاب نمایید")
|
||||
permissions: array().min(1, "حداقل یک دسترسی را انتخاب نمایید"),
|
||||
});
|
||||
|
||||
const CreateRoleForm = ({ setOpen, mutate }) => {
|
||||
@@ -43,7 +45,7 @@ const CreateRoleForm = ({ setOpen, mutate }) => {
|
||||
|
||||
const onSubmit = async (data) => {
|
||||
try {
|
||||
await requestServer(CREATE_ROLE, "post", {
|
||||
await requestServer(ROLE_SERVICE, "post", {
|
||||
data: {
|
||||
permissions: data.permissions,
|
||||
name: data.name,
|
||||
@@ -104,17 +106,17 @@ const CreateRoleForm = ({ setOpen, mutate }) => {
|
||||
name={"name_fa"}
|
||||
/>
|
||||
</Grid>
|
||||
<Box sx={{width: "100%"}}>
|
||||
<Box sx={{ width: "100%" }}>
|
||||
<Divider>
|
||||
<Chip label="سطوح دسترسی" size="medium" />
|
||||
</Divider>
|
||||
</Box>
|
||||
<Grid container spacing={1} sx={{width: "100%"}}>
|
||||
<Grid container spacing={1} sx={{ width: "100%" }}>
|
||||
{!loadingPermissions ? (
|
||||
<Controller
|
||||
control={control}
|
||||
name="permissions"
|
||||
render={({ field, fieldState: {error} }) => (
|
||||
render={({ field, fieldState: { error } }) => (
|
||||
<>
|
||||
{permissions.map((permission) => (
|
||||
<Grid key={permission.id} size={{ xs: 12, md: 4 }}>
|
||||
@@ -128,7 +130,9 @@ const CreateRoleForm = ({ setOpen, mutate }) => {
|
||||
if (e.target.checked) {
|
||||
field.onChange([...field.value, value]);
|
||||
} else {
|
||||
field.onChange(field.value.filter((id) => id !== value));
|
||||
field.onChange(
|
||||
field.value.filter((id) => id !== value)
|
||||
);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
@@ -137,18 +141,32 @@ const CreateRoleForm = ({ setOpen, mutate }) => {
|
||||
/>
|
||||
</Grid>
|
||||
))}
|
||||
<FormHelperText sx={{color: "error.main"}}>{!!error && error.message}</FormHelperText>
|
||||
<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 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>
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
"use client";
|
||||
import DataTableWithAuth from "@/core/components/DataTableWithAuth";
|
||||
import { GET_USER_LIST } from "@/core/utils/routes";
|
||||
import { Box, Stack } from "@mui/material";
|
||||
import { USER_SERVICE } from "@/core/utils/routes";
|
||||
import { Box } from "@mui/material";
|
||||
import { useMemo } from "react";
|
||||
import RowActions from "./RowActions";
|
||||
import Toolbar from "./Toolbar";
|
||||
import useProvinces from "@/lib/hooks/useProvince";
|
||||
import CustomSelectByDependency from "@/core/components/DataTable/filter/fieldsType/CustomSelectByDependency";
|
||||
import { Power, PowerOff } from "@mui/icons-material";
|
||||
import useRoles from "@/lib/hooks/useRoles";
|
||||
import OnlineCell from "./RowActions/Online";
|
||||
import TelephoneId from "./RowActions/TelephoneId";
|
||||
@@ -197,7 +196,7 @@ const DataTable = () => {
|
||||
need_filter={true}
|
||||
columns={columns}
|
||||
sorting={[{ id: "id", desc: true }]}
|
||||
table_url={GET_USER_LIST}
|
||||
table_url={USER_SERVICE}
|
||||
page_name={"usersPage"}
|
||||
table_name={"usersList"}
|
||||
TableToolbar={Toolbar}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { DELETE_USER } from "@/core/utils/routes";
|
||||
import { USER_SERVICE } from "@/core/utils/routes";
|
||||
import useRequest from "@/lib/hooks/useRequest";
|
||||
import { Button, DialogActions, DialogContent, Stack, Typography } from "@mui/material";
|
||||
import { useState } from "react";
|
||||
@@ -9,7 +9,7 @@ const DeleteContent = ({ rowId, mutate, setOpenDeleteDialog }) => {
|
||||
const handleClick = async () => {
|
||||
setSubmitting(true);
|
||||
try {
|
||||
await requestServer(`${DELETE_USER}/${rowId}`, "delete");
|
||||
await requestServer(`${USER_SERVICE}/${rowId}`, "delete");
|
||||
mutate();
|
||||
setOpenDeleteDialog(false);
|
||||
} catch (error) {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import LtrTextField from "@/core/components/LtrTextField";
|
||||
import StyledForm from "@/core/components/StyledForm";
|
||||
import validateNationalCode from "@/core/utils/nationalCodeValidation";
|
||||
import { UPDATE_USER } from "@/core/utils/routes";
|
||||
import { USER_SERVICE } from "@/core/utils/routes";
|
||||
import useProvinces from "@/lib/hooks/useProvince";
|
||||
import useRequest from "@/lib/hooks/useRequest";
|
||||
import useRoles from "@/lib/hooks/useRoles";
|
||||
@@ -40,7 +40,7 @@ const validationSchema = object().shape({
|
||||
position: string().required("سمت را وارد کنید"),
|
||||
province_id: string().required("استان را وارد کنید"),
|
||||
role_id: string().required("نقش را وارد کنید"),
|
||||
telephone_id: string().required("شماره تماس داخلی را وارد کنید")
|
||||
telephone_id: string().required("شماره تماس داخلی را وارد کنید"),
|
||||
});
|
||||
|
||||
const UpdateUserForm = ({ values, setOpen, mutate }) => {
|
||||
@@ -57,7 +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
|
||||
telephone_id: values.telephone_id,
|
||||
};
|
||||
|
||||
const provinceSelectOptions = useMemo(() => {
|
||||
@@ -104,7 +104,7 @@ const UpdateUserForm = ({ values, setOpen, mutate }) => {
|
||||
formData.append(key, data[key]);
|
||||
});
|
||||
try {
|
||||
await requestServer(`${UPDATE_USER}/${values.id}`, "post", {
|
||||
await requestServer(`${USER_SERVICE}/${values.id}`, "post", {
|
||||
data: formData,
|
||||
});
|
||||
setOpen(false);
|
||||
|
||||
@@ -26,7 +26,7 @@ import { object, string } from "yup";
|
||||
import { useMemo, useState } from "react";
|
||||
import useRoles from "@/lib/hooks/useRoles";
|
||||
import useRequest from "@/lib/hooks/useRequest";
|
||||
import { CREATE_USER } from "@/core/utils/routes";
|
||||
import { USER_SERVICE } from "@/core/utils/routes";
|
||||
import { Visibility, VisibilityOff } from "@mui/icons-material";
|
||||
|
||||
const defaultValues = {
|
||||
@@ -114,7 +114,7 @@ const CreateUserForm = ({ setOpen, mutate }) => {
|
||||
formData.append(key, data[key]);
|
||||
});
|
||||
try {
|
||||
await requestServer(CREATE_USER, "post", {
|
||||
await requestServer(USER_SERVICE, "post", {
|
||||
data: formData,
|
||||
});
|
||||
setOpen(false);
|
||||
|
||||
118
src/components/dashboard/monitoring/SystemMessages/DataTable.jsx
Normal file
118
src/components/dashboard/monitoring/SystemMessages/DataTable.jsx
Normal file
@@ -0,0 +1,118 @@
|
||||
"use client";
|
||||
|
||||
import DataTableWithAuth from "@/core/components/DataTableWithAuth";
|
||||
import { GET_SYSTEM_MESSAGES_SUPERVISOR } from "@/core/utils/routes";
|
||||
import { Box } from "@mui/material";
|
||||
import { useMemo } from "react";
|
||||
import moment from "jalali-moment";
|
||||
import Player from "./Player";
|
||||
import RateMessage from "./RateMessage";
|
||||
|
||||
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,
|
||||
},
|
||||
{
|
||||
header: "تاریخ",
|
||||
id: "date",
|
||||
enableColumnFilter: true,
|
||||
datatype: "text",
|
||||
filterMode: "equals",
|
||||
sortDescFirst: false,
|
||||
columnFilterModeOptions: ["equals", "contains"],
|
||||
grow: false,
|
||||
size: 100,
|
||||
Cell: ({ row }) =>
|
||||
row.original.date ? moment(row.original.date).locale("fa").format("yyyy/MM/DD") : <>-</>,
|
||||
},
|
||||
{
|
||||
header: "ساعت",
|
||||
id: "time",
|
||||
enableColumnFilter: true,
|
||||
datatype: "text",
|
||||
filterMode: "equals",
|
||||
sortDescFirst: false,
|
||||
columnFilterModeOptions: ["equals", "contains"],
|
||||
grow: false,
|
||||
size: 100,
|
||||
Cell: ({ row }) =>
|
||||
row.original.date ? moment(row.original.date).locale("fa").format("HH:mm") : <>-</>,
|
||||
},
|
||||
{
|
||||
header: "طول تماس ( ثانیه )",
|
||||
id: "duration",
|
||||
enableColumnFilter: true,
|
||||
datatype: "text",
|
||||
filterMode: "equals",
|
||||
sortDescFirst: false,
|
||||
columnFilterModeOptions: ["equals", "contains"],
|
||||
grow: false,
|
||||
size: 100,
|
||||
},
|
||||
{
|
||||
header: "پخش صدا",
|
||||
id: "player",
|
||||
enableColumnFilter: true,
|
||||
datatype: "text",
|
||||
filterMode: "equals",
|
||||
sortDescFirst: false,
|
||||
columnFilterModeOptions: ["equals", "contains"],
|
||||
grow: false,
|
||||
size: 100,
|
||||
Cell: ({ row }) => <Player audioUrl={row.original.voice} messageId={row.original.id} />,
|
||||
},
|
||||
{
|
||||
header: "ارزیابی",
|
||||
id: "rate",
|
||||
enableColumnFilter: true,
|
||||
datatype: "text",
|
||||
filterMode: "equals",
|
||||
sortDescFirst: false,
|
||||
columnFilterModeOptions: ["equals", "contains"],
|
||||
grow: false,
|
||||
size: 100,
|
||||
Cell: ({ cell, row, table }) => {
|
||||
const mutate = table.options.meta?.mutate;
|
||||
|
||||
return (
|
||||
<RateMessage
|
||||
mutate={mutate}
|
||||
messageId={row.original.id}
|
||||
initialValues={{
|
||||
message_quality: row.original.message_quality,
|
||||
format_quality: row.original.format_quality,
|
||||
description: row.original.description,
|
||||
}}
|
||||
/>
|
||||
);
|
||||
},
|
||||
},
|
||||
],
|
||||
[]
|
||||
);
|
||||
|
||||
return (
|
||||
<Box sx={{ p: 1, border: 1, borderColor: "divider", borderRadius: 1 }}>
|
||||
<DataTableWithAuth
|
||||
need_filter={true}
|
||||
columns={columns}
|
||||
table_url={GET_SYSTEM_MESSAGES_SUPERVISOR}
|
||||
page_name={"systemMessagesPage"}
|
||||
table_name={"systemMessagesList"}
|
||||
positionActionsColumn={"last"}
|
||||
/>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
export default DataTable;
|
||||
@@ -0,0 +1,26 @@
|
||||
"use client";
|
||||
|
||||
import React from "react";
|
||||
import { IconButton, Box } from "@mui/material";
|
||||
import PlayArrowIcon from "@mui/icons-material/PlayArrow";
|
||||
import PauseIcon from "@mui/icons-material/Pause";
|
||||
import useWaveSurferPlayer from "@/lib/hooks/useWaveSurferPlayer";
|
||||
|
||||
const Player = ({ audioUrl }) => {
|
||||
const { containerRef, isPlaying, playPause } = useWaveSurferPlayer(audioUrl);
|
||||
|
||||
return (
|
||||
<Box sx={{ display: "flex", alignItems: "center", gap: 1, justifyContent: "center" }}>
|
||||
<div ref={containerRef} style={{ width: 180 }} />
|
||||
<IconButton aria-label="play-pause" onClick={playPause}>
|
||||
{isPlaying ? (
|
||||
<PauseIcon sx={{ color: "#d32f2f" }} />
|
||||
) : (
|
||||
<PlayArrowIcon sx={{ color: "#1b4332" }} />
|
||||
)}
|
||||
</IconButton>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
export default Player;
|
||||
@@ -0,0 +1,163 @@
|
||||
"use client";
|
||||
|
||||
import { Button, FormControl, FormHelperText, Grid, InputLabel, MenuItem, OutlinedInput, Select } from "@mui/material";
|
||||
import LtrTextField from "@/core/components/LtrTextField";
|
||||
import { Controller, useForm } from "react-hook-form";
|
||||
import { yupResolver } from "@hookform/resolvers/yup";
|
||||
import { object, string, number } from "yup";
|
||||
import { GET_SYSTEM_MESSAGES_SUPERVISOR } from "@/core/utils/routes";
|
||||
import StyledForm from "@/core/components/StyledForm";
|
||||
import useRequest from "@/lib/hooks/useRequest";
|
||||
import usePermissionsList from "@/lib/hooks/usePermissionsList";
|
||||
import { useEffect } from "react";
|
||||
|
||||
const RateMessage = ({ messageId, initialValues, mutate }) => {
|
||||
const requestServer = useRequest({ notificationSuccess: true });
|
||||
|
||||
const defaultValues = {
|
||||
message_quality: initialValues?.message_quality ?? "",
|
||||
format_quality: initialValues?.format_quality ?? "",
|
||||
description: initialValues?.description ?? "",
|
||||
};
|
||||
|
||||
const validationSchema = object().shape({
|
||||
message_quality: string().required("وضعیت کیفیت پیام را مشخص کنید"),
|
||||
format_quality: string().required("وضعیت فرمت پیام را مشخص کنید"),
|
||||
description: string().optional(),
|
||||
});
|
||||
|
||||
const {
|
||||
control,
|
||||
handleSubmit,
|
||||
reset,
|
||||
formState: { isSubmitting, errors, isDirty, isValid },
|
||||
} = useForm({ defaultValues, resolver: yupResolver(validationSchema) });
|
||||
|
||||
const onSubmit = async (data) => {
|
||||
const fixData = {
|
||||
message_quality: parseInt(data.message_quality),
|
||||
format_quality: parseInt(data.format_quality),
|
||||
...(data.description !== "" && { description: data.description }),
|
||||
};
|
||||
try {
|
||||
await requestServer(`${GET_SYSTEM_MESSAGES_SUPERVISOR}/${messageId}`, "post", {
|
||||
data: fixData,
|
||||
});
|
||||
mutate();
|
||||
reset({
|
||||
message_quality: initialValues?.message_quality ?? "",
|
||||
format_quality: initialValues?.format_quality ?? "",
|
||||
description: initialValues?.description ?? "",
|
||||
});
|
||||
} catch (error) {}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
reset({
|
||||
message_quality: initialValues?.message_quality ?? "",
|
||||
format_quality: initialValues?.format_quality ?? "",
|
||||
description: initialValues?.description ?? "",
|
||||
});
|
||||
}, [initialValues.message_quality, initialValues.format_quality, initialValues.description]);
|
||||
|
||||
return (
|
||||
<StyledForm id="monitoringForm" onSubmit={handleSubmit(onSubmit)} style={{ width: "100%", height: "100%" }}>
|
||||
<Grid container spacing={2} sx={{ flexWrap: "nowrap", alignItems: "start" }}>
|
||||
<Grid item sx={{ xs: 3, sm: 3 }}>
|
||||
<Controller
|
||||
control={control}
|
||||
render={({ field, fieldState: { error } }) => {
|
||||
return (
|
||||
<FormControl fullWidth error={!!error} variant="outlined">
|
||||
<InputLabel id="label-message-quality" size="small" sx={{ fontSize: "12px" }}>
|
||||
کیفیت پیام
|
||||
</InputLabel>
|
||||
<Select
|
||||
variant="outlined"
|
||||
labelId="label-message-quality"
|
||||
id="message_quality"
|
||||
name="message_quality"
|
||||
size="small"
|
||||
sx={{ width: "100px", fontSize: "12px" }}
|
||||
value={field.value}
|
||||
label="کیفیت پیام"
|
||||
onChange={(e) => field.onChange(e.target.value)}
|
||||
>
|
||||
<MenuItem value={0}>نامناسب</MenuItem>
|
||||
<MenuItem value={1}>مناسب</MenuItem>
|
||||
</Select>
|
||||
</FormControl>
|
||||
);
|
||||
}}
|
||||
name="message_quality"
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item sx={{ xs: 3, sm: 3 }}>
|
||||
<Controller
|
||||
control={control}
|
||||
render={({ field, fieldState: { error } }) => {
|
||||
return (
|
||||
<FormControl fullWidth error={!!error} variant="outlined">
|
||||
<InputLabel id="label-format-quality" size="small" sx={{ fontSize: "12px" }}>
|
||||
فرمت پیام
|
||||
</InputLabel>
|
||||
<Select
|
||||
variant="outlined"
|
||||
labelId="label-format-quality"
|
||||
id="format_quality"
|
||||
name="format_quality"
|
||||
size="small"
|
||||
sx={{ width: "100px", fontSize: "12px" }}
|
||||
value={field.value}
|
||||
label="فرمت پیام"
|
||||
onChange={(e) => field.onChange(e.target.value)}
|
||||
>
|
||||
<MenuItem value={0}>نامناسب</MenuItem>
|
||||
<MenuItem value={1}>مناسب</MenuItem>
|
||||
</Select>
|
||||
</FormControl>
|
||||
);
|
||||
}}
|
||||
name="format_quality"
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item sx={{ xs: 3, sm: 3 }}>
|
||||
<Controller
|
||||
control={control}
|
||||
render={({ field, fieldState: { error } }) => {
|
||||
return (
|
||||
<LtrTextField
|
||||
{...field}
|
||||
variant="outlined"
|
||||
label="توضیحات"
|
||||
size="small"
|
||||
sx={{
|
||||
width: "180px",
|
||||
}}
|
||||
InputProps={{ sx: { fontSize: "12px" } }}
|
||||
InputLabelProps={{ sx: { fontSize: "12px" } }}
|
||||
error={!!error}
|
||||
helperText={!!error && error.message}
|
||||
/>
|
||||
);
|
||||
}}
|
||||
name="description"
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item sx={{ xs: 3, sm: 3 }}>
|
||||
<Button
|
||||
type="submit"
|
||||
disabled={isSubmitting || !isDirty || !isValid}
|
||||
size="medium"
|
||||
autoFocus
|
||||
variant="contained"
|
||||
>
|
||||
{isSubmitting ? "درحال ثبت..." : "ثبت"}
|
||||
</Button>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</StyledForm>
|
||||
);
|
||||
};
|
||||
|
||||
export default RateMessage;
|
||||
16
src/components/dashboard/monitoring/SystemMessages/index.jsx
Normal file
16
src/components/dashboard/monitoring/SystemMessages/index.jsx
Normal file
@@ -0,0 +1,16 @@
|
||||
"use client";
|
||||
|
||||
import PageTitle from "@/core/components/PageTitle";
|
||||
import { Stack } from "@mui/material";
|
||||
import DataTable from "./DataTable";
|
||||
|
||||
const SystemMessagesPage = () => {
|
||||
return (
|
||||
<Stack spacing={1}>
|
||||
<PageTitle title={"پیام های سیستمی"} />
|
||||
<DataTable />
|
||||
</Stack>
|
||||
);
|
||||
};
|
||||
|
||||
export default SystemMessagesPage;
|
||||
@@ -0,0 +1,205 @@
|
||||
"use client";
|
||||
|
||||
import DataTableWithAuth from "@/core/components/DataTableWithAuth";
|
||||
import { GET_COUNTRY_CALLS_REPORT } from "@/core/utils/routes";
|
||||
import { Box } from "@mui/material";
|
||||
import { useMemo } from "react";
|
||||
|
||||
const DataTable = () => {
|
||||
const columns = useMemo(
|
||||
() => [
|
||||
{
|
||||
accessorKey: "province_name",
|
||||
header: "استان",
|
||||
id: "province_id",
|
||||
enableColumnFilter: true,
|
||||
datatype: "text",
|
||||
filterMode: "equals",
|
||||
sortDescFirst: false,
|
||||
columnFilterModeOptions: ["equals", "contains"],
|
||||
grow: false,
|
||||
size: 100,
|
||||
},
|
||||
{
|
||||
accessorKey: "total",
|
||||
header: "تمامی تماس ها",
|
||||
id: "total",
|
||||
enableColumnFilter: true,
|
||||
datatype: "text",
|
||||
filterMode: "equals",
|
||||
sortDescFirst: false,
|
||||
grow: false,
|
||||
size: 100,
|
||||
},
|
||||
{
|
||||
header: "تماس با تهران",
|
||||
id: "call_to_tehran",
|
||||
enableColumnFilter: false,
|
||||
enableSorting: false,
|
||||
grow: false,
|
||||
size: 50,
|
||||
columns: [
|
||||
{
|
||||
accessorKey: "route_to_teh4",
|
||||
header: "کلید 4",
|
||||
id: "route_to_teh4",
|
||||
enableColumnFilter: true,
|
||||
datatype: "integer",
|
||||
filterMode: "equals",
|
||||
sortDescFirst: false,
|
||||
columnFilterModeOptions: ["equals", "contains"],
|
||||
grow: false,
|
||||
size: 100,
|
||||
},
|
||||
{
|
||||
accessorKey: "route_to_teh5",
|
||||
header: "کلید 5",
|
||||
id: "route_to_teh5",
|
||||
enableColumnFilter: true,
|
||||
datatype: "text",
|
||||
filterMode: "equals",
|
||||
sortDescFirst: false,
|
||||
columnFilterModeOptions: ["equals", "contains"],
|
||||
grow: false,
|
||||
size: 100,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
header: "تماس با اپراتور استانی",
|
||||
id: "call_to_ostan",
|
||||
enableColumnFilter: false,
|
||||
enableSorting: false,
|
||||
grow: false,
|
||||
size: 50,
|
||||
columns: [
|
||||
{
|
||||
accessorKey: "answered",
|
||||
header: "موفق",
|
||||
id: "answered",
|
||||
enableColumnFilter: true,
|
||||
datatype: "text",
|
||||
filterMode: "equals",
|
||||
sortDescFirst: false,
|
||||
columnFilterModeOptions: ["equals", "contains"],
|
||||
grow: false,
|
||||
size: 100,
|
||||
},
|
||||
{
|
||||
accessorKey: "missed",
|
||||
header: "جواب داده نشده",
|
||||
id: "missed",
|
||||
enableColumnFilter: true,
|
||||
datatype: "text",
|
||||
filterMode: "equals",
|
||||
sortDescFirst: false,
|
||||
columnFilterModeOptions: ["equals", "contains"],
|
||||
grow: false,
|
||||
size: 100,
|
||||
},
|
||||
{
|
||||
accessorKey: "fails",
|
||||
header: "نا موفق",
|
||||
id: "fails",
|
||||
enableColumnFilter: true,
|
||||
datatype: "text",
|
||||
filterMode: "equals",
|
||||
sortDescFirst: false,
|
||||
columnFilterModeOptions: ["equals", "contains"],
|
||||
grow: false,
|
||||
size: 100,
|
||||
},
|
||||
{
|
||||
accessorKey: "route_to_os4",
|
||||
header: "کلید 4",
|
||||
id: "route_to_os4",
|
||||
enableColumnFilter: true,
|
||||
datatype: "text",
|
||||
filterMode: "equals",
|
||||
sortDescFirst: false,
|
||||
columnFilterModeOptions: ["equals", "contains"],
|
||||
grow: false,
|
||||
size: 100,
|
||||
},
|
||||
{
|
||||
accessorKey: "route_to_os5",
|
||||
header: "کلید 5",
|
||||
id: "route_to_os5",
|
||||
enableColumnFilter: true,
|
||||
datatype: "text",
|
||||
filterMode: "equals",
|
||||
sortDescFirst: false,
|
||||
columnFilterModeOptions: ["equals", "contains"],
|
||||
grow: false,
|
||||
size: 100,
|
||||
},
|
||||
{
|
||||
accessorKey: "dnd",
|
||||
header: "dnd",
|
||||
id: "dnd",
|
||||
enableColumnFilter: true,
|
||||
datatype: "text",
|
||||
filterMode: "equals",
|
||||
sortDescFirst: false,
|
||||
columnFilterModeOptions: ["equals", "contains"],
|
||||
grow: false,
|
||||
size: 100,
|
||||
},
|
||||
{
|
||||
accessorKey: "transferred",
|
||||
header: "انتقال تماس",
|
||||
id: "transferred",
|
||||
enableColumnFilter: true,
|
||||
datatype: "text",
|
||||
filterMode: "equals",
|
||||
sortDescFirst: false,
|
||||
columnFilterModeOptions: ["equals", "contains"],
|
||||
grow: false,
|
||||
size: 100,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
accessorKey: "answered_over10",
|
||||
header: "تماس بالای 10 ثانیه",
|
||||
id: "answered_over10",
|
||||
enableColumnFilter: true,
|
||||
datatype: "text",
|
||||
filterMode: "equals",
|
||||
sortDescFirst: false,
|
||||
columnFilterModeOptions: ["equals", "contains"],
|
||||
grow: false,
|
||||
size: 100,
|
||||
},
|
||||
{
|
||||
accessorKey: "average_calls_time",
|
||||
header: "میانگین تماس ها",
|
||||
id: "average_calls_time",
|
||||
enableColumnFilter: true,
|
||||
datatype: "text",
|
||||
filterMode: "equals",
|
||||
sortDescFirst: false,
|
||||
columnFilterModeOptions: ["equals", "contains"],
|
||||
grow: false,
|
||||
size: 100,
|
||||
},
|
||||
],
|
||||
[]
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Box sx={{ p: 1, border: 1, borderColor: "divider", borderRadius: 1 }}>
|
||||
<DataTableWithAuth
|
||||
need_filter={true}
|
||||
columns={columns}
|
||||
table_url={GET_COUNTRY_CALLS_REPORT}
|
||||
page_name={"countryCallsReportPage"}
|
||||
table_name={"countryCallsReportList"}
|
||||
positionActionsColumn={"last"}
|
||||
/>
|
||||
</Box>
|
||||
</>
|
||||
);
|
||||
};
|
||||
export default DataTable;
|
||||
@@ -0,0 +1,16 @@
|
||||
"use client";
|
||||
|
||||
import PageTitle from "@/core/components/PageTitle";
|
||||
import { Stack } from "@mui/material";
|
||||
import DataTable from "./DataTable";
|
||||
|
||||
const CountryCallsReportPage = () => {
|
||||
return (
|
||||
<Stack spacing={1}>
|
||||
<PageTitle title={"تجمعی تمام مراکز"} />
|
||||
<DataTable />
|
||||
</Stack>
|
||||
);
|
||||
};
|
||||
|
||||
export default CountryCallsReportPage;
|
||||
@@ -0,0 +1,236 @@
|
||||
"use client";
|
||||
|
||||
import DataTableWithAuth from "@/core/components/DataTableWithAuth";
|
||||
import { GET_COUNTRY_KEYPRESS_REPORT } from "@/core/utils/routes";
|
||||
import { Box } from "@mui/material";
|
||||
import { useMemo } from "react";
|
||||
|
||||
const DataTable = () => {
|
||||
const columns = useMemo(
|
||||
() => [
|
||||
{
|
||||
accessorKey: "province_name",
|
||||
header: "استان",
|
||||
id: "province_id",
|
||||
enableColumnFilter: true,
|
||||
datatype: "text",
|
||||
filterMode: "equals",
|
||||
sortDescFirst: false,
|
||||
columnFilterModeOptions: ["equals", "contains"],
|
||||
grow: false,
|
||||
size: 100,
|
||||
},
|
||||
{
|
||||
accessorKey: "total",
|
||||
header: "مجموع تماس ها",
|
||||
id: "total",
|
||||
enableColumnFilter: true,
|
||||
datatype: "text",
|
||||
filterMode: "equals",
|
||||
sortDescFirst: false,
|
||||
grow: false,
|
||||
size: 100,
|
||||
},
|
||||
{
|
||||
header: "تماس با اعداد",
|
||||
id: "call_with_nums",
|
||||
enableColumnFilter: false,
|
||||
enableSorting: false,
|
||||
grow: false,
|
||||
size: 50,
|
||||
columns: [
|
||||
{
|
||||
accessorKey: "key1",
|
||||
header: "کلید 1",
|
||||
id: "key1",
|
||||
enableColumnFilter: true,
|
||||
datatype: "integer",
|
||||
filterMode: "equals",
|
||||
sortDescFirst: false,
|
||||
columnFilterModeOptions: ["equals", "contains"],
|
||||
grow: false,
|
||||
size: 100,
|
||||
},
|
||||
{
|
||||
accessorKey: "key2",
|
||||
header: "کلید 2",
|
||||
id: "key2",
|
||||
enableColumnFilter: true,
|
||||
datatype: "integer",
|
||||
filterMode: "equals",
|
||||
sortDescFirst: false,
|
||||
columnFilterModeOptions: ["equals", "contains"],
|
||||
grow: false,
|
||||
size: 100,
|
||||
},
|
||||
{
|
||||
accessorKey: "key3",
|
||||
header: "کلید 3",
|
||||
id: "key3",
|
||||
enableColumnFilter: true,
|
||||
datatype: "integer",
|
||||
filterMode: "equals",
|
||||
sortDescFirst: false,
|
||||
columnFilterModeOptions: ["equals", "contains"],
|
||||
grow: false,
|
||||
size: 100,
|
||||
},
|
||||
{
|
||||
accessorKey: "key4",
|
||||
header: "کلید 4",
|
||||
id: "key4",
|
||||
enableColumnFilter: true,
|
||||
datatype: "integer",
|
||||
filterMode: "equals",
|
||||
sortDescFirst: false,
|
||||
columnFilterModeOptions: ["equals", "contains"],
|
||||
grow: false,
|
||||
size: 100,
|
||||
},
|
||||
{
|
||||
accessorKey: "key5",
|
||||
header: "کلید 5",
|
||||
id: "key5",
|
||||
enableColumnFilter: true,
|
||||
datatype: "integer",
|
||||
filterMode: "equals",
|
||||
sortDescFirst: false,
|
||||
columnFilterModeOptions: ["equals", "contains"],
|
||||
grow: false,
|
||||
size: 100,
|
||||
},
|
||||
{
|
||||
accessorKey: "key6",
|
||||
header: "کلید 6",
|
||||
id: "key6",
|
||||
enableColumnFilter: true,
|
||||
datatype: "text",
|
||||
filterMode: "equals",
|
||||
sortDescFirst: false,
|
||||
columnFilterModeOptions: ["equals", "contains"],
|
||||
grow: false,
|
||||
size: 100,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
accessorKey: "key9",
|
||||
header: "منوی مدیریت",
|
||||
id: "key9",
|
||||
enableColumnFilter: true,
|
||||
datatype: "text",
|
||||
filterMode: "equals",
|
||||
sortDescFirst: false,
|
||||
grow: false,
|
||||
size: 100,
|
||||
},
|
||||
{
|
||||
accessorKey: "key4_1",
|
||||
header: "تماس با استان",
|
||||
id: "key4_1",
|
||||
enableColumnFilter: true,
|
||||
datatype: "text",
|
||||
filterMode: "equals",
|
||||
sortDescFirst: false,
|
||||
grow: false,
|
||||
size: 100,
|
||||
},
|
||||
{
|
||||
accessorKey: "key4_2",
|
||||
header: "تماس با تهران",
|
||||
id: "key4_2",
|
||||
enableColumnFilter: true,
|
||||
datatype: "text",
|
||||
filterMode: "equals",
|
||||
sortDescFirst: false,
|
||||
grow: false,
|
||||
size: 100,
|
||||
},
|
||||
{
|
||||
accessorKey: "key5_1",
|
||||
header: "تماس راننده با استان",
|
||||
id: "key5_1",
|
||||
enableColumnFilter: true,
|
||||
datatype: "text",
|
||||
filterMode: "equals",
|
||||
sortDescFirst: false,
|
||||
grow: false,
|
||||
size: 100,
|
||||
},
|
||||
{
|
||||
accessorKey: "key5_2",
|
||||
header: "تماس راننده با تهران",
|
||||
id: "key5_2",
|
||||
enableColumnFilter: true,
|
||||
datatype: "text",
|
||||
filterMode: "equals",
|
||||
sortDescFirst: false,
|
||||
grow: false,
|
||||
size: 100,
|
||||
},
|
||||
{
|
||||
header: "محدودیت",
|
||||
id: "limits",
|
||||
enableColumnFilter: false,
|
||||
enableSorting: false,
|
||||
grow: false,
|
||||
size: 50,
|
||||
columns: [
|
||||
{
|
||||
accessorKey: "key2_1",
|
||||
header: "انسداد فصلی",
|
||||
id: "key2_1",
|
||||
enableColumnFilter: true,
|
||||
datatype: "integer",
|
||||
filterMode: "equals",
|
||||
sortDescFirst: false,
|
||||
columnFilterModeOptions: ["equals", "contains"],
|
||||
grow: false,
|
||||
size: 100,
|
||||
},
|
||||
{
|
||||
accessorKey: "key2_2",
|
||||
header: "تردد وسایل نقلیه سنگین و موتورسیکلت",
|
||||
id: "key2_2",
|
||||
enableColumnFilter: true,
|
||||
datatype: "integer",
|
||||
filterMode: "equals",
|
||||
sortDescFirst: false,
|
||||
columnFilterModeOptions: ["equals", "contains"],
|
||||
grow: false,
|
||||
size: 100,
|
||||
},
|
||||
{
|
||||
accessorKey: "key2_3",
|
||||
header: "سایر",
|
||||
id: "key2_3",
|
||||
enableColumnFilter: true,
|
||||
datatype: "integer",
|
||||
filterMode: "equals",
|
||||
sortDescFirst: false,
|
||||
columnFilterModeOptions: ["equals", "contains"],
|
||||
grow: false,
|
||||
size: 100,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
[]
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Box sx={{ p: 1, border: 1, borderColor: "divider", borderRadius: 1 }}>
|
||||
<DataTableWithAuth
|
||||
need_filter={true}
|
||||
columns={columns}
|
||||
table_url={GET_COUNTRY_KEYPRESS_REPORT}
|
||||
page_name={"countryKeypressReportPage"}
|
||||
table_name={"countryKeypressReportList"}
|
||||
positionActionsColumn={"last"}
|
||||
/>
|
||||
</Box>
|
||||
</>
|
||||
);
|
||||
};
|
||||
export default DataTable;
|
||||
@@ -0,0 +1,14 @@
|
||||
import PageTitle from "@/core/components/PageTitle";
|
||||
import { Stack } from "@mui/material";
|
||||
import DataTable from "./DataTable";
|
||||
|
||||
const CountryKeyPressReportPage = () => {
|
||||
return (
|
||||
<Stack spacing={1}>
|
||||
<PageTitle title={"گزارش تماس ها"} />
|
||||
<DataTable />
|
||||
</Stack>
|
||||
);
|
||||
};
|
||||
|
||||
export default CountryKeyPressReportPage;
|
||||
@@ -0,0 +1,150 @@
|
||||
"use client";
|
||||
|
||||
import DataTableWithAuth from "@/core/components/DataTableWithAuth";
|
||||
import { GET_COUNTRY_MESSAGE_RATING_REPORT } from "@/core/utils/routes";
|
||||
import { Box } from "@mui/material";
|
||||
import { useMemo } from "react";
|
||||
|
||||
const DataTable = () => {
|
||||
const columns = useMemo(
|
||||
() => [
|
||||
{
|
||||
accessorKey: "province_name",
|
||||
header: "استان",
|
||||
id: "province_id",
|
||||
enableColumnFilter: true,
|
||||
datatype: "text",
|
||||
filterMode: "equals",
|
||||
sortDescFirst: false,
|
||||
columnFilterModeOptions: ["equals", "contains"],
|
||||
grow: false,
|
||||
size: 100,
|
||||
},
|
||||
{
|
||||
accessorKey: "total",
|
||||
header: "پیام ها",
|
||||
id: "total",
|
||||
enableColumnFilter: true,
|
||||
datatype: "text",
|
||||
filterMode: "equals",
|
||||
sortDescFirst: false,
|
||||
columnFilterModeOptions: ["equals", "contains"],
|
||||
grow: false,
|
||||
size: 100,
|
||||
},
|
||||
{
|
||||
accessorKey: "listens",
|
||||
header: "شنیده شده",
|
||||
id: "listens",
|
||||
enableColumnFilter: true,
|
||||
datatype: "text",
|
||||
filterMode: "equals",
|
||||
sortDescFirst: false,
|
||||
columnFilterModeOptions: ["equals", "contains"],
|
||||
grow: false,
|
||||
size: 100,
|
||||
},
|
||||
{
|
||||
accessorKey: "not_listens",
|
||||
header: "شنیده نشده",
|
||||
id: "not_listens",
|
||||
enableColumnFilter: true,
|
||||
datatype: "text",
|
||||
filterMode: "equals",
|
||||
sortDescFirst: false,
|
||||
columnFilterModeOptions: ["equals", "contains"],
|
||||
grow: false,
|
||||
size: 100,
|
||||
},
|
||||
{
|
||||
accessorKey: "review_average",
|
||||
header: "میانگین زمان بررسی",
|
||||
id: "review_average",
|
||||
enableColumnFilter: true,
|
||||
datatype: "text",
|
||||
filterMode: "equals",
|
||||
sortDescFirst: false,
|
||||
columnFilterModeOptions: ["equals", "contains"],
|
||||
grow: false,
|
||||
size: 100,
|
||||
},
|
||||
{
|
||||
accessorKey: "action1",
|
||||
header: "میانگین زمان بررسی (دقیقه)",
|
||||
id: "action1",
|
||||
enableColumnFilter: true,
|
||||
datatype: "text",
|
||||
filterMode: "equals",
|
||||
sortDescFirst: false,
|
||||
columnFilterModeOptions: ["equals", "contains"],
|
||||
grow: false,
|
||||
size: 100,
|
||||
},
|
||||
{
|
||||
accessorKey: "action2",
|
||||
header: "عدم نیاز به ثبت (مشکل راه)",
|
||||
id: "action2",
|
||||
enableColumnFilter: true,
|
||||
datatype: "text",
|
||||
filterMode: "equals",
|
||||
sortDescFirst: false,
|
||||
columnFilterModeOptions: ["equals", "contains"],
|
||||
grow: false,
|
||||
size: 100,
|
||||
},
|
||||
{
|
||||
accessorKey: "action3",
|
||||
header: "عدم نیاز به ثبت (مشکل حمل و نقلی)",
|
||||
id: "action3",
|
||||
enableColumnFilter: true,
|
||||
datatype: "text",
|
||||
filterMode: "equals",
|
||||
sortDescFirst: false,
|
||||
columnFilterModeOptions: ["equals", "contains"],
|
||||
grow: false,
|
||||
size: 100,
|
||||
},
|
||||
{
|
||||
accessorKey: "action4",
|
||||
header: "عدم نیاز به ثبت (مشکل عوارضی)",
|
||||
id: "action4",
|
||||
enableColumnFilter: true,
|
||||
datatype: "text",
|
||||
filterMode: "equals",
|
||||
sortDescFirst: false,
|
||||
columnFilterModeOptions: ["equals", "contains"],
|
||||
grow: false,
|
||||
size: 100,
|
||||
},
|
||||
{
|
||||
accessorKey: "action5",
|
||||
header: "ثبت سوانح (مشکل راه)",
|
||||
id: "action5",
|
||||
enableColumnFilter: true,
|
||||
datatype: "text",
|
||||
filterMode: "equals",
|
||||
sortDescFirst: false,
|
||||
columnFilterModeOptions: ["equals", "contains"],
|
||||
grow: false,
|
||||
size: 100,
|
||||
},
|
||||
],
|
||||
[]
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Box sx={{ p: 1, border: 1, borderColor: "divider", borderRadius: 1 }}>
|
||||
<DataTableWithAuth
|
||||
need_filter={true}
|
||||
columns={columns}
|
||||
table_url={GET_COUNTRY_MESSAGE_RATING_REPORT}
|
||||
page_name={"countryMessageRatingReportPage"}
|
||||
table_name={"countryMessageRatingReportList"}
|
||||
positionActionsColumn={"last"}
|
||||
/>
|
||||
</Box>
|
||||
</>
|
||||
);
|
||||
};
|
||||
export default DataTable;
|
||||
@@ -0,0 +1,14 @@
|
||||
import PageTitle from "@/core/components/PageTitle";
|
||||
import { Stack } from "@mui/material";
|
||||
import DataTable from "./DataTable";
|
||||
|
||||
const CountryMessageRatingReportPage = () => {
|
||||
return (
|
||||
<Stack spacing={1}>
|
||||
<PageTitle title={"تجمعی پیام های مردمی مراکز"} />
|
||||
<DataTable />
|
||||
</Stack>
|
||||
);
|
||||
};
|
||||
|
||||
export default CountryMessageRatingReportPage;
|
||||
@@ -0,0 +1,110 @@
|
||||
"use client";
|
||||
|
||||
import DataTableWithAuth from "@/core/components/DataTableWithAuth";
|
||||
import { GET_COUNTRY_VOICE_RATING_REPORT } from "@/core/utils/routes";
|
||||
import { Box } from "@mui/material";
|
||||
import { useMemo } from "react";
|
||||
|
||||
const DataTable = () => {
|
||||
const columns = useMemo(
|
||||
() => [
|
||||
{
|
||||
accessorKey: "province_name",
|
||||
header: "استان",
|
||||
id: "province_id",
|
||||
enableColumnFilter: true,
|
||||
datatype: "text",
|
||||
filterMode: "equals",
|
||||
sortDescFirst: false,
|
||||
columnFilterModeOptions: ["equals", "contains"],
|
||||
grow: false,
|
||||
size: 100,
|
||||
},
|
||||
{
|
||||
header: "کیفیت",
|
||||
id: "quality",
|
||||
enableColumnFilter: false,
|
||||
enableSorting: false,
|
||||
grow: false,
|
||||
size: 50,
|
||||
columns: [
|
||||
{
|
||||
accessorKey: "message_quality_ok",
|
||||
header: "مناسب",
|
||||
id: "message_quality_ok",
|
||||
enableColumnFilter: true,
|
||||
datatype: "integer",
|
||||
filterMode: "equals",
|
||||
sortDescFirst: false,
|
||||
columnFilterModeOptions: ["equals", "contains"],
|
||||
grow: false,
|
||||
size: 100,
|
||||
},
|
||||
{
|
||||
accessorKey: "message_quality_nok",
|
||||
header: "نامناسب",
|
||||
id: "message_quality_nok",
|
||||
enableColumnFilter: true,
|
||||
datatype: "text",
|
||||
filterMode: "equals",
|
||||
sortDescFirst: false,
|
||||
columnFilterModeOptions: ["equals", "contains"],
|
||||
grow: false,
|
||||
size: 100,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
header: "فرمت",
|
||||
id: "format",
|
||||
enableColumnFilter: false,
|
||||
enableSorting: false,
|
||||
grow: false,
|
||||
size: 50,
|
||||
columns: [
|
||||
{
|
||||
accessorKey: "message_format_ok",
|
||||
header: "مناسب",
|
||||
id: "message_format_ok",
|
||||
enableColumnFilter: true,
|
||||
datatype: "integer",
|
||||
filterMode: "equals",
|
||||
sortDescFirst: false,
|
||||
columnFilterModeOptions: ["equals", "contains"],
|
||||
grow: false,
|
||||
size: 100,
|
||||
},
|
||||
{
|
||||
accessorKey: "message_format_nok",
|
||||
header: "نامناسب",
|
||||
id: "message_format_nok",
|
||||
enableColumnFilter: true,
|
||||
datatype: "text",
|
||||
filterMode: "equals",
|
||||
sortDescFirst: false,
|
||||
columnFilterModeOptions: ["equals", "contains"],
|
||||
grow: false,
|
||||
size: 100,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
[]
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Box sx={{ p: 1, border: 1, borderColor: "divider", borderRadius: 1 }}>
|
||||
<DataTableWithAuth
|
||||
need_filter={true}
|
||||
columns={columns}
|
||||
table_url={GET_COUNTRY_VOICE_RATING_REPORT}
|
||||
page_name={"countryVoiceRatingReportPage"}
|
||||
table_name={"countryVoiceRatingReportList"}
|
||||
positionActionsColumn={"last"}
|
||||
/>
|
||||
</Box>
|
||||
</>
|
||||
);
|
||||
};
|
||||
export default DataTable;
|
||||
@@ -0,0 +1,14 @@
|
||||
import PageTitle from "@/core/components/PageTitle";
|
||||
import { Stack } from "@mui/material";
|
||||
import DataTable from "./DataTable";
|
||||
|
||||
const CountryVoiceRatingReportPage = () => {
|
||||
return (
|
||||
<Stack spacing={1}>
|
||||
<PageTitle title={"گزارش کیفی استان ها"} />
|
||||
<DataTable />
|
||||
</Stack>
|
||||
);
|
||||
};
|
||||
|
||||
export default CountryVoiceRatingReportPage;
|
||||
@@ -156,6 +156,9 @@ const DataTable_Main = (props) => {
|
||||
</>
|
||||
),
|
||||
renderRowActions: ({ row }) => <RowActions row={row} mutate={mutate} />,
|
||||
meta: {
|
||||
mutate,
|
||||
},
|
||||
...props,
|
||||
});
|
||||
|
||||
|
||||
@@ -1,5 +1,15 @@
|
||||
import { Settings } from "@mui/icons-material";
|
||||
import AssessmentIcon from "@mui/icons-material/Assessment";
|
||||
import SupervisedUserCircleIcon from "@mui/icons-material/SupervisedUserCircle";
|
||||
import VerifiedUserIcon from "@mui/icons-material/VerifiedUser";
|
||||
import SpaceDashboardIcon from "@mui/icons-material/SpaceDashboard";
|
||||
import PointOfSaleIcon from "@mui/icons-material/PointOfSale";
|
||||
import ThreePIcon from "@mui/icons-material/ThreeP";
|
||||
import VoiceChatIcon from "@mui/icons-material/VoiceChat";
|
||||
import ZoomInMapIcon from "@mui/icons-material/ZoomInMap";
|
||||
import StarIcon from "@mui/icons-material/Star";
|
||||
import MarkEmailReadIcon from "@mui/icons-material/MarkEmailRead";
|
||||
import TtyIcon from "@mui/icons-material/Tty";
|
||||
|
||||
export const pageMenu = [
|
||||
{
|
||||
@@ -10,6 +20,47 @@ export const pageMenu = [
|
||||
icon: <SpaceDashboardIcon sx={{ width: "inherit", height: "inherit" }} />,
|
||||
permissions: ["all"],
|
||||
},
|
||||
{
|
||||
id: "reports",
|
||||
label: "گزارشات",
|
||||
type: "menu",
|
||||
icon: <AssessmentIcon sx={{ width: "inherit", height: "inherit" }} />,
|
||||
hasSubitems: true,
|
||||
Subitems: [
|
||||
{
|
||||
id: "reports-countryCallReport",
|
||||
label: "تجمعی تمام مراکز",
|
||||
type: "page",
|
||||
icon: <ZoomInMapIcon sx={{ width: "inherit", height: "inherit" }} />,
|
||||
route: "/dashboard/reports/country-calls-report",
|
||||
permissions: ["all"],
|
||||
},
|
||||
{
|
||||
id: "reports-countryVoiceRatingReport",
|
||||
label: "گزارش کیفی استان ها",
|
||||
type: "page",
|
||||
icon: <StarIcon sx={{ width: "inherit", height: "inherit" }} />,
|
||||
route: "/dashboard/reports/country-voice-rating-report",
|
||||
permissions: ["all"],
|
||||
},
|
||||
{
|
||||
id: "reports-countryMessageRatingReport",
|
||||
label: "تجمعی پیام های مردمی مراکز",
|
||||
type: "page",
|
||||
icon: <MarkEmailReadIcon sx={{ width: "inherit", height: "inherit" }} />,
|
||||
route: "/dashboard/reports/country-message-rating-report",
|
||||
permissions: ["all"],
|
||||
},
|
||||
{
|
||||
id: "reports-countryKeypressReport",
|
||||
label: "گزارش تماس ها",
|
||||
type: "page",
|
||||
icon: <TtyIcon sx={{ width: "inherit", height: "inherit" }} />,
|
||||
route: "/dashboard/reports/country-keypress-report",
|
||||
permissions: ["all"],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: "systemManagment",
|
||||
label: "مدیریت سامانه",
|
||||
@@ -21,6 +72,7 @@ export const pageMenu = [
|
||||
id: "systemManagment-users",
|
||||
label: "کاربران",
|
||||
type: "page",
|
||||
icon: <SupervisedUserCircleIcon sx={{ width: "inherit", height: "inherit" }} />,
|
||||
route: "/dashboard/users",
|
||||
permissions: ["manage_users"],
|
||||
},
|
||||
@@ -28,9 +80,43 @@ export const pageMenu = [
|
||||
id: "systemManagment-roles",
|
||||
label: "نقش ها",
|
||||
type: "page",
|
||||
icon: <VerifiedUserIcon sx={{ width: "inherit", height: "inherit" }} />,
|
||||
route: "/dashboard/roles",
|
||||
permissions: ["manage_roles"],
|
||||
}
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: "monitoring",
|
||||
label: "پایش 141",
|
||||
type: "menu",
|
||||
icon: <Settings sx={{ width: "inherit", height: "inherit" }} />,
|
||||
hasSubitems: true,
|
||||
Subitems: [
|
||||
{
|
||||
id: "monitoring-operator-dialogue",
|
||||
label: "صدای کارشناسان",
|
||||
type: "page",
|
||||
icon: <VoiceChatIcon sx={{ width: "inherit", height: "inherit" }} />,
|
||||
route: "/dashboard/monitoring/operator-dialogue",
|
||||
permissions: ["all"],
|
||||
},
|
||||
{
|
||||
id: "monitoring-system-messages",
|
||||
label: "پیام های سیستمی",
|
||||
type: "page",
|
||||
icon: <PointOfSaleIcon sx={{ width: "inherit", height: "inherit" }} />,
|
||||
route: "/dashboard/monitoring/system-messages",
|
||||
permissions: ["all"],
|
||||
},
|
||||
{
|
||||
id: "monitoring-people-messages",
|
||||
label: "پیام های مردمی",
|
||||
type: "page",
|
||||
icon: <ThreePIcon sx={{ width: "inherit", height: "inherit" }} />,
|
||||
route: "/dashboard/monitoring/people-messages",
|
||||
permissions: ["all"],
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
@@ -14,12 +14,14 @@ export const GET_CATEGORY = api + "/categories/list";
|
||||
export const GET_CALLER_HISTORY = api + "/calls/list";
|
||||
export const CALL_ACTION = api + "/calls";
|
||||
|
||||
export const GET_USER_LIST = api + "/users";
|
||||
export const CREATE_USER = api + "/users";
|
||||
export const DELETE_USER = api + "/users";
|
||||
export const UPDATE_USER = api + "/users";
|
||||
export const USER_SERVICE = api + "/users";
|
||||
|
||||
export const GET_ROLE_LIST = api + "/roles";
|
||||
export const CREATE_ROLE = api + "/roles";
|
||||
export const DELETE_ROLE = api + "/roles";
|
||||
export const UPDATE_ROLE = api + "/roles";
|
||||
export const ROLE_SERVICE = api + "/roles";
|
||||
|
||||
export const GET_COUNTRY_CALLS_REPORT = api + "/cumulative_stats";
|
||||
export const GET_COUNTRY_VOICE_RATING_REPORT = api + "/cumulative_voice_ratings";
|
||||
export const GET_COUNTRY_MESSAGE_RATING_REPORT = api + "/cumulative_message_ratings";
|
||||
export const GET_COUNTRY_KEYPRESS_REPORT = api + "/cumulative_keypress_stats";
|
||||
|
||||
export const GET_SYSTEM_MESSAGES_SUPERVISOR = api + "/system_messages/supervisor";
|
||||
export const GET_SYSTEM_MESSAGES_OPERATOR = api + "/system_messages/operator";
|
||||
|
||||
64
src/lib/hooks/useWaveSurferPlayer.js
Normal file
64
src/lib/hooks/useWaveSurferPlayer.js
Normal file
@@ -0,0 +1,64 @@
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
import WaveSurfer from "wavesurfer.js";
|
||||
|
||||
const playerRegistry = new Set();
|
||||
|
||||
export default function useWaveSurferPlayer(audioUrl, options = {}) {
|
||||
const containerRef = useRef(null);
|
||||
const wavesurferRef = useRef(null);
|
||||
const [isPlaying, setIsPlaying] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (!containerRef.current) return;
|
||||
|
||||
wavesurferRef.current = WaveSurfer.create({
|
||||
container: containerRef.current,
|
||||
waveColor: "#4BB183",
|
||||
progressColor: "#1b4332",
|
||||
cursorColor: "#d32f2f",
|
||||
height: 40,
|
||||
url: audioUrl,
|
||||
...options,
|
||||
});
|
||||
|
||||
playerRegistry.add(wavesurferRef.current);
|
||||
|
||||
wavesurferRef.current.on("finish", () => setIsPlaying(false));
|
||||
wavesurferRef.current.on("play", () => setIsPlaying(true));
|
||||
wavesurferRef.current.on("pause", () => setIsPlaying(false));
|
||||
|
||||
return () => {
|
||||
playerRegistry.delete(wavesurferRef.current);
|
||||
wavesurferRef.current?.destroy();
|
||||
};
|
||||
}, [audioUrl]);
|
||||
|
||||
const playPause = () => {
|
||||
if (!wavesurferRef.current) return;
|
||||
|
||||
playerRegistry.forEach((player) => {
|
||||
if (player !== wavesurferRef.current && player.isPlaying()) {
|
||||
player.stop();
|
||||
}
|
||||
});
|
||||
|
||||
wavesurferRef.current.playPause();
|
||||
};
|
||||
|
||||
const stop = () => {
|
||||
wavesurferRef.current?.stop();
|
||||
};
|
||||
|
||||
const seekTo = (progress) => {
|
||||
wavesurferRef.current?.seekTo(progress);
|
||||
};
|
||||
|
||||
return {
|
||||
containerRef,
|
||||
isPlaying,
|
||||
playPause,
|
||||
stop,
|
||||
seekTo,
|
||||
wavesurfer: wavesurferRef.current,
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user