Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: filter components, constants and helper functions #2297

Merged
merged 12 commits into from
Sep 29, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 8 additions & 47 deletions web/components/core/filters/date-filter-modal.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
import { Fragment } from "react";

// react-hook-form
import { Controller, useForm } from "react-hook-form";
// react-datepicker
import DatePicker from "react-datepicker";
// headless ui
import { Dialog, Transition } from "@headlessui/react";

// components
import { DateFilterSelect } from "./date-filter-select";
// ui
Expand All @@ -14,15 +11,12 @@ import { PrimaryButton, SecondaryButton } from "components/ui";
import { XMarkIcon } from "@heroicons/react/20/solid";
// helpers
import { renderDateFormat, renderShortDateWithYearFormat } from "helpers/date-time.helper";
import { IIssueFilterOptions } from "types";

type Props = {
title: string;
field: keyof IIssueFilterOptions;
filters: IIssueFilterOptions;
handleClose: () => void;
isOpen: boolean;
onSelect: (option: any) => void;
onSelect: (val: string[]) => void;
};

type TFormValues = {
Expand All @@ -37,47 +31,21 @@ const defaultValues: TFormValues = {
date2: new Date(new Date().getFullYear(), new Date().getMonth() + 1, new Date().getDate()),
};

export const DateFilterModal: React.FC<Props> = ({
title,
field,
filters,
handleClose,
isOpen,
onSelect,
}) => {
export const DateFilterModal: React.FC<Props> = ({ title, handleClose, isOpen, onSelect }) => {
const { handleSubmit, watch, control } = useForm<TFormValues>({
defaultValues,
});

const handleFormSubmit = (formData: TFormValues) => {
const { filterType, date1, date2 } = formData;

if (filterType === "range") {
onSelect({
key: field,
value: [`${renderDateFormat(date1)};after`, `${renderDateFormat(date2)};before`],
});
} else {
const filteredArray = (filters?.[field] as string[])?.filter((item) => {
if (item?.includes(filterType)) return false;
if (filterType === "range") onSelect([`${renderDateFormat(date1)};after`, `${renderDateFormat(date2)};before`]);
else onSelect([`${renderDateFormat(date1)};${filterType}`]);

return true;
});

const filterOne = filteredArray && filteredArray?.length > 0 ? filteredArray[0] : null;
if (filterOne)
onSelect({ key: field, value: [filterOne, `${renderDateFormat(date1)};${filterType}`] });
else
onSelect({
key: field,
value: [`${renderDateFormat(date1)};${filterType}`],
});
}
handleClose();
};

const isInvalid =
watch("filterType") === "range" ? new Date(watch("date1")) > new Date(watch("date2")) : false;
const isInvalid = watch("filterType") === "range" ? new Date(watch("date1")) > new Date(watch("date2")) : false;

const nextDay = new Date(watch("date1"));
nextDay.setDate(nextDay.getDate() + 1);
Expand Down Expand Up @@ -117,10 +85,7 @@ export const DateFilterModal: React.FC<Props> = ({
<DateFilterSelect title={title} value={value} onChange={onChange} />
)}
/>
<XMarkIcon
className="border-base h-4 w-4 cursor-pointer"
onClick={handleClose}
/>
<XMarkIcon className="border-base h-4 w-4 cursor-pointer" onClick={handleClose} />
</div>
<div className="flex w-full justify-between gap-4">
<Controller
Expand Down Expand Up @@ -165,11 +130,7 @@ export const DateFilterModal: React.FC<Props> = ({
<SecondaryButton className="flex items-center gap-2" onClick={handleClose}>
Cancel
</SecondaryButton>
<PrimaryButton
type="submit"
className="flex items-center gap-2"
disabled={isInvalid}
>
<PrimaryButton type="submit" className="flex items-center gap-2" disabled={isInvalid}>
Apply
</PrimaryButton>
</div>
Expand Down
96 changes: 76 additions & 20 deletions web/components/headers/project-issues.tsx
Original file line number Diff line number Diff line change
@@ -1,42 +1,98 @@
import { useCallback } from "react";
import { useRouter } from "next/router";

// mobx
import { observer } from "mobx-react-lite";

// mobx store
import { useMobxStore } from "lib/mobx/store-provider";
// components
import { DisplayFiltersSelection, FilterSelection, IssueDropdown, LayoutSelection } from "components/issue-layouts";
import { DisplayFiltersSelection, FiltersDropdown, FilterSelection, LayoutSelection } from "components/issues";
// types
import { TIssueLayouts } from "types";
import { IIssueDisplayFilterOptions, IIssueFilterOptions, TIssueLayouts } from "types";
// constants
import { ISSUE_DISPLAY_FILTERS_BY_LAYOUT } from "constants/issue";

export const ProjectIssuesHeader = observer(() => {
export const ProjectIssuesHeader: React.FC = observer(() => {
const router = useRouter();
const { workspaceSlug, projectId } = router.query;

const { issueFilter: issueFilterStore } = useMobxStore();

const handleLayoutChange = (layout: TIssueLayouts) => {
if (!workspaceSlug || !projectId) return;
const handleLayoutChange = useCallback(
(layout: TIssueLayouts) => {
if (!workspaceSlug || !projectId) return;

issueFilterStore.updateUserFilters(workspaceSlug.toString(), projectId.toString(), {
display_filters: {
layout,
},
});
},
[issueFilterStore, projectId, workspaceSlug]
);

const handleFiltersUpdate = useCallback(
(key: keyof IIssueFilterOptions, value: string | string[]) => {
if (!workspaceSlug || !projectId) return;

const newValues = issueFilterStore.userFilters?.[key] ?? [];

issueFilterStore.updateUserFilters(workspaceSlug.toString(), projectId.toString(), {
display_filters: {
layout,
},
});
};
if (Array.isArray(value)) {
value.forEach((val) => {
if (!newValues.includes(val)) newValues.push(val);
});
} else {
if (issueFilterStore.userFilters?.[key]?.includes(value)) newValues.splice(newValues.indexOf(value), 1);
else newValues.push(value);
}

issueFilterStore.updateUserFilters(workspaceSlug.toString(), projectId.toString(), {
filters: {
[key]: newValues,
},
});
},
[issueFilterStore, projectId, workspaceSlug]
);

const handleDisplayFiltersUpdate = useCallback(
(updatedDisplayFilter: Partial<IIssueDisplayFilterOptions>) => {
if (!workspaceSlug || !projectId) return;

issueFilterStore.updateUserFilters(workspaceSlug.toString(), projectId.toString(), {
display_filters: {
...updatedDisplayFilter,
},
});
},
[issueFilterStore, projectId, workspaceSlug]
);

return (
<div className="flex items-center gap-2">
<LayoutSelection
layouts={["calendar", "gantt_chart", "kanban", "list", "spreadsheet"]}
layouts={["list", "kanban", "calendar", "spreadsheet", "gantt_chart"]}
onChange={(layout) => handleLayoutChange(layout)}
selectedLayout={issueFilterStore.userDisplayFilters.layout ?? "list"}
/>
<IssueDropdown title="Filters">
<FilterSelection workspaceSlug={workspaceSlug?.toString() ?? ""} projectId={projectId?.toString() ?? ""} />
</IssueDropdown>
<IssueDropdown title="View">
<DisplayFiltersSelection />
</IssueDropdown>
<FiltersDropdown title="Filters">
<FilterSelection
filters={issueFilterStore.userFilters}
handleFiltersUpdate={handleFiltersUpdate}
layoutDisplayFiltersOptions={
ISSUE_DISPLAY_FILTERS_BY_LAYOUT.issues[issueFilterStore.userDisplayFilters.layout ?? "list"]
}
projectId={projectId?.toString() ?? ""}
/>
</FiltersDropdown>
<FiltersDropdown title="View">
<DisplayFiltersSelection
displayFilters={issueFilterStore.userDisplayFilters}
handleDisplayFiltersUpdate={handleDisplayFiltersUpdate}
layoutDisplayFiltersOptions={
ISSUE_DISPLAY_FILTERS_BY_LAYOUT.issues[issueFilterStore.userDisplayFilters.layout ?? "list"]
}
/>
</FiltersDropdown>
</div>
);
});

This file was deleted.

47 changes: 0 additions & 47 deletions web/components/issue-layouts/display-filters/extra-options.tsx

This file was deleted.

Loading
Loading