Skip to content

Commit

Permalink
Port Sent page to use React Table v7
Browse files Browse the repository at this point in the history
  • Loading branch information
jake-low committed Feb 27, 2025
1 parent d947368 commit 4ea3d76
Show file tree
Hide file tree
Showing 5 changed files with 186 additions and 115 deletions.
14 changes: 14 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@
"react-router-dom": "^5.2.0",
"react-share": "^4.2.0",
"react-syntax-highlighter": "^15.4.3",
"react-table": "^7.8.0",
"react-table-6": "^6.11.0",
"react-tagsinput": "^3.19.0",
"redux": "^4.1.2",
Expand Down
75 changes: 75 additions & 0 deletions src/components/PaginationControl/PaginationControl.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
export default function PaginationControl({
currentPage,
totalPages,
pageSize,
gotoPage,
setPageSize,
}) {
const canPreviousPage = currentPage > 0;
const canNextPage = currentPage < totalPages - 1;

const previousPage = () => gotoPage(Math.max(currentPage - 1, 0));
const nextPage = () => gotoPage(Math.min(currentPage + 1, totalPages - 1));

return (
<div className="mr-mx-auto mr-flex mr-items-center mr-gap-3 mr-text-white">
<button
className="mr-button mr-button--small"
onClick={() => gotoPage(0)}
disabled={!canPreviousPage}
>
{"<< First"}
</button>
<button
className="mr-button mr-button--small"
onClick={() => previousPage()}
disabled={!canPreviousPage}
>
{"< Previous"}
</button>
<span>
{"Page "}
<input
className="mr-input mr-px-1 mr-py-0 mr-w-16"
type="number"
min={1}
max={totalPages}
defaultValue={currentPage + 1}
onChange={(e) => gotoPage(e.target.value ? Number(e.target.value) - 1 : 0)}
/>
{" of "}
{totalPages}
</span>
<button
className="mr-button mr-button--small"
onClick={() => nextPage()}
disabled={!canNextPage}
>
{"Next >"}
</button>
<button
className="mr-button mr-button--small"
onClick={() => gotoPage(totalPages - 1)}
disabled={!canNextPage}
>
{"Last >>"}
</button>

{setPageSize && (
<select
className="mr-select mr-px-3"
value={pageSize}
onChange={(e) => {
setPageSize(Number(e.target.value));
}}
>
{[25, 50, 100].map((pageSize) => (
<option key={pageSize} value={pageSize}>
Show {pageSize} per page
</option>
))}
</select>
)}
</div>
);
}
194 changes: 88 additions & 106 deletions src/pages/Sent/Sent.jsx
Original file line number Diff line number Diff line change
@@ -1,30 +1,50 @@
import { useEffect, useState } from "react";
import { FormattedDate, FormattedTime, injectIntl } from "react-intl";
import { Link } from "react-router-dom";
import ReactTable from "react-table-6";
import { usePagination, useSortBy, useTable } from "react-table";
import WithCurrentUser from "../../components/HOCs/WithCurrentUser/WithCurrentUser";
import { intlTableProps } from "../../components/IntlTable/IntlTable";
import PaginationControl from "../../components/PaginationControl/PaginationControl";
import CommentType from "../../services/Comment/CommentType";
import HeaderSent from "./HeaderSent";
import Notification from "./Notification";
import { useSentComments } from "./SentCommentsHooks";

