feat(link): update useAddLink to accept additional parameters for improved error handling

This commit is contained in:
daniel31x13
2026-02-19 17:11:42 -05:00
parent c8b1129e4f
commit 389a96dadc
11 changed files with 43 additions and 99 deletions

View File

@@ -21,7 +21,7 @@ export default function IncomingScreen() {
const { auth } = useAuthStore();
const router = useRouter();
const { data, updateData } = useDataStore();
const addLink = useAddLink(auth);
const addLink = useAddLink({ auth });
const { colorScheme } = useColorScheme();
const [showSuccess, setShowSuccess] = useState(false);
const [link, setLink] = useState<LinkIncludingShortenedCollectionAndTags>();

View File

@@ -12,7 +12,7 @@ import { useSafeAreaInsets } from "react-native-safe-area-context";
export default function AddLinkSheet() {
const actionSheetRef = useRef<ActionSheetRef>(null);
const { auth } = useAuthStore();
const addLink = useAddLink(auth);
const addLink = useAddLink({ auth, Alert });
const [link, setLink] = useState("");
const { colorScheme } = useColorScheme();
@@ -43,21 +43,12 @@ export default function AddLinkSheet() {
/>
<Button
onPress={() =>
addLink.mutate(
{ url: link },
{
onSuccess: () => {
actionSheetRef.current?.hide();
setLink("");
},
onError: (error) => {
Alert.alert("Error", "There was an error adding the link.");
console.error("Error adding link:", error);
},
}
)
}
onPress={() => {
addLink.mutate({ url: link });
actionSheetRef.current?.hide();
setLink("");
}}
isLoading={addLink.isPending}
variant="accent"
className="mb-2"

View File

@@ -162,7 +162,7 @@ const Main = (props: SheetProps<"edit-link-sheet">) => {
const Collections = () => {
const { auth } = useAuthStore();
const addLink = useAddLink(auth);
const addLink = useAddLink({ auth });
const [searchQuery, setSearchQuery] = useState("");
const router = useSheetRouter("edit-link-sheet");
const { link: currentLink } = useSheetRouteParams<
@@ -270,7 +270,7 @@ const Collections = () => {
const Tags = () => {
const { auth } = useAuthStore();
const addLink = useAddLink(auth);
const addLink = useAddLink({ auth });
const [searchQuery, setSearchQuery] = useState("");
const router = useSheetRouter("edit-link-sheet");
const params = useSheetRouteParams("edit-link-sheet", "tags");

View File

@@ -50,6 +50,7 @@ const LinkListing = ({ link, dashboard }: Props) => {
const [url, setUrl] = useState("");
useEffect(() => {
console.log(link.url);
try {
if (link.url) {
setUrl(new URL(link.url).host.toLowerCase());
@@ -57,7 +58,7 @@ const LinkListing = ({ link, dashboard }: Props) => {
} catch (error) {
console.log(error);
}
}, [link]);
}, [link.url]);
return (
<ContextMenu.Root>
@@ -122,8 +123,8 @@ const LinkListing = ({ link, dashboard }: Props) => {
<View className="flex flex-row gap-1 items-center mt-1.5 pr-1.5 self-start rounded-md">
<Folder
size={16}
fill={link.collection.color || ""}
color={link.collection.color || ""}
fill={link.collection.color || "#0ea5e9"}
color={link.collection.color || "#0ea5e9"}
/>
<Text
numberOfLines={1}

View File

@@ -17,7 +17,7 @@ import {
import useOnScreen from "@/hooks/useOnScreen";
import { useCollections } from "@linkwarden/router/collections";
import { useUser } from "@linkwarden/router/user";
import { useGetLink, useLinks } from "@linkwarden/router/links";
import { useGetLink } from "@linkwarden/router/links";
import { useRouter } from "next/router";
import openLink from "@/lib/client/openLink";
import LinkIcon from "./LinkViews/LinkComponents/LinkIcon";
@@ -82,8 +82,6 @@ export function Card({ link, editMode, dashboardType }: Props) {
settings: { show },
} = useLocalSettingsStore();
const { links } = useLinks();
const router = useRouter();
const isPublicRoute = router.pathname.startsWith("/public") ? true : false;
@@ -102,7 +100,7 @@ export function Card({ link, editMode, dashboardType }: Props) {
(e) => e.id === link.collection.id
) as CollectionIncludingMembersAndLinkCount
);
}, [collections, links]);
}, [collections, link]);
const ref = useRef<HTMLDivElement>(null);
const isVisible = useOnScreen(ref);

View File

@@ -13,8 +13,6 @@ import {
DropdownMenuItem,
} from "@/components/ui/dropdown-menu";
import { Button } from "./ui/button";
import { useAddLink } from "@linkwarden/router/links";
import toast from "react-hot-toast";
type Props = {};
@@ -24,20 +22,6 @@ export default function MobileNavigation({}: Props) {
const [newCollectionModal, setNewCollectionModal] = useState(false);
const [uploadFileModal, setUploadFileModal] = useState(false);
const addLink = useAddLink();
const submitLink = (link: any) => {
addLink.mutateAsync(link, {
onSettled: (data, error) => {
if (error) {
toast.error(t(error.message));
} else {
toast.success(t("link_created"));
}
},
});
};
return (
<>
<div
@@ -87,7 +71,6 @@ export default function MobileNavigation({}: Props) {
onClose={() => {
setNewLinkModal(false);
}}
onSubmit={submitLink}
/>
)}
{newCollectionModal && (

View File

@@ -14,13 +14,13 @@ import {
} from "@linkwarden/lib/schemaValidation";
import { Button } from "@/components/ui/button";
import { Separator } from "../ui/separator";
import { useAddLink } from "@linkwarden/router/links";
type Props = {
onClose: () => void;
onSubmit: Function;
};
export default function NewLinkModal({ onClose, onSubmit }: Props) {
export default function NewLinkModal({ onClose }: Props) {
const { t } = useTranslation();
const initial = {
name: "",
@@ -34,6 +34,11 @@ export default function NewLinkModal({ onClose, onSubmit }: Props) {
},
} as PostLinkSchemaType;
const addLink = useAddLink({
toast,
t,
});
const inputRef = useRef<HTMLInputElement>(null);
const [link, setLink] = useState<PostLinkSchemaType>(initial);
const [optionsExpanded, setOptionsExpanded] = useState(false);
@@ -90,7 +95,7 @@ export default function NewLinkModal({ onClose, onSubmit }: Props) {
} [${dataValidation.error.issues[0].path.join(", ")}]`
);
onSubmit(link);
addLink.mutateAsync(link);
onClose();
};

View File

@@ -28,8 +28,6 @@ import { useUser } from "@linkwarden/router/user";
import Link from "next/link";
import SettingsSidebar from "@/components/SettingsSidebar";
import AdminSidebar from "@/components/AdminSidebar";
import { useAddLink } from "@linkwarden/router/links";
import toast from "react-hot-toast";
const STRIPE_ENABLED = process.env.NEXT_PUBLIC_STRIPE === "true";
const TRIAL_PERIOD_DAYS =
@@ -89,20 +87,6 @@ export default function Navbar({
setIsTrialing(Boolean(isTrialing));
}, [user, daysLeft]);
const addLink = useAddLink();
const submitLink = (link: any) => {
addLink.mutateAsync(link, {
onSettled: (data, error) => {
if (error) {
toast.error(t(error.message));
} else {
toast.success(t("link_created"));
}
},
});
};
return (
<>
{STRIPE_ENABLED && isTrialing && (
@@ -202,7 +186,6 @@ export default function Navbar({
onClose={() => {
setNewLinkModal(false);
}}
onSubmit={submitLink}
/>
)}
{newCollectionModal && (

View File

@@ -2,8 +2,6 @@ import React, { useState } from "react";
import NewLinkModal from "./ModalContent/NewLinkModal";
import { useTranslation } from "next-i18next";
import { Button } from "./ui/button";
import { useAddLink } from "@linkwarden/router/links";
import toast from "react-hot-toast";
type Props = {
text?: string;
@@ -13,20 +11,6 @@ export default function NoLinksFound({ text }: Props) {
const { t } = useTranslation();
const [newLinkModal, setNewLinkModal] = useState(false);
const addLink = useAddLink();
const submitLink = (link: any) => {
addLink.mutateAsync(link, {
onSettled: (data, error) => {
if (error) {
toast.error(t(error.message));
} else {
toast.success(t("link_created"));
}
},
});
};
return (
<div className="w-full h-full flex flex-col justify-center p-3">
<svg
@@ -61,7 +45,6 @@ export default function NoLinksFound({ text }: Props) {
onClose={() => {
setNewLinkModal(false);
}}
onSubmit={submitLink}
/>
)}
</div>

View File

@@ -26,7 +26,6 @@ import ViewDropdown from "@/components/ViewDropdown";
import clsx from "clsx";
import Icon from "@/components/Icon";
import Droppable from "@/components/Droppable";
import { useAddLink, useUpdateLink } from "@linkwarden/router/links";
import { NextPageWithLayout } from "./_app";
const Page: NextPageWithLayout = () => {
@@ -95,7 +94,6 @@ const Page: NextPageWithLayout = () => {
const [showSurveyModal, setShowsSurveyModal] = useState(false);
const updateUser = useUpdateUser();
const updateLink = useUpdateLink();
const [submitLoader, setSubmitLoader] = useState(false);
@@ -129,20 +127,6 @@ const Page: NextPageWithLayout = () => {
);
};
const addLink = useAddLink();
const submitLink = (link: any) => {
addLink.mutateAsync(link, {
onSettled: (data, error) => {
if (error) {
toast.error(t(error.message));
} else {
toast.success(t("link_created"));
}
},
});
};
return (
<>
<div className="p-5 flex flex-col gap-4">
@@ -211,7 +195,6 @@ const Page: NextPageWithLayout = () => {
onClose={() => {
setNewLinkModal(false);
}}
onSubmit={submitLink}
/>
)}
</>

View File

@@ -19,6 +19,9 @@ import {
} from "@linkwarden/lib/schemaValidation";
import getFormatFromContentType from "@linkwarden/lib/getFormatFromContentType";
import getLinkTypeFromFormat from "@linkwarden/lib/getLinkTypeFromFormat";
import type toaster from "react-hot-toast";
import { TFunction } from "next-i18next";
import type { Alert as Alert_ } from "react-native";
const useLinks = (params: LinkRequestQuery = {}, auth?: MobileAuth) => {
const sort =
@@ -190,7 +193,17 @@ const upsertLinkInDashboardData = (
};
};
const useAddLink = (auth?: MobileAuth) => {
const useAddLink = ({
auth,
Alert,
toast,
t,
}: {
auth?: MobileAuth;
Alert?: typeof Alert_;
toast?: typeof toaster;
t?: TFunction;
}) => {
const queryClient = useQueryClient();
return useMutation({
@@ -314,7 +327,11 @@ const useAddLink = (auth?: MobileAuth) => {
optimisticId: tempId,
};
},
onError: (_error, _variables, context) => {
onError: (error, _variables, context) => {
if (toast && t) toast.error(t(error.message));
else if (Alert)
Alert.alert("Error", "There was an error adding the link.");
if (!context) return;
context.previousLinks?.forEach(([queryKey, data]: [unknown, unknown]) => {