parent
f7c8743ed9
commit
8188dab2b4
@ -0,0 +1,146 @@
|
|||||||
|
import dayjs from "dayjs";
|
||||||
|
import {
|
||||||
|
CartesianGrid,
|
||||||
|
Legend,
|
||||||
|
Line,
|
||||||
|
LineChart,
|
||||||
|
ResponsiveContainer,
|
||||||
|
Tooltip,
|
||||||
|
XAxis,
|
||||||
|
YAxis,
|
||||||
|
} from "recharts";
|
||||||
|
|
||||||
|
import { useGeneralStats } from "../../Hooks/Statistics";
|
||||||
|
|
||||||
|
interface StatisticGeneralProps {
|
||||||
|
startDate: string;
|
||||||
|
endDate: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const StatisticGeneral: React.FC<StatisticGeneralProps> = ({
|
||||||
|
startDate,
|
||||||
|
endDate,
|
||||||
|
}) => {
|
||||||
|
const formatDate = (dateString: string): string => {
|
||||||
|
const date = new Date(dateString);
|
||||||
|
return new Intl.DateTimeFormat("en-EN", {
|
||||||
|
day: "2-digit",
|
||||||
|
month: "short",
|
||||||
|
}).format(date);
|
||||||
|
};
|
||||||
|
|
||||||
|
const today = dayjs().endOf("day");
|
||||||
|
let finalEndDate = dayjs(endDate);
|
||||||
|
|
||||||
|
if (finalEndDate.isAfter(today)) {
|
||||||
|
finalEndDate = today;
|
||||||
|
}
|
||||||
|
const formattedEndDate = finalEndDate.format("YYYY-MM-DD HH:mm:ss");
|
||||||
|
|
||||||
|
const { data, isLoading, refetch } = useGeneralStats({
|
||||||
|
start_date: startDate,
|
||||||
|
end_date: formattedEndDate,
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
display: "flex",
|
||||||
|
alignItems: "center",
|
||||||
|
gap: 20,
|
||||||
|
marginTop: 40,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
display: "flex",
|
||||||
|
alignItems: "center",
|
||||||
|
justifyContent: "space-around",
|
||||||
|
flexDirection: "column",
|
||||||
|
gap: 20,
|
||||||
|
flexWrap: "wrap",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{data?.summary && (
|
||||||
|
<div
|
||||||
|
className="card_stat"
|
||||||
|
style={{
|
||||||
|
backgroundColor: "#F99E2C",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<p>Total</p>
|
||||||
|
<span>{data?.summary?.total}</span>
|
||||||
|
<p>Tasks</p>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{data?.summary && (
|
||||||
|
<div
|
||||||
|
className="card_stat"
|
||||||
|
style={{
|
||||||
|
backgroundColor: "#27AE60",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<p>Active</p>
|
||||||
|
<span>{data?.summary?.total_completed}</span>
|
||||||
|
<p>Tasks</p>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{data?.summary && (
|
||||||
|
<div
|
||||||
|
className="card_stat"
|
||||||
|
style={{
|
||||||
|
backgroundColor: "#F64747",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<p>Inactive</p>
|
||||||
|
<span>{data?.summary?.total_incomplete}</span>
|
||||||
|
<p>Tasks</p>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<ResponsiveContainer
|
||||||
|
width="100%"
|
||||||
|
height={517}
|
||||||
|
style={{ textTransform: "capitalize" }}
|
||||||
|
>
|
||||||
|
<LineChart data={data?.daily_stats}>
|
||||||
|
<CartesianGrid vertical={false} stroke="#D7D8E080" />
|
||||||
|
<XAxis
|
||||||
|
dataKey="task_date"
|
||||||
|
style={{
|
||||||
|
color: "#9B9DAA",
|
||||||
|
fontSize: 10,
|
||||||
|
lineHeight: "12.4px",
|
||||||
|
fontWeight: 400,
|
||||||
|
}}
|
||||||
|
tickFormatter={formatDate}
|
||||||
|
/>
|
||||||
|
<YAxis
|
||||||
|
style={{
|
||||||
|
color: "#9B9DAA",
|
||||||
|
fontSize: 10,
|
||||||
|
fontWeight: 400,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Tooltip />
|
||||||
|
<Legend />
|
||||||
|
<Line dataKey="total_tasks" stroke="#F99E2C" name="Total Tasks" />
|
||||||
|
<Line
|
||||||
|
dataKey="completed_tasks"
|
||||||
|
stroke="#27AE60"
|
||||||
|
name="Active tasks"
|
||||||
|
/>
|
||||||
|
<Line
|
||||||
|
dataKey="incomplete_tasks"
|
||||||
|
stroke="#F64747"
|
||||||
|
name="Inactive Tasks"
|
||||||
|
/>
|
||||||
|
</LineChart>
|
||||||
|
</ResponsiveContainer>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default StatisticGeneral;
|
@ -1,136 +0,0 @@
|
|||||||
import { Table, Tooltip } from "antd";
|
|
||||||
import { TStat } from "../../types/Statistic/TStat";
|
|
||||||
import {
|
|
||||||
QueryObserverResult,
|
|
||||||
RefetchOptions,
|
|
||||||
RefetchQueryFilters,
|
|
||||||
} from "react-query";
|
|
||||||
import { QuestionCircleOutlined, QuestionOutlined } from "@ant-design/icons";
|
|
||||||
// @ts-ignore
|
|
||||||
import tagIcon from "../../assets/tagIcon.svg";
|
|
||||||
|
|
||||||
import { theme } from "antd";
|
|
||||||
|
|
||||||
const StatTable = ({
|
|
||||||
data,
|
|
||||||
isLoading,
|
|
||||||
refetch,
|
|
||||||
}: {
|
|
||||||
refetch: <TPageData>(
|
|
||||||
options?: (RefetchOptions & RefetchQueryFilters<TPageData>) | undefined
|
|
||||||
) => Promise<QueryObserverResult<TStat[], unknown>>;
|
|
||||||
data: any;
|
|
||||||
isLoading: boolean;
|
|
||||||
}) => {
|
|
||||||
const { token } = theme.useToken();
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<Table
|
|
||||||
size="small"
|
|
||||||
loading={isLoading}
|
|
||||||
dataSource={data?.map((u: any, i: any) => ({
|
|
||||||
no: i + 1,
|
|
||||||
...u,
|
|
||||||
}))}
|
|
||||||
columns={[
|
|
||||||
{
|
|
||||||
title: <img src={tagIcon} alt="" />,
|
|
||||||
dataIndex: "no",
|
|
||||||
key: "no",
|
|
||||||
width: "5%",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "Support specialist",
|
|
||||||
dataIndex: "username",
|
|
||||||
key: "username",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "Team",
|
|
||||||
dataIndex: "team_name",
|
|
||||||
key: "team_name ",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "Tasks",
|
|
||||||
dataIndex: "number_of_tasks",
|
|
||||||
key: "number_of_tasks",
|
|
||||||
sorter: (a: any, b: any) => a.number_of_tasks - b.number_of_tasks,
|
|
||||||
sortDirections: ["ascend", "descend"],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "Points",
|
|
||||||
dataIndex: "total_points",
|
|
||||||
key: "total_points",
|
|
||||||
sorter: (a: any, b: any) => a.total_points - b.total_points,
|
|
||||||
sortDirections: ["ascend", "descend"],
|
|
||||||
},
|
|
||||||
// {
|
|
||||||
// title: (
|
|
||||||
// <div>
|
|
||||||
// <span>Salary</span>
|
|
||||||
// <Tooltip title="The calculation of salary begins at the start of the month and continues to the current day. Select a month to review salary details for prior periods.">
|
|
||||||
// <QuestionCircleOutlined />
|
|
||||||
// </Tooltip>
|
|
||||||
// </div>
|
|
||||||
// ),
|
|
||||||
// dataIndex: "salary",
|
|
||||||
// key: "salary",
|
|
||||||
// render: (text: string, record: any) => (
|
|
||||||
// <Tooltip
|
|
||||||
// title={
|
|
||||||
// <div>
|
|
||||||
// {record.salary_type === "hybrid" ? (
|
|
||||||
// <p>
|
|
||||||
// <strong>Fixed Amount:</strong> $
|
|
||||||
// {record.salary_base_amount}
|
|
||||||
// </p>
|
|
||||||
// ) : (
|
|
||||||
// ""
|
|
||||||
// )}
|
|
||||||
// <p>
|
|
||||||
// <strong>Performance based amount:</strong> $
|
|
||||||
// {record.performance_based_amount}
|
|
||||||
// </p>
|
|
||||||
// </div>
|
|
||||||
// }
|
|
||||||
// overlayStyle={{
|
|
||||||
// maxWidth: "700px",
|
|
||||||
// }}
|
|
||||||
// >
|
|
||||||
// <span>${record.salary}</span>
|
|
||||||
// </Tooltip>
|
|
||||||
// ),
|
|
||||||
// sorter: (a: any, b: any) => a.salary - b.total_points,
|
|
||||||
// sortDirections: ["ascend", "descend"],
|
|
||||||
// },
|
|
||||||
]}
|
|
||||||
// pagination={{
|
|
||||||
// pageSize: 10,
|
|
||||||
// size: "default",
|
|
||||||
// style: {
|
|
||||||
// margin: 0,
|
|
||||||
// justifyContent: "end",
|
|
||||||
// position: "fixed",
|
|
||||||
// bottom: 0,
|
|
||||||
// left: 0,
|
|
||||||
// width: "100%",
|
|
||||||
// backgroundColor: token.colorBgContainer,
|
|
||||||
// boxShadow: "0 4px 8px rgba(0, 0, 0, 0.4)",
|
|
||||||
// padding: "10px 0",
|
|
||||||
// zIndex: 1000,
|
|
||||||
// },
|
|
||||||
// showLessItems: true,
|
|
||||||
// }}
|
|
||||||
pagination={false}
|
|
||||||
rowClassName={(record, index) =>
|
|
||||||
index % 2 === 0 ? "odd-row" : "even-row"
|
|
||||||
}
|
|
||||||
bordered
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default StatTable;
|
|
||||||
|
|
||||||
// The calculation of salary begins at the start of the month and continues to the current day. Select a month to review salary details for prior periods.
|
|
@ -0,0 +1,324 @@
|
|||||||
|
import { Button, Input, Select, Space, Table, Tag } from "antd";
|
||||||
|
import { TStatTeam, TteamChartData } from "../../types/Statistic/TStat";
|
||||||
|
import {
|
||||||
|
QueryObserverResult,
|
||||||
|
RefetchOptions,
|
||||||
|
RefetchQueryFilters,
|
||||||
|
} from "react-query";
|
||||||
|
import {
|
||||||
|
CartesianGrid,
|
||||||
|
Legend,
|
||||||
|
Line,
|
||||||
|
LineChart,
|
||||||
|
ResponsiveContainer,
|
||||||
|
Tooltip,
|
||||||
|
XAxis,
|
||||||
|
YAxis,
|
||||||
|
} from "recharts";
|
||||||
|
|
||||||
|
import { RightOutlined, LeftOutlined } from "@ant-design/icons";
|
||||||
|
|
||||||
|
import { theme } from "antd";
|
||||||
|
import tagIcon from "../../assets/tagIcon.svg";
|
||||||
|
import { useStatTeamData, useTeamChartData } from "../../Hooks/Statistics";
|
||||||
|
import { useEffect, useState } from "react";
|
||||||
|
import dayjs from "dayjs";
|
||||||
|
|
||||||
|
interface StatisticTeamProps {
|
||||||
|
startDate: string;
|
||||||
|
endDate: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const StatisticTeam: React.FC<StatisticTeamProps> = ({
|
||||||
|
startDate,
|
||||||
|
endDate,
|
||||||
|
}) => {
|
||||||
|
const [page, setPage] = useState(1);
|
||||||
|
|
||||||
|
const [pageSize, setPageSize] = useState<number>(() => {
|
||||||
|
const saved = localStorage.getItem("general_pageSize");
|
||||||
|
return saved ? Number(saved) : 15;
|
||||||
|
});
|
||||||
|
|
||||||
|
const pageSizeOptions = [15, 20, 30, 40, 50];
|
||||||
|
|
||||||
|
const handlePageSizeChange = (value: number) => {
|
||||||
|
setPageSize(value);
|
||||||
|
setPage(1);
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
localStorage.setItem("general_pageSize", String(pageSize));
|
||||||
|
}, [pageSize]);
|
||||||
|
|
||||||
|
const Next = () => {
|
||||||
|
const a = Number(page) + 1;
|
||||||
|
setPage(a);
|
||||||
|
};
|
||||||
|
const Previos = () => {
|
||||||
|
Number(page);
|
||||||
|
if (page > 1) {
|
||||||
|
const a = Number(page) - 1;
|
||||||
|
setPage(a);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const { data, isLoading, refetch } = useStatTeamData({
|
||||||
|
page: page,
|
||||||
|
page_size: pageSize,
|
||||||
|
start_date: startDate,
|
||||||
|
end_date: endDate,
|
||||||
|
});
|
||||||
|
|
||||||
|
const today = dayjs().endOf("day");
|
||||||
|
|
||||||
|
let finalEndDate = dayjs(endDate);
|
||||||
|
|
||||||
|
if (finalEndDate.isAfter(today)) {
|
||||||
|
finalEndDate = today;
|
||||||
|
}
|
||||||
|
const formattedEndDate = finalEndDate.format("YYYY-MM-DD HH:mm:ss");
|
||||||
|
|
||||||
|
interface TeamschartDataType {
|
||||||
|
data?: TteamChartData[];
|
||||||
|
refetch: <TPageData>(
|
||||||
|
options?: (RefetchOptions & RefetchQueryFilters<TPageData>) | undefined
|
||||||
|
) => Promise<QueryObserverResult<TteamChartData[], unknown>>;
|
||||||
|
isLoading: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
const TeamschartData: TeamschartDataType = useTeamChartData({
|
||||||
|
start_date: startDate,
|
||||||
|
end_date: formattedEndDate,
|
||||||
|
});
|
||||||
|
|
||||||
|
const predefinedColors = [
|
||||||
|
"#ff2600",
|
||||||
|
"#FF4500",
|
||||||
|
"#FF1493",
|
||||||
|
"#006800",
|
||||||
|
"#3CB371",
|
||||||
|
"#00BFFF",
|
||||||
|
"#FFD700",
|
||||||
|
"#F08080",
|
||||||
|
"#8A2BE2",
|
||||||
|
"#FFB6C1",
|
||||||
|
];
|
||||||
|
|
||||||
|
function updateLines(chartData: any, predefinedColors: any) {
|
||||||
|
if (!chartData || chartData.length === 0) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
const keys = Object.keys(chartData[0]).filter((key) => key !== "date");
|
||||||
|
|
||||||
|
const newLines = keys.flatMap((key, index) => {
|
||||||
|
const color = predefinedColors[index % predefinedColors.length];
|
||||||
|
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
key: `${key}.total_points`,
|
||||||
|
color,
|
||||||
|
name: `${key} points`,
|
||||||
|
legend_name: `${key}`,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
});
|
||||||
|
|
||||||
|
return newLines;
|
||||||
|
}
|
||||||
|
|
||||||
|
const lines = TeamschartData.data
|
||||||
|
? updateLines(TeamschartData.data, predefinedColors)
|
||||||
|
: [];
|
||||||
|
|
||||||
|
const formatDate = (dateString: string): string => {
|
||||||
|
const date = new Date(dateString);
|
||||||
|
return new Intl.DateTimeFormat("en-EN", {
|
||||||
|
day: "2-digit",
|
||||||
|
month: "short",
|
||||||
|
}).format(date);
|
||||||
|
};
|
||||||
|
|
||||||
|
const { token } = theme.useToken();
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div>
|
||||||
|
<Table
|
||||||
|
loading={isLoading}
|
||||||
|
size="small"
|
||||||
|
dataSource={data?.data?.map((u: any, i: any) => ({
|
||||||
|
no: i + 1,
|
||||||
|
...u,
|
||||||
|
}))}
|
||||||
|
columns={[
|
||||||
|
{
|
||||||
|
title: <img src={tagIcon} alt="" />,
|
||||||
|
dataIndex: "no",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Team",
|
||||||
|
dataIndex: "name",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Total tasks",
|
||||||
|
dataIndex: "number_of_tasks",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Total points",
|
||||||
|
dataIndex: "total_points",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Is Active",
|
||||||
|
dataIndex: "is_active",
|
||||||
|
render: (tag: boolean) => (
|
||||||
|
<Tag color={tag ? "geekblue" : "red"}>
|
||||||
|
{tag ? "True" : "False"}
|
||||||
|
</Tag>
|
||||||
|
),
|
||||||
|
filters: [
|
||||||
|
{
|
||||||
|
text: "True",
|
||||||
|
value: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: "False",
|
||||||
|
value: false,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
onFilter: (
|
||||||
|
value: string | number | boolean,
|
||||||
|
record: TStatTeam
|
||||||
|
) => {
|
||||||
|
return record.is_active === value;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
pagination={false}
|
||||||
|
rowClassName={(record, index) =>
|
||||||
|
index % 2 === 0 ? "odd-row" : "even-row"
|
||||||
|
}
|
||||||
|
bordered
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div style={{ display: "flex", alignItems: "center", marginTop: 30 }}>
|
||||||
|
<ResponsiveContainer width="100%" height={517}>
|
||||||
|
<LineChart
|
||||||
|
data={TeamschartData.data || []}
|
||||||
|
margin={{ top: 20, right: 30, left: 20, bottom: 10 }}
|
||||||
|
>
|
||||||
|
<CartesianGrid vertical={false} stroke="#D7D8E080" />
|
||||||
|
<XAxis
|
||||||
|
dataKey="date"
|
||||||
|
style={{
|
||||||
|
color: "#9B9DAA",
|
||||||
|
fontSize: 12,
|
||||||
|
lineHeight: "15.4px",
|
||||||
|
fontWeight: 400,
|
||||||
|
|
||||||
|
letterSpacing: 0.8,
|
||||||
|
}}
|
||||||
|
tickFormatter={formatDate}
|
||||||
|
/>
|
||||||
|
<YAxis
|
||||||
|
style={{
|
||||||
|
color: "#9B9DAA",
|
||||||
|
fontSize: 10,
|
||||||
|
fontWeight: 400,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Tooltip />
|
||||||
|
<Legend
|
||||||
|
payload={lines.map((line) => ({
|
||||||
|
value: line.legend_name,
|
||||||
|
type: "line",
|
||||||
|
id: line.key,
|
||||||
|
color: line.color,
|
||||||
|
}))}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{lines.map((line, index) => (
|
||||||
|
<Line
|
||||||
|
key={index}
|
||||||
|
type="linear"
|
||||||
|
dataKey={line.key}
|
||||||
|
name={line.name}
|
||||||
|
stroke={line.color}
|
||||||
|
activeDot={{ r: 7 }}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</LineChart>
|
||||||
|
</ResponsiveContainer>
|
||||||
|
</div>
|
||||||
|
<Space style={{ width: "100%", marginTop: 40 }} direction="vertical">
|
||||||
|
<Space
|
||||||
|
style={{
|
||||||
|
justifyContent: "end",
|
||||||
|
position: "fixed",
|
||||||
|
bottom: 0,
|
||||||
|
left: 0,
|
||||||
|
width: "100%",
|
||||||
|
backgroundColor: token.colorBgContainer,
|
||||||
|
boxShadow: "0 4px 8px rgba(0, 0, 0, 0.4)",
|
||||||
|
padding: "10px 0",
|
||||||
|
zIndex: 1000,
|
||||||
|
}}
|
||||||
|
wrap
|
||||||
|
>
|
||||||
|
<Select
|
||||||
|
value={pageSize}
|
||||||
|
onChange={handlePageSizeChange}
|
||||||
|
style={{ width: 65, marginRight: 16 }}
|
||||||
|
options={pageSizeOptions.map((size) => ({
|
||||||
|
label: `${size}`,
|
||||||
|
value: size,
|
||||||
|
}))}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
onClick={Previos}
|
||||||
|
disabled={data?.data?.previous ? false : true}
|
||||||
|
style={{
|
||||||
|
backgroundColor: token.colorBgContainer,
|
||||||
|
color: token.colorText,
|
||||||
|
border: "none",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<LeftOutlined />
|
||||||
|
</Button>
|
||||||
|
<Input
|
||||||
|
disabled
|
||||||
|
style={{
|
||||||
|
width: 40,
|
||||||
|
textAlign: "center",
|
||||||
|
background: token.colorBgContainer,
|
||||||
|
border: "1px solid",
|
||||||
|
borderColor: token.colorText,
|
||||||
|
color: token.colorText,
|
||||||
|
}}
|
||||||
|
value={page}
|
||||||
|
onChange={(e) => {
|
||||||
|
let num = e.target.value;
|
||||||
|
if (Number(num) && num !== "0") {
|
||||||
|
setPage(Number(num));
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Button
|
||||||
|
onClick={Next}
|
||||||
|
disabled={data?.data?.next ? false : true}
|
||||||
|
style={{
|
||||||
|
backgroundColor: token.colorBgContainer,
|
||||||
|
color: token.colorText,
|
||||||
|
border: "none",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<RightOutlined />
|
||||||
|
</Button>
|
||||||
|
</Space>
|
||||||
|
</Space>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default StatisticTeam;
|
@ -1,98 +0,0 @@
|
|||||||
import { Table, Tag } from "antd";
|
|
||||||
import { TStatTeam } from "../../types/Statistic/TStat";
|
|
||||||
import {
|
|
||||||
QueryObserverResult,
|
|
||||||
RefetchOptions,
|
|
||||||
RefetchQueryFilters,
|
|
||||||
} from "react-query";
|
|
||||||
|
|
||||||
import { theme } from "antd";
|
|
||||||
// @ts-ignore
|
|
||||||
import tagIcon from "../../assets/tagIcon.svg";
|
|
||||||
const StatTeamTable = ({
|
|
||||||
data,
|
|
||||||
isLoading,
|
|
||||||
refetch,
|
|
||||||
}: {
|
|
||||||
refetch: <TPageData>(
|
|
||||||
options?: (RefetchOptions & RefetchQueryFilters<TPageData>) | undefined
|
|
||||||
) => Promise<QueryObserverResult<TStatTeam[], unknown>>;
|
|
||||||
data: any;
|
|
||||||
isLoading: boolean;
|
|
||||||
}) => {
|
|
||||||
const { token } = theme.useToken();
|
|
||||||
return (
|
|
||||||
<div style={{ maxHeight: "400px", overflow: "auto" }}>
|
|
||||||
<Table
|
|
||||||
loading={isLoading}
|
|
||||||
size="small"
|
|
||||||
dataSource={data?.map((u: any, i: any) => ({
|
|
||||||
no: i + 1,
|
|
||||||
...u,
|
|
||||||
}))}
|
|
||||||
columns={[
|
|
||||||
{
|
|
||||||
title: <img src={tagIcon} alt="" />,
|
|
||||||
dataIndex: "no",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "Team",
|
|
||||||
dataIndex: "name",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "Total tasks",
|
|
||||||
dataIndex: "number_of_tasks",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "Total points",
|
|
||||||
dataIndex: "total_points",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "Is Active",
|
|
||||||
dataIndex: "is_active",
|
|
||||||
render: (tag: boolean) => (
|
|
||||||
<Tag color={tag ? "geekblue" : "red"}>
|
|
||||||
{tag ? "True" : "False"}
|
|
||||||
</Tag>
|
|
||||||
),
|
|
||||||
filters: [
|
|
||||||
{
|
|
||||||
text: "True",
|
|
||||||
value: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
text: "False",
|
|
||||||
value: false,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
onFilter: (value: string | number | boolean, record: TStatTeam) => {
|
|
||||||
return record.is_active === value;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
]}
|
|
||||||
// pagination={{
|
|
||||||
// pageSize: 10,
|
|
||||||
// size: "default",
|
|
||||||
// style: {
|
|
||||||
// margin: 0,
|
|
||||||
// justifyContent: "end",
|
|
||||||
// position: "fixed",
|
|
||||||
// bottom: 0,
|
|
||||||
// left: 0,
|
|
||||||
// width: "100%",
|
|
||||||
// backgroundColor: token.colorBgContainer,
|
|
||||||
// boxShadow: "0 4px 8px rgba(0, 0, 0, 0.4)",
|
|
||||||
// padding: "10px 0",
|
|
||||||
// zIndex: 1000,
|
|
||||||
// },
|
|
||||||
// }}
|
|
||||||
pagination={false}
|
|
||||||
rowClassName={(record, index) =>
|
|
||||||
index % 2 === 0 ? "odd-row" : "even-row"
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default StatTeamTable;
|
|
@ -0,0 +1,249 @@
|
|||||||
|
import { Button, Input, Select, Space, Table, Tooltip } from "antd";
|
||||||
|
import { LeftOutlined, RightOutlined, SearchOutlined } from "@ant-design/icons";
|
||||||
|
import tagIcon from "../../assets/tagIcon.svg";
|
||||||
|
|
||||||
|
import { theme } from "antd";
|
||||||
|
import { useEffect, useMemo, useState } from "react";
|
||||||
|
import { useTeamData } from "../../Hooks/Teams";
|
||||||
|
import { useStatsData } from "../../Hooks/Statistics";
|
||||||
|
import { statController } from "../../API/LayoutApi/statistic";
|
||||||
|
import { debounce } from "lodash";
|
||||||
|
|
||||||
|
interface StatisticsChekersProps {
|
||||||
|
startDate: string;
|
||||||
|
endDate: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const StatisticsChekers: React.FC<StatisticsChekersProps> = ({
|
||||||
|
startDate,
|
||||||
|
endDate,
|
||||||
|
}) => {
|
||||||
|
const [team, setTeam] = useState<any>("");
|
||||||
|
const [search, setSearch] = useState<string>("");
|
||||||
|
const { token } = theme.useToken();
|
||||||
|
const teamData = useTeamData({});
|
||||||
|
const teamOptions: { label: string; value: any }[] | undefined =
|
||||||
|
teamData?.data?.map((item: any) => ({
|
||||||
|
label: item?.name,
|
||||||
|
value: item?.name,
|
||||||
|
}));
|
||||||
|
|
||||||
|
const [page, setPage] = useState(1);
|
||||||
|
|
||||||
|
const [pageSize, setPageSize] = useState<number>(() => {
|
||||||
|
const saved = localStorage.getItem("general_pageSize");
|
||||||
|
return saved ? Number(saved) : 15;
|
||||||
|
});
|
||||||
|
|
||||||
|
const pageSizeOptions = [15, 20, 30, 40, 50];
|
||||||
|
|
||||||
|
const handlePageSizeChange = (value: number) => {
|
||||||
|
setPageSize(value);
|
||||||
|
setPage(1);
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
localStorage.setItem("general_pageSize", String(pageSize));
|
||||||
|
}, [pageSize]);
|
||||||
|
|
||||||
|
const Next = () => {
|
||||||
|
const a = Number(page) + 1;
|
||||||
|
setPage(a);
|
||||||
|
};
|
||||||
|
const Previos = () => {
|
||||||
|
Number(page);
|
||||||
|
if (page > 1) {
|
||||||
|
const a = Number(page) - 1;
|
||||||
|
setPage(a);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSearchChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
|
debouncedSearch(e.target.value);
|
||||||
|
};
|
||||||
|
|
||||||
|
const debouncedSearch = useMemo(
|
||||||
|
() =>
|
||||||
|
debounce((value: string) => {
|
||||||
|
setSearch(value);
|
||||||
|
}, 1000),
|
||||||
|
[]
|
||||||
|
);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
return () => {
|
||||||
|
debouncedSearch.cancel();
|
||||||
|
};
|
||||||
|
}, [debouncedSearch]);
|
||||||
|
|
||||||
|
const handleSave = (a: string) => {
|
||||||
|
const trimmedStartDate = startDate.slice(0, 10);
|
||||||
|
const trimmedEndDate = endDate.slice(0, 10);
|
||||||
|
const fileName = `${trimmedStartDate}-${trimmedEndDate}`;
|
||||||
|
if (a === "team") {
|
||||||
|
const teamName = `${team}_${fileName}`;
|
||||||
|
statController.saveUsersStats(teamName, startDate, endDate, team);
|
||||||
|
} else {
|
||||||
|
statController.saveTeamStats(fileName, startDate, endDate);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const { data, refetch, isLoading } = useStatsData({
|
||||||
|
search: search,
|
||||||
|
team: team,
|
||||||
|
start_date: startDate,
|
||||||
|
end_date: endDate,
|
||||||
|
page: page,
|
||||||
|
page_size: pageSize,
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
display: "flex",
|
||||||
|
alignItems: "center",
|
||||||
|
marginBottom: 10,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div style={{ marginRight: 12 }}>
|
||||||
|
<Input
|
||||||
|
placeholder="Search"
|
||||||
|
prefix={<SearchOutlined />}
|
||||||
|
onChange={handleSearchChange}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<Select
|
||||||
|
style={{ width: 260 }}
|
||||||
|
placeholder="Team"
|
||||||
|
onChange={(value: any) => setTeam(value)}
|
||||||
|
options={teamOptions}
|
||||||
|
allowClear
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Table
|
||||||
|
size="small"
|
||||||
|
loading={isLoading}
|
||||||
|
dataSource={data?.data?.map((u: any, i: any) => ({
|
||||||
|
no: i + 1,
|
||||||
|
...u,
|
||||||
|
}))}
|
||||||
|
columns={[
|
||||||
|
{
|
||||||
|
title: <img src={tagIcon} alt="" />,
|
||||||
|
dataIndex: "no",
|
||||||
|
key: "no",
|
||||||
|
width: "5%",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Support specialist",
|
||||||
|
dataIndex: "username",
|
||||||
|
key: "username",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Team",
|
||||||
|
dataIndex: "team_name",
|
||||||
|
key: "team_name ",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Tasks",
|
||||||
|
dataIndex: "number_of_tasks",
|
||||||
|
key: "number_of_tasks",
|
||||||
|
sorter: (a: any, b: any) => a.number_of_tasks - b.number_of_tasks,
|
||||||
|
sortDirections: ["ascend", "descend"],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Points",
|
||||||
|
dataIndex: "total_points",
|
||||||
|
key: "total_points",
|
||||||
|
sorter: (a: any, b: any) => a.total_points - b.total_points,
|
||||||
|
sortDirections: ["ascend", "descend"],
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
pagination={false}
|
||||||
|
rowClassName={(record, index) =>
|
||||||
|
index % 2 === 0 ? "odd-row" : "even-row"
|
||||||
|
}
|
||||||
|
bordered
|
||||||
|
/>
|
||||||
|
<Button
|
||||||
|
type="primary"
|
||||||
|
onClick={(e) => handleSave("team")}
|
||||||
|
style={{ marginTop: 10, marginBottom: 40 }}
|
||||||
|
>
|
||||||
|
Save as file
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
<Space style={{ width: "100%", marginTop: 40 }} direction="vertical">
|
||||||
|
<Space
|
||||||
|
style={{
|
||||||
|
justifyContent: "end",
|
||||||
|
position: "fixed",
|
||||||
|
bottom: 0,
|
||||||
|
left: 0,
|
||||||
|
width: "100%",
|
||||||
|
backgroundColor: token.colorBgContainer,
|
||||||
|
boxShadow: "0 4px 8px rgba(0, 0, 0, 0.4)",
|
||||||
|
padding: "10px 0",
|
||||||
|
zIndex: 1000,
|
||||||
|
}}
|
||||||
|
wrap
|
||||||
|
>
|
||||||
|
<Select
|
||||||
|
value={pageSize}
|
||||||
|
onChange={handlePageSizeChange}
|
||||||
|
style={{ width: 65, marginRight: 16 }}
|
||||||
|
options={pageSizeOptions.map((size) => ({
|
||||||
|
label: `${size}`,
|
||||||
|
value: size,
|
||||||
|
}))}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
onClick={Previos}
|
||||||
|
disabled={data?.data?.previous ? false : true}
|
||||||
|
style={{
|
||||||
|
backgroundColor: token.colorBgContainer,
|
||||||
|
color: token.colorText,
|
||||||
|
border: "none",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<LeftOutlined />
|
||||||
|
</Button>
|
||||||
|
<Input
|
||||||
|
disabled
|
||||||
|
style={{
|
||||||
|
width: 40,
|
||||||
|
textAlign: "center",
|
||||||
|
background: token.colorBgContainer,
|
||||||
|
border: "1px solid",
|
||||||
|
borderColor: token.colorText,
|
||||||
|
color: token.colorText,
|
||||||
|
}}
|
||||||
|
value={page}
|
||||||
|
onChange={(e) => {
|
||||||
|
let num = e.target.value;
|
||||||
|
if (Number(num) && num !== "0") {
|
||||||
|
setPage(Number(num));
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Button
|
||||||
|
onClick={Next}
|
||||||
|
disabled={data?.data?.next ? false : true}
|
||||||
|
style={{
|
||||||
|
backgroundColor: token.colorBgContainer,
|
||||||
|
color: token.colorText,
|
||||||
|
border: "none",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<RightOutlined />
|
||||||
|
</Button>
|
||||||
|
</Space>
|
||||||
|
</Space>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default StatisticsChekers;
|
@ -1,81 +0,0 @@
|
|||||||
import React from "react";
|
|
||||||
import { Table, Tag, Tooltip } from "antd";
|
|
||||||
import { theme } from "antd";
|
|
||||||
import {
|
|
||||||
QueryObserverResult,
|
|
||||||
RefetchOptions,
|
|
||||||
RefetchQueryFilters,
|
|
||||||
} from "react-query";
|
|
||||||
import { TStatCreators } from "../../types/Statistic/TStat";
|
|
||||||
import tagIcon from "../../assets/tagIcon.svg";
|
|
||||||
|
|
||||||
const StatisticsSupportTable = ({
|
|
||||||
data,
|
|
||||||
isLoading,
|
|
||||||
refetch,
|
|
||||||
}: {
|
|
||||||
refetch: <TPageData>(
|
|
||||||
options?: (RefetchOptions & RefetchQueryFilters<TPageData>) | undefined
|
|
||||||
) => Promise<QueryObserverResult<TStatCreators[], unknown>>;
|
|
||||||
data: any;
|
|
||||||
isLoading: boolean;
|
|
||||||
}) => {
|
|
||||||
const { token } = theme.useToken();
|
|
||||||
return (
|
|
||||||
<div style={{ paddingBottom: 40 }}>
|
|
||||||
<Table
|
|
||||||
loading={isLoading}
|
|
||||||
size="small"
|
|
||||||
dataSource={data?.data?.map((u: any, i: any) => ({
|
|
||||||
no: i + 1,
|
|
||||||
...u,
|
|
||||||
}))}
|
|
||||||
columns={[
|
|
||||||
{
|
|
||||||
title: <img src={tagIcon} alt="" />,
|
|
||||||
dataIndex: "no",
|
|
||||||
key: "no",
|
|
||||||
width: "5%",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "Support specialist",
|
|
||||||
dataIndex: "username",
|
|
||||||
render: (text, record) => {
|
|
||||||
return record.full_name.trim()
|
|
||||||
? record.full_name
|
|
||||||
: record.username;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "Total tasks",
|
|
||||||
dataIndex: "number_of_tasks",
|
|
||||||
},
|
|
||||||
]}
|
|
||||||
// pagination={{
|
|
||||||
// pageSize: 10,
|
|
||||||
// size: "default",
|
|
||||||
// style: {
|
|
||||||
// margin: 0,
|
|
||||||
// justifyContent: "end",
|
|
||||||
// position: "fixed",
|
|
||||||
// bottom: 0,
|
|
||||||
// left: 0,
|
|
||||||
// width: "100%",
|
|
||||||
// backgroundColor: token.colorBgContainer,
|
|
||||||
// boxShadow: "0 4px 8px rgba(0, 0, 0, 0.4)",
|
|
||||||
// padding: "10px 0",
|
|
||||||
// zIndex: 1000,
|
|
||||||
// },
|
|
||||||
// showLessItems: true,
|
|
||||||
// }}
|
|
||||||
pagination={false}
|
|
||||||
rowClassName={(record, index) =>
|
|
||||||
index % 2 === 0 ? "odd-row" : "even-row"
|
|
||||||
}
|
|
||||||
bordered
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default StatisticsSupportTable;
|
|
@ -0,0 +1,206 @@
|
|||||||
|
import React, { useEffect, useMemo, useRef, useState } from "react";
|
||||||
|
import { Button, Input, Select, Space, Table, Tag, Tooltip } from "antd";
|
||||||
|
import { theme } from "antd";
|
||||||
|
import tagIcon from "../../assets/tagIcon.svg";
|
||||||
|
import { useCreatorsData } from "../../Hooks/Statistics";
|
||||||
|
|
||||||
|
import { debounce } from "lodash";
|
||||||
|
|
||||||
|
import { SearchOutlined, RightOutlined, LeftOutlined } from "@ant-design/icons";
|
||||||
|
|
||||||
|
interface StatisticsTechSupportProps {
|
||||||
|
startDate: string;
|
||||||
|
endDate: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const StatisticsTechSupport: React.FC<StatisticsTechSupportProps> = ({
|
||||||
|
startDate,
|
||||||
|
endDate,
|
||||||
|
}) => {
|
||||||
|
const { token } = theme.useToken();
|
||||||
|
|
||||||
|
const [SupportSearch, setSupportSearch] = useState<string>("");
|
||||||
|
|
||||||
|
const [page, setPage] = useState(1);
|
||||||
|
|
||||||
|
const [pageSize, setPageSize] = useState<number>(() => {
|
||||||
|
const saved = localStorage.getItem("general_pageSize");
|
||||||
|
return saved ? Number(saved) : 15;
|
||||||
|
});
|
||||||
|
|
||||||
|
const pageSizeOptions = [15, 20, 30, 40, 50];
|
||||||
|
|
||||||
|
const handlePageSizeChange = (value: number) => {
|
||||||
|
setPageSize(value);
|
||||||
|
setPage(1);
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
localStorage.setItem("general_pageSize", String(pageSize));
|
||||||
|
}, [pageSize]);
|
||||||
|
|
||||||
|
const Next = () => {
|
||||||
|
const a = Number(page) + 1;
|
||||||
|
setPage(a);
|
||||||
|
};
|
||||||
|
const Previos = () => {
|
||||||
|
Number(page);
|
||||||
|
if (page > 1) {
|
||||||
|
const a = Number(page) - 1;
|
||||||
|
setPage(a);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleTechSupportSearchChange = (
|
||||||
|
e: React.ChangeEvent<HTMLInputElement>
|
||||||
|
) => {
|
||||||
|
debouncedSearch(e.target.value);
|
||||||
|
};
|
||||||
|
|
||||||
|
const debouncedSearch = useMemo(
|
||||||
|
() =>
|
||||||
|
debounce((value: string) => {
|
||||||
|
setSupportSearch(value);
|
||||||
|
}, 1000),
|
||||||
|
[]
|
||||||
|
);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
return () => {
|
||||||
|
debouncedSearch.cancel();
|
||||||
|
};
|
||||||
|
}, [debouncedSearch]);
|
||||||
|
|
||||||
|
const { data, isLoading } = useCreatorsData({
|
||||||
|
page: page,
|
||||||
|
page_size: pageSize,
|
||||||
|
search: SupportSearch,
|
||||||
|
start_date: startDate,
|
||||||
|
end_date: endDate,
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
display: "flex",
|
||||||
|
alignItems: "center",
|
||||||
|
marginBottom: 10,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div>
|
||||||
|
<Input
|
||||||
|
placeholder="Search"
|
||||||
|
prefix={<SearchOutlined />}
|
||||||
|
onChange={handleTechSupportSearchChange}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Table
|
||||||
|
loading={isLoading}
|
||||||
|
size="small"
|
||||||
|
dataSource={data?.data?.map((u: any, i: any) => ({
|
||||||
|
no: i + 1,
|
||||||
|
...u,
|
||||||
|
}))}
|
||||||
|
columns={[
|
||||||
|
{
|
||||||
|
title: <img src={tagIcon} alt="" />,
|
||||||
|
dataIndex: "no",
|
||||||
|
key: "no",
|
||||||
|
width: "5%",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Support specialist",
|
||||||
|
dataIndex: "username",
|
||||||
|
render: (text, record) => {
|
||||||
|
return record.full_name.trim()
|
||||||
|
? record.full_name
|
||||||
|
: record.username;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Total tasks",
|
||||||
|
dataIndex: "number_of_tasks",
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
pagination={false}
|
||||||
|
rowClassName={(record, index) =>
|
||||||
|
index % 2 === 0 ? "odd-row" : "even-row"
|
||||||
|
}
|
||||||
|
bordered
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Space style={{ width: "100%", marginTop: 40 }} direction="vertical">
|
||||||
|
<Space
|
||||||
|
style={{
|
||||||
|
justifyContent: "end",
|
||||||
|
position: "fixed",
|
||||||
|
bottom: 0,
|
||||||
|
left: 0,
|
||||||
|
width: "100%",
|
||||||
|
backgroundColor: token.colorBgContainer,
|
||||||
|
boxShadow: "0 4px 8px rgba(0, 0, 0, 0.4)",
|
||||||
|
padding: "10px 0",
|
||||||
|
zIndex: 1000,
|
||||||
|
}}
|
||||||
|
wrap
|
||||||
|
>
|
||||||
|
<Select
|
||||||
|
value={pageSize}
|
||||||
|
onChange={handlePageSizeChange}
|
||||||
|
style={{ width: 65, marginRight: 16 }}
|
||||||
|
options={pageSizeOptions.map((size) => ({
|
||||||
|
label: `${size}`,
|
||||||
|
value: size,
|
||||||
|
}))}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
onClick={Previos}
|
||||||
|
disabled={data?.data?.previous ? false : true}
|
||||||
|
style={{
|
||||||
|
backgroundColor: token.colorBgContainer,
|
||||||
|
color: token.colorText,
|
||||||
|
border: "none",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<LeftOutlined />
|
||||||
|
</Button>
|
||||||
|
<Input
|
||||||
|
disabled
|
||||||
|
style={{
|
||||||
|
width: 40,
|
||||||
|
textAlign: "center",
|
||||||
|
background: token.colorBgContainer,
|
||||||
|
border: "1px solid",
|
||||||
|
borderColor: token.colorText,
|
||||||
|
color: token.colorText,
|
||||||
|
}}
|
||||||
|
value={page}
|
||||||
|
onChange={(e) => {
|
||||||
|
let num = e.target.value;
|
||||||
|
if (Number(num) && num !== "0") {
|
||||||
|
setPage(Number(num));
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Button
|
||||||
|
onClick={Next}
|
||||||
|
disabled={data?.data?.next ? false : true}
|
||||||
|
style={{
|
||||||
|
backgroundColor: token.colorBgContainer,
|
||||||
|
color: token.colorText,
|
||||||
|
border: "none",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<RightOutlined />
|
||||||
|
</Button>
|
||||||
|
</Space>
|
||||||
|
</Space>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default StatisticsTechSupport;
|
Loading…
Reference in new issue