diff --git a/apps/app/components/core/issues-view-filter.tsx b/apps/app/components/core/issues-view-filter.tsx index ecb7b5680..16081b56c 100644 --- a/apps/app/components/core/issues-view-filter.tsx +++ b/apps/app/components/core/issues-view-filter.tsx @@ -153,8 +153,8 @@ export const IssuesFilterView: React.FC = () => { ], }, { - id: "assignee", - label: "Assignee", + id: "assignees", + label: "Assignees", value: members, children: [ ...(members?.map((member) => ({ @@ -168,7 +168,7 @@ export const IssuesFilterView: React.FC = () => { ), value: { - key: "assignee", + key: "assignees", value: member.member.id, }, selected: filters?.assignees?.includes(member.member.id), diff --git a/apps/app/components/core/issues-view.tsx b/apps/app/components/core/issues-view.tsx index 2d964d771..83f149332 100644 --- a/apps/app/components/core/issues-view.tsx +++ b/apps/app/components/core/issues-view.tsx @@ -19,7 +19,7 @@ import { CreateUpdateIssueModal, DeleteIssueModal } from "components/issues"; import StrictModeDroppable from "components/dnd/StrictModeDroppable"; import { CreateUpdateViewModal } from "components/views"; // ui -import { EmptySpace, EmptySpaceItem, PrimaryButton } from "components/ui"; +import { Avatar, EmptySpace, EmptySpaceItem, PrimaryButton } from "components/ui"; // icons import { PlusIcon, RectangleStackIcon, TrashIcon, XMarkIcon } from "@heroicons/react/24/outline"; // helpers @@ -42,6 +42,8 @@ import { PROJECT_MEMBERS, STATE_LIST, } from "constants/fetch-keys"; +import { getPriorityIcon } from "components/icons/priority-icon"; +import { getStateGroupIcon } from "components/icons"; type Props = { type?: "issue" | "cycle" | "module"; @@ -71,7 +73,7 @@ export const IssuesView: React.FC = ({ type = "issue", openIssuesListModa const [trashBox, setTrashBox] = useState(false); const router = useRouter(); - const { workspaceSlug, projectId, cycleId, moduleId } = router.query; + const { workspaceSlug, projectId, cycleId, moduleId, viewId } = router.query; const { groupedByIssues, @@ -369,6 +371,10 @@ export const IssuesView: React.FC = ({ type = "issue", openIssuesListModa [trashBox, setTrashBox] ); + const nullFilters = Object.keys(filters).filter( + (key) => filters[key as keyof IIssueFilterOptions] === null + ); + return ( <> = ({ type = "issue", openIssuesListModa isOpen={deleteIssueModal} data={issueToDelete} /> -
-
+
+
{Object.keys(filters).map((key) => { if (filters[key as keyof typeof filters] !== null) return ( -
-

- Filter for {key}:{" "} -

+
+ {key}: {filters[key as keyof IIssueFilterOptions] === null || (filters[key as keyof IIssueFilterOptions]?.length ?? 0) <= 0 ? ( -

None

+ None + ) : Array.isArray(filters[key as keyof IIssueFilterOptions]) ? ( +
+ {key === "state" + ? filters.state?.map((stateId: any) => { + const state = states?.find((s) => s.id === stateId); + + return ( +

+ + {getStateGroupIcon( + state?.group ?? "backlog", + "12", + "12", + state?.color + )} + + {state?.name ?? ""} + + setFilters({ + state: filters.state?.filter((s: any) => s !== stateId), + }) + } + > + + +

+ ); + }) + : key === "priority" + ? filters.priority?.map((priority: any) => ( +

+ {getPriorityIcon(priority)} + {priority} + + setFilters({ + priority: filters.priority?.filter((p: any) => p !== priority), + }) + } + > + + +

+ )) + : key === "assignees" + ? filters.assignees?.map((memberId: string) => { + const member = members?.find((m) => m.member.id === memberId)?.member; + + return ( +

+ + {member?.first_name} + + setFilters({ + assignees: filters.assignees?.filter( + (p: any) => p !== memberId + ), + }) + } + > + + +

+ ); + }) + : (filters[key as keyof IIssueFilterOptions] as any)?.join(", ")} +
) : ( - Array.isArray(filters[key as keyof IIssueFilterOptions]) && ( -

- {key === "state" - ? (filters[key as keyof IIssueFilterOptions] as any)?.map( - (stateId: any) => { - const state = states?.find((s) => s.id === stateId); - return ( -

- {state?.name ?? "Loading..."} - { - setFilters({ - ...filters, - [key]: ( - filters[key as keyof IIssueFilterOptions] as any - )?.filter((s: any) => s !== stateId), - }); - }} - > - - -

- ); - } - ) - : key === "priority" - ? (filters[key as keyof IIssueFilterOptions] as any)?.map( - (priority: any) => ( -

- {priority} - { - setFilters({ - ...filters, - [key]: ( - filters[key as keyof IIssueFilterOptions] as any - )?.filter((p: any) => p !== priority), - }); - }} - > - - -

- ) - ) - : key === "assignee" - ? (filters[key as keyof IIssueFilterOptions] as any)?.map( - (member: any) => ( -

- - { - members?.find((m) => m.member.id === member)?.member - .first_name - } - - { - setFilters({ - ...filters, - [key as keyof IIssueFilterOptions]: ( - filters[key as keyof IIssueFilterOptions] as any - )?.filter((p: any) => p !== member), - }); - }} - > - - -

- ) - ) - : (filters[key as keyof IIssueFilterOptions] as any)?.join(", ")} -

- ) + {filters[key as keyof typeof filters]} )}
); })}
- {Object.keys(filters).length > 0 && ( - - setCreateViewModal({ - query: filters, - }) - } - className="flex items-center gap-2 text-sm" - > - - Save view - - )} + {Object.keys(filters).length > 0 && + nullFilters.length !== Object.keys(filters).length && + !viewId && ( + + setCreateViewModal({ + query: filters, + }) + } + className="flex items-center gap-2 text-sm" + > + + Save view + + )}
diff --git a/apps/app/components/ui/empty-state.tsx b/apps/app/components/ui/empty-state.tsx index 2b625c45b..ade972982 100644 --- a/apps/app/components/ui/empty-state.tsx +++ b/apps/app/components/ui/empty-state.tsx @@ -7,13 +7,14 @@ import { PlusIcon } from "@heroicons/react/24/outline"; import { capitalizeFirstLetter } from "helpers/string.helper"; type Props = { - type: "cycle" | "module" | "project" | "issue"; + type: "cycle" | "module" | "project" | "issue" | "view"; title: string; description: React.ReactNode | string; imgURL: string; + action?: () => void; }; -export const EmptyState: React.FC = ({ type, title, description, imgURL }) => { +export const EmptyState: React.FC = ({ type, title, description, imgURL, action }) => { const shortcutKey = (type: string) => { switch (type) { case "cycle": @@ -22,8 +23,10 @@ export const EmptyState: React.FC = ({ type, title, description, imgURL } return "M"; case "project": return "P"; - default: + case "issue": return "C"; + default: + return null; } }; return ( @@ -33,20 +36,30 @@ export const EmptyState: React.FC = ({ type, title, description, imgURL }

{title}

- - Use shortcut{" "} - - {shortcutKey(type)} - {" "} - to create {type} from anywhere. - + {shortcutKey(type) && ( + + Use shortcut{" "} + + {shortcutKey(type)} + {" "} + to create {type} from anywhere. + + )}

{description}