refactor: view props structure (#2159)
* chore: update view_props types * refactor: view props structure
This commit is contained in:
parent
cdb888c23e
commit
8e9a4dca78
45 changed files with 765 additions and 1146 deletions
|
|
@ -41,16 +41,10 @@ export const ProfileIssuesViewOptions: React.FC = () => {
|
|||
const { projects } = useProjects();
|
||||
|
||||
const {
|
||||
issueView,
|
||||
setIssueView,
|
||||
groupByProperty,
|
||||
setGroupByProperty,
|
||||
orderBy,
|
||||
setOrderBy,
|
||||
showEmptyGroups,
|
||||
setShowEmptyGroups,
|
||||
displayFilters,
|
||||
setDisplayFilters,
|
||||
filters,
|
||||
properties,
|
||||
displayProperties,
|
||||
setProperties,
|
||||
setFilters,
|
||||
} = useProfileIssues(workspaceSlug?.toString(), userId?.toString());
|
||||
|
|
@ -94,11 +88,11 @@ export const ProfileIssuesViewOptions: React.FC = () => {
|
|||
<button
|
||||
type="button"
|
||||
className={`grid h-7 w-7 place-items-center rounded p-1 outline-none hover:bg-custom-sidebar-background-80 duration-300 ${
|
||||
issueView === option.type
|
||||
displayFilters.layout === option.type
|
||||
? "bg-custom-sidebar-background-80"
|
||||
: "text-custom-sidebar-text-200"
|
||||
}`}
|
||||
onClick={() => setIssueView(option.type)}
|
||||
onClick={() => setDisplayFilters({ layout: option.type })}
|
||||
>
|
||||
<option.Icon
|
||||
sx={{
|
||||
|
|
@ -165,82 +159,89 @@ export const ProfileIssuesViewOptions: React.FC = () => {
|
|||
<Popover.Panel className="absolute right-0 z-30 mt-1 w-screen max-w-xs transform rounded-lg border border-custom-border-200 bg-custom-background-90 p-3 shadow-lg">
|
||||
<div className="relative divide-y-2 divide-custom-border-200">
|
||||
<div className="space-y-4 pb-3 text-xs">
|
||||
{issueView !== "calendar" && issueView !== "spreadsheet" && (
|
||||
<>
|
||||
<div className="flex items-center justify-between">
|
||||
<h4 className="text-custom-text-200">Group by</h4>
|
||||
<div className="w-28">
|
||||
<CustomMenu
|
||||
label={
|
||||
groupByProperty === "project"
|
||||
? "Project"
|
||||
: GROUP_BY_OPTIONS.find(
|
||||
(option) => option.key === groupByProperty
|
||||
)?.name ?? "Select"
|
||||
}
|
||||
className="!w-full"
|
||||
buttonClassName="w-full"
|
||||
>
|
||||
{GROUP_BY_OPTIONS.map((option) => {
|
||||
if (issueView === "kanban" && option.key === null) return null;
|
||||
if (
|
||||
option.key === "state" ||
|
||||
option.key === "created_by" ||
|
||||
option.key === "assignees"
|
||||
)
|
||||
return null;
|
||||
{displayFilters.layout !== "calendar" &&
|
||||
displayFilters.layout !== "spreadsheet" && (
|
||||
<>
|
||||
<div className="flex items-center justify-between">
|
||||
<h4 className="text-custom-text-200">Group by</h4>
|
||||
<div className="w-28">
|
||||
<CustomMenu
|
||||
label={
|
||||
displayFilters.group_by === "project"
|
||||
? "Project"
|
||||
: GROUP_BY_OPTIONS.find(
|
||||
(option) => option.key === displayFilters.group_by
|
||||
)?.name ?? "Select"
|
||||
}
|
||||
className="!w-full"
|
||||
buttonClassName="w-full"
|
||||
>
|
||||
{GROUP_BY_OPTIONS.map((option) => {
|
||||
if (displayFilters.layout === "kanban" && option.key === null)
|
||||
return null;
|
||||
if (
|
||||
option.key === "state" ||
|
||||
option.key === "created_by" ||
|
||||
option.key === "assignees"
|
||||
)
|
||||
return null;
|
||||
|
||||
return (
|
||||
<CustomMenu.MenuItem
|
||||
key={option.key}
|
||||
onClick={() => setGroupByProperty(option.key)}
|
||||
>
|
||||
{option.name}
|
||||
</CustomMenu.MenuItem>
|
||||
);
|
||||
})}
|
||||
</CustomMenu>
|
||||
return (
|
||||
<CustomMenu.MenuItem
|
||||
key={option.key}
|
||||
onClick={() => setDisplayFilters({ group_by: option.key })}
|
||||
>
|
||||
{option.name}
|
||||
</CustomMenu.MenuItem>
|
||||
);
|
||||
})}
|
||||
</CustomMenu>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-center justify-between">
|
||||
<h4 className="text-custom-text-200">Order by</h4>
|
||||
<div className="w-28">
|
||||
<CustomMenu
|
||||
label={
|
||||
ORDER_BY_OPTIONS.find((option) => option.key === orderBy)?.name ??
|
||||
"Select"
|
||||
}
|
||||
className="!w-full"
|
||||
buttonClassName="w-full"
|
||||
>
|
||||
{ORDER_BY_OPTIONS.map((option) => {
|
||||
if (groupByProperty === "priority" && option.key === "priority")
|
||||
return null;
|
||||
if (option.key === "sort_order") return null;
|
||||
<div className="flex items-center justify-between">
|
||||
<h4 className="text-custom-text-200">Order by</h4>
|
||||
<div className="w-28">
|
||||
<CustomMenu
|
||||
label={
|
||||
ORDER_BY_OPTIONS.find(
|
||||
(option) => option.key === displayFilters.order_by
|
||||
)?.name ?? "Select"
|
||||
}
|
||||
className="!w-full"
|
||||
buttonClassName="w-full"
|
||||
>
|
||||
{ORDER_BY_OPTIONS.map((option) => {
|
||||
if (
|
||||
displayFilters.group_by === "priority" &&
|
||||
option.key === "priority"
|
||||
)
|
||||
return null;
|
||||
if (option.key === "sort_order") return null;
|
||||
|
||||
return (
|
||||
<CustomMenu.MenuItem
|
||||
key={option.key}
|
||||
onClick={() => {
|
||||
setOrderBy(option.key);
|
||||
}}
|
||||
>
|
||||
{option.name}
|
||||
</CustomMenu.MenuItem>
|
||||
);
|
||||
})}
|
||||
</CustomMenu>
|
||||
return (
|
||||
<CustomMenu.MenuItem
|
||||
key={option.key}
|
||||
onClick={() => {
|
||||
setDisplayFilters({ order_by: option.key });
|
||||
}}
|
||||
>
|
||||
{option.name}
|
||||
</CustomMenu.MenuItem>
|
||||
);
|
||||
})}
|
||||
</CustomMenu>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
<div className="flex items-center justify-between">
|
||||
<h4 className="text-custom-text-200">Issue type</h4>
|
||||
<div className="w-28">
|
||||
<CustomMenu
|
||||
label={
|
||||
FILTER_ISSUE_OPTIONS.find((option) => option.key === filters?.type)
|
||||
?.name ?? "Select"
|
||||
FILTER_ISSUE_OPTIONS.find(
|
||||
(option) => option.key === displayFilters?.type
|
||||
)?.name ?? "Select"
|
||||
}
|
||||
className="!w-full"
|
||||
buttonClassName="w-full"
|
||||
|
|
@ -249,7 +250,7 @@ export const ProfileIssuesViewOptions: React.FC = () => {
|
|||
<CustomMenu.MenuItem
|
||||
key={option.key}
|
||||
onClick={() =>
|
||||
setFilters({
|
||||
setDisplayFilters({
|
||||
type: option.key,
|
||||
})
|
||||
}
|
||||
|
|
@ -261,26 +262,34 @@ export const ProfileIssuesViewOptions: React.FC = () => {
|
|||
</div>
|
||||
</div>
|
||||
|
||||
{issueView !== "calendar" && issueView !== "spreadsheet" && (
|
||||
<>
|
||||
<div className="flex items-center justify-between">
|
||||
<h4 className="text-custom-text-200">Show empty states</h4>
|
||||
<div className="w-28">
|
||||
<ToggleSwitch value={showEmptyGroups} onChange={setShowEmptyGroups} />
|
||||
{displayFilters.layout !== "calendar" &&
|
||||
displayFilters.layout !== "spreadsheet" && (
|
||||
<>
|
||||
<div className="flex items-center justify-between">
|
||||
<h4 className="text-custom-text-200">Show empty states</h4>
|
||||
<div className="w-28">
|
||||
<ToggleSwitch
|
||||
value={displayFilters.show_empty_groups ?? true}
|
||||
onChange={() =>
|
||||
setDisplayFilters({
|
||||
show_empty_groups: !displayFilters.show_empty_groups,
|
||||
})
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="space-y-2 py-3">
|
||||
<h4 className="text-sm text-custom-text-200">Display Properties</h4>
|
||||
<div className="flex flex-wrap items-center gap-2 text-custom-text-200">
|
||||
{Object.keys(properties).map((key) => {
|
||||
{Object.keys(displayProperties).map((key) => {
|
||||
if (key === "estimate" && !isEstimateActive) return null;
|
||||
|
||||
if (
|
||||
issueView === "spreadsheet" &&
|
||||
displayFilters.layout === "spreadsheet" &&
|
||||
(key === "attachment_count" ||
|
||||
key === "link" ||
|
||||
key === "sub_issue_count")
|
||||
|
|
@ -288,7 +297,7 @@ export const ProfileIssuesViewOptions: React.FC = () => {
|
|||
return null;
|
||||
|
||||
if (
|
||||
issueView !== "spreadsheet" &&
|
||||
displayFilters.layout !== "spreadsheet" &&
|
||||
(key === "created_on" || key === "updated_on")
|
||||
)
|
||||
return null;
|
||||
|
|
@ -298,7 +307,7 @@ export const ProfileIssuesViewOptions: React.FC = () => {
|
|||
key={key}
|
||||
type="button"
|
||||
className={`rounded border px-2 py-1 text-xs capitalize ${
|
||||
properties[key as keyof Properties]
|
||||
displayProperties[key as keyof Properties]
|
||||
? "border-custom-primary bg-custom-primary text-white"
|
||||
: "border-custom-border-200"
|
||||
}`}
|
||||
|
|
|
|||
|
|
@ -50,14 +50,12 @@ export const ProfileIssuesView = () => {
|
|||
const {
|
||||
groupedIssues,
|
||||
mutateProfileIssues,
|
||||
issueView,
|
||||
groupByProperty,
|
||||
orderBy,
|
||||
displayFilters,
|
||||
setDisplayFilters,
|
||||
isEmpty,
|
||||
showEmptyGroups,
|
||||
filters,
|
||||
setFilters,
|
||||
properties,
|
||||
displayProperties,
|
||||
params,
|
||||
} = useProfileIssues(workspaceSlug?.toString(), userId?.toString());
|
||||
|
||||
|
|
@ -92,7 +90,12 @@ export const ProfileIssuesView = () => {
|
|||
async (result: DropResult) => {
|
||||
setTrashBox(false);
|
||||
|
||||
if (!result.destination || !workspaceSlug || !groupedIssues || groupByProperty !== "priority")
|
||||
if (
|
||||
!result.destination ||
|
||||
!workspaceSlug ||
|
||||
!groupedIssues ||
|
||||
displayFilters.group_by !== "priority"
|
||||
)
|
||||
return;
|
||||
|
||||
const { source, destination } = result;
|
||||
|
|
@ -108,7 +111,7 @@ export const ProfileIssuesView = () => {
|
|||
const sourceGroup = source.droppableId;
|
||||
const destinationGroup = destination.droppableId;
|
||||
|
||||
draggedItem[groupByProperty] = destinationGroup as TIssuePriorities;
|
||||
draggedItem[displayFilters.group_by] = destinationGroup as TIssuePriorities;
|
||||
|
||||
mutateProfileIssues((prevData: any) => {
|
||||
if (!prevData) return prevData;
|
||||
|
|
@ -121,8 +124,11 @@ export const ProfileIssuesView = () => {
|
|||
|
||||
return {
|
||||
...prevData,
|
||||
[sourceGroup]: orderArrayBy(sourceGroupArray, orderBy),
|
||||
[destinationGroup]: orderArrayBy(destinationGroupArray, orderBy),
|
||||
[sourceGroup]: orderArrayBy(sourceGroupArray, displayFilters.order_by ?? "-created_at"),
|
||||
[destinationGroup]: orderArrayBy(
|
||||
destinationGroupArray,
|
||||
displayFilters.order_by ?? "-created_at"
|
||||
),
|
||||
};
|
||||
}, false);
|
||||
|
||||
|
|
@ -140,15 +146,7 @@ export const ProfileIssuesView = () => {
|
|||
.catch(() => mutateProfileIssues());
|
||||
}
|
||||
},
|
||||
[
|
||||
groupByProperty,
|
||||
groupedIssues,
|
||||
handleDeleteIssue,
|
||||
mutateProfileIssues,
|
||||
orderBy,
|
||||
user,
|
||||
workspaceSlug,
|
||||
]
|
||||
[displayFilters, groupedIssues, handleDeleteIssue, mutateProfileIssues, user, workspaceSlug]
|
||||
);
|
||||
|
||||
const addIssueToGroup = useCallback(
|
||||
|
|
@ -157,19 +155,19 @@ export const ProfileIssuesView = () => {
|
|||
|
||||
let preloadedValue: string | string[] = groupTitle;
|
||||
|
||||
if (groupByProperty === "labels") {
|
||||
if (displayFilters.group_by === "labels") {
|
||||
if (groupTitle === "None") preloadedValue = [];
|
||||
else preloadedValue = [groupTitle];
|
||||
}
|
||||
|
||||
if (groupByProperty)
|
||||
if (displayFilters.group_by)
|
||||
setPreloadedData({
|
||||
[groupByProperty]: preloadedValue,
|
||||
[displayFilters.group_by]: preloadedValue,
|
||||
actionType: "createIssue",
|
||||
});
|
||||
else setPreloadedData({ actionType: "createIssue" });
|
||||
},
|
||||
[setCreateIssueModal, setPreloadedData, groupByProperty]
|
||||
[setCreateIssueModal, setPreloadedData, displayFilters.group_by]
|
||||
);
|
||||
|
||||
const addIssueToDate = useCallback(
|
||||
|
|
@ -277,7 +275,6 @@ export const ProfileIssuesView = () => {
|
|||
state_group: null,
|
||||
start_date: null,
|
||||
target_date: null,
|
||||
type: null,
|
||||
})
|
||||
}
|
||||
/>
|
||||
|
|
@ -289,7 +286,7 @@ export const ProfileIssuesView = () => {
|
|||
addIssueToDate={addIssueToDate}
|
||||
addIssueToGroup={addIssueToGroup}
|
||||
disableUserActions={false}
|
||||
dragDisabled={groupByProperty !== "priority"}
|
||||
dragDisabled={displayFilters.group_by !== "priority"}
|
||||
emptyState={{
|
||||
title: router.pathname.includes("assigned")
|
||||
? `Issues assigned to ${profileData?.user_data.display_name} will appear here`
|
||||
|
|
@ -305,15 +302,12 @@ export const ProfileIssuesView = () => {
|
|||
trashBox={trashBox}
|
||||
setTrashBox={setTrashBox}
|
||||
viewProps={{
|
||||
groupByProperty,
|
||||
groupedIssues,
|
||||
displayFilters,
|
||||
isEmpty,
|
||||
issueView,
|
||||
mutateIssues: mutateProfileIssues,
|
||||
orderBy,
|
||||
params,
|
||||
properties,
|
||||
showEmptyGroups,
|
||||
properties: displayProperties,
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue