forked from github/plane
chore: new global select filters component (#501)
This commit is contained in:
committed by
GitHub
parent
10e5ba7b3e
commit
ad2fa91a2b
@@ -6,14 +6,7 @@ import useSWR from "swr";
|
||||
|
||||
import { useForm } from "react-hook-form";
|
||||
// ui
|
||||
import {
|
||||
Avatar,
|
||||
Input,
|
||||
MultiLevelDropdown,
|
||||
PrimaryButton,
|
||||
SecondaryButton,
|
||||
TextArea,
|
||||
} from "components/ui";
|
||||
import { Avatar, Input, PrimaryButton, SecondaryButton, TextArea } from "components/ui";
|
||||
// types
|
||||
import { IView } from "types";
|
||||
// constant
|
||||
@@ -23,11 +16,12 @@ import { getStatesList } from "helpers/state.helper";
|
||||
// services
|
||||
import stateService from "services/state.service";
|
||||
import projectService from "services/project.service";
|
||||
// components
|
||||
import { SelectFilters } from "components/views";
|
||||
// icons
|
||||
import { getStateGroupIcon } from "components/icons";
|
||||
import { getPriorityIcon } from "components/icons/priority-icon";
|
||||
// components
|
||||
import { PRIORITIES } from "constants/project";
|
||||
|
||||
type Props = {
|
||||
handleFormSubmit: (values: IView) => Promise<void>;
|
||||
@@ -139,8 +133,8 @@ export const ViewForm: React.FC<Props> = ({
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<MultiLevelDropdown
|
||||
label="Filters"
|
||||
<SelectFilters
|
||||
filters={filters}
|
||||
onSelect={(option) => {
|
||||
const key = option.key as keyof typeof filters;
|
||||
|
||||
@@ -156,72 +150,6 @@ export const ViewForm: React.FC<Props> = ({
|
||||
});
|
||||
}
|
||||
}}
|
||||
direction="right"
|
||||
options={[
|
||||
{
|
||||
id: "priority",
|
||||
label: "Priority",
|
||||
value: PRIORITIES,
|
||||
children: [
|
||||
...PRIORITIES.map((priority) => ({
|
||||
id: priority ?? "none",
|
||||
label: (
|
||||
<div className="flex items-center gap-2">
|
||||
{getPriorityIcon(priority)} {priority ?? "None"}
|
||||
</div>
|
||||
),
|
||||
value: {
|
||||
key: "priority",
|
||||
value: priority,
|
||||
},
|
||||
selected: filters?.priority?.includes(priority ?? "none"),
|
||||
})),
|
||||
],
|
||||
},
|
||||
{
|
||||
id: "state",
|
||||
label: "State",
|
||||
value: statesList,
|
||||
children: [
|
||||
...statesList.map((state) => ({
|
||||
id: state.id,
|
||||
label: (
|
||||
<div className="flex items-center gap-2">
|
||||
{getStateGroupIcon(state.group, "16", "16", state.color)} {state.name}
|
||||
</div>
|
||||
),
|
||||
value: {
|
||||
key: "state",
|
||||
value: state.id,
|
||||
},
|
||||
selected: filters?.state?.includes(state.id),
|
||||
})),
|
||||
],
|
||||
},
|
||||
{
|
||||
id: "assignee",
|
||||
label: "Assignee",
|
||||
value: members,
|
||||
children: [
|
||||
...(members?.map((member) => ({
|
||||
id: member.member.id,
|
||||
label: (
|
||||
<div className="flex items-center gap-2">
|
||||
<Avatar user={member.member} />
|
||||
{member.member.first_name && member.member.first_name !== ""
|
||||
? member.member.first_name
|
||||
: member.member.email}
|
||||
</div>
|
||||
),
|
||||
value: {
|
||||
key: "assignees",
|
||||
value: member.member.id,
|
||||
},
|
||||
selected: filters?.assignees?.includes(member.member.id),
|
||||
})) ?? []),
|
||||
],
|
||||
},
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
@@ -257,8 +185,9 @@ export const ViewForm: React.FC<Props> = ({
|
||||
else if (queryKey === "assignees")
|
||||
return (
|
||||
<div className="flex gap-3" key={key}>
|
||||
{filters.assignees?.map((assigneeID) => {
|
||||
const member = members?.find((member) => member.member.id === assigneeID);
|
||||
{filters.assignees?.map((assigneeId) => {
|
||||
const member = members?.find((member) => member.member.id === assigneeId);
|
||||
|
||||
if (!member) return null;
|
||||
return (
|
||||
<div className="flex items-center gap-2 text-xs" key={member.member.id}>
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
export * from "./delete-view-modal";
|
||||
export * from "./form";
|
||||
export * from "./modal";
|
||||
export * from "./select-filters";
|
||||
|
||||
118
apps/app/components/views/select-filters.tsx
Normal file
118
apps/app/components/views/select-filters.tsx
Normal file
@@ -0,0 +1,118 @@
|
||||
import { useRouter } from "next/router";
|
||||
|
||||
import useSWR from "swr";
|
||||
|
||||
// services
|
||||
import stateService from "services/state.service";
|
||||
import projectService from "services/project.service";
|
||||
// ui
|
||||
import { Avatar, MultiLevelDropdown } from "components/ui";
|
||||
// icons
|
||||
import { getPriorityIcon, getStateGroupIcon } from "components/icons";
|
||||
// helpers
|
||||
import { getStatesList } from "helpers/state.helper";
|
||||
// types
|
||||
import { IIssueFilterOptions, IQuery } from "types";
|
||||
// fetch-keys
|
||||
import { PROJECT_MEMBERS, STATE_LIST } from "constants/fetch-keys";
|
||||
// constants
|
||||
import { PRIORITIES } from "constants/project";
|
||||
|
||||
type Props = {
|
||||
filters: IIssueFilterOptions | IQuery;
|
||||
onSelect: (option: any) => void;
|
||||
direction?: "left" | "right";
|
||||
};
|
||||
|
||||
export const SelectFilters: React.FC<Props> = ({ filters, onSelect, direction = "right" }) => {
|
||||
const router = useRouter();
|
||||
const { workspaceSlug, projectId } = router.query;
|
||||
|
||||
const { data: states } = useSWR(
|
||||
workspaceSlug && projectId ? STATE_LIST(projectId as string) : null,
|
||||
workspaceSlug && projectId
|
||||
? () => stateService.getStates(workspaceSlug as string, projectId as string)
|
||||
: null
|
||||
);
|
||||
const statesList = getStatesList(states ?? {});
|
||||
|
||||
const { data: members } = useSWR(
|
||||
projectId ? PROJECT_MEMBERS(projectId as string) : null,
|
||||
workspaceSlug && projectId
|
||||
? () => projectService.projectMembers(workspaceSlug as string, projectId as string)
|
||||
: null
|
||||
);
|
||||
|
||||
return (
|
||||
<MultiLevelDropdown
|
||||
label="Filters"
|
||||
onSelect={onSelect}
|
||||
direction={direction}
|
||||
options={[
|
||||
{
|
||||
id: "priority",
|
||||
label: "Priority",
|
||||
value: PRIORITIES,
|
||||
children: [
|
||||
...PRIORITIES.map((priority) => ({
|
||||
id: priority ?? "none",
|
||||
label: (
|
||||
<div className="flex items-center gap-2">
|
||||
{getPriorityIcon(priority)} {priority ?? "None"}
|
||||
</div>
|
||||
),
|
||||
value: {
|
||||
key: "priority",
|
||||
value: priority,
|
||||
},
|
||||
selected: filters?.priority?.includes(priority ?? "none"),
|
||||
})),
|
||||
],
|
||||
},
|
||||
{
|
||||
id: "state",
|
||||
label: "State",
|
||||
value: statesList,
|
||||
children: [
|
||||
...statesList.map((state) => ({
|
||||
id: state.id,
|
||||
label: (
|
||||
<div className="flex items-center gap-2">
|
||||
{getStateGroupIcon(state.group, "16", "16", state.color)} {state.name}
|
||||
</div>
|
||||
),
|
||||
value: {
|
||||
key: "state",
|
||||
value: state.id,
|
||||
},
|
||||
selected: filters?.state?.includes(state.id),
|
||||
})),
|
||||
],
|
||||
},
|
||||
{
|
||||
id: "assignees",
|
||||
label: "Assignees",
|
||||
value: members,
|
||||
children: [
|
||||
...(members?.map((member) => ({
|
||||
id: member.member.id,
|
||||
label: (
|
||||
<div className="flex items-center gap-2">
|
||||
<Avatar user={member.member} />
|
||||
{member.member.first_name && member.member.first_name !== ""
|
||||
? member.member.first_name
|
||||
: member.member.email}
|
||||
</div>
|
||||
),
|
||||
value: {
|
||||
key: "assignees",
|
||||
value: member.member.id,
|
||||
},
|
||||
selected: filters?.assignees?.includes(member.member.id),
|
||||
})) ?? []),
|
||||
],
|
||||
},
|
||||
]}
|
||||
/>
|
||||
);
|
||||
};
|
||||
Reference in New Issue
Block a user