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 { 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,
}
}, []);
);
return {
filteredIssues: groupedByIssues,
groupByProperty,
properties,
setMyIssueProperty,
setMyIssueGroupByProperty,
} as const;
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 {
...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;

View File

@ -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

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

View File

@ -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;