Skip to content
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
28 changes: 28 additions & 0 deletions web/ce/components/issues/worklog/activity/filter-root.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
"use client";

import { FC } from "react";
// components
import { ActivityFilter } from "@/components/issues";
// plane web constants
import { TActivityFilters, ACTIVITY_FILTER_TYPE_OPTIONS, TActivityFilterOption } from "@/plane-web/constants/issues";

export type TActivityFilterRoot = {
selectedFilters: TActivityFilters[];
toggleFilter: (filter: TActivityFilters) => void;
};

export const ActivityFilterRoot: FC<TActivityFilterRoot> = (props) => {
const { selectedFilters, toggleFilter } = props;

const filters: TActivityFilterOption[] = Object.entries(ACTIVITY_FILTER_TYPE_OPTIONS).map(([key, value]) => {
const filterKey = key as TActivityFilters;
return {
key: filterKey,
label: value.label,
isSelected: selectedFilters.includes(filterKey),
onClick: () => toggleFilter(filterKey),
};
});

return <ActivityFilter selectedFilters={selectedFilters} filterOptions={filters} />;
};
2 changes: 2 additions & 0 deletions web/ce/components/issues/worklog/activity/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
export * from "./root";
export * from "./worklog-create-button";

export * from "./filter-root";
7 changes: 7 additions & 0 deletions web/ce/constants/issues.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,13 @@ export const ACTIVITY_FILTER_TYPE_OPTIONS: Record<EActivityFilterType, { label:

export const defaultActivityFilters: TActivityFilters[] = [EActivityFilterType.ACTIVITY, EActivityFilterType.COMMENT];

export type TActivityFilterOption = {
key: EActivityFilterType;
label: string;
isSelected: boolean;
onClick: () => void;
};

export const filterActivityOnSelectedFilters = (
activity: TIssueActivityComment[],
filter: TActivityFilters[]
Expand Down
Original file line number Diff line number Diff line change
@@ -1,85 +1,59 @@
import React, { FC, Fragment } from "react";
import React, { FC } from "react";
import { observer } from "mobx-react";
import { Check, ListFilter } from "lucide-react";
import { Popover, Transition } from "@headlessui/react";
// ui
import { Button } from "@plane/ui";
import { Button, PopoverMenu } from "@plane/ui";
// helper
import { cn } from "@/helpers/common.helper";
// constants
import { TActivityFilters, ACTIVITY_FILTER_TYPE_OPTIONS } from "@/plane-web/constants/issues";
import { TActivityFilterOption, TActivityFilters } from "@/plane-web/constants/issues";

type Props = {
type TActivityFilter = {
selectedFilters: TActivityFilters[];
toggleFilter: (filter: TActivityFilters) => void;
filterOptions: TActivityFilterOption[];
};

export const ActivityFilter: FC<Props> = observer((props) => {
const { selectedFilters, toggleFilter } = props;
return (
<Popover as="div" className="relative">
{({ open }) => (
<>
<Popover.Button as={React.Fragment}>
<Button
variant="neutral-primary"
size="sm"
prependIcon={<ListFilter className="h-3 w-3" />}
className="relative"
>
<span className={`${open ? "text-custom-text-100" : "text-custom-text-200"}`}>Filters</span>
</Button>
</Popover.Button>
export const ActivityFilter: FC<TActivityFilter> = observer((props) => {
const { selectedFilters = [], filterOptions } = props;

<Transition
as={Fragment}
enter="transition ease-out duration-200"
enterFrom="opacity-0 translate-y-1"
enterTo="opacity-100 translate-y-0"
leave="transition ease-in duration-150"
leaveFrom="opacity-100 translate-y-0"
leaveTo="opacity-0 translate-y-1"
return (
<PopoverMenu
buttonClassName="outline-none"
button={
<Button
variant="neutral-primary"
size="sm"
prependIcon={<ListFilter className="h-3 w-3" />}
className="relative"
>
<span className="text-custom-text-200">Filters</span>
</Button>
}
panelClassName="p-2 rounded-md border border-custom-border-200 bg-custom-background-100"
data={filterOptions}
keyExtractor={(item) => item.key}
render={(item) => (
<div
key={item.key}
className="flex items-center gap-2 text-sm cursor-pointer px-2 p-1 transition-all hover:bg-custom-background-80 rounded-sm"
onClick={item.onClick}
>
<div
className={cn(
"flex-shrink-0 w-3 h-3 flex justify-center items-center rounded-sm transition-all bg-custom-background-90",
{
"bg-custom-primary text-white": item.isSelected,
"bg-custom-background-80 text-custom-text-400": item.isSelected && selectedFilters.length === 1,
"bg-custom-background-90": !item.isSelected,
}
)}
>
<Popover.Panel className="absolute mt-2 right-0 z-10 min-w-40">
<div className="p-2 rounded-md border border-custom-border-200 bg-custom-background-100">
{Object.keys(ACTIVITY_FILTER_TYPE_OPTIONS).map((key) => {
const filterKey = key as TActivityFilters;
const filter = ACTIVITY_FILTER_TYPE_OPTIONS[filterKey];
const isSelected = selectedFilters.includes(filterKey);
return (
<div
key={filterKey}
className="flex items-center gap-2 text-sm cursor-pointer px-2 p-1 transition-all hover:bg-custom-background-80 rounded-sm"
onClick={() => toggleFilter(filterKey)}
>
<div
className={cn(
"flex-shrink-0 w-3 h-3 flex justify-center items-center rounded-sm transition-all bg-custom-background-90",
{
"bg-custom-primary text-white": isSelected,
"bg-custom-background-80 text-custom-text-400": isSelected && selectedFilters.length === 1,
"bg-custom-background-90": !isSelected,
}
)}
>
{isSelected && <Check className="h-2.5 w-2.5" />}
</div>
<div
className={cn(
"whitespace-nowrap",
isSelected ? "text-custom-text-100" : "text-custom-text-200"
)}
>
{filter.label}
</div>
</div>
);
})}
</div>
</Popover.Panel>
</Transition>
</>
{item.isSelected && <Check className="h-2.5 w-2.5" />}
</div>
<div className={cn("whitespace-nowrap", item.isSelected ? "text-custom-text-100" : "text-custom-text-200")}>
{item.label}
</div>
</div>
)}
</Popover>
/>
Comment on lines +15 to +57
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM! Consider adding tests for the new component structure.

The ActivityFilter component has been refactored to use PopoverMenu, improving modularity and maintainability. The rendering logic is now more streamlined.

Do you want me to generate the unit testing code or open a GitHub issue to track this task?

);
});
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,12 @@ import { TIssueComment } from "@plane/types";
// ui
import { TOAST_TYPE, setToast } from "@plane/ui";
// components
import { ActivityFilter, IssueCommentCreate } from "@/components/issues";
import { IssueCommentCreate } from "@/components/issues";
import { IssueActivityCommentRoot } from "@/components/issues/issue-detail";
// hooks
import { useIssueDetail, useProject } from "@/hooks/store";
// plane web components
import { IssueActivityWorklogCreateButton } from "@/plane-web/components/issues/worklog";
import { ActivityFilterRoot, IssueActivityWorklogCreateButton } from "@/plane-web/components/issues/worklog";
// plane web constants
import { TActivityFilters, defaultActivityFilters } from "@/plane-web/constants/issues";

Expand Down Expand Up @@ -120,7 +120,7 @@ export const IssueActivity: FC<TIssueActivity> = observer((props) => {
issueId={issueId}
disabled={disabled}
/>
<ActivityFilter selectedFilters={selectedFilters} toggleFilter={toggleFilter} />
<ActivityFilterRoot selectedFilters={selectedFilters} toggleFilter={toggleFilter} />
</div>
</div>

Expand Down
1 change: 1 addition & 0 deletions web/ee/components/issues/worklog/activity/filter-root.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from "ce/components/issues/worklog/activity/filter-root";
2 changes: 2 additions & 0 deletions web/ee/components/issues/worklog/activity/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
export * from "./root";
export * from "./worklog-create-button";

export * from "./filter-root";
13 changes: 6 additions & 7 deletions web/helpers/date-time.helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -323,14 +323,13 @@ export const convertMinutesToHoursAndMinutes = (mins: number): { hours: number;
};

/**
* @description converts minutes to days, hours and minutes
* @description converts minutes to hours and minutes string
* @param { number } totalMinutes
* @returns { string } days, hours and minutes
* @returns { string } 0h 0m
* @example convertMinutesToHoursAndMinutes(150) // Output: 2h 10m
*/
export const convertMinutesToDaysHoursMinutes = (totalMinutes: number): string => {
const days = Math.floor(totalMinutes / (60 * 24));
const hours = Math.floor((totalMinutes % (60 * 24)) / 60);
const minutes = totalMinutes % 60;
export const convertMinutesToHoursMinutesString = (totalMinutes: number): string => {
const { hours, minutes } = convertMinutesToHoursAndMinutes(totalMinutes);

return `${days ? `${days}d ` : ``}${hours ? `${hours}h ` : ``}${minutes ? `${minutes}m ` : ``} `;
return `${hours ? `${hours}h ` : ``}${minutes ? `${minutes}m ` : ``}`;
};