diff --git a/components/FilterSearchDropdown.tsx b/components/FilterSearchDropdown.tsx index b7e1758..e9fc001 100644 --- a/components/FilterSearchDropdown.tsx +++ b/components/FilterSearchDropdown.tsx @@ -8,7 +8,7 @@ type Props = { searchFilter: { name: boolean; url: boolean; - title: boolean; + description: boolean; collection: boolean; tags: boolean; }; @@ -44,10 +44,13 @@ export default function FilterSearchDropdown({ } /> - setSearchFilter({ ...searchFilter, title: !searchFilter.title }) + setSearchFilter({ + ...searchFilter, + description: !searchFilter.description, + }) } />

- {link.title} + {link.description}

diff --git a/components/Modal/LinkModal.tsx b/components/Modal/LinkModal.tsx index 74e5db5..d3f24b7 100644 --- a/components/Modal/LinkModal.tsx +++ b/components/Modal/LinkModal.tsx @@ -36,7 +36,7 @@ export default function EditLink({ : { name: "", url: "", - title: "", + description: "", tags: [], collection: { name: "", @@ -106,7 +106,7 @@ export default function EditLink({ {method === "UPDATE" ? (

- {shortendURL} | {link.title} + {shortendURL} | {link.description}

) : null} diff --git a/components/PublicPage/LinkCard.tsx b/components/PublicPage/LinkCard.tsx index a71b04f..70bb112 100644 --- a/components/PublicPage/LinkCard.tsx +++ b/components/PublicPage/LinkCard.tsx @@ -55,7 +55,9 @@ export default function LinkCard({ link, count }: Props) {

{link.name}

-

{link.title}

+

+ {link.description} +

{formattedDate}

diff --git a/components/SortLinkDropdown.tsx b/components/SortDropdown.tsx similarity index 65% rename from components/SortLinkDropdown.tsx rename to components/SortDropdown.tsx index 145355f..6ae3a36 100644 --- a/components/SortLinkDropdown.tsx +++ b/components/SortDropdown.tsx @@ -1,18 +1,19 @@ -import React, { ChangeEvent } from "react"; +import React, { Dispatch, SetStateAction } from "react"; import ClickAwayHandler from "./ClickAwayHandler"; import RadioButton from "./RadioButton"; import { Sort } from "@/types/global"; type Props = { - handleSortChange: (e: Sort) => void; sortBy: Sort; + setSort: Dispatch>; + toggleSortDropdown: Function; }; -export default function SortLinkDropdown({ - handleSortChange, +export default function SortDropdown({ sortBy, toggleSortDropdown, + setSort, }: Props) { return ( handleSortChange(Sort.NameAZ)} + onClick={() => setSort(Sort.NameAZ)} /> handleSortChange(Sort.NameZA)} + onClick={() => setSort(Sort.NameZA)} /> handleSortChange(Sort.TitleAZ)} + label="Description (A-Z)" + state={sortBy === Sort.DescriptionAZ} + onClick={() => setSort(Sort.DescriptionAZ)} /> handleSortChange(Sort.TitleZA)} + label="Description (Z-A)" + state={sortBy === Sort.DescriptionZA} + onClick={() => setSort(Sort.DescriptionZA)} /> handleSortChange(Sort.DateNewestFirst)} + onClick={() => setSort(Sort.DateNewestFirst)} /> handleSortChange(Sort.DateOldestFirst)} + onClick={() => setSort(Sort.DateOldestFirst)} />
diff --git a/hooks/useSort.tsx b/hooks/useSort.tsx new file mode 100644 index 0000000..38893e5 --- /dev/null +++ b/hooks/useSort.tsx @@ -0,0 +1,52 @@ +import { + CollectionIncludingMembers, + LinkIncludingCollectionAndTags, + Sort, +} from "@/types/global"; +import { SetStateAction, useEffect } from "react"; + +type Props< + T extends CollectionIncludingMembers | LinkIncludingCollectionAndTags +> = { + sortBy: Sort; + + data: T[]; + setData: (value: SetStateAction) => void; +}; + +export default function useSort< + T extends CollectionIncludingMembers | LinkIncludingCollectionAndTags +>({ sortBy, data, setData }: Props) { + useEffect(() => { + const dataArray = [...data]; + + 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( + (a, b) => + new Date(b.createdAt as string).getTime() - + new Date(a.createdAt as string).getTime() + ) + ); + else if (sortBy === Sort.DateOldestFirst) + setData( + dataArray.sort( + (a, b) => + new Date(a.createdAt as string).getTime() - + new Date(b.createdAt as string).getTime() + ) + ); + }, [sortBy, data]); +} diff --git a/lib/api/controllers/links/postLink.ts b/lib/api/controllers/links/postLink.ts index d518595..37d2ad1 100644 --- a/lib/api/controllers/links/postLink.ts +++ b/lib/api/controllers/links/postLink.ts @@ -72,7 +72,7 @@ export default async function postLink( }, })), }, - title, + description: title, }, include: { tags: true, collection: true }, }); diff --git a/lib/api/controllers/public/getCollection.ts b/lib/api/controllers/public/getCollection.ts index 7a73aa4..b68610a 100644 --- a/lib/api/controllers/public/getCollection.ts +++ b/lib/api/controllers/public/getCollection.ts @@ -14,7 +14,7 @@ export default async function getCollection(collectionId: number) { id: true, name: true, url: true, - title: true, + description: true, collectionId: true, createdAt: true, }, diff --git a/pages/collections/[id].tsx b/pages/collections/[id].tsx index 288f605..95c3f96 100644 --- a/pages/collections/[id].tsx +++ b/pages/collections/[id].tsx @@ -14,8 +14,9 @@ import { useEffect, useState } from "react"; import MainLayout from "@/layouts/MainLayout"; import { useSession } from "next-auth/react"; import ProfilePhoto from "@/components/ProfilePhoto"; -import SortLinkDropdown from "@/components/SortLinkDropdown"; +import SortDropdown from "@/components/SortDropdown"; import useModalStore from "@/store/modals"; +import useSort from "@/hooks/useSort"; export default function Index() { const { setModal } = useModalStore(); @@ -36,46 +37,13 @@ export default function Index() { const [sortedLinks, setSortedLinks] = useState(links); - const handleSortChange = (e: Sort) => { - setSortBy(e); - }; + useSort({ sortBy, setData: setSortedLinks, data: links }); useEffect(() => { setActiveCollection( collections.find((e) => e.id === Number(router.query.id)) ); - - // Sorting logic - - const linksArray = [ - ...links.filter((e) => e.collection.id === Number(router.query.id)), - ]; - - if (sortBy === Sort.NameAZ) - setSortedLinks(linksArray.sort((a, b) => a.name.localeCompare(b.name))); - else if (sortBy === Sort.TitleAZ) - setSortedLinks(linksArray.sort((a, b) => a.title.localeCompare(b.title))); - else if (sortBy === Sort.NameZA) - setSortedLinks(linksArray.sort((a, b) => b.name.localeCompare(a.name))); - else if (sortBy === Sort.TitleZA) - setSortedLinks(linksArray.sort((a, b) => b.title.localeCompare(a.title))); - else if (sortBy === Sort.DateNewestFirst) - setSortedLinks( - linksArray.sort( - (a, b) => - new Date(b.createdAt as string).getTime() - - new Date(a.createdAt as string).getTime() - ) - ); - else if (sortBy === Sort.DateOldestFirst) - setSortedLinks( - linksArray.sort( - (a, b) => - new Date(a.createdAt as string).getTime() - - new Date(b.createdAt as string).getTime() - ) - ); - }, [links, router, collections, sortBy]); + }, [router, collections]); return ( @@ -166,9 +134,9 @@ export default function Index() { {sortDropdown ? ( - setSortDropdown(!sortDropdown)} /> ) : null} diff --git a/pages/collections/index.tsx b/pages/collections/index.tsx index 3c81f78..a5c1e8f 100644 --- a/pages/collections/index.tsx +++ b/pages/collections/index.tsx @@ -8,68 +8,26 @@ import { import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import CollectionCard from "@/components/CollectionCard"; import Dropdown from "@/components/Dropdown"; -import { ChangeEvent, useEffect, useState } from "react"; +import { useState } from "react"; import MainLayout from "@/layouts/MainLayout"; -import ClickAwayHandler from "@/components/ClickAwayHandler"; -import RadioButton from "@/components/RadioButton"; import { useSession } from "next-auth/react"; import useModalStore from "@/store/modals"; +import SortDropdown from "@/components/SortDropdown"; +import { Sort } from "@/types/global"; +import useSort from "@/hooks/useSort"; export default function Collections() { const { collections } = useCollectionStore(); const [expandDropdown, setExpandDropdown] = useState(false); const [sortDropdown, setSortDropdown] = useState(false); - const [sortBy, setSortBy] = useState("Name (A-Z)"); + const [sortBy, setSortBy] = useState(Sort.NameAZ); const [sortedCollections, setSortedCollections] = useState(collections); const session = useSession(); const { setModal } = useModalStore(); - const handleSortChange = (event: ChangeEvent) => { - setSortBy(event.target.value); - }; - - useEffect(() => { - const collectionsArray = [...collections]; - - if (sortBy === "Name (A-Z)") - setSortedCollections( - collectionsArray.sort((a, b) => a.name.localeCompare(b.name)) - ); - else if (sortBy === "Description (A-Z)") - setSortedCollections( - collectionsArray.sort((a, b) => - a.description.localeCompare(b.description) - ) - ); - else if (sortBy === "Name (Z-A)") - setSortedCollections( - collectionsArray.sort((a, b) => b.name.localeCompare(a.name)) - ); - else if (sortBy === "Description (Z-A)") - setSortedCollections( - collectionsArray.sort((a, b) => - b.description.localeCompare(a.description) - ) - ); - else if (sortBy === "Date (Newest First)") - setSortedCollections( - collectionsArray.sort( - (a, b) => - new Date(b.createdAt as string).getTime() - - new Date(a.createdAt as string).getTime() - ) - ); - else if (sortBy === "Date (Oldest First)") - setSortedCollections( - collectionsArray.sort( - (a, b) => - new Date(a.createdAt as string).getTime() - - new Date(b.createdAt as string).getTime() - ) - ); - }, [collections, sortBy]); + useSort({ sortBy, setData: setSortedCollections, data: collections }); return ( @@ -146,54 +104,11 @@ export default function Collections() { {sortDropdown ? ( - { - const target = e.target as HTMLInputElement; - if (target.id !== "sort-dropdown") setSortDropdown(false); - }} - className="absolute top-8 right-0 shadow-md bg-gray-50 rounded-md p-2 z-10 border border-sky-100 w-48" - > -

- Sort by -

-
- - - - - - - - - - - -
-
+ setSortDropdown(!sortDropdown)} + /> ) : null} diff --git a/pages/links.tsx b/pages/links.tsx index 992184a..9ebcc58 100644 --- a/pages/links.tsx +++ b/pages/links.tsx @@ -1,11 +1,12 @@ import LinkCard from "@/components/LinkCard"; -import SortLinkDropdown from "@/components/SortLinkDropdown"; +import SortDropdown from "@/components/SortDropdown"; +import useSort from "@/hooks/useSort"; import MainLayout from "@/layouts/MainLayout"; import useLinkStore from "@/store/links"; import { Sort } from "@/types/global"; import { faLink, faSort } from "@fortawesome/free-solid-svg-icons"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -import { ChangeEvent, useEffect, useState } from "react"; +import { useState } from "react"; export default function Links() { const { links } = useLinkStore(); @@ -14,38 +15,7 @@ export default function Links() { const [sortBy, setSortBy] = useState(Sort.NameAZ); const [sortedLinks, setSortedLinks] = useState(links); - const handleSortChange = (e: Sort) => { - setSortBy(e); - }; - - useEffect(() => { - const linksArray = [...links]; - - if (sortBy === Sort.NameAZ) - setSortedLinks(linksArray.sort((a, b) => a.name.localeCompare(b.name))); - else if (sortBy === Sort.TitleAZ) - setSortedLinks(linksArray.sort((a, b) => a.title.localeCompare(b.title))); - else if (sortBy === Sort.NameZA) - setSortedLinks(linksArray.sort((a, b) => b.name.localeCompare(a.name))); - else if (sortBy === Sort.TitleZA) - setSortedLinks(linksArray.sort((a, b) => b.title.localeCompare(a.title))); - else if (sortBy === Sort.DateNewestFirst) - setSortedLinks( - linksArray.sort( - (a, b) => - new Date(b.createdAt as string).getTime() - - new Date(a.createdAt as string).getTime() - ) - ); - else if (sortBy === Sort.DateOldestFirst) - setSortedLinks( - linksArray.sort( - (a, b) => - new Date(a.createdAt as string).getTime() - - new Date(b.createdAt as string).getTime() - ) - ); - }, [links, sortBy]); + useSort({ sortBy, setData: setSortedLinks, data: links }); return ( @@ -75,9 +45,9 @@ export default function Links() { {sortDropdown ? ( - setSortDropdown(!sortDropdown)} /> ) : null} diff --git a/pages/search/[query].tsx b/pages/search/[query].tsx index fce1a47..98c1e7b 100644 --- a/pages/search/[query].tsx +++ b/pages/search/[query].tsx @@ -1,18 +1,19 @@ import FilterSearchDropdown from "@/components/FilterSearchDropdown"; import LinkCard from "@/components/LinkCard"; -import SortLinkDropdown from "@/components/SortLinkDropdown"; +import SortDropdown from "@/components/SortDropdown"; +import useSort from "@/hooks/useSort"; import MainLayout from "@/layouts/MainLayout"; import useLinkStore from "@/store/links"; import { Sort } from "@/types/global"; import { faFilter, faSearch, faSort } from "@fortawesome/free-solid-svg-icons"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { useRouter } from "next/router"; -import { ChangeEvent, useEffect, useState } from "react"; +import { useEffect, useState } from "react"; type SearchFilter = { name: boolean; url: boolean; - title: boolean; + description: boolean; collection: boolean; tags: boolean; }; @@ -29,7 +30,7 @@ export default function Links() { const [searchFilter, setSearchFilter] = useState({ name: true, url: true, - title: true, + description: true, collection: true, tags: true, }); @@ -37,20 +38,20 @@ export default function Links() { const [filterDropdown, setFilterDropdown] = useState(false); const [sortDropdown, setSortDropdown] = useState(false); const [sortBy, setSortBy] = useState(Sort.NameAZ); - const [sortedLinks, setSortedLinks] = useState(links); - const handleSortChange = (e: Sort) => { - setSortBy(e); - }; + const [filteredLinks, setFilteredLinks] = useState(links); + const [sortedLinks, setSortedLinks] = useState(filteredLinks); + + useSort({ sortBy, setData: setSortedLinks, data: links }); useEffect(() => { - const linksArray = [ - ...links.filter((link) => { + setFilteredLinks([ + ...sortedLinks.filter((link) => { if ( (searchFilter.name && link.name.toLowerCase().includes(routeQuery)) || (searchFilter.url && link.url.toLowerCase().includes(routeQuery)) || - (searchFilter.title && - link.title.toLowerCase().includes(routeQuery)) || + (searchFilter.description && + link.description.toLowerCase().includes(routeQuery)) || (searchFilter.collection && link.collection.name.toLowerCase().includes(routeQuery)) || (searchFilter.tags && @@ -60,33 +61,8 @@ export default function Links() { ) return true; }), - ]; - - if (sortBy === Sort.NameAZ) - setSortedLinks(linksArray.sort((a, b) => a.name.localeCompare(b.name))); - else if (sortBy === Sort.TitleAZ) - setSortedLinks(linksArray.sort((a, b) => a.title.localeCompare(b.title))); - else if (sortBy === Sort.NameZA) - setSortedLinks(linksArray.sort((a, b) => b.name.localeCompare(a.name))); - else if (sortBy === Sort.TitleZA) - setSortedLinks(linksArray.sort((a, b) => b.title.localeCompare(a.title))); - else if (sortBy === Sort.DateNewestFirst) - setSortedLinks( - linksArray.sort( - (a, b) => - new Date(b.createdAt as string).getTime() - - new Date(a.createdAt as string).getTime() - ) - ); - else if (sortBy === Sort.DateOldestFirst) - setSortedLinks( - linksArray.sort( - (a, b) => - new Date(a.createdAt as string).getTime() - - new Date(b.createdAt as string).getTime() - ) - ); - }, [links, searchFilter, sortBy, router]); + ]); + }, [searchFilter, sortedLinks, router]); return ( @@ -141,17 +117,17 @@ export default function Links() { {sortDropdown ? ( - setSortDropdown(!sortDropdown)} /> ) : null} - {sortedLinks[0] ? ( - sortedLinks.map((e, i) => { + {filteredLinks[0] ? ( + filteredLinks.map((e, i) => { return ; }) ) : ( diff --git a/pages/tags/[id].tsx b/pages/tags/[id].tsx index 190876c..0cf913a 100644 --- a/pages/tags/[id].tsx +++ b/pages/tags/[id].tsx @@ -3,12 +3,13 @@ import useLinkStore from "@/store/links"; import { faHashtag, faSort } from "@fortawesome/free-solid-svg-icons"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { useRouter } from "next/router"; -import { ChangeEvent, useEffect, useState } from "react"; +import { useEffect, useState } from "react"; import MainLayout from "@/layouts/MainLayout"; import { Tag } from "@prisma/client"; import useTagStore from "@/store/tags"; -import SortLinkDropdown from "@/components/SortLinkDropdown"; +import SortDropdown from "@/components/SortDropdown"; import { Sort } from "@/types/global"; +import useSort from "@/hooks/useSort"; export default function Index() { const router = useRouter(); @@ -23,46 +24,11 @@ export default function Index() { const [sortedLinks, setSortedLinks] = useState(links); - const handleSortChange = (e: Sort) => { - setSortBy(e); - }; + useSort({ sortBy, setData: setSortedLinks, data: links }); useEffect(() => { setActiveTag(tags.find((e) => e.id === Number(router.query.id))); - - // Sorting logic - - const linksArray = [ - ...links.filter((e) => - e.tags.some((e) => e.id === Number(router.query.id)) - ), - ]; - - if (sortBy === Sort.NameAZ) - setSortedLinks(linksArray.sort((a, b) => a.name.localeCompare(b.name))); - else if (sortBy === Sort.TitleAZ) - setSortedLinks(linksArray.sort((a, b) => a.title.localeCompare(b.title))); - else if (sortBy === Sort.NameZA) - setSortedLinks(linksArray.sort((a, b) => b.name.localeCompare(a.name))); - else if (sortBy === Sort.TitleZA) - setSortedLinks(linksArray.sort((a, b) => b.title.localeCompare(a.title))); - else if (sortBy === Sort.DateNewestFirst) - setSortedLinks( - linksArray.sort( - (a, b) => - new Date(b.createdAt as string).getTime() - - new Date(a.createdAt as string).getTime() - ) - ); - else if (sortBy === Sort.DateOldestFirst) - setSortedLinks( - linksArray.sort( - (a, b) => - new Date(a.createdAt as string).getTime() - - new Date(b.createdAt as string).getTime() - ) - ); - }, [links, router, tags, sortBy]); + }, [router, tags]); return ( @@ -94,9 +60,9 @@ export default function Index() { {sortDropdown ? ( - setSortDropdown(!sortDropdown)} /> ) : null} diff --git a/prisma/migrations/20230613191848_init/migration.sql b/prisma/migrations/20230614043921_init/migration.sql similarity index 98% rename from prisma/migrations/20230613191848_init/migration.sql rename to prisma/migrations/20230614043921_init/migration.sql index e882db8..989f508 100644 --- a/prisma/migrations/20230613191848_init/migration.sql +++ b/prisma/migrations/20230614043921_init/migration.sql @@ -40,7 +40,7 @@ CREATE TABLE "Link" ( "id" SERIAL NOT NULL, "name" TEXT NOT NULL, "url" TEXT NOT NULL, - "title" TEXT NOT NULL, + "description" TEXT NOT NULL DEFAULT '', "collectionId" INTEGER NOT NULL, "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 4607fad..83e289c 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -58,7 +58,7 @@ model Link { id Int @id @default(autoincrement()) name String url String - title String + description String @default("") pinnedBy User[] diff --git a/types/global.ts b/types/global.ts index 8e73d47..a0b9b96 100644 --- a/types/global.ts +++ b/types/global.ts @@ -46,8 +46,8 @@ export interface PublicCollectionIncludingLinks export enum Sort { NameAZ, NameZA, - TitleAZ, - TitleZA, + DescriptionAZ, + DescriptionZA, DateNewestFirst, DateOldestFirst, }