table-pagination #29

Merged
nik.polishuk merged 2 commits from table-pagination into main 2024-03-31 20:40:00 +03:00
2 changed files with 315 additions and 45 deletions

View File

@ -1,5 +1,11 @@
import { getTheme } from "@table-library/react-table-library/baseline";
import { CompactTable } from "@table-library/react-table-library/compact";
import { usePagination } from "@table-library/react-table-library/pagination";
import { useSort } from "@table-library/react-table-library/sort";
import { useTheme } from "@table-library/react-table-library/theme";
import React, { useEffect, useState } from "react"; import React, { useEffect, useState } from "react";
import { useDispatch, useSelector } from "react-redux"; import { useDispatch, useSelector } from "react-redux";
import { Link } from "react-router-dom";
import { import {
getProjects, getProjects,
@ -9,7 +15,8 @@ import {
setToggleTab setToggleTab
} from "@redux/projectsTrackerSlice"; } from "@redux/projectsTrackerSlice";
import { caseOfNum } from "@utils/helper"; import { getCorrectDate } from "@utils/calendarHelper";
import { caseOfNum, urlForLocal } from "@utils/helper";
import { apiRequest } from "@api/request"; import { apiRequest } from "@api/request";
@ -26,9 +33,10 @@ import ProjectTicket from "@components/ProjectTicket/ProjectTicket";
import addProjectImg from "assets/icons/addProjectImg.svg"; import addProjectImg from "assets/icons/addProjectImg.svg";
import archiveTrackerProjects from "assets/icons/archiveTrackerProjects.svg"; import archiveTrackerProjects from "assets/icons/archiveTrackerProjects.svg";
import rightArrow from "assets/icons/arrows/arrowRight.svg";
import arrowViewReport from "assets/icons/arrows/arrowViewReport.svg"; import arrowViewReport from "assets/icons/arrows/arrowViewReport.svg";
import filterIcon from "assets/icons/filterIcon.svg"; import filterIcon from "assets/icons/filterIcon.svg";
import search from "assets/icons/serchIcon.png"; import searchImg from "assets/icons/serchIcon.png";
import project from "assets/icons/trackerProject.svg"; import project from "assets/icons/trackerProject.svg";
import tasks from "assets/icons/trackerTasks.svg"; import tasks from "assets/icons/trackerTasks.svg";
import archive from "assets/images/archiveIcon.png"; import archive from "assets/images/archiveIcon.png";
@ -43,15 +51,110 @@ export const Tracker = () => {
const dispatch = useDispatch(); const dispatch = useDispatch();
const projects = useSelector(getProjects); const projects = useSelector(getProjects);
const tab = useSelector(getToggleTab); const tab = useSelector(getToggleTab);
const theme = useTheme(getTheme());
const [nodes, setNodes] = useState([]);
const [initialNodes, setInitialNodes] = useState([]);
const [allTasks, setAllTasks] = useState([]); const [allTasks, setAllTasks] = useState([]);
const [filteredAllTasks, setFilteredAllTasks] = useState([]); const [filteredAllTasks, setFilteredAllTasks] = useState([]);
const [loader, setLoader] = useState(false); const [loader, setLoader] = useState(false);
const [filterCompleteTasks, setFilterCompleteTasks] = useState([]); const [filterCompleteTasks, setFilterCompleteTasks] = useState([]);
const [allCompletedTasks, setAllCompletedTasks] = useState([]); const [allCompletedTasks, setAllCompletedTasks] = useState([]);
const [search, setSearch] = useState("");
const [modalCreateProject, setModalCreateProject] = useState(false); const [modalCreateProject, setModalCreateProject] = useState(false);
const COLUMNS = [
{
label: "Задача",
renderCell: (item) => (
<p dangerouslySetInnerHTML={{ __html: item.title }}></p>
),
sort: { sortKey: "NAME" }
},
{
label: "Создано",
renderCell: (item) => <span>{getCorrectDate(item.created_at)}</span>,
sort: { sortKey: "CREATE" }
},
{
label: "Дедлайн",
renderCell: (item) => (
<span>
{item.dead_line ? getCorrectDate(item.dead_line) : "Без дедлайна"}
</span>
),
sort: { sortKey: "DEADLINE" }
},
{
label: "Потраченное время",
renderCell: (item) => (
<span>
{item.timers.length
? getSpendTime(item.timers)
: "Трекер не был включен"}
</span>
),
sort: { sortKey: "SPEND" }
}
];
let data = { nodes };
const sort = useSort(
data,
{
onChange: onSortChange
},
{
sortFns: {
NAME: (array) => array.sort((a, b) => a.title.localeCompare(b.title)),
CREATE: (array) =>
array.sort((a, b) => new Date(a.created_at) - new Date(b.created_at)),
DEADLINE: (array) =>
array.sort((a, b) => new Date(a.dead_line) - new Date(b.dead_line)),
SPEND: (array) =>
array.sort(
(a, b) =>
getSpendTime(a.timers, true) - getSpendTime(b.timers, true)
)
}
}
);
const pagination = usePagination(data, {
state: {
page: 0,
size: 11
}
});
function getSpendTime(times, seconds) {
let timerSeconds = 0;
times.forEach((time) => {
timerSeconds += time.deltaSeconds;
});
if (seconds) {
return timerSeconds;
}
return `${Math.floor(timerSeconds / 60 / 60)}:${Math.floor(
(timerSeconds / 60) % 60
)}:${timerSeconds % 60}`;
}
function onSortChange(action, state) {
console.log(action, state);
}
const handleSearch = (event) => {
setSearch(event.target.value);
setNodes(
initialNodes.filter((item) =>
item.title.toLowerCase().includes(event.target.value.toLowerCase())
)
);
};
useEffect(() => { useEffect(() => {
setLoader(true); setLoader(true);
apiRequest( apiRequest(
@ -84,6 +187,8 @@ export const Tracker = () => {
: []; : [];
setAllTasks(allTasks); setAllTasks(allTasks);
setFilteredAllTasks(allTasks); setFilteredAllTasks(allTasks);
setNodes(allTasks);
setInitialNodes(allTasks);
setAllCompletedTasks(completedTasks); setAllCompletedTasks(completedTasks);
setFilterCompleteTasks(completedTasks); setFilterCompleteTasks(completedTasks);
}) })
@ -238,53 +343,122 @@ export const Tracker = () => {
: "tracker__tabs__content__projects" : "tracker__tabs__content__projects"
} }
> >
<div className="task-list__head"> {/*<div className="task-list__head">*/}
<div className="task-list__tasks-period"> {/* <div className="task-list__tasks-period">*/}
<div className="month-period"> {/* <div className="month-period">*/}
<p> {/* <p>*/}
{25} - {35} {/* {25} - {35}*/}
</p> {/* </p>*/}
<h3>Сентября,</h3> {/* <h3>Сентября,</h3>*/}
<h3>2023</h3> {/* <h3>2023</h3>*/}
</div> {/* </div>*/}
<div className="buttons-month"> {/* <div className="buttons-month">*/}
<button> {/* <button>*/}
<img src={arrowViewReport} alt="<"></img> {/* <img src={arrowViewReport} alt="<"></img>*/}
</button> {/* </button>*/}
<button> {/* <button>*/}
<img src={arrowViewReport} alt=">"></img> {/* <img src={arrowViewReport} alt=">"></img>*/}
</button> {/* </button>*/}
</div> {/* </div>*/}
</div> {/* </div>*/}
<div className="task-list__head__search"> {/* <div className="task-list__head__search">*/}
<img src={search} alt="search" /> {/* <img src={search} alt="search" />*/}
<input {/* <input*/}
type="text" {/* type="text"*/}
placeholder="Найти задачу" {/* placeholder="Найти задачу"*/}
onChange={(event) => filterAllTask(event)} {/* onChange={(event) => filterAllTask(event)}*/}
{/* />*/}
{/* </div>*/}
{/* <div className="task-list__filters">*/}
{/* <BaseButton styles={"task-list__filters-filter"}>*/}
{/* <img src={filterIcon} alt="#" />*/}
{/* <p>Фильтр</p>*/}
{/* </BaseButton>*/}
{/* <BaseButton styles={"task-list__filters-clear"}>*/}
{/* <p> Очистить фильтр</p>*/}
{/* </BaseButton>*/}
{/* </div>*/}
{/*</div>*/}
{loader ? (
<Loader style="green" />
) : (
<>
<div className="table__search">
<img src={searchImg} alt="search" />
<input
type="text"
placeholder="Поиск по задачам"
value={search}
onChange={handleSearch}
/>
</div>
<CompactTable
columns={COLUMNS}
data={data}
theme={theme}
sort={sort}
pagination={pagination}
/> />
</div> <div className="table__pagination">
<button
className={
pagination.state.page === 0 ? "switch disable" : "switch"
}
type="button"
disabled={pagination.state.page === 0}
onClick={() =>
pagination.fns.onSetPage(pagination.state.page - 1)
}
>
{"<"}
</button>
<span className="table__pages">
{pagination.state.getPages(data.nodes).map((_, index) => (
<button
key={index}
type="button"
className={
pagination.state.page === index
? "page page--active "
: "page"
}
onClick={() => pagination.fns.onSetPage(index)}
>
{index + 1}
</button>
))}
</span>
<button
className={
pagination.state.page + 1 ===
pagination.state.getPages(data.nodes).length
? "switch disable"
: "switch"
}
type="button"
disabled={
pagination.state.page + 1 ===
pagination.state.getPages(data.nodes).length
}
onClick={() =>
pagination.fns.onSetPage(pagination.state.page + 1)
}
>
{">"}
</button>
</div>
</>
)}
<div className="task-list__filters"> {/*<AllTaskTableTracker*/}
<BaseButton styles={"task-list__filters-filter"}> {/* loader={loader}*/}
<img src={filterIcon} alt="#" /> {/* filteredAllTasks={filteredAllTasks}*/}
<p>Фильтр</p> {/* projects={projects}*/}
</BaseButton> {/*/>*/}
<BaseButton styles={"task-list__filters-clear"}>
<p> Очистить фильтр</p>
</BaseButton>
</div>
</div>
{loader && <Loader style="green" />}
<AllTaskTableTracker
loader={loader}
filteredAllTasks={filteredAllTasks}
projects={projects}
/>
<div className="task-list__time"> <div className="task-list__time">
<div className="task-list__time-compited"> <div className="task-list__time-compited">

View File

@ -1937,4 +1937,100 @@
} }
} }
} }
.table {
&__search {
display: flex;
background: #F0F2F5;
border-radius: 5px;
width: 100%;
padding: 14px 12px;
column-gap: 10px;
align-items: center;
margin-bottom: 20px;
img {
width: 20px;
height: 20px;
}
input {
background: none;
border: none;
outline: none;
font-size: 16px;
color: #9BABC5;
width: 100%;
&::placeholder {
color: #9BABC5;
}
}
}
&__pagination {
display: flex;
margin: 25px auto 0;
column-gap: 12px;
button {
font-size: 14px;
width: 32px;
border-radius: 5px;
height: 32px;
color: #2E3A59;
}
.switch {
border: none;
background: #F0F2F5;
font-weight: 600;
}
.disable {
opacity: 0.7;
}
}
&__pages {
display: flex;
column-gap: 4px;
color: black;
background: white;
.page {
border: 1px solid #E8ECF8;
background: none;
&--active {
border: none;
background: #9DA65D;
color: white;
}
}
}
}
table {
grid-template-columns: minmax(0px, 2fr) minmax(0px, 1fr) minmax(0px, 1fr) minmax(0px, 1fr);
th {
border-top: none;
border-bottom: 1px solid #F5F6F8;
color: #2E3A59;
padding: 0 7.5px 15px;
}
td {
padding: 22px 7.5px;
color: #2E3A59;
border-top: none;
p {
max-width: 430px;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
}
}
} }