chore: added issue activity filters to local storage (#6324)
chore: added sort order to local storage
This commit is contained in:
parent
bc27bc9dd2
commit
208df80c86
6 changed files with 55 additions and 31 deletions
|
|
@ -16,6 +16,7 @@ import {
|
|||
TIssueServiceType,
|
||||
} from "@plane/types";
|
||||
// plane web constants
|
||||
import { TSORT_ORDER } from "@/constants/common";
|
||||
import { EActivityFilterType } from "@/plane-web/constants/issues";
|
||||
// services
|
||||
import { IssueActivityService } from "@/services/issue";
|
||||
|
|
@ -36,20 +37,17 @@ export interface IIssueActivityStoreActions {
|
|||
|
||||
export interface IIssueActivityStore extends IIssueActivityStoreActions {
|
||||
// observables
|
||||
sortOrder: "asc" | "desc";
|
||||
loader: TActivityLoader;
|
||||
activities: TIssueActivityIdMap;
|
||||
activityMap: TIssueActivityMap;
|
||||
// helper methods
|
||||
getActivitiesByIssueId: (issueId: string) => string[] | undefined;
|
||||
getActivityById: (activityId: string) => TIssueActivity | undefined;
|
||||
getActivityCommentByIssueId: (issueId: string) => TIssueActivityComment[] | undefined;
|
||||
toggleSortOrder: () => void;
|
||||
getActivityCommentByIssueId: (issueId: string, sortOrder: TSORT_ORDER) => TIssueActivityComment[] | undefined;
|
||||
}
|
||||
|
||||
export class IssueActivityStore implements IIssueActivityStore {
|
||||
// observables
|
||||
sortOrder: "asc" | "desc" = "asc";
|
||||
loader: TActivityLoader = "fetch";
|
||||
activities: TIssueActivityIdMap = {};
|
||||
activityMap: TIssueActivityMap = {};
|
||||
|
|
@ -64,13 +62,11 @@ export class IssueActivityStore implements IIssueActivityStore {
|
|||
) {
|
||||
makeObservable(this, {
|
||||
// observables
|
||||
sortOrder: observable.ref,
|
||||
loader: observable.ref,
|
||||
activities: observable,
|
||||
activityMap: observable,
|
||||
// actions
|
||||
fetchActivities: action,
|
||||
toggleSortOrder: action,
|
||||
});
|
||||
this.serviceType = serviceType;
|
||||
// services
|
||||
|
|
@ -88,7 +84,7 @@ export class IssueActivityStore implements IIssueActivityStore {
|
|||
return this.activityMap[activityId] ?? undefined;
|
||||
};
|
||||
|
||||
getActivityCommentByIssueId = computedFn((issueId: string) => {
|
||||
getActivityCommentByIssueId = computedFn((issueId: string, sortOrder: TSORT_ORDER) => {
|
||||
if (!issueId) return undefined;
|
||||
|
||||
let activityComments: TIssueActivityComment[] = [];
|
||||
|
|
@ -119,15 +115,11 @@ export class IssueActivityStore implements IIssueActivityStore {
|
|||
});
|
||||
});
|
||||
|
||||
activityComments = orderBy(activityComments, (e) => new Date(e.created_at || 0), this.sortOrder);
|
||||
activityComments = orderBy(activityComments, (e) => new Date(e.created_at || 0), sortOrder);
|
||||
|
||||
return activityComments;
|
||||
});
|
||||
|
||||
toggleSortOrder = () => {
|
||||
this.sortOrder = this.sortOrder === "asc" ? "desc" : "asc";
|
||||
};
|
||||
|
||||
// actions
|
||||
public async fetchActivities(
|
||||
workspaceSlug: string,
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
import { FC } from "react";
|
||||
import { observer } from "mobx-react";
|
||||
// constants
|
||||
import { TSORT_ORDER } from "@/constants/common";
|
||||
// hooks
|
||||
import { useIssueDetail } from "@/hooks/store";
|
||||
// plane web components
|
||||
|
|
@ -21,18 +23,27 @@ type TIssueActivityCommentRoot = {
|
|||
activityOperations: TActivityOperations;
|
||||
showAccessSpecifier?: boolean;
|
||||
disabled?: boolean;
|
||||
sortOrder: TSORT_ORDER;
|
||||
};
|
||||
|
||||
export const IssueActivityCommentRoot: FC<TIssueActivityCommentRoot> = observer((props) => {
|
||||
const { workspaceSlug, issueId, selectedFilters, activityOperations, showAccessSpecifier, projectId, disabled } =
|
||||
props;
|
||||
const {
|
||||
workspaceSlug,
|
||||
issueId,
|
||||
selectedFilters,
|
||||
activityOperations,
|
||||
showAccessSpecifier,
|
||||
projectId,
|
||||
disabled,
|
||||
sortOrder,
|
||||
} = props;
|
||||
// hooks
|
||||
const {
|
||||
activity: { getActivityCommentByIssueId },
|
||||
comment: {},
|
||||
} = useIssueDetail();
|
||||
|
||||
const activityComments = getActivityCommentByIssueId(issueId);
|
||||
const activityComments = getActivityCommentByIssueId(issueId, sortOrder);
|
||||
|
||||
if (!activityComments || (activityComments && activityComments.length <= 0)) return <></>;
|
||||
|
||||
|
|
|
|||
|
|
@ -26,6 +26,9 @@ export const ActivityFilter: FC<TActivityFilter> = observer((props) => {
|
|||
className="relative"
|
||||
>
|
||||
<span className="text-custom-text-200">Filters</span>
|
||||
{selectedFilters.length < filterOptions.length && (
|
||||
<span className="absolute h-2 w-2 -right-0.5 -top-0.5 bg-custom-primary-100 rounded-full" />
|
||||
)}
|
||||
</Button>
|
||||
}
|
||||
panelClassName="p-2 rounded-md border border-custom-border-200 bg-custom-background-100"
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
"use client";
|
||||
|
||||
import { FC, useMemo, useState } from "react";
|
||||
import { FC, useMemo } from "react";
|
||||
import { observer } from "mobx-react";
|
||||
import { useLocalStorage } from "@plane/hooks";
|
||||
// types
|
||||
import { TFileSignedURLResponse, TIssueComment } from "@plane/types";
|
||||
import { EFileAssetType } from "@plane/types/src/enums";
|
||||
|
|
@ -10,6 +11,8 @@ import { TOAST_TYPE, setToast } from "@plane/ui";
|
|||
// components
|
||||
import { IssueCommentCreate } from "@/components/issues";
|
||||
import { ActivitySortRoot, IssueActivityCommentRoot } from "@/components/issues/issue-detail";
|
||||
// constants
|
||||
import { TSORT_ORDER } from "@/constants/common";
|
||||
// hooks
|
||||
import { useIssueDetail, useProject, useUser, useUserPermissions } from "@/hooks/store";
|
||||
// plane web components
|
||||
|
|
@ -38,12 +41,14 @@ export type TActivityOperations = {
|
|||
|
||||
export const IssueActivity: FC<TIssueActivity> = observer((props) => {
|
||||
const { workspaceSlug, projectId, issueId, disabled = false, isIntakeIssue = false } = props;
|
||||
// state
|
||||
const [selectedFilters, setSelectedFilters] = useState<TActivityFilters[]>(defaultActivityFilters);
|
||||
// hooks
|
||||
const { setValue: setFilterValue, storedValue: selectedFilters } = useLocalStorage(
|
||||
"issue_activity_filters",
|
||||
defaultActivityFilters
|
||||
);
|
||||
const { setValue: setSortOrder, storedValue: sortOrder } = useLocalStorage("activity_sort_order", TSORT_ORDER.ASC);
|
||||
const {
|
||||
issue: { getIssueById },
|
||||
activity: { sortOrder, toggleSortOrder },
|
||||
createComment,
|
||||
updateComment,
|
||||
removeComment,
|
||||
|
|
@ -60,14 +65,20 @@ export const IssueActivity: FC<TIssueActivity> = observer((props) => {
|
|||
const isWorklogButtonEnabled = !isIntakeIssue && !isGuest && (isAdmin || isAssigned);
|
||||
// toggle filter
|
||||
const toggleFilter = (filter: TActivityFilters) => {
|
||||
setSelectedFilters((prevFilters) => {
|
||||
if (prevFilters.includes(filter)) {
|
||||
if (prevFilters.length === 1) return prevFilters; // Ensure at least one filter is applied
|
||||
return prevFilters.filter((f) => f !== filter);
|
||||
} else {
|
||||
return [...prevFilters, filter];
|
||||
}
|
||||
});
|
||||
if (!selectedFilters) return;
|
||||
let _filters = [];
|
||||
if (selectedFilters.includes(filter)) {
|
||||
if (selectedFilters.length === 1) return selectedFilters; // Ensure at least one filter is applied
|
||||
_filters = selectedFilters.filter((f) => f !== filter);
|
||||
} else {
|
||||
_filters = [...selectedFilters, filter];
|
||||
}
|
||||
|
||||
setFilterValue(_filters);
|
||||
};
|
||||
|
||||
const toggleSortOrder = () => {
|
||||
setSortOrder(sortOrder === TSORT_ORDER.ASC ? TSORT_ORDER.DESC : TSORT_ORDER.ASC);
|
||||
};
|
||||
|
||||
const activityOperations: TActivityOperations = useMemo(
|
||||
|
|
@ -163,9 +174,9 @@ export const IssueActivity: FC<TIssueActivity> = observer((props) => {
|
|||
disabled={disabled}
|
||||
/>
|
||||
)}
|
||||
<ActivitySortRoot sortOrder={sortOrder} toggleSort={toggleSortOrder} />
|
||||
<ActivitySortRoot sortOrder={sortOrder || TSORT_ORDER.ASC} toggleSort={toggleSortOrder} />
|
||||
<ActivityFilterRoot
|
||||
selectedFilters={selectedFilters}
|
||||
selectedFilters={selectedFilters || defaultActivityFilters}
|
||||
toggleFilter={toggleFilter}
|
||||
isIntakeIssue={isIntakeIssue}
|
||||
projectId={projectId}
|
||||
|
|
@ -181,10 +192,11 @@ export const IssueActivity: FC<TIssueActivity> = observer((props) => {
|
|||
projectId={projectId}
|
||||
workspaceSlug={workspaceSlug}
|
||||
issueId={issueId}
|
||||
selectedFilters={selectedFilters}
|
||||
selectedFilters={selectedFilters || defaultActivityFilters}
|
||||
activityOperations={activityOperations}
|
||||
showAccessSpecifier={!!project.anchor}
|
||||
disabled={disabled}
|
||||
sortOrder={sortOrder || TSORT_ORDER.ASC}
|
||||
/>
|
||||
{!disabled && (
|
||||
<IssueCommentCreate
|
||||
|
|
|
|||
|
|
@ -3,11 +3,12 @@
|
|||
import { FC, memo } from "react";
|
||||
import { ArrowUpWideNarrow, ArrowDownWideNarrow } from "lucide-react";
|
||||
import { getButtonStyling } from "@plane/ui";
|
||||
import { TSORT_ORDER } from "@/constants/common";
|
||||
// helpers
|
||||
import { cn } from "@/helpers/common.helper";
|
||||
|
||||
export type TActivitySortRoot = {
|
||||
sortOrder: "asc" | "desc";
|
||||
sortOrder: TSORT_ORDER;
|
||||
toggleSort: () => void;
|
||||
className?: string;
|
||||
iconClassName?: string;
|
||||
|
|
|
|||
|
|
@ -28,3 +28,8 @@ export const PROGRESS_STATE_GROUPS_DETAILS = [
|
|||
color: "#A3A3A3",
|
||||
},
|
||||
];
|
||||
|
||||
export enum TSORT_ORDER {
|
||||
ASC = "asc",
|
||||
DESC = "desc",
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue