feat: storing my issue view display properties (#1124)

This commit is contained in:
Anmol Singh Bhatia 2023-05-25 12:19:37 +05:30 committed by GitHub
parent f095594be9
commit def391cb76
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 98 additions and 106 deletions

View File

@ -1,26 +1,18 @@
import { useEffect, useState } from "react"; import { useState, useEffect, useCallback } from "react";
import { useRouter } from "next/router"; import useSWR, { mutate } from "swr";
import useSWR from "swr";
// services // services
import stateService from "services/state.service"; import workspaceService from "services/workspace.service";
import userService from "services/user.service";
// hooks // hooks
import useUser from "hooks/use-user"; import useUser from "hooks/use-user";
// helpers
import { groupBy } from "helpers/array.helper";
import { getStatesList } from "helpers/state.helper";
// types // types
import { Properties, NestedKeyOf, IIssue } from "types"; import { IWorkspaceMember, Properties } from "types";
// fetch-keys import { WORKSPACE_MEMBERS_ME } from "constants/fetch-keys";
import { STATES_LIST } from "constants/fetch-keys";
// constants
import { PRIORITIES } from "constants/project";
const initialValues: Properties = { const initialValues: Properties = {
assignee: true, assignee: true,
due_date: false, due_date: false,
key: true, key: true,
labels: true, labels: false,
priority: false, priority: false,
state: true, state: true,
sub_issue_count: false, sub_issue_count: false,
@ -29,99 +21,80 @@ const initialValues: Properties = {
estimate: false, estimate: false,
}; };
// TODO: Refactor this logic const useMyIssuesProperties = (workspaceSlug?: string) => {
const useMyIssuesProperties = (issues?: IIssue[]) => {
const [properties, setProperties] = useState<Properties>(initialValues); 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 { user } = useUser();
const { data: stateGroups } = useSWR( const { data: myWorkspace } = useSWR(
workspaceSlug && projectId ? STATES_LIST(projectId as string) : null, workspaceSlug ? WORKSPACE_MEMBERS_ME(workspaceSlug as string) : null,
workspaceSlug && projectId workspaceSlug ? () => workspaceService.workspaceMemberMe(workspaceSlug as string) : null,
? () => stateService.getStates(workspaceSlug as string, projectId as string) {
: null shouldRetryOnError: false,
);
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);
} }
}, []); );
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 { return {
filteredIssues: groupedByIssues, ...prevData,
groupByProperty, view_props: { ...prevData?.view_props, [key]: !prevData.view_props?.[key] },
properties, };
setMyIssueProperty, },
setMyIssueGroupByProperty, false
} as const; );
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; export default useMyIssuesProperties;

View File

@ -14,7 +14,7 @@ import useIssues from "hooks/use-issues";
import { Spinner, EmptySpace, EmptySpaceItem, PrimaryButton } from "components/ui"; import { Spinner, EmptySpace, EmptySpaceItem, PrimaryButton } from "components/ui";
import { Breadcrumbs, BreadcrumbItem } from "components/breadcrumbs"; import { Breadcrumbs, BreadcrumbItem } from "components/breadcrumbs";
// hooks // hooks
import useIssuesProperties from "hooks/use-issue-properties"; import useMyIssuesProperties from "hooks/use-my-issues-filter";
// types // types
import { IIssue, Properties } from "types"; import { IIssue, Properties } from "types";
// components // components
@ -31,10 +31,7 @@ const MyIssuesPage: NextPage = () => {
// fetching user issues // fetching user issues
const { myIssues } = useIssues(workspaceSlug as string); const { myIssues } = useIssues(workspaceSlug as string);
const [properties, setProperties] = useIssuesProperties( const [properties, setProperties] = useMyIssuesProperties(workspaceSlug as string);
workspaceSlug ? (workspaceSlug as string) : undefined,
undefined
);
return ( return (
<WorkspaceAuthorizationLayout <WorkspaceAuthorizationLayout

View File

@ -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( async updateWorkspaceMember(
workspaceSlug: string, workspaceSlug: string,
memberId: string, memberId: string,

View File

@ -33,6 +33,19 @@ export interface IWorkspaceMemberInvitation {
workspace: IWorkspace; 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 { export interface IWorkspaceMember {
readonly id: string; readonly id: string;
user: IUserLite; user: IUserLite;
@ -40,6 +53,7 @@ export interface IWorkspaceMember {
member: IUserLite; member: IUserLite;
role: 5 | 10 | 15 | 20; role: 5 | 10 | 15 | 20;
company_role: string | null; company_role: string | null;
view_props: Properties;
created_at: Date; created_at: Date;
updated_at: Date; updated_at: Date;
created_by: string; created_by: string;