const defaultSorted = {
const DEFAULT_SORT_CRITERIA = {
id: "created",
desc: true,
};

const defaultPagination = {
const DEFAULT_PAGINATION = {
page: 0,
pageSize: 25,
};

const Sent = (props) => {
const [commentType, setCommentType] = useState(CommentType.TASK);
const comments = useSentComments(commentType);
const [sortCriteria, setSortCriteria] = useState(defaultSorted);
const [pagination, setPagination] = useState(defaultPagination);
const [selectedComment, setSelectedComment] = useState(null);
const [sortCriteria, setSortCriteria] = useState(DEFAULT_SORT_CRITERIA);
const [pagination, setPagination] = useState(DEFAULT_PAGINATION);

const data = comments.data;
const columns = commentType === CommentType.TASK ? TASK_COLUMNS : CHALLENGE_COLUMNS;

const {
getTableProps,
getTableBodyProps,
headerGroups,
rows,
prepareRow,
state: { sortBy },
} = useTable(
{
data,
columns,
manualPagination: true,
manualSortBy: true,
pageCount: comments.count,
},
useSortBy,
usePagination,
);

useEffect(() => {
comments.fetch(props.user?.id, sortCriteria, pagination);
Expand All @@ -37,13 +57,19 @@ const Sent = (props) => {
pagination.pageSize,
]);

useEffect(() => {
if (sortBy && sortBy[0]) setSortCriteria(sortBy[0]);
}, [sortBy]);

const resetTable = () => {
setSortCriteria(defaultSorted);
setPagination(defaultPagination);
setSortCriteria(DEFAULT_SORT_CRITERIA);
setPagination(DEFAULT_PAGINATION);
};

const totalPages = Math.ceil(comments.count / pagination.pageSize);

return (
<div className="mr-bg-gradient-r-green-dark-blue mr-px-6 mr-py-8 md:mr-py-12 mr-flex mr-justify-center mr-items-center">
<div className="mr-bg-gradient-r-green-dark-blue mr-px-6 mr-py-8 md:mr-py-12 mr-flex mr-flex-col mr-justify-center mr-items-center">
<section className="mr-flex-grow mr-w-full mr-bg-black-15 mr-p-4 md:mr-p-8 mr-rounded">
<HeaderSent
commentType={commentType}
Expand All @@ -53,64 +79,57 @@ const Sent = (props) => {
resetTable();
}}
/>
<ReactTable
data={comments.data}
columns={
commentType === CommentType.TASK
? taskColumns({ setSelectedComment })
: challengeColumns({ setSelectedComment })
}
defaultPageSize={defaultPagination.pageSize}
defaultSorted={[defaultSorted]}
minRows={1}
manual
sorted={[sortCriteria]}
multiSort={false}
noDataText={"no data"}
loading={comments.loading}
pageSize={pagination.pageSize}
pages={Math.ceil(comments.count / pagination.pageSize)}
onSortedChange={(criteria) => {
setSortCriteria(criteria[0]);
}}
onPageChange={(page) => setPagination({ ...pagination, page })}
onPageSizeChange={(pageSize) => setPagination({ ...pagination, pageSize })}
page={pagination.page}
getTrProps={() => {
const styles = {};
return { style: styles };
}}
{...intlTableProps(props.intl)}
>
{(state, makeTable) => {
return makeTable();
}}
</ReactTable>

<table className="mr-text-white mr-links-green-lighter" {...getTableProps()}>
<thead>
{headerGroups.map((headerGroup) => (
<tr {...headerGroup.getHeaderGroupProps()}>
{headerGroup.headers.map((column) => (
<th className="mr-px-2" {...column.getHeaderProps(column.getSortByToggleProps())}>
{column.render("Header")}
{column.isSorted ? (column.isSortedDesc ? " ▼" : " ▲") : ""}
</th>
))}
</tr>
))}
</thead>

<tbody {...getTableBodyProps()}>
{rows.map((row) => {
prepareRow(row);
return (
<tr className="mr-border-y mr-border-white-10" {...row.getRowProps()}>
{row.cells.map((cell) => {
return (
<td className="mr-px-2" {...cell.getCellProps()}>
{cell.render("Cell")}
</td>
);
})}
</tr>
);
})}
</tbody>
</table>
</section>

{selectedComment && (
<Notification
onClose={() => setSelectedComment(null)}
id={selectedComment.id}
text={selectedComment.text}
type={selectedComment.type}
/>
)}
<PaginationControl
currentPage={pagination.page}
totalPages={totalPages}
pageSize={pagination.pageSize}
gotoPage={(page) => setPagination({ ...pagination, page })}
setPageSize={(pageSize) => setPagination({ ...pagination, pageSize })}
/>
</div>
);
};

const taskColumns = ({ setSelectedComment }) => [
const TASK_COLUMNS = [
{
id: "task_id",
Header: "Task ID",
accessor: "taskId",
Cell: ({ value }) => (
<Link to={`task/${value}`} target="_blank" rel="noopener noreferrer">
{value}
</Link>
),
maxWidth: 100,
Cell: ({ value }) => <Link to={`task/${value}`}>{value}</Link>,
sortable: true,
resizable: false,
},
Expand All @@ -119,52 +138,31 @@ const taskColumns = ({ setSelectedComment }) => [
Header: "Date",
accessor: "created",
Cell: ({ value }) => (
<>
<div className="mr-whitespace-nowrap">
<FormattedDate value={value} /> <FormattedTime value={value} />
</>
</div>
),
maxWidth: 200,
sortable: true,
resizable: false,
},
{
id: "comment",
Header: "Comment",
accessor: "comment",
Cell: ({ value, row }) => {
return (
<button
className="mr-text-green-light hover:mr-text-white"
onClick={() =>
setSelectedComment({ id: row.task_id, text: value, type: CommentType.TASK })
}
style={{ textOverflow: "ellipsis", overflow: "hidden", whiteSpace: "nowrap" }}
>
{value}
</button>
);
},
Cell: ({ value }) => <p>{value}</p>,
sortable: true,
resizable: false,
},
];

const challengeColumns = ({ setSelectedComment }) => [
const CHALLENGE_COLUMNS = [
{
id: "challenge_name",
Header: "Challenge",
accessor: "challengeName",
Cell: ({ value, original }) => {
return (
<Link
to={`browse/challenges/${original.challengeId}?tab=conversation`}
target="_blank"
rel="noopener noreferrer"
>
{value}
</Link>
);
},
Cell: ({ value, original }) => (
<Link to={`browse/challenges/${original.challengeId}?tab=conversation`}>{value}</Link>
),
maxWidth: 200,
sortable: true,
resizable: false,
Expand All @@ -174,9 +172,9 @@ const challengeColumns = ({ setSelectedComment }) => [
Header: "Date",
accessor: "created",
Cell: ({ value }) => (
<>
<div className="mr-whitespace-nowrap">
<FormattedDate value={value} /> <FormattedTime value={value} />
</>
</div>
),
maxWidth: 200,
sortable: true,
Expand All @@ -186,23 +184,7 @@ const challengeColumns = ({ setSelectedComment }) => [
id: "comment",
Header: "Comment",
accessor: "comment",
Cell: ({ value, original }) => {
return (
<button
className="mr-text-green-light hover:mr-text-white"
onClick={() =>
setSelectedComment({
id: original.challengeId,
text: value,
type: CommentType.CHALLENGE,
})
}
style={{ textOverflow: "ellipsis", overflow: "hidden", whiteSpace: "nowrap" }}
>
{value}
</button>
);
},
Cell: ({ value }) => <p>{value}</p>,
sortable: true,
resizable: false,
},
Expand Down
Loading

0 comments on commit 4ea3d76

Please sign in to comment.