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