Added allLinksOfCollection to linksStore

Removed duplicated tags
Fixed overflow for line
added disclosure for tags in public collection
This commit is contained in:
Oliver Schwamb
2024-07-09 13:50:08 +02:00
parent e045c18b7d
commit e8d0cce58a
3 changed files with 87 additions and 36 deletions
+40 -25
View File
@@ -18,7 +18,7 @@ export default function useLinks(
searchByTextContent,
}: LinkRequestQuery = { sort: 0 }
) {
const { links, setLinks, resetLinks, selectedLinks, setSelectedLinks } =
const { links, setLinks, resetLinks, selectedLinks, setSelectedLinks, setAllLinksOfCollection } =
useLinkStore();
const router = useRouter();
@@ -26,6 +26,34 @@ export default function useLinks(
const { reachedBottom, setReachedBottom } = useDetectPageBottom();
const getPath = (params?: LinkRequestQuery) => {
const buildQueryString = (params: LinkRequestQuery) => {
return Object.keys(params)
.filter((key) => params[key as keyof LinkRequestQuery] !== undefined)
.map(
(key) =>
`${encodeURIComponent(key)}=${encodeURIComponent(
params[key as keyof LinkRequestQuery] as string
)}`
)
.join("&");
};
let queryString = '';
if (params) {
queryString = buildQueryString(params);
}
let basePath;
if (router.pathname === "/dashboard") basePath = "/api/v1/dashboard";
else if (router.pathname.startsWith("/public/collections/[id]")) {
queryString = queryString + "&collectionId=" + router.query.id;
basePath = "/api/v1/public/collections/links";
} else basePath = "/api/v1/links";
return `${basePath}?${queryString}`;
}
const getLinks = async (isInitialCall: boolean, cursor?: number) => {
const params = {
sort,
@@ -40,32 +68,10 @@ export default function useLinks(
searchByTags,
searchByTextContent,
};
const buildQueryString = (params: LinkRequestQuery) => {
return Object.keys(params)
.filter((key) => params[key as keyof LinkRequestQuery] !== undefined)
.map(
(key) =>
`${encodeURIComponent(key)}=${encodeURIComponent(
params[key as keyof LinkRequestQuery] as string
)}`
)
.join("&");
};
let queryString = buildQueryString(params);
let basePath;
if (router.pathname === "/dashboard") basePath = "/api/v1/dashboard";
else if (router.pathname.startsWith("/public/collections/[id]")) {
queryString = queryString + "&collectionId=" + router.query.id;
basePath = "/api/v1/public/collections/links";
} else basePath = "/api/v1/links";
setIsLoading(true);
const response = await fetch(`${basePath}?${queryString}`);
const response = await fetch(getPath(params));
const data = await response.json();
@@ -74,6 +80,14 @@ export default function useLinks(
if (response.ok) setLinks(data.response, isInitialCall);
};
const getAllLinks = async () => {
const response = await fetch(getPath());
const data = await response.json();
if (response.ok) setAllLinksOfCollection(data.response);
};
useEffect(() => {
// Save the selected links before resetting the links
// and then restore the selected links after resetting the links
@@ -81,6 +95,7 @@ export default function useLinks(
resetLinks();
setSelectedLinks(previouslySelected);
getAllLinks();
getLinks(true);
}, [
router,
+43 -11
View File
@@ -26,6 +26,7 @@ import ViewDropdown from "@/components/ViewDropdown";
import CardView from "@/components/LinkViews/Layouts/CardView";
import ListView from "@/components/LinkViews/Layouts/ListView";
import useTagStore from "@/store/tags";
import { Disclosure, Transition } from "@headlessui/react";
// import GridView from "@/components/LinkViews/Layouts/GridView";
const cardVariants: Variants = {
@@ -43,9 +44,11 @@ const cardVariants: Variants = {
};
export default function PublicCollections() {
const { links } = useLinkStore();
const tagsInCollection = links.map(l => l.tags).flat();
const { links, allLinksOfCollection } = useLinkStore();
const tagsInCollection = allLinksOfCollection.map(l => l.tags).flat().filter((value, index, self) =>
index === self.findIndex((t) => (
t.name === value.name
)));
const { settings } = useLocalSettingsStore();
const router = useRouter();
@@ -101,7 +104,6 @@ export default function PublicCollections() {
const [collection, setCollection] =
useState<CollectionIncludingMembersAndLinkCount>();
useEffect(() => {
if (router.query.id) {
getPublicCollectionData(Number(router.query.id), setCollection);
@@ -132,6 +134,14 @@ export default function PublicCollections() {
[ViewMode.List]: ListView,
};
const [tagDisclosure, setTagDisclosure] = useState<boolean>(() => {
const storedValue = localStorage.getItem("tagDisclosureForPublicCollection" + collection?.id);
return storedValue ? storedValue === "true" : true;
});
useEffect(() => {
localStorage.setItem("tagDisclosureForPublicCollection" + collection?.id, tagDisclosure ? "true" : "false");
}, [tagDisclosure]);
// @ts-ignore
const LinkComponent = linkView[viewMode];
@@ -243,10 +253,31 @@ export default function PublicCollections() {
</div>
</div>
{collection.tagsArePublic && tagsInCollection[0] && (
<div>
<p className="text-sm">Browse by topic</p>
<div className="flex gap-2 mt-2 mb-6">
<button onClick={() => handleTagSelection(undefined)}>
<Disclosure defaultOpen={tagDisclosure}>
<Disclosure.Button
onClick={() => {
setTagDisclosure(!tagDisclosure);
}}
className="flex items-center justify-between w-full text-left mb-2 pl-2 font-bold text-neutral mt-5"
>
<p className="text-sm">Browse by topic</p>
<i
className={`bi-chevron-down ${
tagDisclosure ? "rotate-reverse" : "rotate"
}`}
></i>
</Disclosure.Button>
<Transition
enter="transition duration-100 ease-out"
enterFrom="transform opacity-0 -translate-y-3"
enterTo="transform opacity-100 translate-y-0"
leave="transition duration-100 ease-out"
leaveFrom="transform opacity-100 translate-y-0"
leaveTo="transform opacity-0 -translate-y-3"
>
<Disclosure.Panel>
<div className="flex gap-2 mt-2 mb-6 flex-wrap">
<button className="max-w-full" onClick={() => handleTagSelection(undefined)}>
<div
className="
bg-neutral-content/20 hover:bg-neutral/20 duration-100 py-1 px-2 cursor-pointer flex items-center gap-2 rounded-md h-8"
@@ -263,7 +294,7 @@ export default function PublicCollections() {
.map((e, i) => {
const active = router.query.q === e.name;
return (
<button key={i} onClick={() => handleTagSelection(e)}>
<button className="max-w-full" key={i} onClick={() => handleTagSelection(e)}>
<div
className={`
${
@@ -283,8 +314,9 @@ export default function PublicCollections() {
})
}
</div>
</div>
)}
</Disclosure.Panel>
</Transition>
</Disclosure>)}
{links[0] ? (
<LinkComponent
links={links
+4
View File
@@ -11,11 +11,13 @@ type ResponseObject = {
type LinkStore = {
links: LinkIncludingShortenedCollectionAndTags[];
selectedLinks: LinkIncludingShortenedCollectionAndTags[];
allLinksOfCollection: LinkIncludingShortenedCollectionAndTags[];
setLinks: (
data: LinkIncludingShortenedCollectionAndTags[],
isInitialCall: boolean
) => void;
setSelectedLinks: (links: LinkIncludingShortenedCollectionAndTags[]) => void;
setAllLinksOfCollection: (links: LinkIncludingShortenedCollectionAndTags[]) => void;
addLink: (
body: LinkIncludingShortenedCollectionAndTags
) => Promise<ResponseObject>;
@@ -39,6 +41,7 @@ type LinkStore = {
const useLinkStore = create<LinkStore>()((set) => ({
links: [],
selectedLinks: [],
allLinksOfCollection: [],
setLinks: async (data, isInitialCall) => {
isInitialCall &&
set(() => ({
@@ -58,6 +61,7 @@ const useLinkStore = create<LinkStore>()((set) => ({
}));
},
setSelectedLinks: (links) => set({ selectedLinks: links }),
setAllLinksOfCollection: (links) => set({allLinksOfCollection: links}),
addLink: async (body) => {
const response = await fetch("/api/v1/links", {
body: JSON.stringify(body),