mirror of
https://github.com/makeplane/plane
synced 2024-06-14 14:31:34 +00:00
feat: storing my issue view display properties (#1124)
This commit is contained in:
parent
f095594be9
commit
def391cb76
@ -1,26 +1,18 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import { useRouter } from "next/router";
|
||||
import useSWR from "swr";
|
||||
import { useState, useEffect, useCallback } from "react";
|
||||
import useSWR, { mutate } from "swr";
|
||||
// services
|
||||
import stateService from "services/state.service";
|
||||
import userService from "services/user.service";
|
||||
import workspaceService from "services/workspace.service";
|
||||
// hooks
|
||||
import useUser from "hooks/use-user";
|
||||
// helpers
|
||||
import { groupBy } from "helpers/array.helper";
|
||||
import { getStatesList } from "helpers/state.helper";
|
||||
// types
|
||||
import { Properties, NestedKeyOf, IIssue } from "types";
|
||||
// fetch-keys
|
||||
import { STATES_LIST } from "constants/fetch-keys";
|
||||
// constants
|
||||
import { PRIORITIES } from "constants/project";
|
||||
import { IWorkspaceMember, Properties } from "types";
|
||||
import { WORKSPACE_MEMBERS_ME } from "constants/fetch-keys";
|
||||
|
||||
const initialValues: Properties = {
|
||||
assignee: true,
|
||||
due_date: false,
|
||||
key: true,
|
||||
labels: true,
|
||||
labels: false,
|
||||
priority: false,
|
||||
state: true,
|
||||
sub_issue_count: false,
|
||||
@ -29,99 +21,80 @@ const initialValues: Properties = {
|
||||
estimate: false,
|
||||
};
|
||||
|
||||
// TODO: Refactor this logic
|
||||
const useMyIssuesProperties = (issues?: IIssue[]) => {
|
||||
const useMyIssuesProperties = (workspaceSlug?: string) => {
|
||||
const [properties, setProperties] = useState<Properties>(initialValues);
|
||||
const [groupByProperty, setGroupByProperty] = useState<NestedKeyOf<IIssue> | null>(null);
|
||||
|
||||
// FIXME: where this hook is used we may not have project id in the url
|
||||
const router = useRouter();
|
||||
const { workspaceSlug, projectId } = router.query;
|
||||
|
||||
const { user } = useUser();
|
||||
|
||||
const { data: stateGroups } = useSWR(
|
||||
workspaceSlug && projectId ? STATES_LIST(projectId as string) : null,
|
||||
workspaceSlug && projectId
|
||||
? () => stateService.getStates(workspaceSlug as string, projectId as string)
|
||||
: null
|
||||
);
|
||||
const states = getStatesList(stateGroups ?? {});
|
||||
|
||||
useEffect(() => {
|
||||
if (!user) return;
|
||||
setProperties({ ...initialValues, ...user.my_issues_prop?.properties });
|
||||
setGroupByProperty(user.my_issues_prop?.groupBy ?? null);
|
||||
}, [user]);
|
||||
|
||||
const groupedByIssues: {
|
||||
[key: string]: IIssue[];
|
||||
} = {
|
||||
...(groupByProperty === "state_detail.name"
|
||||
? Object.fromEntries(
|
||||
states
|
||||
?.sort((a, b) => a.sequence - b.sequence)
|
||||
?.map((state) => [
|
||||
state.name,
|
||||
issues?.filter((issue) => issue.state === state.name) ?? [],
|
||||
]) ?? []
|
||||
)
|
||||
: groupByProperty === "priority"
|
||||
? Object.fromEntries(
|
||||
PRIORITIES.map((priority) => [
|
||||
priority,
|
||||
issues?.filter((issue) => issue.priority === priority) ?? [],
|
||||
])
|
||||
)
|
||||
: {}),
|
||||
...groupBy(issues ?? [], groupByProperty ?? ""),
|
||||
};
|
||||
|
||||
const setMyIssueProperty = (key: keyof Properties) => {
|
||||
if (!user) return;
|
||||
userService.updateUser({ my_issues_prop: { properties, groupBy: groupByProperty } });
|
||||
setProperties((prevData) => ({
|
||||
...prevData,
|
||||
[key]: !prevData[key],
|
||||
}));
|
||||
localStorage.setItem(
|
||||
"my_issues_prop",
|
||||
JSON.stringify({
|
||||
properties: {
|
||||
...properties,
|
||||
[key]: !properties[key],
|
||||
},
|
||||
groupBy: groupByProperty,
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
const setMyIssueGroupByProperty = (groupByProperty: NestedKeyOf<IIssue> | null) => {
|
||||
if (!user) return;
|
||||
userService.updateUser({ my_issues_prop: { properties, groupBy: groupByProperty } });
|
||||
setGroupByProperty(groupByProperty);
|
||||
localStorage.setItem(
|
||||
"my_issues_prop",
|
||||
JSON.stringify({ properties, groupBy: groupByProperty })
|
||||
);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const viewProps = localStorage.getItem("my_issues_prop");
|
||||
if (viewProps) {
|
||||
const { properties, groupBy } = JSON.parse(viewProps);
|
||||
setProperties(properties);
|
||||
setGroupByProperty(groupBy);
|
||||
const { data: myWorkspace } = useSWR(
|
||||
workspaceSlug ? WORKSPACE_MEMBERS_ME(workspaceSlug as string) : null,
|
||||
workspaceSlug ? () => workspaceService.workspaceMemberMe(workspaceSlug as string) : null,
|
||||
{
|
||||
shouldRetryOnError: false,
|
||||
}
|
||||
}, []);
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (!myWorkspace || !workspaceSlug || !user) return;
|
||||
|
||||
setProperties({ ...initialValues, ...myWorkspace.view_props });
|
||||
|
||||
if (!myWorkspace.view_props) {
|
||||
workspaceService.updateWorkspaceView(workspaceSlug, {
|
||||
view_props: { ...initialValues },
|
||||
});
|
||||
}
|
||||
}, [myWorkspace, workspaceSlug, user]);
|
||||
|
||||
const updateIssueProperties = useCallback(
|
||||
(key: keyof Properties) => {
|
||||
if (!workspaceSlug || !user) return;
|
||||
|
||||
setProperties((prev) => ({ ...prev, [key]: !prev[key] }));
|
||||
|
||||
if (myWorkspace) {
|
||||
mutate<IWorkspaceMember>(
|
||||
WORKSPACE_MEMBERS_ME(workspaceSlug.toString()),
|
||||
(prevData) => {
|
||||
if (!prevData) return;
|
||||
return {
|
||||
filteredIssues: groupedByIssues,
|
||||
groupByProperty,
|
||||
properties,
|
||||
setMyIssueProperty,
|
||||
setMyIssueGroupByProperty,
|
||||
} as const;
|
||||
...prevData,
|
||||
view_props: { ...prevData?.view_props, [key]: !prevData.view_props?.[key] },
|
||||
};
|
||||
},
|
||||
false
|
||||
);
|
||||
if (myWorkspace.view_props) {
|
||||
workspaceService.updateWorkspaceView(workspaceSlug, {
|
||||
view_props: {
|
||||
...myWorkspace.view_props,
|
||||
[key]: !myWorkspace.view_props[key],
|
||||
},
|
||||
});
|
||||
} else {
|
||||
workspaceService.updateWorkspaceView(workspaceSlug, {
|
||||
view_props: { ...initialValues },
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
[workspaceSlug, myWorkspace, user]
|
||||
);
|
||||
|
||||
const newProperties: Properties = {
|
||||
assignee: properties.assignee,
|
||||
due_date: properties.due_date,
|
||||
key: properties.key,
|
||||
labels: properties.labels,
|
||||
priority: properties.priority,
|
||||
state: properties.state,
|
||||
sub_issue_count: properties.sub_issue_count,
|
||||
attachment_count: properties.attachment_count,
|
||||
link: properties.link,
|
||||
estimate: properties.estimate,
|
||||
};
|
||||
|
||||
return [newProperties, updateIssueProperties] as const;
|
||||
};
|
||||
|
||||
export default useMyIssuesProperties;
|
||||
|
@ -14,7 +14,7 @@ import useIssues from "hooks/use-issues";
|
||||
import { Spinner, EmptySpace, EmptySpaceItem, PrimaryButton } from "components/ui";
|
||||
import { Breadcrumbs, BreadcrumbItem } from "components/breadcrumbs";
|
||||
// hooks
|
||||
import useIssuesProperties from "hooks/use-issue-properties";
|
||||
import useMyIssuesProperties from "hooks/use-my-issues-filter";
|
||||
// types
|
||||
import { IIssue, Properties } from "types";
|
||||
// components
|
||||
@ -31,10 +31,7 @@ const MyIssuesPage: NextPage = () => {
|
||||
// fetching user issues
|
||||
const { myIssues } = useIssues(workspaceSlug as string);
|
||||
|
||||
const [properties, setProperties] = useIssuesProperties(
|
||||
workspaceSlug ? (workspaceSlug as string) : undefined,
|
||||
undefined
|
||||
);
|
||||
const [properties, setProperties] = useMyIssuesProperties(workspaceSlug as string);
|
||||
|
||||
return (
|
||||
<WorkspaceAuthorizationLayout
|
||||
|
@ -142,6 +142,14 @@ class WorkspaceService extends APIService {
|
||||
});
|
||||
}
|
||||
|
||||
async updateWorkspaceView(workspaceSlug: string, data: any): Promise<any> {
|
||||
return this.post(`/api/workspaces/${workspaceSlug}/workspace-views/`, data)
|
||||
.then((response) => response?.data)
|
||||
.catch((error) => {
|
||||
throw error?.response?.data;
|
||||
});
|
||||
}
|
||||
|
||||
async updateWorkspaceMember(
|
||||
workspaceSlug: string,
|
||||
memberId: string,
|
||||
|
14
apps/app/types/workspace.d.ts
vendored
14
apps/app/types/workspace.d.ts
vendored
@ -33,6 +33,19 @@ export interface IWorkspaceMemberInvitation {
|
||||
workspace: IWorkspace;
|
||||
}
|
||||
|
||||
export type Properties = {
|
||||
assignee: boolean;
|
||||
due_date: boolean;
|
||||
labels: boolean;
|
||||
key: boolean;
|
||||
priority: boolean;
|
||||
state: boolean;
|
||||
sub_issue_count: boolean;
|
||||
link: boolean;
|
||||
attachment_count: boolean;
|
||||
estimate: boolean;
|
||||
};
|
||||
|
||||
export interface IWorkspaceMember {
|
||||
readonly id: string;
|
||||
user: IUserLite;
|
||||
@ -40,6 +53,7 @@ export interface IWorkspaceMember {
|
||||
member: IUserLite;
|
||||
role: 5 | 10 | 15 | 20;
|
||||
company_role: string | null;
|
||||
view_props: Properties;
|
||||
created_at: Date;
|
||||
updated_at: Date;
|
||||
created_by: string;
|
||||
|
Loading…
Reference in New Issue
Block a user