Files
my-links/pages/index.tsx

156 lines
3.9 KiB
TypeScript

import { useRouter } from "next/router";
import { useCallback, useState } from "react";
import { useHotkeys } from "react-hotkeys-hook";
import useModal from "../hooks/useModal";
import Links from "../components/Links/Links";
import SearchModal from "../components/SearchModal/SearchModal";
import SideMenu from "../components/SideMenu/SideMenu";
import { Category, ItemComplete, Link } from "../types";
import { prisma } from "../utils/back";
import { BuildCategory } from "../utils/front";
const OPEN_SEARCH_KEY = "s";
const CLOSE_SEARCH_KEY = "escape";
const OPEN_CREATE_LINK_KEY = "l";
const OPEN_CREATE_CATEGORY_KEY = "c";
interface HomeProps {
categories: Category[];
favorites: Link[];
items: ItemComplete[];
currentCategory: Category | undefined;
}
function Home({ categories, favorites, currentCategory, items }: HomeProps) {
const router = useRouter();
const modal = useModal();
const [categoryActive, setCategoryActive] = useState<Category | null>(
currentCategory || categories?.[0]
);
const handleSelectCategory = (category: Category) => {
setCategoryActive(category);
const newUrl = `/?categoryId=${category.id}`;
window.history.replaceState(
{ ...window.history.state, as: newUrl, url: newUrl },
"",
newUrl
);
};
const openSearchModal = useCallback(
(event) => {
event.preventDefault();
modal.open();
},
[modal]
);
const closeSearchModal = useCallback(() => modal.close(), [modal]);
const gotoCreateLink = useCallback(() => {
router.push(`/link/create?categoryId=${categoryActive.id}`);
}, [categoryActive.id, router]);
const gotoCreateCategory = useCallback(() => {
router.push("/category/create");
}, [router]);
useHotkeys(OPEN_SEARCH_KEY, openSearchModal, { enabled: !modal.isShowing });
useHotkeys(CLOSE_SEARCH_KEY, closeSearchModal, { enabled: modal.isShowing });
useHotkeys(OPEN_CREATE_LINK_KEY, gotoCreateLink, {
enabled: !modal.isShowing,
});
useHotkeys(OPEN_CREATE_CATEGORY_KEY, gotoCreateCategory, {
enabled: !modal.isShowing,
});
return (
<div className="App">
<SideMenu
categories={categories}
favorites={favorites}
handleSelectCategory={handleSelectCategory}
categoryActive={categoryActive}
/>
<Links category={categoryActive} />
{modal.isShowing && (
<SearchModal
close={modal.close}
categories={categories}
favorites={favorites}
items={items}
handleSelectCategory={handleSelectCategory}
/>
)}
</div>
);
}
export async function getServerSideProps({ query }) {
const queryCategoryId = (query?.categoryId as string) || "";
const categoriesDB = await prisma.category.findMany({
include: { links: true },
});
const items = [] as ItemComplete[];
const favorites = [] as Link[];
const categories = categoriesDB.map((categoryDB) => {
const category = BuildCategory(categoryDB);
category.links.map((link) => {
if (link.favorite) {
favorites.push(link);
}
items.push({
id: link.id,
name: link.name,
url: link.url,
type: "link",
});
});
items.push({
id: category.id,
name: category.name,
url: `/?categoryId=${category.id}`,
type: "category",
});
return category;
});
if (categories.length === 0) {
return {
redirect: {
destination: "/category/create",
},
};
}
const currentCategory = categories.find(
(c) => c.id === Number(queryCategoryId)
);
return {
props: {
categories: JSON.parse(JSON.stringify(categories)),
favorites: JSON.parse(JSON.stringify(favorites)),
items: JSON.parse(JSON.stringify(items)),
currentCategory: currentCategory
? JSON.parse(JSON.stringify(currentCategory))
: null,
},
};
}
Home.authRequired = true;
export default Home;