fix calendar pagination

This commit is contained in:
rahulramesha 2024-03-27 16:38:12 +05:30
parent 57133122ec
commit 9b4176aa17
4 changed files with 42 additions and 58 deletions

View File

@ -106,7 +106,7 @@ export const CalendarChart: React.FC<Props> = observer((props) => {
</div> </div>
); );
const issueIdList = groupedIssueIds ? groupedIssueIds[formattedDatePayload] : null; const issueIdList = groupedIssueIds ? groupedIssueIds[formattedDatePayload] : [];
return ( return (
<> <>
@ -182,6 +182,9 @@ export const CalendarChart: React.FC<Props> = observer((props) => {
date={selectedDate} date={selectedDate}
issues={issues} issues={issues}
issueIdList={issueIdList} issueIdList={issueIdList}
loadMoreIssues={loadMoreIssues}
getPaginationData={getPaginationData}
getGroupIssueCount={getGroupIssueCount}
quickActions={quickActions} quickActions={quickActions}
enableQuickIssueCreate enableQuickIssueCreate
disableIssueCreation={!enableIssueCreation || !isEditingAllowed} disableIssueCreation={!enableIssueCreation || !isEditingAllowed}

View File

@ -4,7 +4,7 @@ import { observer } from "mobx-react-lite";
// types // types
import { TGroupedIssues, TIssue, TIssueMap, TPaginationData } from "@plane/types"; import { TGroupedIssues, TIssue, TIssueMap, TPaginationData } from "@plane/types";
// components // components
import { CalendarIssueBlocks, ICalendarDate, CalendarQuickAddIssueForm } from "@/components/issues"; import { CalendarIssueBlocks, ICalendarDate } from "@/components/issues";
// helpers // helpers
import { MONTHS_LIST } from "@/constants/calendar"; import { MONTHS_LIST } from "@/constants/calendar";
import { cn } from "@/helpers/common.helper"; import { cn } from "@/helpers/common.helper";
@ -63,11 +63,6 @@ export const CalendarDayTile: React.FC<Props> = observer((props) => {
const formattedDatePayload = renderFormattedPayloadDate(date.date); const formattedDatePayload = renderFormattedPayloadDate(date.date);
if (!formattedDatePayload) return null; if (!formattedDatePayload) return null;
const issueIds = groupedIssueIds?.[formattedDatePayload]; const issueIds = groupedIssueIds?.[formattedDatePayload];
const dayIssueCount = getGroupIssueCount(formattedDatePayload);
const nextPageResults = getPaginationData(formattedDatePayload)?.nextPageResults;
const shouldLoadMore =
nextPageResults === undefined && dayIssueCount !== undefined ? issueIds?.length < dayIssueCount : !!nextPageResults;
const isToday = date.date.toDateString() === new Date().toDateString(); const isToday = date.date.toDateString() === new Date().toDateString();
const isSelectedDate = date.date.toDateString() == selectedDate.toDateString(); const isSelectedDate = date.date.toDateString() == selectedDate.toDateString();
@ -117,6 +112,9 @@ export const CalendarDayTile: React.FC<Props> = observer((props) => {
issues={issues} issues={issues}
issueIdList={issueIds ?? []} issueIdList={issueIds ?? []}
quickActions={quickActions} quickActions={quickActions}
loadMoreIssues={loadMoreIssues}
getPaginationData={getPaginationData}
getGroupIssueCount={getGroupIssueCount}
isDragDisabled={readOnly} isDragDisabled={readOnly}
addIssuesToView={addIssuesToView} addIssuesToView={addIssuesToView}
disableIssueCreation={disableIssueCreation} disableIssueCreation={disableIssueCreation}
@ -126,33 +124,6 @@ export const CalendarDayTile: React.FC<Props> = observer((props) => {
readOnly={readOnly} readOnly={readOnly}
/> />
{enableQuickIssueCreate && !disableIssueCreation && !readOnly && (
<div className="px-2 py-1">
<CalendarQuickAddIssueForm
formKey="target_date"
groupId={formattedDatePayload}
prePopulatedData={{
target_date: renderFormattedPayloadDate(date.date) ?? undefined,
}}
quickAddCallback={quickAddCallback}
addIssuesToView={addIssuesToView}
viewId={viewId}
/>
</div>
)}
{shouldLoadMore && (
<div className="flex items-center px-2.5 py-1">
<button
type="button"
className="w-min whitespace-nowrap rounded text-xs px-1.5 py-1 text-custom-text-400 font-medium hover:bg-custom-background-80 hover:text-custom-text-300"
onClick={() => loadMoreIssues(formattedDatePayload)}
>
Load More
</button>
</div>
)}
{provided.placeholder} {provided.placeholder}
</div> </div>
)} )}

View File

@ -1,8 +1,7 @@
import { useState } from "react";
import { Draggable } from "@hello-pangea/dnd"; import { Draggable } from "@hello-pangea/dnd";
import { Placement } from "@popperjs/core"; import { Placement } from "@popperjs/core";
import { observer } from "mobx-react-lite"; import { observer } from "mobx-react-lite";
import { TIssue, TIssueMap } from "@plane/types"; import { TIssue, TIssueMap, TPaginationData } from "@plane/types";
// components // components
import { CalendarQuickAddIssueForm, CalendarIssueBlockRoot } from "@/components/issues"; import { CalendarQuickAddIssueForm, CalendarIssueBlockRoot } from "@/components/issues";
// helpers // helpers
@ -12,8 +11,11 @@ import { renderFormattedPayloadDate } from "@/helpers/date-time.helper";
type Props = { type Props = {
date: Date; date: Date;
issues: TIssueMap | undefined; issues: TIssueMap | undefined;
issueIdList: string[] | null; issueIdList: string[];
quickActions: (issue: TIssue, customActionButton?: React.ReactElement, placement?: Placement) => React.ReactNode; quickActions: (issue: TIssue, customActionButton?: React.ReactElement, placement?: Placement) => React.ReactNode;
loadMoreIssues: (dateString: string) => void;
getPaginationData: (groupId: string | undefined) => TPaginationData | undefined;
getGroupIssueCount: (groupId: string | undefined) => number | undefined;
isDragDisabled?: boolean; isDragDisabled?: boolean;
enableQuickIssueCreate?: boolean; enableQuickIssueCreate?: boolean;
disableIssueCreation?: boolean; disableIssueCreation?: boolean;
@ -35,6 +37,9 @@ export const CalendarIssueBlocks: React.FC<Props> = observer((props) => {
issues, issues,
issueIdList, issueIdList,
quickActions, quickActions,
loadMoreIssues,
getPaginationData,
getGroupIssueCount,
isDragDisabled = false, isDragDisabled = false,
enableQuickIssueCreate, enableQuickIssueCreate,
disableIssueCreation, disableIssueCreation,
@ -45,13 +50,18 @@ export const CalendarIssueBlocks: React.FC<Props> = observer((props) => {
isMobileView = false, isMobileView = false,
} = props; } = props;
// states // states
const [showAllIssues, setShowAllIssues] = useState(false);
const formattedDatePayload = renderFormattedPayloadDate(date); const formattedDatePayload = renderFormattedPayloadDate(date);
const totalIssues = issueIdList?.length ?? 0;
if (!formattedDatePayload) return null; if (!formattedDatePayload) return null;
const dayIssueCount = getGroupIssueCount(formattedDatePayload);
const nextPageResults = getPaginationData(formattedDatePayload)?.nextPageResults;
const shouldLoadMore =
nextPageResults === undefined && dayIssueCount !== undefined
? issueIdList?.length < dayIssueCount
: !!nextPageResults;
return ( return (
<> <>
{issueIdList?.map((issueId, index) => {issueIdList?.map((issueId, index) =>
@ -79,7 +89,7 @@ export const CalendarIssueBlocks: React.FC<Props> = observer((props) => {
)} )}
{enableQuickIssueCreate && !disableIssueCreation && !readOnly && ( {enableQuickIssueCreate && !disableIssueCreation && !readOnly && (
<div className="px-1 md:px-2 py-1 border-custom-border-200 border-b md:border-none"> <div className="px-1 md:px-2 py-1 border-custom-border-200 border-b md:border-none md:hidden group-hover:block">
<CalendarQuickAddIssueForm <CalendarQuickAddIssueForm
formKey="target_date" formKey="target_date"
groupId={formattedDatePayload} groupId={formattedDatePayload}
@ -89,18 +99,18 @@ export const CalendarIssueBlocks: React.FC<Props> = observer((props) => {
quickAddCallback={quickAddCallback} quickAddCallback={quickAddCallback}
addIssuesToView={addIssuesToView} addIssuesToView={addIssuesToView}
viewId={viewId} viewId={viewId}
onOpen={() => setShowAllIssues(true)}
/> />
</div> </div>
)} )}
{totalIssues > 4 && (
<div className="hidden md:flex items-center px-2.5 py-1"> {shouldLoadMore && (
<div className="flex items-center px-2.5 py-1">
<button <button
type="button" type="button"
className="w-min whitespace-nowrap rounded text-xs px-1.5 py-1 text-custom-text-400 font-medium hover:bg-custom-background-80 hover:text-custom-text-300" className="w-min whitespace-nowrap rounded text-xs px-1.5 py-1 text-custom-text-400 font-medium hover:bg-custom-background-80 hover:text-custom-text-300"
onClick={() => setShowAllIssues(!showAllIssues)} onClick={() => loadMoreIssues(formattedDatePayload)}
> >
{showAllIssues ? "Hide" : totalIssues - 4 + " more"} Load More
</button> </button>
</div> </div>
)} )}

View File

@ -800,11 +800,11 @@ export class BaseIssuesStore implements IBaseIssuesStore {
return this.getIssueIds(orderBy(array, "sort_order")); return this.getIssueIds(orderBy(array, "sort_order"));
case "state__name": case "state__name":
return this.getIssueIds( return this.getIssueIds(
orderBy(array, (issue) => this.populateIssueDataForSorting("state_id", issue["state_id"])) orderBy(array, (issue) => this.populateIssueDataForSorting("state_id", issue?.["state_id"]))
); );
case "-state__name": case "-state__name":
return this.getIssueIds( return this.getIssueIds(
orderBy(array, (issue) => this.populateIssueDataForSorting("state_id", issue["state_id"]), ["desc"]) orderBy(array, (issue) => this.populateIssueDataForSorting("state_id", issue?.["state_id"]), ["desc"])
); );
// dates // dates
case "created_at": case "created_at":
@ -844,12 +844,12 @@ export class BaseIssuesStore implements IBaseIssuesStore {
// custom // custom
case "priority": { case "priority": {
const sortArray = ISSUE_PRIORITIES.map((i) => i.key); const sortArray = ISSUE_PRIORITIES.map((i) => i.key);
return this.getIssueIds(orderBy(array, (currentIssue: TIssue) => indexOf(sortArray, currentIssue.priority))); return this.getIssueIds(orderBy(array, (currentIssue: TIssue) => indexOf(sortArray, currentIssue?.priority)));
} }
case "-priority": { case "-priority": {
const sortArray = ISSUE_PRIORITIES.map((i) => i.key); const sortArray = ISSUE_PRIORITIES.map((i) => i.key);
return this.getIssueIds( return this.getIssueIds(
orderBy(array, (currentIssue: TIssue) => indexOf(sortArray, currentIssue.priority), ["desc"]) orderBy(array, (currentIssue: TIssue) => indexOf(sortArray, currentIssue?.priority), ["desc"])
); );
} }
@ -887,7 +887,7 @@ export class BaseIssuesStore implements IBaseIssuesStore {
return this.getIssueIds( return this.getIssueIds(
orderBy(array, [ orderBy(array, [
this.getSortOrderToFilterEmptyValues.bind(null, "label_ids"), //preferring sorting based on empty values to always keep the empty values below this.getSortOrderToFilterEmptyValues.bind(null, "label_ids"), //preferring sorting based on empty values to always keep the empty values below
(issue) => this.populateIssueDataForSorting("label_ids", issue["label_ids"], "asc"), (issue) => this.populateIssueDataForSorting("label_ids", issue?.["label_ids"], "asc"),
]) ])
); );
case "-labels__name": case "-labels__name":
@ -896,7 +896,7 @@ export class BaseIssuesStore implements IBaseIssuesStore {
array, array,
[ [
this.getSortOrderToFilterEmptyValues.bind(null, "label_ids"), //preferring sorting based on empty values to always keep the empty values below this.getSortOrderToFilterEmptyValues.bind(null, "label_ids"), //preferring sorting based on empty values to always keep the empty values below
(issue) => this.populateIssueDataForSorting("label_ids", issue["label_ids"], "desc"), (issue) => this.populateIssueDataForSorting("label_ids", issue?.["label_ids"], "desc"),
], ],
["asc", "desc"] ["asc", "desc"]
) )
@ -906,7 +906,7 @@ export class BaseIssuesStore implements IBaseIssuesStore {
return this.getIssueIds( return this.getIssueIds(
orderBy(array, [ orderBy(array, [
this.getSortOrderToFilterEmptyValues.bind(null, "module_ids"), //preferring sorting based on empty values to always keep the empty values below this.getSortOrderToFilterEmptyValues.bind(null, "module_ids"), //preferring sorting based on empty values to always keep the empty values below
(issue) => this.populateIssueDataForSorting("module_ids", issue["module_ids"], "asc"), (issue) => this.populateIssueDataForSorting("module_ids", issue?.["module_ids"], "asc"),
]) ])
); );
case "-issue_module__module__name": case "-issue_module__module__name":
@ -915,7 +915,7 @@ export class BaseIssuesStore implements IBaseIssuesStore {
array, array,
[ [
this.getSortOrderToFilterEmptyValues.bind(null, "module_ids"), //preferring sorting based on empty values to always keep the empty values below this.getSortOrderToFilterEmptyValues.bind(null, "module_ids"), //preferring sorting based on empty values to always keep the empty values below
(issue) => this.populateIssueDataForSorting("module_ids", issue["module_ids"], "desc"), (issue) => this.populateIssueDataForSorting("module_ids", issue?.["module_ids"], "desc"),
], ],
["asc", "desc"] ["asc", "desc"]
) )
@ -925,7 +925,7 @@ export class BaseIssuesStore implements IBaseIssuesStore {
return this.getIssueIds( return this.getIssueIds(
orderBy(array, [ orderBy(array, [
this.getSortOrderToFilterEmptyValues.bind(null, "cycle_id"), //preferring sorting based on empty values to always keep the empty values below this.getSortOrderToFilterEmptyValues.bind(null, "cycle_id"), //preferring sorting based on empty values to always keep the empty values below
(issue) => this.populateIssueDataForSorting("cycle_id", issue["cycle_id"], "asc"), (issue) => this.populateIssueDataForSorting("cycle_id", issue?.["cycle_id"], "asc"),
]) ])
); );
case "-issue_cycle__cycle__name": case "-issue_cycle__cycle__name":
@ -934,7 +934,7 @@ export class BaseIssuesStore implements IBaseIssuesStore {
array, array,
[ [
this.getSortOrderToFilterEmptyValues.bind(null, "cycle_id"), //preferring sorting based on empty values to always keep the empty values below this.getSortOrderToFilterEmptyValues.bind(null, "cycle_id"), //preferring sorting based on empty values to always keep the empty values below
(issue) => this.populateIssueDataForSorting("cycle_id", issue["cycle_id"], "desc"), (issue) => this.populateIssueDataForSorting("cycle_id", issue?.["cycle_id"], "desc"),
], ],
["asc", "desc"] ["asc", "desc"]
) )
@ -944,7 +944,7 @@ export class BaseIssuesStore implements IBaseIssuesStore {
return this.getIssueIds( return this.getIssueIds(
orderBy(array, [ orderBy(array, [
this.getSortOrderToFilterEmptyValues.bind(null, "assignee_ids"), //preferring sorting based on empty values to always keep the empty values below this.getSortOrderToFilterEmptyValues.bind(null, "assignee_ids"), //preferring sorting based on empty values to always keep the empty values below
(issue) => this.populateIssueDataForSorting("assignee_ids", issue["assignee_ids"], "asc"), (issue) => this.populateIssueDataForSorting("assignee_ids", issue?.["assignee_ids"], "asc"),
]) ])
); );
case "-assignees__first_name": case "-assignees__first_name":
@ -953,7 +953,7 @@ export class BaseIssuesStore implements IBaseIssuesStore {
array, array,
[ [
this.getSortOrderToFilterEmptyValues.bind(null, "assignee_ids"), //preferring sorting based on empty values to always keep the empty values below this.getSortOrderToFilterEmptyValues.bind(null, "assignee_ids"), //preferring sorting based on empty values to always keep the empty values below
(issue) => this.populateIssueDataForSorting("assignee_ids", issue["assignee_ids"], "desc"), (issue) => this.populateIssueDataForSorting("assignee_ids", issue?.["assignee_ids"], "desc"),
], ],
["asc", "desc"] ["asc", "desc"]
) )