From 1c9b32a6be6ba0a3a2ab27f0718c4c5ccd00d3f8 Mon Sep 17 00:00:00 2001 From: Andrew Moscardino Date: Wed, 12 Jul 2023 13:24:32 -0400 Subject: [PATCH 1/2] Fixed tag group sorting. Closes #32 --- package.json | 2 +- src/hooks/useGroupedTags.ts | 21 +++++++++++++-------- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/package.json b/package.json index 783a014..35ab136 100644 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ }, "scripts": { "serve": "ionic serve", - "local-cors-proxy": "lcp --proxyUrl 'http://linkding.me' --proxyPartial ''", + "local-cors-proxy": "lcp --proxyUrl 'https://linkding.moscardino.synology.me' --proxyPartial ''", "build": "ionic build", "ios:build": "ionic cap sync ios", "ios:run": "ionic cap run ios -l", diff --git a/src/hooks/useGroupedTags.ts b/src/hooks/useGroupedTags.ts index 8ec9ddc..59f1573 100644 --- a/src/hooks/useGroupedTags.ts +++ b/src/hooks/useGroupedTags.ts @@ -13,16 +13,21 @@ interface UseGroupedTagsResult extends QueryResult { const useGroupedTags = (): UseGroupedTagsResult => { const { tags, isSuccess, isLoading, isError } = useTags(); - const groups = tags.reduce((groups: TagGroup[], tag: string) => { - const groupName = /[A-Z]/i.test(tag[0]) ? tag[0].toUpperCase() : '#'; - const existingGroups = groups.filter(g => g.name === groupName); + const groups = tags + .reduce((groups: TagGroup[], tag: string) => { + const groupName = /[A-Z]/.test(tag[0].toUpperCase()) ? tag[0].toUpperCase() : '#'; + const existingGroups = groups.filter(g => g.name === groupName); - if (!existingGroups.length) - return [...groups, { name: groupName, tags: [tag] }]; + if (!existingGroups.length) + return [...groups, { name: groupName, tags: [tag] }]; - existingGroups[0].tags.push(tag); - return [...groups]; - }, [] as TagGroup[]); + existingGroups[0].tags.push(tag); + return [...groups]; + }, [] as TagGroup[]) + .sort((a, b) => a.name === "#" ? -1 : a.name.localeCompare(b.name)); + + for (let group of groups) + group.tags.sort((a, b) => a.localeCompare(b)); return { groups, From 747eac00afec9ed5419f1933da27c75d412be063 Mon Sep 17 00:00:00 2001 From: Andrew Moscardino Date: Wed, 12 Jul 2023 13:55:15 -0400 Subject: [PATCH 2/2] Added ability to delete bookmarks. Closes #31 --- src/api/linkdigApi.ts | 18 +++++++++++++++++ src/hooks/useBookmark.ts | 11 ++++++++-- src/pages/AddPage.tsx | 4 ++-- src/pages/EditPage.tsx | 43 ++++++++++++++++++++++++++++++++++++---- 4 files changed, 68 insertions(+), 8 deletions(-) diff --git a/src/api/linkdigApi.ts b/src/api/linkdigApi.ts index 901f4ef..9808791 100644 --- a/src/api/linkdigApi.ts +++ b/src/api/linkdigApi.ts @@ -153,6 +153,23 @@ const updateBookmarkRead = async (id: number): Promise => { }); }; +const deleteBookmark = async (id: number): Promise => { + const settings = await getSettings(); + + if (settings.instanceUrl === undefined || settings.token === undefined) + throw new Error('Missing Linkdig settings. Please provide them from the Settings page.'); + + const url = new URL(`api/bookmarks/${id}/`, settings.instanceUrl); + + await CapacitorHttp.delete({ + url: url.toString(), + headers: { + 'Authorization': `Token ${settings.token}`, + 'Content-Type': 'application/json' + } + }); +}; + const getTags = async (): Promise => { const settings = await getSettings(); @@ -184,5 +201,6 @@ export { createBookmark, updateBookmark, updateBookmarkRead, + deleteBookmark, getTags }; diff --git a/src/hooks/useBookmark.ts b/src/hooks/useBookmark.ts index 8f97d6e..563999a 100644 --- a/src/hooks/useBookmark.ts +++ b/src/hooks/useBookmark.ts @@ -1,12 +1,13 @@ import { SetStateAction, useEffect, useState } from "react"; import Bookmark from "api/types/bookmark"; -import { getBookmark, updateBookmark } from "api/linkdigApi"; +import { deleteBookmark, getBookmark, updateBookmark } from "api/linkdigApi"; import { useQueryClient } from "@tanstack/react-query"; interface UseBookmarkResult { bookmark: Bookmark; setBookmark: (value: SetStateAction) => void; saveBookmark: () => Promise; + removeBookmark: () => Promise; } const useBookmark = (id: number): UseBookmarkResult => { @@ -27,10 +28,16 @@ const useBookmark = (id: number): UseBookmarkResult => { await queryClient.invalidateQueries(); }; + const removeBookmark = async (): Promise => { + await deleteBookmark(bookmark.id); + await queryClient.invalidateQueries(); + }; + return { bookmark, setBookmark, - saveBookmark + saveBookmark, + removeBookmark }; }; diff --git a/src/pages/AddPage.tsx b/src/pages/AddPage.tsx index 34149db..39e6efa 100644 --- a/src/pages/AddPage.tsx +++ b/src/pages/AddPage.tsx @@ -83,14 +83,14 @@ const AddPage = ({ dismiss }: AddPageProps) => { secondaryButton={closeButton} > - + setBookmark(prev => ({ ...prev, url: e.target.value || '' } as Bookmark))} - errorText={isExistingBookmark ? "It looks like this URL matches an existing bookmark. If you save this URL again, it will update the older bookmark." : undefined} + helperText={isExistingBookmark ? "It looks like this URL matches an existing bookmark. If you save this URL again, it will update the older bookmark." : undefined} /> diff --git a/src/pages/EditPage.tsx b/src/pages/EditPage.tsx index c6af337..fd11c55 100644 --- a/src/pages/EditPage.tsx +++ b/src/pages/EditPage.tsx @@ -7,11 +7,12 @@ import { IonList, IonTextarea, IonToggle, + useIonAlert, useIonModal } from "@ionic/react"; -import { checkmarkOutline, closeOutline, pricetagOutline } from "ionicons/icons"; +import { checkmarkOutline, closeOutline, pricetagOutline, trashOutline } from "ionicons/icons"; import StandardPage from "components/StandardPage"; -import { tapMedium } from "utils/haptics"; +import { tapHeavy, tapMedium } from "utils/haptics"; import useBookmark from "hooks/useBookmark"; import Bookmark from "api/types/bookmark"; import Footer from "components/Footer"; @@ -24,8 +25,9 @@ interface EditPageProps { } const EditPage = ({ id, dismiss }: EditPageProps) => { - const { bookmark, setBookmark, saveBookmark } = useBookmark(id); + const { bookmark, setBookmark, saveBookmark, removeBookmark } = useBookmark(id); const pageRef = useRef(null); + const [showDeleteAlert] = useIonAlert(); const handleTagDismiss = (newTags: string[] | null) => { if (newTags !== null) @@ -50,6 +52,25 @@ const EditPage = ({ id, dismiss }: EditPageProps) => { dismiss(true); }; + const handleDeleteButton = async () => { + await showDeleteAlert({ + header: "Delete Bookmark?", + message: "Are you sure you want to delete this bookmark? This is a permanent action.", + buttons: [{ + text: 'Cancel', + role: 'cancel' + }, { + text: "Delete", + role: "destructive", + handler: async () => { + await removeBookmark(); + await tapHeavy(); + dismiss(true); + } + }] + }) + }; + const closeButton = ( @@ -124,7 +145,7 @@ const EditPage = ({ id, dismiss }: EditPageProps) => { /> - + Unread? @@ -136,6 +157,20 @@ const EditPage = ({ id, dismiss }: EditPageProps) => { /> + + + + + Delete + + + +