Add "My Salary" to profile; fix edit modal bugs in shift data tabs; add "Send to Telegram" button

dilmurod
Dilmurod 4 weeks ago
parent 52a8c317d1
commit 3cdc0ce06f

@ -1,5 +1,6 @@
import { message } from "antd"; import { message } from "antd";
import { import {
MySalaryResponse,
TMyTaskHistory, TMyTaskHistory,
TMystats, TMystats,
TProfile, TProfile,
@ -71,7 +72,7 @@ export const prof = {
if (params.username) { if (params.username) {
localStorage.setItem("username", params.username); localStorage.setItem("username", params.username);
} }
window.location.reload() window.location.reload();
return data; return data;
} catch (error: any) { } catch (error: any) {
setTimeout(() => { setTimeout(() => {
@ -105,4 +106,9 @@ export const prof = {
throw error; throw error;
} }
}, },
async mySalary() {
const { data } = await instance.get<MySalaryResponse>("users/my-salary/");
return data;
},
}; };

@ -188,4 +188,19 @@ export const taskController = {
} }
return { data: res, error }; return { data: res, error };
}, },
async sendTelegram(id: string) {
try {
const { data } = await instance.post(`task-send-to-telegram-bot/${id}/`);
return data;
} catch (error: any) {
if (error.response) {
console.error("Telegram API error:", error.response.data);
} else if (error.request) {
console.error("No response from server:", error.request);
} else {
console.error("Unexpected error:", error.message);
}
}
},
}; };

