fix: change booking page filter ui to match Figma (#12134)
* fix: change booking page filter ui to match figma * fix: style change for filters in mobile * made all changes requested by reviewers * fix: add clear filter --------- Co-authored-by: Udit Takkar <53316345+Udit-takkar@users.noreply.github.com> Co-authored-by: Udit Takkar <udit222001@gmail.com>
This commit is contained in:
parent
50e405353c
commit
1aa8b8439a
|
@ -1,12 +1,13 @@
|
|||
import { useAutoAnimate } from "@formkit/auto-animate/react";
|
||||
import type { GetStaticPaths, GetStaticProps } from "next";
|
||||
import { Fragment } from "react";
|
||||
import { Fragment, useState } from "react";
|
||||
import React from "react";
|
||||
import { z } from "zod";
|
||||
|
||||
import { WipeMyCalActionButton } from "@calcom/app-store/wipemycalother/components";
|
||||
import dayjs from "@calcom/dayjs";
|
||||
import { getLayout } from "@calcom/features/MainLayout";
|
||||
import { FilterToggle } from "@calcom/features/bookings/components/FilterToggle";
|
||||
import { FiltersContainer } from "@calcom/features/bookings/components/FiltersContainer";
|
||||
import type { filterQuerySchema } from "@calcom/features/bookings/lib/useFilterQuery";
|
||||
import { useFilterQuery } from "@calcom/features/bookings/lib/useFilterQuery";
|
||||
|
@ -81,6 +82,7 @@ export default function Bookings() {
|
|||
const { status } = params ? querySchema.parse(params) : { status: "upcoming" as const };
|
||||
const { t } = useLocale();
|
||||
const user = useMeQuery().data;
|
||||
const [isFiltersVisible, setIsFiltersVisible] = useState<boolean>(false);
|
||||
|
||||
const query = trpc.viewer.bookings.get.useInfiniteQuery(
|
||||
{
|
||||
|
@ -151,12 +153,11 @@ export default function Bookings() {
|
|||
return (
|
||||
<ShellMain hideHeadingOnMobile heading={t("bookings")} subtitle={t("bookings_description")}>
|
||||
<div className="flex flex-col">
|
||||
<div className="flex flex-col flex-wrap lg:flex-row">
|
||||
<div className="flex flex-row flex-wrap justify-between">
|
||||
<HorizontalTabs tabs={tabs} />
|
||||
<div className="max-w-full overflow-x-auto xl:ml-auto">
|
||||
<FiltersContainer />
|
||||
</div>
|
||||
<FilterToggle setIsFiltersVisible={setIsFiltersVisible} />
|
||||
</div>
|
||||
<FiltersContainer isFiltersVisible={isFiltersVisible} />
|
||||
<main className="w-full">
|
||||
<div className="flex w-full flex-col" ref={animationParentRef}>
|
||||
{query.status === "error" && (
|
||||
|
|
|
@ -1638,6 +1638,7 @@
|
|||
"individual": "Individual",
|
||||
"all_bookings_filter_label": "All Bookings",
|
||||
"all_users_filter_label": "All Users",
|
||||
"all_event_types_filter_label": "All Event Types",
|
||||
"your_bookings_filter_label": "Your Bookings",
|
||||
"meeting_url_variable": "Meeting url",
|
||||
"meeting_url_info": "The event meeting conference url",
|
||||
|
@ -1868,6 +1869,7 @@
|
|||
"review_event_type": "Review Event Type",
|
||||
"looking_for_more_analytics": "Looking for more analytics?",
|
||||
"looking_for_more_insights": "Looking for more Insights?",
|
||||
"filters": "Filters",
|
||||
"add_filter": "Add filter",
|
||||
"remove_filters": "Clear all filters",
|
||||
"select_user": "Select User",
|
||||
|
|
|
@ -1,52 +0,0 @@
|
|||
import { create } from "zustand";
|
||||
|
||||
import type { SVGComponent } from "@calcom/types/SVGComponent";
|
||||
import { User, Link } from "@calcom/ui/components/icon";
|
||||
|
||||
interface addFilterOption {
|
||||
StartIcon?: SVGComponent;
|
||||
label: "people" | "event_type" | "date_range" | "location";
|
||||
}
|
||||
|
||||
export type BookingMultiFilterStore = {
|
||||
addFilterOptions: addFilterOption[];
|
||||
toggleOption: (option: addFilterOption) => void;
|
||||
isFilterActive: (label: addFilterOption["label"]) => boolean;
|
||||
};
|
||||
|
||||
export const useBookingMultiFilterStore = create<BookingMultiFilterStore>((set, get) => ({
|
||||
addFilterOptions: [
|
||||
{
|
||||
label: "people",
|
||||
StartIcon: User,
|
||||
},
|
||||
{
|
||||
label: "event_type",
|
||||
StartIcon: Link,
|
||||
},
|
||||
// {
|
||||
// label: "date_range",
|
||||
// StartIcon: Calendar,
|
||||
// },
|
||||
// {
|
||||
// label: "location",
|
||||
// StartIcon: MapPin,
|
||||
// },
|
||||
],
|
||||
isFilterActive: (label: addFilterOption["label"]) => {
|
||||
return !get().addFilterOptions.some((option) => option.label === label);
|
||||
},
|
||||
setState: (state: BookingMultiFilterStore) => set(state),
|
||||
toggleOption: (option: addFilterOption) => {
|
||||
const availableOptions = get().addFilterOptions;
|
||||
const foundOption = availableOptions.find((activeOption) => activeOption.label === option.label);
|
||||
|
||||
if (foundOption) {
|
||||
set({
|
||||
addFilterOptions: availableOptions.filter((activeOption) => activeOption.label !== foundOption.label),
|
||||
});
|
||||
} else {
|
||||
set({ addFilterOptions: [...availableOptions, option] });
|
||||
}
|
||||
},
|
||||
}));
|
|
@ -1,11 +1,16 @@
|
|||
import { useSession } from "next-auth/react";
|
||||
import { Fragment, useState } from "react";
|
||||
|
||||
import {
|
||||
FilterCheckboxFieldsContainer,
|
||||
FilterCheckboxField,
|
||||
} from "@calcom/features/filters/components/TeamsFilter";
|
||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
import type { RouterOutputs } from "@calcom/trpc/react";
|
||||
import { trpc } from "@calcom/trpc/react";
|
||||
import { AnimatedPopover } from "@calcom/ui";
|
||||
import { CheckboxField } from "@calcom/ui";
|
||||
import { Divider } from "@calcom/ui";
|
||||
import { Link } from "@calcom/ui/components/icon";
|
||||
|
||||
import { groupBy } from "../groupBy";
|
||||
import { useFilterQuery } from "../lib/useFilterQuery";
|
||||
|
@ -29,7 +34,7 @@ type GroupedEventTypeState = Record<
|
|||
export const EventTypeFilter = () => {
|
||||
const { t } = useLocale();
|
||||
const { data: user } = useSession();
|
||||
const { data: query, pushItemToKey, removeItemByKeyAndValue } = useFilterQuery();
|
||||
const { data: query, pushItemToKey, removeItemByKeyAndValue, removeAllQueryParams } = useFilterQuery();
|
||||
|
||||
const [groupedEventTypes, setGroupedEventTypes] = useState<GroupedEventTypeState>();
|
||||
|
||||
|
@ -56,24 +61,32 @@ export const EventTypeFilter = () => {
|
|||
const getTextForPopover = () => {
|
||||
const eventTypeIds = query.eventTypeIds;
|
||||
if (eventTypeIds) {
|
||||
return `${t("event_type")}: ${t("number_selected", { count: eventTypeIds.length })}`;
|
||||
return `${t("number_selected", { count: eventTypeIds.length })}`;
|
||||
}
|
||||
return `${t("event_type")}: ${t("all")}`;
|
||||
return `${t("all")}`;
|
||||
};
|
||||
|
||||
return (
|
||||
<AnimatedPopover text={getTextForPopover()}>
|
||||
<div>
|
||||
{groupedEventTypes &&
|
||||
!isEmpty &&
|
||||
Object.keys(groupedEventTypes).map((teamName) => (
|
||||
<Fragment key={teamName}>
|
||||
<div className="text-subtle px-4 py-2 text-xs font-medium uppercase leading-none">
|
||||
{teamName === "user_own_event_types" ? t("individual") : teamName}
|
||||
</div>
|
||||
{groupedEventTypes[teamName].map((eventType) => (
|
||||
<div key={eventType.id} className="flex items-center px-4 py-1.5">
|
||||
<CheckboxField
|
||||
<AnimatedPopover text={getTextForPopover()} prefix={`${t("event_type")}: `}>
|
||||
{!isEmpty ? (
|
||||
<FilterCheckboxFieldsContainer>
|
||||
<FilterCheckboxField
|
||||
id="all"
|
||||
icon={<Link className="h-4 w-4" />}
|
||||
checked={!query.eventTypeIds?.length}
|
||||
onChange={removeAllQueryParams}
|
||||
label={t("all_event_types_filter_label")}
|
||||
/>
|
||||
<Divider />
|
||||
{groupedEventTypes &&
|
||||
Object.keys(groupedEventTypes).map((teamName) => (
|
||||
<Fragment key={teamName}>
|
||||
<div className="text-subtle px-4 py-2 text-xs font-medium uppercase leading-none">
|
||||
{teamName === "user_own_event_types" ? t("individual") : teamName}
|
||||
</div>
|
||||
{groupedEventTypes[teamName].map((eventType) => (
|
||||
<FilterCheckboxField
|
||||
key={eventType.id}
|
||||
checked={query.eventTypeIds?.includes(eventType.id)}
|
||||
onChange={(e) => {
|
||||
if (e.target.checked) {
|
||||
|
@ -82,16 +95,15 @@ export const EventTypeFilter = () => {
|
|||
removeItemByKeyAndValue("eventTypeIds", eventType.id);
|
||||
}
|
||||
}}
|
||||
description={eventType.title}
|
||||
label={eventType.title}
|
||||
/>
|
||||
</div>
|
||||
))}
|
||||
</Fragment>
|
||||
))}
|
||||
{isEmpty && (
|
||||
<h2 className="text-default px-4 py-2 text-sm font-medium">{t("no_options_available")}</h2>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
</Fragment>
|
||||
))}
|
||||
</FilterCheckboxFieldsContainer>
|
||||
) : (
|
||||
<h2 className="text-default px-4 py-2 text-sm font-medium">{t("no_options_available")}</h2>
|
||||
)}
|
||||
</AnimatedPopover>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
import type { Dispatch, SetStateAction } from "react";
|
||||
|
||||
import { useFilterQuery } from "@calcom/features/bookings/lib/useFilterQuery";
|
||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
import { Tooltip, Badge, Button } from "@calcom/ui";
|
||||
import { Filter } from "@calcom/ui/components/icon";
|
||||
|
||||
export interface FilterToggleProps {
|
||||
setIsFiltersVisible: Dispatch<SetStateAction<boolean>>;
|
||||
}
|
||||
|
||||
export function FilterToggle({ setIsFiltersVisible }: FilterToggleProps) {
|
||||
const {
|
||||
data: { teamIds, userIds, eventTypeIds },
|
||||
} = useFilterQuery();
|
||||
const { t } = useLocale();
|
||||
|
||||
function toggleFiltersVisibility() {
|
||||
setIsFiltersVisible((prev) => !prev);
|
||||
}
|
||||
|
||||
return (
|
||||
<Button color="secondary" onClick={toggleFiltersVisibility} className="mb-4">
|
||||
<Filter className="h-4 w-4" />
|
||||
<Tooltip content={t("filters")}>
|
||||
<div className="mx-2">{t("filters")}</div>
|
||||
</Tooltip>
|
||||
{(teamIds || userIds || eventTypeIds) && (
|
||||
<Badge variant="gray" rounded>
|
||||
{(teamIds ? 1 : 0) + (userIds ? 1 : 0) + (eventTypeIds ? 1 : 0)}
|
||||
</Badge>
|
||||
)}
|
||||
</Button>
|
||||
);
|
||||
}
|
|
@ -1,156 +1,41 @@
|
|||
import { useState } from "react";
|
||||
import { shallow } from "zustand/shallow";
|
||||
import { useAutoAnimate } from "@formkit/auto-animate/react";
|
||||
|
||||
import { PeopleFilter } from "@calcom/features/bookings/components/PeopleFilter";
|
||||
import { useFilterQuery } from "@calcom/features/bookings/lib/useFilterQuery";
|
||||
import { useOrgBranding } from "@calcom/features/ee/organizations/context/provider";
|
||||
import {
|
||||
TeamsFilter,
|
||||
FilterCheckboxFieldsContainer,
|
||||
FilterCheckboxField,
|
||||
} from "@calcom/features/filters/components/TeamsFilter";
|
||||
import { WEBAPP_URL } from "@calcom/lib/constants";
|
||||
import { TeamsFilter } from "@calcom/features/filters/components/TeamsFilter";
|
||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
import { trpc } from "@calcom/trpc/react";
|
||||
import {
|
||||
Dropdown,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuItem,
|
||||
DropdownItem,
|
||||
DropdownMenuTrigger,
|
||||
AnimatedPopover,
|
||||
Avatar,
|
||||
FilterSearchField,
|
||||
Tooltip,
|
||||
Button,
|
||||
} from "@calcom/ui";
|
||||
import { Plus } from "@calcom/ui/components/icon";
|
||||
import { Tooltip, Button } from "@calcom/ui";
|
||||
|
||||
import { useBookingMultiFilterStore } from "../BookingMultiFiltersStore";
|
||||
import { EventTypeFilter } from "./EventTypeFilter";
|
||||
|
||||
const PeopleFilter = () => {
|
||||
const { t } = useLocale();
|
||||
const orgBranding = useOrgBranding();
|
||||
|
||||
const { data: query, pushItemToKey, removeItemByKeyAndValue, removeByKey } = useFilterQuery();
|
||||
const [searchText, setSearchText] = useState("");
|
||||
|
||||
const members = trpc.viewer.teams.listMembers.useQuery({});
|
||||
|
||||
const filteredMembers = members?.data
|
||||
?.filter((member) => member.accepted)
|
||||
?.filter((member) =>
|
||||
searchText.trim() !== ""
|
||||
? member?.name?.toLowerCase()?.includes(searchText.toLowerCase()) ||
|
||||
member?.username?.toLowerCase()?.includes(searchText.toLowerCase())
|
||||
: true
|
||||
);
|
||||
|
||||
const getTextForPopover = () => {
|
||||
const userIds = query.userIds;
|
||||
if (userIds) {
|
||||
return `${t("people")}: ${t("number_selected", { count: userIds.length })}`;
|
||||
}
|
||||
return `${t("people")}: ${t("all")}`;
|
||||
};
|
||||
|
||||
return (
|
||||
<AnimatedPopover text={getTextForPopover()}>
|
||||
<FilterSearchField onChange={(e) => setSearchText(e.target.value)} placeholder={t("search")} />
|
||||
<FilterCheckboxFieldsContainer>
|
||||
{filteredMembers?.map((member) => (
|
||||
<FilterCheckboxField
|
||||
key={member.id}
|
||||
id={member.id.toString()}
|
||||
label={member?.name ?? member.username ?? t("no_name")}
|
||||
checked={!!query.userIds?.includes(member.id)}
|
||||
onChange={(e) => {
|
||||
if (e.target.checked) {
|
||||
pushItemToKey("userIds", member.id);
|
||||
} else if (!e.target.checked) {
|
||||
removeItemByKeyAndValue("userIds", member.id);
|
||||
}
|
||||
}}
|
||||
icon={
|
||||
<Avatar
|
||||
alt={`${member?.id} avatar`}
|
||||
imageSrc={
|
||||
member.username
|
||||
? `${orgBranding?.fullDomain ?? WEBAPP_URL}/${member.username}/avatar.png`
|
||||
: undefined
|
||||
}
|
||||
size="xs"
|
||||
/>
|
||||
}
|
||||
/>
|
||||
))}
|
||||
{filteredMembers?.length === 0 && (
|
||||
<h2 className="text-default px-4 py-2 text-sm font-medium">{t("no_options_available")}</h2>
|
||||
)}
|
||||
</FilterCheckboxFieldsContainer>
|
||||
</AnimatedPopover>
|
||||
);
|
||||
};
|
||||
|
||||
export function FiltersContainer() {
|
||||
const { t } = useLocale();
|
||||
export interface FiltersContainerProps {
|
||||
isFiltersVisible: boolean;
|
||||
}
|
||||
|
||||
export function FiltersContainer({ isFiltersVisible }: FiltersContainerProps) {
|
||||
const [animationParentRef] = useAutoAnimate<HTMLDivElement>();
|
||||
const { removeAllQueryParams } = useFilterQuery();
|
||||
|
||||
const [addFilterOptions, toggleOption, isFilterActive] = useBookingMultiFilterStore((state) => [
|
||||
state.addFilterOptions,
|
||||
state.toggleOption,
|
||||
state.isFilterActive,
|
||||
shallow,
|
||||
]);
|
||||
|
||||
const isPeopleFilterActive = isFilterActive("people");
|
||||
const isEventTypeFilterActive = isFilterActive("event_type");
|
||||
const { t } = useLocale();
|
||||
|
||||
return (
|
||||
<div className="flex w-full space-x-2 rtl:space-x-reverse">
|
||||
{addFilterOptions.length > 0 && (
|
||||
<Dropdown>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<div className="hover:border-emphasis border-default text-default hover:text-emphasis mb-4 flex h-9 max-h-72 items-center justify-between whitespace-nowrap rounded-md border px-3 py-2 text-sm hover:cursor-pointer focus:border-neutral-300 focus:outline-none focus:ring-2 focus:ring-neutral-800 focus:ring-offset-1">
|
||||
<Plus className="mr-2 h-4 w-4" />
|
||||
<Tooltip content={t("add_filter")}>
|
||||
<div>{t("add_filter")}</div>
|
||||
</Tooltip>
|
||||
</div>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent className="w-56">
|
||||
{addFilterOptions?.map((option) => (
|
||||
<DropdownMenuItem key={option.label}>
|
||||
<DropdownItem
|
||||
type="button"
|
||||
StartIcon={option.StartIcon}
|
||||
onClick={() => {
|
||||
toggleOption(option);
|
||||
}}>
|
||||
{t(option.label)}
|
||||
</DropdownItem>
|
||||
</DropdownMenuItem>
|
||||
))}
|
||||
</DropdownMenuContent>
|
||||
</Dropdown>
|
||||
)}
|
||||
|
||||
{isPeopleFilterActive && <PeopleFilter />}
|
||||
{isEventTypeFilterActive && <EventTypeFilter />}
|
||||
{(isPeopleFilterActive || isEventTypeFilterActive) && (
|
||||
<Tooltip content={t("remove_filters")}>
|
||||
<Button
|
||||
color="secondary"
|
||||
type="button"
|
||||
onClick={() => {
|
||||
removeAllQueryParams();
|
||||
}}>
|
||||
{t("remove_filters")}
|
||||
</Button>
|
||||
</Tooltip>
|
||||
)}
|
||||
<TeamsFilter />
|
||||
<div ref={animationParentRef}>
|
||||
{isFiltersVisible ? (
|
||||
<div className="no-scrollbar flex w-full space-x-2 overflow-x-scroll rtl:space-x-reverse">
|
||||
<PeopleFilter />
|
||||
<EventTypeFilter />
|
||||
<TeamsFilter />
|
||||
<Tooltip content={t("remove_filters")}>
|
||||
<Button
|
||||
color="secondary"
|
||||
type="button"
|
||||
onClick={() => {
|
||||
removeAllQueryParams();
|
||||
}}>
|
||||
{t("remove_filters")}
|
||||
</Button>
|
||||
</Tooltip>
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,85 @@
|
|||
import { useState } from "react";
|
||||
|
||||
import { useFilterQuery } from "@calcom/features/bookings/lib/useFilterQuery";
|
||||
import { useOrgBranding } from "@calcom/features/ee/organizations/context/provider";
|
||||
import {
|
||||
FilterCheckboxFieldsContainer,
|
||||
FilterCheckboxField,
|
||||
} from "@calcom/features/filters/components/TeamsFilter";
|
||||
import { WEBAPP_URL } from "@calcom/lib/constants";
|
||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
import { trpc } from "@calcom/trpc/react";
|
||||
import { AnimatedPopover, Avatar, Divider, FilterSearchField } from "@calcom/ui";
|
||||
import { User } from "@calcom/ui/components/icon";
|
||||
|
||||
export const PeopleFilter = () => {
|
||||
const { t } = useLocale();
|
||||
const orgBranding = useOrgBranding();
|
||||
|
||||
const { data: query, pushItemToKey, removeItemByKeyAndValue, removeAllQueryParams } = useFilterQuery();
|
||||
const [searchText, setSearchText] = useState("");
|
||||
|
||||
const members = trpc.viewer.teams.listMembers.useQuery({});
|
||||
|
||||
const filteredMembers = members?.data
|
||||
?.filter((member) => member.accepted)
|
||||
?.filter((member) =>
|
||||
searchText.trim() !== ""
|
||||
? member?.name?.toLowerCase()?.includes(searchText.toLowerCase()) ||
|
||||
member?.username?.toLowerCase()?.includes(searchText.toLowerCase())
|
||||
: true
|
||||
);
|
||||
|
||||
const getTextForPopover = () => {
|
||||
const userIds = query.userIds;
|
||||
if (userIds) {
|
||||
return `${t("number_selected", { count: userIds.length })}`;
|
||||
}
|
||||
return `${t("all")}`;
|
||||
};
|
||||
|
||||
return (
|
||||
<AnimatedPopover text={getTextForPopover()} prefix={`${t("people")}: `}>
|
||||
<FilterCheckboxFieldsContainer>
|
||||
<FilterCheckboxField
|
||||
id="all"
|
||||
icon={<User className="h-4 w-4" />}
|
||||
checked={!query.userIds?.length}
|
||||
onChange={removeAllQueryParams}
|
||||
label={t("all_users_filter_label")}
|
||||
/>
|
||||
<Divider />
|
||||
<FilterSearchField onChange={(e) => setSearchText(e.target.value)} placeholder={t("search")} />
|
||||
{filteredMembers?.map((member) => (
|
||||
<FilterCheckboxField
|
||||
key={member.id}
|
||||
id={member.id.toString()}
|
||||
label={member?.name ?? member.username ?? t("no_name")}
|
||||
checked={!!query.userIds?.includes(member.id)}
|
||||
onChange={(e) => {
|
||||
if (e.target.checked) {
|
||||
pushItemToKey("userIds", member.id);
|
||||
} else if (!e.target.checked) {
|
||||
removeItemByKeyAndValue("userIds", member.id);
|
||||
}
|
||||
}}
|
||||
icon={
|
||||
<Avatar
|
||||
alt={`${member?.id} avatar`}
|
||||
imageSrc={
|
||||
member.username
|
||||
? `${orgBranding?.fullDomain ?? WEBAPP_URL}/${member.username}/avatar.png`
|
||||
: undefined
|
||||
}
|
||||
size="xs"
|
||||
/>
|
||||
}
|
||||
/>
|
||||
))}
|
||||
{filteredMembers?.length === 0 && (
|
||||
<h2 className="text-default px-4 py-2 text-sm font-medium">{t("no_options_available")}</h2>
|
||||
)}
|
||||
</FilterCheckboxFieldsContainer>
|
||||
</AnimatedPopover>
|
||||
);
|
||||
};
|
|
@ -60,15 +60,16 @@ export const TeamsFilter = ({
|
|||
|
||||
return (
|
||||
<div className="flex items-center">
|
||||
<AnimatedPopover text={getCheckedOptionsNames()} popoverTriggerClassNames={popoverTriggerClassNames}>
|
||||
<AnimatedPopover
|
||||
text={getCheckedOptionsNames()}
|
||||
popoverTriggerClassNames={popoverTriggerClassNames}
|
||||
prefix={`${t("teams")}: `}>
|
||||
<FilterCheckboxFieldsContainer>
|
||||
<FilterCheckboxField
|
||||
id="all"
|
||||
icon={<Layers className="h-4 w-4" />}
|
||||
checked={!query.teamIds && !query.userIds?.includes(session.data?.user.id || 0)}
|
||||
onChange={(e) => {
|
||||
removeAllQueryParams();
|
||||
}}
|
||||
onChange={removeAllQueryParams}
|
||||
label={t("all")}
|
||||
/>
|
||||
|
||||
|
@ -134,7 +135,7 @@ export const FilterCheckboxFieldsContainer = ({
|
|||
|
||||
type Props = InputHTMLAttributes<HTMLInputElement> & {
|
||||
label: string;
|
||||
icon: ReactNode;
|
||||
icon?: ReactNode;
|
||||
};
|
||||
|
||||
export const FilterCheckboxField = forwardRef<HTMLInputElement, Props>(({ label, icon, ...rest }, ref) => {
|
||||
|
@ -142,9 +143,11 @@ export const FilterCheckboxField = forwardRef<HTMLInputElement, Props>(({ label,
|
|||
<div className="hover:bg-muted flex items-center py-2 pl-3 pr-2.5 hover:cursor-pointer">
|
||||
<label className="flex w-full max-w-full items-center justify-between hover:cursor-pointer">
|
||||
<div className="flex items-center truncate">
|
||||
<div className="text-default flex h-4 w-4 items-center justify-center ltr:mr-2 rtl:ml-2">
|
||||
{icon}
|
||||
</div>
|
||||
{icon && (
|
||||
<div className="text-default flex h-4 w-4 items-center justify-center ltr:mr-2 rtl:ml-2">
|
||||
{icon}
|
||||
</div>
|
||||
)}
|
||||
<Tooltip content={label}>
|
||||
<label
|
||||
htmlFor={rest.id}
|
||||
|
@ -158,7 +161,7 @@ export const FilterCheckboxField = forwardRef<HTMLInputElement, Props>(({ label,
|
|||
{...rest}
|
||||
ref={ref}
|
||||
type="checkbox"
|
||||
className="text-primary-600 focus:ring-primary-500 border-default bg-default h-4 w-4 rounded hover:cursor-pointer"
|
||||
className="text-emphasis focus:ring-emphasis border-default bg-default h-4 w-4 rounded hover:cursor-pointer"
|
||||
/>
|
||||
</div>
|
||||
</label>
|
||||
|
|
|
@ -13,6 +13,7 @@ export const AnimatedPopover = ({
|
|||
children,
|
||||
Trigger,
|
||||
defaultOpen,
|
||||
prefix,
|
||||
}: {
|
||||
text: string;
|
||||
count?: number;
|
||||
|
@ -20,6 +21,7 @@ export const AnimatedPopover = ({
|
|||
popoverTriggerClassNames?: string;
|
||||
Trigger?: React.ReactNode;
|
||||
defaultOpen?: boolean;
|
||||
prefix?: string;
|
||||
}) => {
|
||||
const [open, setOpen] = React.useState(defaultOpen ?? false);
|
||||
const ref = React.useRef<HTMLDivElement>(null);
|
||||
|
@ -58,8 +60,9 @@ export const AnimatedPopover = ({
|
|||
Trigger
|
||||
) : (
|
||||
<div className="max-w-36 flex items-center">
|
||||
<Tooltip content={text}>
|
||||
<Tooltip content={`${prefix}${text}`}>
|
||||
<div className="flex select-none truncate font-medium">
|
||||
{prefix && <span className="text-subtle">{prefix} </span>}
|
||||
{text}
|
||||
{count && count > 0 && (
|
||||
<div className="text-emphasis flex items-center justify-center rounded-full font-semibold">
|
||||
|
|
Loading…
Reference in New Issue
Block a user