import MainLayout from "@/layouts/MainLayout"; import { useEffect, useMemo, useState } from "react"; import Link from "next/link"; import React from "react"; import { toast } from "react-hot-toast"; import { MigrationFormat, MigrationRequest, ViewMode } from "@/types/global"; import DashboardItem from "@/components/DashboardItem"; import NewLinkModal from "@/components/ModalContent/NewLinkModal"; import PageHeader from "@/components/PageHeader"; import ViewDropdown from "@/components/ViewDropdown"; import { dropdownTriggerer } from "@/lib/client/utils"; import getServerSideProps from "@/lib/client/getServerSideProps"; import { useTranslation } from "next-i18next"; import { useCollections } from "@/hooks/store/collections"; import { useTags } from "@/hooks/store/tags"; import { useDashboardData } from "@/hooks/store/dashboardData"; import Links from "@/components/LinkViews/Links"; import useLocalSettingsStore from "@/store/localSettings"; import { useUpdateUser, useUser } from "@/hooks/store/user"; import SurveyModal from "@/components/ModalContent/SurveyModal"; export default function Dashboard() { const { t } = useTranslation(); const { data: collections = [] } = useCollections(); const { data: { links = [], numberOfPinnedLinks } = { links: [] }, ...dashboardData } = useDashboardData(); const { data: tags = [] } = useTags(); const { data: account = [] } = useUser(); const [numberOfLinks, setNumberOfLinks] = useState(0); const { settings } = useLocalSettingsStore(); useEffect(() => { setNumberOfLinks( collections.reduce( (accumulator, collection) => accumulator + (collection._count as any).links, 0 ) ); }, [collections]); useEffect(() => { if ( process.env.NEXT_PUBLIC_STRIPE === "true" && account && account.id && account.referredBy === null && // if user is using Linkwarden for more than 3 days new Date().getTime() - new Date(account.createdAt).getTime() > 3 * 24 * 60 * 60 * 1000 ) { setShowsSurveyModal(true); } }, [account]); const numberOfLinksToShow = useMemo(() => { if (window.innerWidth > 1900) { return 10; } else if (window.innerWidth > 1500) { return 8; } else if (window.innerWidth > 880) { return 6; } else if (window.innerWidth > 550) { return 4; } else { return 2; } }, []); const importBookmarks = async ( e: React.ChangeEvent, format: MigrationFormat ) => { const file: File | null = e.target.files && e.target.files[0]; if (file) { const reader = new FileReader(); reader.readAsText(file, "UTF-8"); reader.onload = async function (e) { const load = toast.loading("Importing..."); const request: string = e.target?.result as string; const body: MigrationRequest = { format, data: request, }; try { const response = await fetch("/api/v1/migration", { method: "POST", body: JSON.stringify(body), }); if (!response.ok) { const errorData = await response.json(); toast.dismiss(load); toast.error( errorData.response || "Failed to import bookmarks. Please try again." ); return; } await response.json(); toast.dismiss(load); toast.success("Imported the Bookmarks! Reloading the page..."); setTimeout(() => { location.reload(); }, 2000); } catch (error) { console.error("Request failed", error); toast.dismiss(load); toast.error( "An error occurred while importing bookmarks. Please check the logs for more info." ); } }; reader.onerror = function (e) { console.log("Error reading file:", e); toast.error( "Failed to read the file. Please make sure the file is correct and try again." ); }; } }; const [newLinkModal, setNewLinkModal] = useState(false); const [viewMode, setViewMode] = useState( (localStorage.getItem("viewMode") as ViewMode) || ViewMode.Card ); const [showSurveyModal, setShowsSurveyModal] = useState(false); const { data: user } = useUser(); const updateUser = useUpdateUser(); const [submitLoader, setSubmitLoader] = useState(false); const submitSurvey = async (referer: string, other?: string) => { if (submitLoader) return; setSubmitLoader(true); const load = toast.loading(t("applying")); await updateUser.mutateAsync( { ...user, referredBy: referer === "other" ? "Other: " + other : referer, }, { onSettled: (data, error) => { console.log(data, error); setSubmitLoader(false); toast.dismiss(load); if (error) { toast.error(error.message); } else { toast.success(t("thanks_for_feedback")); setShowsSurveyModal(false); } }, } ); }; return (
{t("view_all")}
{dashboardData.isLoading ? (
) : links && links[0] && !dashboardData.isLoading ? (
) : (

{t("view_added_links_here")}

{t("view_added_links_here_desc")}

{ setNewLinkModal(true); }} className="inline-flex items-center gap-2 text-sm btn btn-accent dark:border-violet-400 text-white" > {t("add_link")}

{t("import_links")}

)}
{t("view_all")}
{dashboardData.isLoading ? (
) : links?.some((e: any) => e.pinnedBy && e.pinnedBy[0]) ? (
e.pinnedBy && e.pinnedBy[0]) .slice( 0, settings.columns ? settings.columns * 2 : numberOfLinksToShow )} layout={viewMode} />
) : (

{t("pin_favorite_links_here")}

{t("pin_favorite_links_here_desc")}

)}
{showSurveyModal && ( { setShowsSurveyModal(false); }} /> )} {newLinkModal && setNewLinkModal(false)} />}
); } export { getServerSideProps };