@ -146,6 +146,12 @@
text-align: right; text-align: right;
} }
.profile-my-salary {
display: flex;
flex-direction: column;
gap: 24px;
}
.dot-true { .dot-true {
width: 10px; width: 10px;
height: 10px; height: 10px;

@ -0,0 +1,141 @@
import { Card, Statistic, Row, Col } from "antd";
import dayjs from "dayjs";
import { CurrentMonth } from "../../../types/Profile/TProfile";
type Props = {
current: CurrentMonth;
};
const CurrentMonthCard: React.FC<Props> = ({ current }) => {
return (
<Card>
<Statistic
title={
<span
style={{
fontFamily: "Geist Mono",
fontSize: "12px",
fontStyle: "normal",
fontWeight: 400,
lineHeight: "16px",
}}
>
{`Current month / ${dayjs().format("MMMM")}`}
</span>
}
value={current.salary}
prefix="$"
precision={2}
valueStyle={{
fontFamily: "Inter",
fontSize: "24px",
fontStyle: "normal",
fontWeight: 700,
lineHeight: "28px",
letterSpacing: "-0.96px",
}}
/>
<Row gutter={12} style={{ marginTop: 12 }}>
<Col span={4}>
<div style={{ display: "flex", alignItems: "center" }}>
<span
style={{
color: "#9b9daa",
fontFamily: "Inter",
fontSize: "14px",
fontWeight: 500,
lineHeight: "20px",
}}
>
Bonuses:
</span>
<Statistic
value={current.total_bonuses}
prefix="+$"
valueStyle={{
fontFamily: "Inter",
fontSize: "14px",
fontWeight: 500,
}}
/>
</div>
</Col>
<Col span={4}>
<div style={{ display: "flex", alignItems: "center", gap: 8 }}>
<span
style={{
color: "#9b9daa",
fontFamily: "Inter",
fontSize: "14px",
fontWeight: 500,
lineHeight: "20px",
}}
>
Charges:
</span>
<Statistic
value={current.total_charges}
prefix="-$"
valueStyle={{
fontFamily: "Inter",
fontSize: "14px",
fontWeight: 500,
}}
/>
</div>
</Col>
<Col span={4}>
<div style={{ display: "flex", alignItems: "center", gap: 8 }}>
<span
style={{
color: "#9b9daa",
fontFamily: "Inter",
fontSize: "14px",
fontWeight: 500,
lineHeight: "20px",
}}
>
Tasks:
</span>
<Statistic
value={current.number_of_tasks}
valueStyle={{
fontFamily: "Inter",
fontSize: "14px",
fontWeight: 500,
}}
/>
</div>
</Col>
<Col span={4}>
<div style={{ display: "flex", alignItems: "center", gap: 8 }}>
<span
style={{
color: "#9b9daa",
fontFamily: "Inter",
fontSize: "14px",
fontWeight: 500,
lineHeight: "20px",
}}
>
Points:
</span>
<Statistic
value={current.total_points}
valueStyle={{
fontFamily: "Inter",
fontSize: "14px",
fontWeight: 500,
}}
/>
</div>
</Col>
</Row>
</Card>
);
};
export default CurrentMonthCard;

@ -0,0 +1,72 @@
import { Table, Typography } from "antd";
import { SalaryHistory } from "../../../types/Profile/TProfile";
const { Title } = Typography;
type Props = {
year: number;
salaries: SalaryHistory[];
};
const SalaryHistoryTable: React.FC<Props> = ({ year, salaries }) => {
return (
<div style={{ marginBottom: 32 }}>
<Title
level={3}
style={{
fontFamily: "Inter",
fontSize: "18px",
fontWeight: 700,
lineHeight: "24px",
letterSpacing: "-0.36px",
}}
>
{year}
</Title>
<Table<SalaryHistory>
dataSource={salaries}
rowKey="id"
pagination={false}
size="large"
columns={[
{
title: "#",
dataIndex: "no",
width: "5%",
align: "center",
render: (_, __, index) => index + 1,
},
{
title: "Month",
dataIndex: "month",
},
{
title: "Total Salary",
dataIndex: "total_salary",
render: (_, record) => <span>${record.total_salary}</span>,
},
{
title: "Total Bonuses",
dataIndex: "total_bonuses",
render: (_, record) => <span>${record.total_bonuses}</span>,
},
{
title: "Total Charges",
dataIndex: "total_charges",
render: (_, record) => <span>${record.total_charges}</span>,
},
{
title: "Total Tasks",
dataIndex: "number_of_tasks",
},
{
title: "Total Points",
dataIndex: "total_points",
},
]}
/>
</div>
);
};
export default SalaryHistoryTable;

@ -0,0 +1,159 @@
import { Row, Col, Statistic } from "antd";
import { Total } from "../../../types/Profile/TProfile";
type Props = {
total: Total;
};
const TotalStatistics: React.FC<Props> = ({ total }) => {
return (
<Row gutter={16}>
<Col span={4}>
<div style={{ display: "flex", flexDirection: "column", rowGap: 4 }}>
<span
style={{
fontFamily: "Geist Mono",
fontSize: "12px",
fontStyle: "normal",
fontWeight: 400,
lineHeight: "16px",
color: "#9B9DAA",
}}
>
Total salary
</span>
<span
style={{
fontFamily: "Inter",
fontSize: "14px",
fontStyle: "normal",
fontWeight: 600,
lineHeight: "20px",
letterSpacing: "-0.14px",
}}
>
${total.total_earned_salary}
</span>
</div>
</Col>
<Col span={4}>
<div style={{ display: "flex", flexDirection: "column", rowGap: 4 }}>
<span
style={{
fontFamily: "Geist Mono",
fontSize: "12px",
fontStyle: "normal",
fontWeight: 400,
lineHeight: "16px",
color: " #9B9DAA",
}}
>
Total bonuses
</span>
<span
style={{
fontFamily: "Inter",
fontSize: "14px",
fontStyle: "normal",
fontWeight: 600,
lineHeight: "20px",
letterSpacing: "-0.14px",
}}
>
+${total.total_bonuses}
</span>
</div>
</Col>
<Col span={4}>
<div style={{ display: "flex", flexDirection: "column", rowGap: 4 }}>
<span
style={{
fontFamily: "Geist Mono",
fontSize: "12px",
fontStyle: "normal",
fontWeight: 400,
lineHeight: "16px",
color: "#9B9DAA",
}}
>
Total charges
</span>
<span
style={{
fontFamily: "Inter",
fontSize: "14px",
fontStyle: "normal",
fontWeight: 600,
lineHeight: "20px",
letterSpacing: "-0.14px",
}}
>
-${total.total_charges}
</span>
</div>
</Col>
<Col span={4}>
<div style={{ display: "flex", flexDirection: "column", rowGap: 4 }}>
<span
style={{
fontFamily: "Geist Mono",
fontSize: "12px",
fontStyle: "normal",
fontWeight: 400,
lineHeight: "16px",
color: "#9B9DAA",
}}
>
Total tasks
</span>
<span
style={{
fontFamily: "Inter",
fontSize: "14px",
fontStyle: "normal",
fontWeight: 600,
lineHeight: "20px",
letterSpacing: "-0.14px",
}}
>
{total.total_number_of_tasks}
</span>
</div>
</Col>
<Col span={4}>
<div style={{ display: "flex", flexDirection: "column", rowGap: 4 }}>
<span
style={{
fontFamily: "Geist Mono",
fontSize: "12px",
fontStyle: "normal",
fontWeight: 400,
lineHeight: "16px",
color: "#9B9DAA",
}}
>
Total points
</span>
<span
style={{
fontFamily: "Inter",
fontSize: "14px",
fontStyle: "normal",
fontWeight: 600,
lineHeight: "20px",
letterSpacing: "-0.14px",
}}
>
{total.total_earned_points}
</span>
</div>
</Col>
</Row>
);
};
export default TotalStatistics;

@ -0,0 +1,104 @@
import React, { useEffect, useState } from "react";
import { Spin, Typography } from "antd";
import { useMySalaryData } from "../../../Hooks/Profile";
import CurrentMonthCard from "./CurrentMonthCard";
import TotalStatistics from "./TotalStatistics";
import SalaryHistoryTable from "./SalaryHistoryTable";
import { SalaryHistory } from "../../../types/Profile/TProfile";
const { Title } = Typography;
const MySalary: React.FC = () => {
const { data, isLoading } = useMySalaryData();
const [years, setYears] = useState<number[]>([]);
const extractYears = (history: SalaryHistory[]): number[] => {
return Array.from(new Set(history.map((s) => s.year))).sort(
(a, b) => b - a
);
};
useEffect(() => {
if (data?.salary_history && data.salary_history.length > 0) {
setYears(extractYears(data.salary_history));
}
}, [data?.salary_history]);
if (isLoading)
return (
<div
style={{
display: "flex",
justifyContent: "center",
alignItems: "center",
}}
>
<Spin size="large" />
</div>
);
if (!data)
return (
<div
style={{
display: "flex",
justifyContent: "center",
alignItems: "center",
height: "100%",
}}
>
<p>No data</p>
</div>
);
return (
<div className="profile-my-salary">
<div>
<Title
level={3}
style={{
fontFamily: "Inter",
fontSize: "18px",
fontWeight: 700,
lineHeight: "24px",
letterSpacing: "-0.36px",
}}
>
Current Month
</Title>
<CurrentMonthCard current={data.current_month} />
</div>
<div>
<Title
level={3}
style={{
fontFamily: "Inter",
fontSize: "18px",
fontWeight: 700,
lineHeight: "24px",
letterSpacing: "-0.36px",
}}
>
Total
</Title>
<TotalStatistics total={data.total} />
</div>
<div>
{years.map((year) => (
<SalaryHistoryTable
key={year}
year={year}
salaries={data.salary_history.filter((s) => s.year === year)}
/>
))}
</div>
</div>
);
};
export default MySalary;

@ -34,10 +34,10 @@ import {
useMystatsData, useMystatsData,
useProfData, useProfData,
} from "../../Hooks/Profile"; } from "../../Hooks/Profile";
// @ts-ignore
import tagIcon from "../../assets/tagIcon.svg"; import tagIcon from "../../assets/tagIcon.svg";
import { role } from "../../App"; import { role } from "../../App";
import ChangePassword from "./ChangePassword"; import ChangePassword from "./ChangePassword";
import MySalary from "./MySalary";
const { Option } = Select; const { Option } = Select;
const Profile = () => { const Profile = () => {
@ -374,6 +374,9 @@ const Profile = () => {
<TabPane tab={<span>Change Password</span>} key="3"> <TabPane tab={<span>Change Password</span>} key="3">
<ChangePassword /> <ChangePassword />
</TabPane> </TabPane>
<TabPane tab={<span>My Salary</span>} key="4">
<MySalary />
</TabPane>
</Tabs> </Tabs>
</Space> </Space>
</Watermark> </Watermark>

@ -16,42 +16,24 @@ const ShiftAndCoDriverEditModal: React.FC<ShiftAndCoDriverEditModalProps> = ({
}) => { }) => {
const [form] = Form.useForm(); const [form] = Form.useForm();
useEffect(() => {
if (recordTask) {
form.setFieldsValue({
shift_date: recordTask.shift_date,
shift_location: recordTask.shift_location,
cycle_date: recordTask.cycle_date,
cycle_location: recordTask.cycle_location,
pickup_date: recordTask.pickup_date,
pickup_time: recordTask.pickup_time,
pickup_location: recordTask.pickup_location,
driver_name: recordTask.driver_name,
co_driver_name: recordTask.co_driver_name,
co_driver_pickup_date: recordTask.co_driver_pickup_date,
co_driver_pickup_time: recordTask.co_driver_pickup_time,
co_driver_pickup_location: recordTask.co_driver_pickup_location,
co_driver_drop_date: recordTask.co_driver_drop_date,
co_driver_drop_time: recordTask.co_driver_drop_time,
co_driver_drop_location: recordTask.co_driver_drop_location,
});
}
}, [recordTask, form]);
const handleOk = async () => { const handleOk = async () => {
try { try {
const values = await form.validateFields(); const values = await form.validateFields();
taskController.taskPatch(values, recordTask.id); await taskController.taskPatch(values, recordTask.id);
onCancel();
form.resetFields(); form.resetFields();
onCancel();
} catch (error) { } catch (error) {
console.log("Validation Failed:", error); console.log("Validation Failed:", error);
} }
}; };
useEffect(() => {
if (recordTask && open) {
form.resetFields();
form.setFieldsValue(recordTask);
}
}, [recordTask, open]);
return ( return (
<Modal <Modal
open={open} open={open}
@ -62,23 +44,64 @@ const ShiftAndCoDriverEditModal: React.FC<ShiftAndCoDriverEditModalProps> = ({
onOk={handleOk} onOk={handleOk}
destroyOnClose destroyOnClose
> >
<Form form={form} layout="vertical"> <Form
key={recordTask?.id}
form={form}
initialValues={recordTask}
layout="vertical"
>
{/* shift */} {/* shift */}
<Form.Item label="Shift Date" name="shift_date"> <Form.Item
label="Shift Date"
name="shift_date"
rules={[
{
required: !!recordTask?.shift_date,
message: "Shift Date is required",
},
]}
>
<Input placeholder="Date and Time" /> <Input placeholder="Date and Time" />
</Form.Item> </Form.Item>
<Form.Item label="Shift Location" name="shift_location"> <Form.Item
label="Shift Location"
name="shift_location"
rules={[
{
required: !!recordTask?.shift_location,
message: "Shift Location is required",
},
]}
>
<Input placeholder="Enter location" /> <Input placeholder="Enter location" />
</Form.Item> </Form.Item>
{/* cycle */} {/* cycle */}
<Form.Item label="Cycle Date" name="cycle_date"> <Form.Item
label="Cycle Date"
name="cycle_date"
rules={[
{
required: !!recordTask?.cycle_date,
message: "Cycle Date is required",
},
]}
>
<Input placeholder="Date and Time" /> <Input placeholder="Date and Time" />
</Form.Item> </Form.Item>
<Form.Item label="Cycle Location" name="cycle_location"> <Form.Item
label="Cycle Location"
name="cycle_location"
rules={[
{
required: !!recordTask?.cycle_location,
message: "Cycle Location is required",
},
]}
>
<Input placeholder="Enter location" /> <Input placeholder="Enter location" />
</Form.Item> </Form.Item>
@ -86,28 +109,73 @@ const ShiftAndCoDriverEditModal: React.FC<ShiftAndCoDriverEditModalProps> = ({
<Row gutter={8}> <Row gutter={8}>
<Col span={12}> <Col span={12}>
<Form.Item label="Pick Up Date" name="pickup_date"> <Form.Item
label="Pick Up Date"
name="pickup_date"
rules={[
{
required: !!recordTask?.pickup_date,
message: "Pick Up Date is required",
},
]}
>
<Input placeholder="Date" /> <Input placeholder="Date" />
</Form.Item> </Form.Item>
</Col> </Col>
<Col span={12}> <Col span={12}>
<Form.Item label="Pick Up Time" name="pickup_time"> <Form.Item
label="Pick Up Time"
name="pickup_time"
rules={[
{
required: !!recordTask?.pickup_time,
message: "Pick Up Time is required",
},
]}
>
<Input placeholder="Time" /> <Input placeholder="Time" />
</Form.Item> </Form.Item>
</Col> </Col>
</Row> </Row>
<Form.Item label="Pick Up Location" name="pickup_location"> <Form.Item
label="Pick Up Location"
name="pickup_location"
rules={[
{
required: !!recordTask?.pickup_location,
message: "Pick Up Location is required",
},
]}
>
<Input placeholder="Enter location" /> <Input placeholder="Enter location" />
</Form.Item> </Form.Item>
{/* co driver */} {/* co driver */}
<Form.Item label="Driver Name" name="driver_name"> <Form.Item
label="Driver Name"
name="driver_name"
rules={[
{
required: !!recordTask?.driver_name,
message: "Driver Name is required",
},
]}
>
<Input placeholder="Driver name" /> <Input placeholder="Driver name" />
</Form.Item> </Form.Item>
<Form.Item label="Co-Driver Name" name="co_driver_name"> <Form.Item
label="Co-Driver Name"
name="co_driver_name"
rules={[
{
required: !!recordTask?.co_driver_name,
message: "Co-Driver Name is required",
},
]}
>
<Input placeholder="Co-driver name" /> <Input placeholder="Co-driver name" />
</Form.Item> </Form.Item>
@ -116,6 +184,12 @@ const ShiftAndCoDriverEditModal: React.FC<ShiftAndCoDriverEditModalProps> = ({
<Form.Item <Form.Item
label="Co-Driver Pick Up Date" label="Co-Driver Pick Up Date"
name="co_driver_pickup_date" name="co_driver_pickup_date"
rules={[
{
required: !!recordTask?.co_driver_pickup_date,
message: "Co-Driver Pick Up Date is required",
},
]}
> >
<Input placeholder="Date" /> <Input placeholder="Date" />
</Form.Item> </Form.Item>
@ -124,6 +198,12 @@ const ShiftAndCoDriverEditModal: React.FC<ShiftAndCoDriverEditModalProps> = ({
<Form.Item <Form.Item
label="Co-Driver Pick Up Time" label="Co-Driver Pick Up Time"
name="co_driver_pickup_time" name="co_driver_pickup_time"
rules={[
{
required: !!recordTask?.co_driver_pickup_time,
message: "Co-Driver Pick Up Time is required",
},
]}
> >
<Input placeholder="Time" /> <Input placeholder="Time" />
</Form.Item> </Form.Item>
@ -133,18 +213,42 @@ const ShiftAndCoDriverEditModal: React.FC<ShiftAndCoDriverEditModalProps> = ({
<Form.Item <Form.Item
label="Co-Driver Pick Up Location" label="Co-Driver Pick Up Location"
name="co_driver_pickup_location" name="co_driver_pickup_location"
rules={[
{
required: !!recordTask?.co_driver_pickup_location,
message: "Co-Driver Pick Up Location is required",
},
]}
> >
<Input placeholder="Enter pickup location" /> <Input placeholder="Enter pickup location" />
</Form.Item> </Form.Item>
<Row gutter={8}> <Row gutter={8}>
<Col span={12}> <Col span={12}>
<Form.Item label="Co-Driver Drop Date" name="co_driver_drop_date"> <Form.Item
label="Co-Driver Drop Date"
name="co_driver_drop_date"
rules={[
{
required: !!recordTask?.co_driver_drop_date,
message: "Co-Driver Drop Date is required",
},
]}
>
<Input placeholder="Date" /> <Input placeholder="Date" />
</Form.Item> </Form.Item>
</Col> </Col>
<Col span={12}> <Col span={12}>
<Form.Item label="Co-Driver Drop Date" name="co_driver_drop_time"> <Form.Item
label="Co-Driver Drop Time"
name="co_driver_drop_time"
rules={[
{
required: !!recordTask?.co_driver_drop_time,
message: "Co-Driver Drop Time is required",
},
]}
>
<Input placeholder="Time" /> <Input placeholder="Time" />
</Form.Item> </Form.Item>
</Col> </Col>
@ -153,6 +257,12 @@ const ShiftAndCoDriverEditModal: React.FC<ShiftAndCoDriverEditModalProps> = ({
<Form.Item <Form.Item
label="Co-Driver Drop Location" label="Co-Driver Drop Location"
name="co_driver_drop_location" name="co_driver_drop_location"
rules={[
{
required: !!recordTask?.co_driver_drop_location,
message: "Co-Driver Drop Location is required",
},
]}
> >
<Input placeholder="Drop location" /> <Input placeholder="Drop location" />
</Form.Item> </Form.Item>

@ -1,7 +1,8 @@
import { Button, Card, message } from "antd"; import { Button, Card, message, notification } from "antd";
import { CopyOutlined, EditOutlined } from "@ant-design/icons"; import { CopyOutlined, EditOutlined, SendOutlined } from "@ant-design/icons";
import { useState } from "react"; import { useState } from "react";
import ShiftAndCoDriverEditModal from "./ShiftAndCoDriverEditModal"; import ShiftAndCoDriverEditModal from "./ShiftAndCoDriverEditModal";
import { taskController } from "../../../API/LayoutApi/tasks";
interface ShiftDataTabProps { interface ShiftDataTabProps {
recordTask?: any; recordTask?: any;
@ -102,12 +103,38 @@ const ShiftDataTab: React.FC<ShiftDataTabProps> = ({ recordTask }) => {
.catch(() => message.error("Failed to copy!")); .catch(() => message.error("Failed to copy!"));
}; };
const handleSendTelegram = async () => {
if (!recordTask?.id) return;
try {
await taskController.sendTelegram(recordTask.id);
notification.success({
message: "Success",
description: "Message sent to Telegram successfully!",
placement: "topRight",
});
} catch (error: any) {
notification.error({
message: "Error",
description: error?.message || "Failed to send message to Telegram.",
placement: "topRight",
});
}
};
return ( return (
<> <>
<Card <Card
title="Shift & Co-Driver Information" title="Shift & Co-Driver Information"
extra={ extra={
<> <>
<Button
style={{ marginRight: 5 }}
icon={<SendOutlined />}
onClick={handleSendTelegram}
>
Send to Telegram
</Button>
<Button <Button
style={{ marginRight: 5 }} style={{ marginRight: 5 }}
icon={<EditOutlined />} icon={<EditOutlined />}

@ -1,5 +1,6 @@
import { useQuery } from "react-query"; import { useQuery } from "react-query";
import { TMyTaskHistoryGetParams, prof } from "../../API/LayoutApi/profile"; import { TMyTaskHistoryGetParams, prof } from "../../API/LayoutApi/profile";
import { MySalaryResponse } from "../../types/Profile/TProfile";
export const useMystatsData = ({ export const useMystatsData = ({
start_date, start_date,
@ -42,3 +43,13 @@ export const useMyHistoryData = ({
{ refetchOnWindowFocus: false } { refetchOnWindowFocus: false }
); );
}; };
export const useMySalaryData = () => {
return useQuery<MySalaryResponse>(
["users/my-salary"],
() => prof.mySalary(),
{
refetchOnWindowFocus: false,
}
);
};

@ -1,25 +1,80 @@
export type TProfile = { export type TProfile = {
id: number; id: number;
username: string; username: string;
team: null; team: null;
first_name: string; first_name: string;
last_name: string; last_name: string;
is_staff: boolean; is_staff: boolean;
} };
export type TMystats = { export type TMystats = {
daily_stats: Array<object>; daily_stats: Array<object>;
total_for_period: number; total_for_period: number;
avg_stats_for_period: number avg_stats_for_period: number;
period: number; period: number;
contribution: number; contribution: number;
} };
export type TMyTaskHistory = { export type TMyTaskHistory = {
id: number; id: number;
task: number; task: number;
user: string; user: string;
action: string; action: string;
description: string; description: string;
timestamp: Date; timestamp: Date;
} };
export interface CurrentMonth {
username: string;
salary_type: string;
salary_base_amount: number;
employee_id: number;
full_name: string;
team_name: string;
number_of_tasks: number;
total_points: number;
total_bonuses: number;
total_charges: number;
performance_salary: number;
role: string;
salary: number;
month: string;
}
export interface Total {
id: number;
username: string;
salary_type: string;
full_name: string;
team_name: string;
role: string;
total_bonuses: number;
total_charges: number;
total_base_salary: number;
total_performance_salary: number;
total_earned_points: number;
total_number_of_tasks: number;
total_earned_salary: number;
salary_months_count: number;
}
export interface SalaryHistory {
id: number;
month: string;
year: number;
number_of_tasks: number;
total_points: number;
total_bonuses: string;
total_charges: string;
salary_type: string;
base_salary: string;
performance_salary: string;
total_salary: string;
salary_document_path: string | null;
}
export interface MySalaryResponse {
current_month: CurrentMonth;
total: Total;
salary_history: SalaryHistory[];
}

Loading…
Cancel
Save