remove filter dropdown

This commit is contained in:
daniel31x13
2025-02-26 09:18:22 -05:00
parent 140ee8c65d
commit bc01b6d4a9
17 changed files with 148 additions and 468 deletions

View File

@@ -40,7 +40,7 @@ DISABLE_PRESERVATION=
NEXT_PUBLIC_RSS_POLLING_INTERVAL_MINUTES=
RSS_SUBSCRIPTION_LIMIT_PER_USER=
TEXT_CONTENT_LIMIT=
SEARCH_QUERY_LIMIT=
SEARCH_FILTER_LIMIT=
INDEX_TAKE_COUNT=
# AI Settings

View File

@@ -1,147 +0,0 @@
import { dropdownTriggerer } from "@/lib/client/utils";
import React, { useEffect } from "react";
import { useTranslation } from "next-i18next";
import { resetInfiniteQueryPagination } from "@/hooks/store/links";
import { useQueryClient } from "@tanstack/react-query";
type Props = {
setSearchFilter: Function;
searchFilter: {
name: boolean;
url: boolean;
description: boolean;
textContent: boolean;
tags: boolean;
};
};
export default function FilterSearchDropdown({
setSearchFilter,
searchFilter,
}: Props) {
const { t } = useTranslation();
const queryClient = useQueryClient();
return (
<div className="dropdown dropdown-bottom dropdown-end">
<div
tabIndex={0}
role="button"
onMouseDown={dropdownTriggerer}
className="btn btn-sm btn-square btn-ghost"
>
<i className="bi-funnel text-neutral text-2xl"></i>
</div>
<ul className="dropdown-content z-[30] menu shadow bg-base-200 border border-neutral-content rounded-box mt-1">
<li>
<label
className="label cursor-pointer flex justify-start"
tabIndex={0}
role="button"
>
<input
type="checkbox"
name="search-filter-checkbox"
className="checkbox checkbox-primary"
checked={searchFilter.name}
onChange={() => {
resetInfiniteQueryPagination(queryClient, ["links"]);
setSearchFilter({ ...searchFilter, name: !searchFilter.name });
}}
/>
<span className="label-text whitespace-nowrap">{t("name")}</span>
</label>
</li>
<li>
<label
className="label cursor-pointer flex justify-start"
tabIndex={0}
role="button"
>
<input
type="checkbox"
name="search-filter-checkbox"
className="checkbox checkbox-primary"
checked={searchFilter.url}
onChange={() => {
resetInfiniteQueryPagination(queryClient, ["links"]);
setSearchFilter({ ...searchFilter, url: !searchFilter.url });
}}
/>
<span className="label-text whitespace-nowrap">{t("link")}</span>
</label>
</li>
<li>
<label
className="label cursor-pointer flex justify-start"
tabIndex={0}
role="button"
>
<input
type="checkbox"
name="search-filter-checkbox"
className="checkbox checkbox-primary"
checked={searchFilter.description}
onChange={() => {
resetInfiniteQueryPagination(queryClient, ["links"]);
setSearchFilter({
...searchFilter,
description: !searchFilter.description,
});
}}
/>
<span className="label-text whitespace-nowrap">
{t("description")}
</span>
</label>
</li>
<li>
<label
className="label cursor-pointer flex justify-start"
tabIndex={0}
role="button"
>
<input
type="checkbox"
name="search-filter-checkbox"
className="checkbox checkbox-primary"
checked={searchFilter.tags}
onChange={() => {
resetInfiniteQueryPagination(queryClient, ["links"]);
setSearchFilter({ ...searchFilter, tags: !searchFilter.tags });
}}
/>
<span className="label-text whitespace-nowrap">{t("tags")}</span>
</label>
</li>
<li>
<label
className="label cursor-pointer flex justify-between"
tabIndex={0}
role="button"
>
<input
type="checkbox"
name="search-filter-checkbox"
className="checkbox checkbox-primary"
checked={searchFilter.textContent}
onChange={() => {
resetInfiniteQueryPagination(queryClient, ["links"]);
setSearchFilter({
...searchFilter,
textContent: !searchFilter.textContent,
});
}}
/>
<span className="label-text whitespace-nowrap">
{t("full_content")}
</span>
<div className="ml-auto badge badge-sm badge-neutral whitespace-nowrap">
{t("slower")}
</div>
</label>
</li>
</ul>
</div>
);
}

