parent
8b53f23835
commit
77863b959d
@ -0,0 +1,28 @@
|
||||
import {
|
||||
TAccounting,
|
||||
TAccountingHistory,
|
||||
} from "../../types/Accounting/TAccounting";
|
||||
import instance from "../api";
|
||||
|
||||
export type TAccountingGetParams = {
|
||||
month: string;
|
||||
};
|
||||
|
||||
export const AccountingController = {
|
||||
async read(filterObject: TAccountingGetParams) {
|
||||
const params = { ...filterObject };
|
||||
|
||||
if (!!filterObject.month) params.month = filterObject.month;
|
||||
|
||||
const { data } = await instance.get<TAccounting[]>(`/employees-salaries/`, {
|
||||
params,
|
||||
});
|
||||
return data;
|
||||
},
|
||||
async history() {
|
||||
const { data } = await instance.get<TAccountingHistory[]>(
|
||||
`/employees-salaries-history/`
|
||||
);
|
||||
return data;
|
||||
},
|
||||
};
|
@ -0,0 +1,62 @@
|
||||
import { Tabs, Typography } from "antd";
|
||||
|
||||
import React, { useState } from "react";
|
||||
|
||||
import TabPane from "antd/es/tabs/TabPane";
|
||||
import AccountingCurrent from "./AccountingCurrent";
|
||||
import AccountingLast from "./AccountingLast";
|
||||
import AccountingHistory from "./AccountingHistory";
|
||||
|
||||
const Accounting: React.FC = () => {
|
||||
const [activeTab, setActiveTab] = useState("1");
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div
|
||||
className="header d-flex statistics-header"
|
||||
style={{ marginBottom: 16 }}
|
||||
>
|
||||
<Typography className="title">Accounting</Typography>
|
||||
</div>
|
||||
|
||||
<Tabs
|
||||
defaultActiveKey="1"
|
||||
activeKey={activeTab}
|
||||
onChange={(key) => setActiveTab(key)}
|
||||
>
|
||||
<TabPane
|
||||
tab={
|
||||
<span style={{ display: "flex", alignItems: "center" }}>
|
||||
Current Month
|
||||
</span>
|
||||
}
|
||||
key="1"
|
||||
>
|
||||
<AccountingCurrent />
|
||||
</TabPane>
|
||||
<TabPane
|
||||
tab={
|
||||
<span style={{ display: "flex", alignItems: "center" }}>
|
||||
Last Month
|
||||
</span>
|
||||
}
|
||||
key="2"
|
||||
>
|
||||
<AccountingLast />
|
||||
</TabPane>
|
||||
<TabPane
|
||||
tab={
|
||||
<span style={{ display: "flex", alignItems: "center" }}>
|
||||
History
|
||||
</span>
|
||||
}
|
||||
key="3"
|
||||
>
|
||||
<AccountingHistory />
|
||||
</TabPane>
|
||||
</Tabs>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Accounting;
|
@ -0,0 +1,178 @@
|
||||
import { Table, Tooltip } from "antd";
|
||||
import React from "react";
|
||||
import tagIcon from "../../assets/tagIcon.png";
|
||||
import { QuestionCircleOutlined } from "@ant-design/icons";
|
||||
import { theme } from "antd";
|
||||
import { useAccountingData } from "../../Hooks/Accounting";
|
||||
|
||||
const AccountingCurrent: React.FC = () => {
|
||||
const { data, refetch, isLoading } = useAccountingData({
|
||||
month: "current",
|
||||
});
|
||||
|
||||
const { token } = theme.useToken();
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Table
|
||||
size="small"
|
||||
loading={isLoading}
|
||||
dataSource={data?.map((u, i) => ({
|
||||
no: i + 1,
|
||||
...u,
|
||||
}))}
|
||||
columns={[
|
||||
{
|
||||
title: <img src={tagIcon} alt="" />,
|
||||
dataIndex: "no",
|
||||
key: "no",
|
||||
width: "5%",
|
||||
},
|
||||
{
|
||||
title: "Username",
|
||||
dataIndex: "username",
|
||||
key: "username",
|
||||
},
|
||||
{
|
||||
title: "Tasks",
|
||||
dataIndex: "number_of_tasks",
|
||||
key: "number_of_tasks",
|
||||
},
|
||||
{
|
||||
title: "Points",
|
||||
dataIndex: "total_points",
|
||||
key: "total_points",
|
||||
},
|
||||
{
|
||||
title: "Salary Type",
|
||||
dataIndex: "salary_type",
|
||||
render: (value: any, record: any) => {
|
||||
if (record.salary_type === "task_based") {
|
||||
return <p>Task Based</p>;
|
||||
} else if (record.salary_type === "hybrid") {
|
||||
return <p>Hybrid</p>;
|
||||
} else {
|
||||
return <p>{record.salary_type}</p>; // Agar boshqa qiymat bo'lsa, oddiy qilib chiqariladi
|
||||
}
|
||||
},
|
||||
filters: [
|
||||
{
|
||||
text: "Hybrid",
|
||||
value: "hybrid",
|
||||
},
|
||||
{
|
||||
text: "Task Based",
|
||||
value: "task_based",
|
||||
},
|
||||
],
|
||||
filterMultiple: false,
|
||||
// defaultFilteredValue: ["hybrid"],
|
||||
onFilter: (value: any, record: any) => {
|
||||
return record.salary_type === value;
|
||||
},
|
||||
},
|
||||
{
|
||||
title: "Base Salary",
|
||||
dataIndex: "salary_base_amount",
|
||||
render: (text: string, record: any) => (
|
||||
<p>${record?.salary_base_amount}</p>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: "Performance Salary",
|
||||
dataIndex: "performance_salary",
|
||||
render: (text: string, record: any) => (
|
||||
<p>${record?.performance_salary}</p>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: "Charges",
|
||||
dataIndex: "total_charges",
|
||||
render: (text: string, record: any) => (
|
||||
<p>${record?.total_charges}</p>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: "Bonuses",
|
||||
dataIndex: "total_bonuses",
|
||||
render: (text: string, record: any) => (
|
||||
<p>${record?.total_bonuses}</p>
|
||||
),
|
||||
},
|
||||
{
|
||||
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"],
|
||||
},
|
||||
]}
|
||||
rowClassName={(record, index) =>
|
||||
index % 2 === 0 ? "odd-row" : "even-row"
|
||||
}
|
||||
bordered
|
||||
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,
|
||||
}}
|
||||
|
||||
// onRow={(record) => ({
|
||||
// onClick: () => {
|
||||
// if (record.user && record.user.id) {
|
||||
// navigate(`/accounting/${record.user.id}`); // `user.id`ni olish
|
||||
// } else {
|
||||
// console.error("User ID mavjud emas");
|
||||
// }
|
||||
// },
|
||||
// })}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default AccountingCurrent;
|
@ -0,0 +1,188 @@
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { useParams } from "react-router-dom";
|
||||
import axios from "axios";
|
||||
import Typography from "antd/es/typography/Typography";
|
||||
import { DatePicker, DatePickerProps, Table } from "antd";
|
||||
import tagIcon from "../../assets/tagIcon.png";
|
||||
import dayjs from "dayjs";
|
||||
|
||||
interface User {
|
||||
id: number;
|
||||
first_name: string;
|
||||
last_name: string;
|
||||
username: string;
|
||||
}
|
||||
|
||||
interface Salary {
|
||||
id: number;
|
||||
month: string;
|
||||
year: number;
|
||||
number_of_tasks: number;
|
||||
total_points: number;
|
||||
salary_type: string;
|
||||
base_salary: number;
|
||||
performance_salary: number;
|
||||
total_salary: number;
|
||||
}
|
||||
|
||||
interface Data {
|
||||
user: User;
|
||||
salaries: Salary[];
|
||||
total: number;
|
||||
}
|
||||
|
||||
const AccountingDetails = () => {
|
||||
const { id } = useParams();
|
||||
const [user, setUser] = useState<Data | null>(null);
|
||||
const [loading, setLoading] = useState(true);
|
||||
|
||||
const now = dayjs();
|
||||
const moment = require("moment");
|
||||
const currentDate = moment();
|
||||
// const defaultDate = `${currentDate.format("YYYY")}`;
|
||||
|
||||
const disabledDate = (current: any) => {
|
||||
return current && current.year() > moment().year();
|
||||
};
|
||||
|
||||
const [date, setDate] = useState<string | null>(null);
|
||||
|
||||
const onChangeDate: DatePickerProps["onChange"] = (date) => {
|
||||
if (!date) {
|
||||
setDate("");
|
||||
} else {
|
||||
const year = date.format("YYYY");
|
||||
setDate(year);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const fetchUserDetails = async () => {
|
||||
const API_URL = `https://api.tteld.co/api/v1/user-salaries/${id}`;
|
||||
const AUTH_TOKEN = localStorage.getItem("access");
|
||||
|
||||
try {
|
||||
const response = await axios.get(API_URL, {
|
||||
params: {
|
||||
user_id: id,
|
||||
year: date,
|
||||
},
|
||||
headers: {
|
||||
Authorization: `Bearer ${AUTH_TOKEN}`,
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
maxRedirects: 0,
|
||||
});
|
||||
|
||||
setUser(response.data);
|
||||
|
||||
setLoading(false);
|
||||
} catch (error: any) {
|
||||
console.error("Error:", error.response?.status, error.response?.data);
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
fetchUserDetails();
|
||||
}, [date]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<div
|
||||
className="header d-flex statistics-header"
|
||||
style={{ marginBottom: 16 }}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
justifyContent: "center",
|
||||
flexDirection: "column",
|
||||
}}
|
||||
>
|
||||
{user?.user.first_name && user.user.last_name ? (
|
||||
<Typography className="title">
|
||||
{user?.user.first_name} {user?.user.last_name}
|
||||
</Typography>
|
||||
) : (
|
||||
<Typography className="title">{user?.user.username}</Typography>
|
||||
)}
|
||||
<Typography style={{ fontSize: 18, fontWeight: 700, marginTop: 24 }}>
|
||||
Total: ${user?.total}
|
||||
</Typography>
|
||||
</div>
|
||||
<div>
|
||||
<DatePicker
|
||||
onChange={onChangeDate}
|
||||
picker="year"
|
||||
format={"YYYY"}
|
||||
disabledDate={disabledDate}
|
||||
// defaultValue={now}
|
||||
style={{ marginRight: 10, width: 120, marginBottom: 10 }}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<Table
|
||||
size="small"
|
||||
loading={loading}
|
||||
dataSource={user?.salaries?.map((u, i) => ({
|
||||
no: i + 1,
|
||||
...u,
|
||||
}))}
|
||||
columns={[
|
||||
{
|
||||
title: <img src={tagIcon} alt="" />,
|
||||
dataIndex: "no",
|
||||
key: "no",
|
||||
width: "5%",
|
||||
},
|
||||
{
|
||||
title: "Salary",
|
||||
dataIndex: "total_salary",
|
||||
render(value, record, index) {
|
||||
return <p>${record?.total_salary}</p>;
|
||||
},
|
||||
},
|
||||
{
|
||||
title: "Salary Type",
|
||||
dataIndex: "salary_type",
|
||||
render: (value: any, record: any) => {
|
||||
if (record.salary_type === "task_based") {
|
||||
return <p>Task Based</p>;
|
||||
} else if (record.salary_type === "hybrid") {
|
||||
return <p>Hybrid</p>;
|
||||
} else {
|
||||
return <p>{record.salary_type}</p>; // Agar boshqa qiymat bo'lsa, oddiy qilib chiqariladi
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
title: "Base Salary",
|
||||
dataIndex: "base_salary",
|
||||
render(value, record, index) {
|
||||
return <p>${record?.base_salary}</p>;
|
||||
},
|
||||
},
|
||||
{
|
||||
title: "Performance Salary",
|
||||
dataIndex: "performance_salary",
|
||||
render(value, record, index) {
|
||||
return <p>${record?.performance_salary}</p>;
|
||||
},
|
||||
},
|
||||
{
|
||||
title: "Month",
|
||||
dataIndex: "month",
|
||||
},
|
||||
{
|
||||
title: "Year",
|
||||
dataIndex: "year",
|
||||
},
|
||||
]}
|
||||
bordered
|
||||
pagination={false}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default AccountingDetails;
|
@ -0,0 +1,158 @@
|
||||
import { Table, Tooltip } from "antd";
|
||||
import React from "react";
|
||||
import tagIcon from "../../assets/tagIcon.png";
|
||||
import { QuestionCircleOutlined } from "@ant-design/icons";
|
||||
import { theme } from "antd";
|
||||
import { useAccountingHistory } from "../../Hooks/Accounting";
|
||||
|
||||
const AccountingHistory: React.FC = () => {
|
||||
const { data, refetch, isLoading } = useAccountingHistory();
|
||||
|
||||
const { token } = theme.useToken();
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Table
|
||||
size="small"
|
||||
loading={isLoading}
|
||||
dataSource={data?.map((u, i) => ({
|
||||
no: i + 1,
|
||||
...u,
|
||||
}))}
|
||||
columns={[
|
||||
{
|
||||
title: <img src={tagIcon} alt="" />,
|
||||
dataIndex: "no",
|
||||
key: "no",
|
||||
width: "5%",
|
||||
},
|
||||
{
|
||||
title: "Username",
|
||||
dataIndex: "username",
|
||||
key: "username",
|
||||
},
|
||||
{
|
||||
title: "Total Tasks",
|
||||
dataIndex: "total_number_of_tasks",
|
||||
key: "total_number_of_tasks",
|
||||
},
|
||||
{
|
||||
title: "Total Points",
|
||||
dataIndex: "total_earned_points",
|
||||
key: "total_earned_points",
|
||||
},
|
||||
{
|
||||
title: "Total worked months",
|
||||
dataIndex: "salary_months_count",
|
||||
key: "salary_months_count",
|
||||
},
|
||||
{
|
||||
title: "Salary Type",
|
||||
dataIndex: "salary_type",
|
||||
render: (value: any, record: any) => {
|
||||
if (record.salary_type === "task_based") {
|
||||
return <p>Task Based</p>;
|
||||
} else if (record.salary_type === "hybrid") {
|
||||
return <p>Hybrid</p>;
|
||||
} else {
|
||||
return <p>{record.salary_type}</p>;
|
||||
}
|
||||
},
|
||||
filters: [
|
||||
{
|
||||
text: "Hybrid",
|
||||
value: "hybrid",
|
||||
},
|
||||
{
|
||||
text: "Task Based",
|
||||
value: "task_based",
|
||||
},
|
||||
],
|
||||
filterMultiple: false,
|
||||
onFilter: (value: any, record: any) => {
|
||||
return record.salary_type === value;
|
||||
},
|
||||
},
|
||||
{
|
||||
title: "Base Salary",
|
||||
dataIndex: "total_base_salary",
|
||||
render: (text: string, record: any) => (
|
||||
<p>${record?.total_base_salary}</p>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: "Performance Salary",
|
||||
dataIndex: "total_performance_salary",
|
||||
render: (text: string, record: any) => (
|
||||
<p>${record?.total_performance_salary}</p>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: "Total Charges",
|
||||
dataIndex: "total_charges",
|
||||
render: (text: string, record: any) => (
|
||||
<p>${record?.total_charges}</p>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: "Total Bonuses",
|
||||
dataIndex: "total_bonuses",
|
||||
render: (text: string, record: any) => (
|
||||
<p>${record?.total_bonuses}</p>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: (
|
||||
<div>
|
||||
<span>Total 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: "total_earned_salary",
|
||||
key: "total_earned_salary",
|
||||
render: (text: string, record: any) => (
|
||||
<span>${record.total_earned_salary}</span>
|
||||
),
|
||||
// sorter: (a: any, b: any) => a.salary - b.total_points,
|
||||
// sortDirections: ["ascend", "descend"],
|
||||
},
|
||||
]}
|
||||
rowClassName={(record, index) =>
|
||||
index % 2 === 0 ? "odd-row" : "even-row"
|
||||
}
|
||||
bordered
|
||||
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,
|
||||
}}
|
||||
|
||||
// onRow={(record) => ({
|
||||
// onClick: () => {
|
||||
// if (record.user && record.user.id) {
|
||||
// navigate(`/accounting/${record.user.id}`); // `user.id`ni olish
|
||||
// } else {
|
||||
// console.error("User ID mavjud emas");
|
||||
// }
|
||||
// },
|
||||
// })}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default AccountingHistory;
|
@ -0,0 +1,161 @@
|
||||
import { Button, Table, Tooltip } from "antd";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import api from "../../API/api";
|
||||
import tagIcon from "../../assets/tagIcon.png";
|
||||
import { QuestionCircleOutlined } from "@ant-design/icons";
|
||||
import { theme } from "antd";
|
||||
import { useAccountingData } from "../../Hooks/Accounting";
|
||||
|
||||
const AccountingCurrent: React.FC = () => {
|
||||
const { data, refetch, isLoading } = useAccountingData({
|
||||
month: "last",
|
||||
});
|
||||
|
||||
const { token } = theme.useToken();
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Table
|
||||
size="small"
|
||||
loading={isLoading}
|
||||
dataSource={data?.map((u, i) => ({
|
||||
no: i + 1,
|
||||
...u,
|
||||
}))}
|
||||
columns={[
|
||||
{
|
||||
title: <img src={tagIcon} alt="" />,
|
||||
dataIndex: "no",
|
||||
key: "no",
|
||||
width: "5%",
|
||||
},
|
||||
{
|
||||
title: "Username",
|
||||
dataIndex: "username",
|
||||
key: "username",
|
||||
},
|
||||
{
|
||||
title: "Tasks",
|
||||
dataIndex: "number_of_tasks",
|
||||
key: "number_of_tasks",
|
||||
},
|
||||
{
|
||||
title: "Points",
|
||||
dataIndex: "total_points",
|
||||
key: "total_points",
|
||||
},
|
||||
{
|
||||
title: "Salary Type",
|
||||
dataIndex: "salary_type",
|
||||
render: (value: any, record: any) => {
|
||||
if (record.salary_type === "task_based") {
|
||||
return <p>Task Based</p>;
|
||||
} else if (record.salary_type === "hybrid") {
|
||||
return <p>Hybrid</p>;
|
||||
} else {
|
||||
return <p>{record.salary_type}</p>; // Agar boshqa qiymat bo'lsa, oddiy qilib chiqariladi
|
||||
}
|
||||
},
|
||||
filters: [
|
||||
{
|
||||
text: "Hybrid",
|
||||
value: "hybrid",
|
||||
},
|
||||
{
|
||||
text: "Task Based",
|
||||
value: "task_based",
|
||||
},
|
||||
],
|
||||
filterMultiple: false,
|
||||
// defaultFilteredValue: ["hybrid"],
|
||||
onFilter: (value: any, record: any) => {
|
||||
return record.salary_type === value;
|
||||
},
|
||||
},
|
||||
{
|
||||
title: "Base Salary",
|
||||
dataIndex: "salary_base_amount",
|
||||
render: (text: string, record: any) => (
|
||||
<p>${record?.salary_base_amount}</p>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: "Performance Salary",
|
||||
dataIndex: "performance_salary",
|
||||
render: (text: string, record: any) => (
|
||||
<p>${record?.performance_salary}</p>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: "Charges",
|
||||
dataIndex: "total_charges",
|
||||
render: (text: string, record: any) => (
|
||||
<p>${record?.total_charges}</p>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: "Bonuses",
|
||||
dataIndex: "total_bonuses",
|
||||
render: (text: string, record: any) => (
|
||||
<p>${record?.total_bonuses}</p>
|
||||
),
|
||||
},
|
||||
{
|
||||
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) => (
|
||||
<span>${record.salary}</span>
|
||||
),
|
||||
// sorter: (a: any, b: any) => a.salary - b.total_points,
|
||||
// sortDirections: ["ascend", "descend"],
|
||||
},
|
||||
]}
|
||||
rowClassName={(record, index) =>
|
||||
index % 2 === 0 ? "odd-row" : "even-row"
|
||||
}
|
||||
bordered
|
||||
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,
|
||||
}}
|
||||
|
||||
// onRow={(record) => ({
|
||||
// onClick: () => {
|
||||
// if (record.user && record.user.id) {
|
||||
// navigate(`/accounting/${record.user.id}`); // `user.id`ni olish
|
||||
// } else {
|
||||
// console.error("User ID mavjud emas");
|
||||
// }
|
||||
// },
|
||||
// })}
|
||||
/>
|
||||
|
||||
{/* <Button disabled={data?.some((item) => item.is_confirmed)} type="primary">
|
||||
Confirm
|
||||
</Button> */}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default AccountingCurrent;
|
@ -0,0 +1,79 @@
|
||||
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.png";
|
||||
|
||||
const StatisticsSupportTable = ({
|
||||
data,
|
||||
isLoading,
|
||||
refetch,
|
||||
}: {
|
||||
refetch: <TPageData>(
|
||||
options?: (RefetchOptions & RefetchQueryFilters<TPageData>) | undefined
|
||||
) => Promise<QueryObserverResult<TStatCreators[], unknown>>;
|
||||
data: TStatCreators[] | undefined;
|
||||
isLoading: boolean;
|
||||
}) => {
|
||||
const { token } = theme.useToken();
|
||||
return (
|
||||
<div style={{ maxHeight: "400px" }}>
|
||||
<Table
|
||||
loading={isLoading}
|
||||
size="small"
|
||||
dataSource={data?.map((u, i) => ({
|
||||
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,
|
||||
},
|
||||
}}
|
||||
rowClassName={(record, index) =>
|
||||
index % 2 === 0 ? "odd-row" : "even-row"
|
||||
}
|
||||
bordered
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default StatisticsSupportTable;
|
@ -0,0 +1,26 @@
|
||||
import { useQuery } from "react-query";
|
||||
import {
|
||||
AccountingController,
|
||||
TAccountingGetParams,
|
||||
} from "../../API/LayoutApi/accounting";
|
||||
|
||||
export const useAccountingData = ({ month }: TAccountingGetParams) => {
|
||||
return useQuery(
|
||||
[`stats/all-users/`, month],
|
||||
() =>
|
||||
AccountingController.read({
|
||||
month,
|
||||
}),
|
||||
{ refetchOnWindowFocus: false }
|
||||
);
|
||||
};
|
||||
|
||||
export const useAccountingHistory = () => {
|
||||
return useQuery(
|
||||
[`employees-salaries-history/`],
|
||||
() => AccountingController.history(),
|
||||
{
|
||||
refetchOnWindowFocus: false,
|
||||
}
|
||||
);
|
||||
};
|
After Width: | Height: | Size: 1.6 KiB |
After Width: | Height: | Size: 1.8 KiB |
After Width: | Height: | Size: 1.5 KiB |
@ -0,0 +1,28 @@
|
||||
export type TAccounting = {
|
||||
full_name: string;
|
||||
is_confirmed: boolean;
|
||||
id: number;
|
||||
number_of_tasks: number;
|
||||
performance_based_amount: string;
|
||||
salary: string;
|
||||
salary_base_amount: string;
|
||||
salary_type: string;
|
||||
total_bonuses: string;
|
||||
total_charges: string;
|
||||
total_points: number;
|
||||
username: string;
|
||||
};
|
||||
|
||||
export type TAccountingHistory = {
|
||||
id: number;
|
||||
full_name: string;
|
||||
username: string;
|
||||
total_number_of_tasks: number;
|
||||
salary_type: string;
|
||||
total_bonuses: string;
|
||||
total_charges: string;
|
||||
total_earned_points: string;
|
||||
total_base_salary: string;
|
||||
total_performance_salary: string;
|
||||
total_earned_salary: string;
|
||||
};
|
Loading…
Reference in new issue