View File

@@ -1,5 +1,4 @@
import React, { Dispatch, SetStateAction, useEffect, useState } from "react";
import FilterSearchDropdown from "./FilterSearchDropdown";
import SortDropdown from "./SortDropdown";
import ViewDropdown from "./ViewDropdown";
import { TFunction } from "i18next";
@@ -17,20 +16,6 @@ type Props = {
t: TFunction<"translation", undefined>;
viewMode: ViewMode;
setViewMode: Dispatch<SetStateAction<ViewMode>>;
searchFilter?: {
name: boolean;
url: boolean;
description: boolean;
tags: boolean;
textContent: boolean;
};
setSearchFilter?: (filter: {
name: boolean;
url: boolean;
description: boolean;
tags: boolean;
textContent: boolean;
}) => void;
sortBy: Sort;
setSortBy: Dispatch<SetStateAction<Sort>>;
editMode?: boolean;
@@ -42,8 +27,6 @@ const LinkListOptions = ({
t,
viewMode,
setViewMode,
searchFilter,
setSearchFilter,
sortBy,
setSortBy,
editMode,
@@ -122,12 +105,6 @@ const LinkListOptions = ({
<i className="bi-pencil-fill text-neutral text-xl"></i>
</div>
)}
{searchFilter && setSearchFilter && (
<FilterSearchDropdown
searchFilter={searchFilter}
setSearchFilter={setSearchFilter}
/>
)}
<SortDropdown
sortBy={sortBy}
setSort={(value) => {

View File

@@ -46,8 +46,10 @@ export default function NewLinkModal({ onClose }: Props) {
});
};
const setTags = (e: any) => {
const tagNames = e.map((e: any) => ({ name: e.label }));
const setTags = (selectedOptions: any = []) => {
const tagNames = selectedOptions.map((option: any) => ({
name: option.label,
}));
setLink({ ...link, tags: tagNames });
};
@@ -138,10 +140,12 @@ export default function NewLinkModal({ onClose }: Props) {
<p className="mb-2">{t("tags")}</p>
<TagSelection
onChange={setTags}
defaultValue={link.tags?.map((e) => ({
label: e.name,
value: e.id,
}))}
defaultValue={
link.tags?.map((e) => ({
label: e.name,
value: e.id,
})) || []
}
/>
</div>
<div className="sm:col-span-2">

View File

@@ -111,48 +111,6 @@ export default function SortDropdown({ sortBy, setSort, t }: Props) {
<span className="label-text whitespace-nowrap">{t("name_za")}</span>
</label>
</li>
<li>
<label
className="label cursor-pointer flex justify-start"
tabIndex={0}
role="button"
>
<input
type="radio"
name="sort-radio"
className="radio checked:bg-primary"
checked={sortBy === Sort.DescriptionAZ}
onChange={() => {
resetInfiniteQueryPagination(queryClient, ["links"]);
setSort(Sort.DescriptionAZ);
}}
/>
<span className="label-text whitespace-nowrap">
{t("description_az")}
</span>
</label>
</li>
<li>
<label
className="label cursor-pointer flex justify-start"
tabIndex={0}
role="button"
>
<input
type="radio"
name="sort-radio"
className="radio checked:bg-primary"
checked={sortBy === Sort.DescriptionZA}
onChange={() => {
resetInfiniteQueryPagination(queryClient, ["links"]);
setSort(Sort.DescriptionZA);
}}
/>
<span className="label-text whitespace-nowrap">
{t("description_za")}
</span>
</label>
</li>
</ul>
</div>
);

View File

@@ -260,30 +260,46 @@ const useGetLink = () => {
});
queryClient.setQueriesData({ queryKey: ["links"] }, (oldData: any) => {
if (!oldData?.pages?.[0]) return undefined;
return {
pages: oldData.pages.map((page: any) => ({
if (!oldData) return undefined;
const newPages = oldData.pages?.map((page: any) => {
if (!page?.links) {
return page;
}
return {
...page,
links: page.links.map((item: any) =>
item.id === data.id ? data : item
),
nextCursor: page?.nextCursor,
})),
pageParams: oldData?.pageParams,
};
});
return {
...oldData,
pages: newPages,
};
});
queryClient.setQueriesData(
{ queryKey: ["publicLinks"] },
(oldData: any) => {
if (!oldData?.pages?.[0]) return undefined;
return {
pages: oldData.pages.map((page: any) => ({
if (!oldData) return undefined;
const newPages = oldData.pages?.map((page: any) => {
if (!page?.links) {
return page;
}
return {
...page,
links: page.links.map((item: any) =>
item.id === data.id ? data : item
),
nextCursor: page?.nextCursor,
})),
pageParams: oldData?.pageParams,
};
});
return {
...oldData,
pages: newPages,
};
}
);

View File

@@ -26,16 +26,8 @@ export default function useSort<
if (sortBy === Sort.NameAZ)
setData(dataArray.sort((a, b) => a.name.localeCompare(b.name)));
else if (sortBy === Sort.DescriptionAZ)
setData(
dataArray.sort((a, b) => a.description.localeCompare(b.description))
);
else if (sortBy === Sort.NameZA)
setData(dataArray.sort((a, b) => b.name.localeCompare(a.name)));
else if (sortBy === Sort.DescriptionZA)
setData(
dataArray.sort((a, b) => b.description.localeCompare(a.description))
);
else if (sortBy === Sort.DateNewestFirst)
setData(
dataArray.sort(

View File

@@ -10,8 +10,6 @@ export default async function getDashboardData(
else if (query.sort === Sort.DateOldestFirst) order = { id: "asc" };
else if (query.sort === Sort.NameAZ) order = { name: "asc" };
else if (query.sort === Sort.NameZA) order = { name: "desc" };
else if (query.sort === Sort.DescriptionAZ) order = { description: "asc" };
else if (query.sort === Sort.DescriptionZA) order = { description: "desc" };
const pinnedLinks = await prisma.link.findMany({
take: 10,

View File

@@ -36,8 +36,6 @@ export default async function getDashboardData(
else if (query.sort === Sort.DateOldestFirst) order = { id: "asc" };
else if (query.sort === Sort.NameAZ) order = { name: "asc" };
else if (query.sort === Sort.NameZA) order = { name: "desc" };
else if (query.sort === Sort.DescriptionAZ) order = { description: "asc" };
else if (query.sort === Sort.DescriptionZA) order = { description: "desc" };
const numberOfPinnedLinks = await prisma.link.count({
where: {

View File

@@ -10,74 +10,55 @@ export default async function getLink(userId: number, query: LinkRequestQuery) {
else if (query.sort === Sort.DateOldestFirst) order = { id: "asc" };
else if (query.sort === Sort.NameAZ) order = { name: "asc" };
else if (query.sort === Sort.NameZA) order = { name: "desc" };
else if (query.sort === Sort.DescriptionAZ) order = { description: "asc" };
else if (query.sort === Sort.DescriptionZA) order = { description: "desc" };
const searchConditions = [];
if (query.searchQueryString) {
if (query.searchByName) {
searchConditions.push({
name: {
contains: query.searchQueryString,
mode: POSTGRES_IS_ENABLED ? "insensitive" : undefined,
},
});
}
searchConditions.push({
name: {
contains: query.searchQueryString,
mode: POSTGRES_IS_ENABLED ? "insensitive" : undefined,
},
});
if (query.searchByUrl) {
searchConditions.push({
url: {
contains: query.searchQueryString,
mode: POSTGRES_IS_ENABLED ? "insensitive" : undefined,
},
});
}
searchConditions.push({
url: {
contains: query.searchQueryString,
mode: POSTGRES_IS_ENABLED ? "insensitive" : undefined,
},
});
if (query.searchByDescription) {
searchConditions.push({
description: {
contains: query.searchQueryString,
mode: POSTGRES_IS_ENABLED ? "insensitive" : undefined,
},
});
}
searchConditions.push({
description: {
contains: query.searchQueryString,
mode: POSTGRES_IS_ENABLED ? "insensitive" : undefined,
},
});
if (query.searchByTextContent) {
searchConditions.push({
textContent: {
contains: query.searchQueryString,
mode: POSTGRES_IS_ENABLED ? "insensitive" : undefined,
},
});
}
if (query.searchByTags) {
searchConditions.push({
tags: {
some: {
name: {
contains: query.searchQueryString,
mode: POSTGRES_IS_ENABLED ? "insensitive" : undefined,
},
OR: [
{ ownerId: userId },
{
links: {
some: {
collection: {
members: {
some: { userId },
},
searchConditions.push({
tags: {
some: {
name: {
contains: query.searchQueryString,
mode: POSTGRES_IS_ENABLED ? "insensitive" : undefined,
},
OR: [
{ ownerId: userId },
{
links: {
some: {
collection: {
members: {
some: { userId },
},
},
},
},
],
},
},
],
},
});
}
},
});
}
const tagCondition = [];

View File

@@ -12,60 +12,41 @@ export default async function getLink(
else if (query.sort === Sort.DateOldestFirst) order = { id: "asc" };
else if (query.sort === Sort.NameAZ) order = { name: "asc" };
else if (query.sort === Sort.NameZA) order = { name: "desc" };
else if (query.sort === Sort.DescriptionAZ) order = { description: "asc" };
else if (query.sort === Sort.DescriptionZA) order = { description: "desc" };
const searchConditions = [];
if (query.searchQueryString) {
if (query.searchByName) {
searchConditions.push({
name: {
contains: query.searchQueryString,
mode: POSTGRES_IS_ENABLED ? "insensitive" : undefined,
},
});
}
searchConditions.push({
name: {
contains: query.searchQueryString,
mode: POSTGRES_IS_ENABLED ? "insensitive" : undefined,
},
});
if (query.searchByUrl) {
searchConditions.push({
url: {
contains: query.searchQueryString,
mode: POSTGRES_IS_ENABLED ? "insensitive" : undefined,
},
});
}
searchConditions.push({
url: {
contains: query.searchQueryString,
mode: POSTGRES_IS_ENABLED ? "insensitive" : undefined,
},
});
if (query.searchByDescription) {
searchConditions.push({
description: {
contains: query.searchQueryString,
mode: POSTGRES_IS_ENABLED ? "insensitive" : undefined,
},
});
}
searchConditions.push({
description: {
contains: query.searchQueryString,
mode: POSTGRES_IS_ENABLED ? "insensitive" : undefined,
},
});
if (query.searchByTextContent) {
searchConditions.push({
textContent: {
contains: query.searchQueryString,
mode: POSTGRES_IS_ENABLED ? "insensitive" : undefined,
},
});
}
if (query.searchByTags) {
searchConditions.push({
tags: {
some: {
name: {
contains: query.searchQueryString,
mode: POSTGRES_IS_ENABLED ? "insensitive" : undefined,
},
searchConditions.push({
tags: {
some: {
name: {
contains: query.searchQueryString,
mode: POSTGRES_IS_ENABLED ? "insensitive" : undefined,
},
},
});
}
},
});
}
const links = await prisma.link.findMany({

View File

@@ -21,8 +21,6 @@ export default async function searchLinks(
else if (query.sort === Sort.DateOldestFirst) order = { id: "asc" };
else if (query.sort === Sort.NameAZ) order = { name: "asc" };
else if (query.sort === Sort.NameZA) order = { name: "desc" };
else if (query.sort === Sort.DescriptionAZ) order = { description: "asc" };
else if (query.sort === Sort.DescriptionZA) order = { description: "desc" };
const tagCondition = [];
if (query.tagId) {
@@ -136,68 +134,51 @@ export default async function searchLinks(
const searchConditions = [];
if (query.searchQueryString) {
if (query.searchByName) {
searchConditions.push({
name: {
contains: query.searchQueryString,
mode: POSTGRES_IS_ENABLED ? "insensitive" : undefined,
},
});
}
searchConditions.push({
name: {
contains: query.searchQueryString,
mode: POSTGRES_IS_ENABLED ? "insensitive" : undefined,
},
});
if (query.searchByUrl) {
searchConditions.push({
url: {
contains: query.searchQueryString,
mode: POSTGRES_IS_ENABLED ? "insensitive" : undefined,
},
});
}
searchConditions.push({
url: {
contains: query.searchQueryString,
mode: POSTGRES_IS_ENABLED ? "insensitive" : undefined,
},
});
if (query.searchByDescription) {
searchConditions.push({
description: {
contains: query.searchQueryString,
mode: POSTGRES_IS_ENABLED ? "insensitive" : undefined,
},
});
}
searchConditions.push({
description: {
contains: query.searchQueryString,
mode: POSTGRES_IS_ENABLED ? "insensitive" : undefined,
},
});
if (query.searchByTextContent) {
searchConditions.push({
textContent: {
contains: query.searchQueryString,
mode: POSTGRES_IS_ENABLED ? "insensitive" : undefined,
},
});
}
if (query.searchByTags) {
searchConditions.push({
tags: {
some: {
name: {
contains: query.searchQueryString,
mode: POSTGRES_IS_ENABLED ? "insensitive" : undefined,
},
OR: [
{ ownerId: userId },
{
links: {
some: {
collection: {
members: {
some: { userId },
},
searchConditions.push({
tags: {
some: {
name: {
contains: query.searchQueryString,
mode: POSTGRES_IS_ENABLED ? "insensitive" : undefined,
},
OR: [
{ ownerId: userId },
{
links: {
some: {
collection: {
members: {
some: { userId },
},
},
},
},
],
},
},
],
},
});
}
},
});
}
const links = await prisma.link.findMany({

View File

@@ -71,14 +71,15 @@ export function parseSearchTokens(searchQueryString: string): Token[] {
}
}
const tokensWithoutGeneralField = tokens.filter((t) => t.field !== "general");
const SEARCH_FILTER_LIMIT = Number(process.env.SEARCH_FILTER_LIMIT);
const SEARCH_QUERY_LIMIT = Number(process.env.SEARCH_QUERY_LIMIT);
if (SEARCH_FILTER_LIMIT) {
const generalTokens = tokens.filter((t) => t.field === "general");
const otherTokens = tokens.filter((t) => t.field !== "general");
return [...generalTokens, ...otherTokens.slice(0, SEARCH_FILTER_LIMIT)];
}
if (SEARCH_QUERY_LIMIT)
return tokensWithoutGeneralField.slice(0, SEARCH_QUERY_LIMIT);
return tokensWithoutGeneralField;
return tokens;
}
export function buildMeiliQuery(tokens: Token[]): string {
@@ -187,6 +188,8 @@ export function buildMeiliFilters(tokens: Token[], userId: number): string[] {
: `tags = "${escapeForMeilisearch(value)}"`
);
break;
// "general" text is handled by the main query, not by filters
case "general":
default:
break;
}

View File

@@ -25,13 +25,6 @@ export default async function links(req: NextApiRequest, res: NextApiResponse) {
searchQueryString: req.query.searchQueryString
? (req.query.searchQueryString as string)
: undefined,
searchByName: req.query.searchByName === "true" ? true : undefined,
searchByUrl: req.query.searchByUrl === "true" ? true : undefined,
searchByDescription:
req.query.searchByDescription === "true" ? true : undefined,
searchByTextContent:
req.query.searchByTextContent === "true" ? true : undefined,
searchByTags: req.query.searchByTags === "true" ? true : undefined,
};
const links = await getLinks(user.id, convertedData);

View File

@@ -37,19 +37,6 @@ export default function PublicCollections() {
const handleTagSelection = (tag: string | undefined) => {
if (tag) {
Object.keys(searchFilter).forEach(
(v) =>
(searchFilter[
v as keyof {
name: boolean;
url: boolean;
description: boolean;
tags: boolean;
textContent: boolean;
}
] = false)
);
searchFilter.tags = true;
return router.push(
"/public/collections/" +
router.query.id +
@@ -61,14 +48,6 @@ export default function PublicCollections() {
}
};
const [searchFilter, setSearchFilter] = useState({
name: true,
url: true,
description: true,
tags: true,
textContent: false,
});
const [sortBy, setSortBy] = useState<Sort>(
Number(localStorage.getItem("sortBy")) ?? Sort.DateNewestFirst
);
@@ -80,11 +59,6 @@ export default function PublicCollections() {
searchQueryString: router.query.q
? decodeURIComponent(router.query.q as string)
: undefined,
searchByName: searchFilter.name,
searchByUrl: searchFilter.url,
searchByDescription: searchFilter.description,
searchByTextContent: searchFilter.textContent,
searchByTags: searchFilter.tags,
});
const [collection, setCollection] =
useState<CollectionIncludingMembersAndLinkCount>();
@@ -245,8 +219,6 @@ export default function PublicCollections() {
setViewMode={setViewMode}
sortBy={sortBy}
setSortBy={setSortBy}
searchFilter={searchFilter}
setSearchFilter={setSearchFilter}
>
<SearchBar
placeholder={

View File

@@ -14,14 +14,6 @@ export default function Search() {
const router = useRouter();
const [searchFilter, setSearchFilter] = useState({
name: true,
url: true,
description: true,
tags: true,
textContent: false,
});
const [viewMode, setViewMode] = useState<ViewMode>(
(localStorage.getItem("viewMode") as ViewMode) || ViewMode.Card
);
@@ -36,24 +28,9 @@ export default function Search() {
if (editMode) return setEditMode(false);
}, [router]);
// const { isLoading } = useLink({
// sort: sortBy,
// searchQueryString: decodeURIComponent(router.query.q as string),
// searchByName: searchFilter.name,
// searchByUrl: searchFilter.url,
// searchByDescription: searchFilter.description,
// searchByTextContent: searchFilter.textContent,
// searchByTags: searchFilter.tags,
// });
const { links, data } = useLinks({
sort: sortBy,
searchQueryString: decodeURIComponent(router.query.q as string),
searchByName: searchFilter.name,
searchByUrl: searchFilter.url,
searchByDescription: searchFilter.description,
searchByTextContent: searchFilter.textContent,
searchByTags: searchFilter.tags,
});
return (
@@ -61,8 +38,6 @@ export default function Search() {
<div className="p-5 flex flex-col gap-5 w-full h-full">
<LinkListOptions
t={t}
searchFilter={searchFilter}
setSearchFilter={setSearchFilter}
viewMode={viewMode}
setViewMode={setViewMode}
sortBy={sortBy}

View File

@@ -83,8 +83,6 @@ export enum Sort {
DateOldestFirst = 1,
NameAZ = 2,
NameZA = 3,
DescriptionAZ = 4,
DescriptionZA = 5,
}
export type Order = { [key: string]: "asc" | "desc" };