refactor: apply prettier conf

This commit is contained in:
Sonny
2023-11-19 23:37:23 +01:00
parent 371eea85dc
commit 1f42fad0ad
19 changed files with 152 additions and 95 deletions

View File

@@ -6,7 +6,7 @@ const config = {
webpack(config) { webpack(config) {
config.module.rules.push({ config.module.rules.push({
test: /\.svg$/, test: /\.svg$/,
use: ["@svgr/webpack"] use: ["@svgr/webpack"],
}); });
return config; return config;
@@ -15,12 +15,12 @@ const config = {
remotePatterns: [ remotePatterns: [
{ hostname: "localhost" }, { hostname: "localhost" },
{ hostname: "t3.gstatic.com" }, { hostname: "t3.gstatic.com" },
{ hostname: "lh3.googleusercontent.com" } { hostname: "lh3.googleusercontent.com" },
], ],
formats: ["image/webp"] formats: ["image/webp"],
}, },
reactStrictMode: false, reactStrictMode: false,
output: "standalone" output: "standalone",
}; };
module.exports = config; module.exports = config;

View File

@@ -18,7 +18,7 @@ interface LinkFaviconProps {
export default function LinkFavicon({ export default function LinkFavicon({
url, url,
size = 32, size = 32,
noMargin = false noMargin = false,
}: LinkFaviconProps) { }: LinkFaviconProps) {
const [isFailed, setFailed] = useState<boolean>(false); const [isFailed, setFailed] = useState<boolean>(false);
const [isLoading, setLoading] = useState<boolean>(true); const [isLoading, setLoading] = useState<boolean>(true);

View File

@@ -13,7 +13,7 @@ import { makeRequest } from "lib/request";
export default function LinkItem({ export default function LinkItem({
link, link,
toggleFavorite, toggleFavorite,
index index,
}: { }: {
link: Link; link: Link;
toggleFavorite: (linkId: Link["id"]) => void; toggleFavorite: (linkId: Link["id"]) => void;
@@ -28,8 +28,8 @@ export default function LinkItem({
name, name,
url, url,
favorite: !favorite, favorite: !favorite,
categoryId: link.category.id categoryId: link.category.id,
} },
}) })
.then(() => toggleFavorite(link.id)) .then(() => toggleFavorite(link.id))
.catch(console.error); .catch(console.error);
@@ -45,7 +45,7 @@ export default function LinkItem({
type: "spring", type: "spring",
stiffness: 260, stiffness: 260,
damping: 20, damping: 20,
delay: index * 0.05 delay: index * 0.05,
}} }}
> >
<LinkFavicon url={url} /> <LinkFavicon url={url} />

View File

@@ -3,11 +3,16 @@ import { useSession } from "next-auth/react";
import PATHS from "constants/paths"; import PATHS from "constants/paths";
import styles from "./navbar.module.scss"; import styles from "./navbar.module.scss";
import { useTranslation } from "next-i18next"; import { useTranslation } from "next-i18next";
import Image from "next/image";
import { TFunctionParam } from "../../types/i18next";
export default function Navbar() { export default function Navbar() {
const { status } = useSession(); const { data, status } = useSession();
const { t } = useTranslation(); const { t } = useTranslation();
const avatarLabel = t("common:avatar", {
name: data?.user?.name,
} as TFunctionParam);
return ( return (
<nav className={styles["navbar"]}> <nav className={styles["navbar"]}>
<ul className="reset"> <ul className="reset">
@@ -21,9 +26,21 @@ export default function Navbar() {
<LinkTag href={PATHS.TERMS}>{t("common:terms")}</LinkTag> <LinkTag href={PATHS.TERMS}>{t("common:terms")}</LinkTag>
</li> </li>
{status === "authenticated" ? ( {status === "authenticated" ? (
<>
<li className={styles["user"]}>
<Image
src={data.user.image}
width={24}
height={24}
alt={avatarLabel}
title={avatarLabel}
/>
{data.user.name}
</li>
<li> <li>
<LinkTag href={PATHS.LOGOUT}>{t("common:logout")}</LinkTag> <LinkTag href={PATHS.LOGOUT}>{t("common:logout")}</LinkTag>
</li> </li>
</>
) : ( ) : (
<li> <li>
<LinkTag href={PATHS.LOGIN}>{t("common:login")}</LinkTag> <LinkTag href={PATHS.LOGIN}>{t("common:login")}</LinkTag>

View File

@@ -8,3 +8,13 @@
gap: 1.5em; gap: 1.5em;
justify-content: center; justify-content: center;
} }
.navbar .user {
display: flex;
gap: 0.25em;
justify-content: center;
& img {
border-radius: 50%;
}
}

View File

@@ -9,7 +9,7 @@ type ApiHandlerMethod = ({
req, req,
res, res,
session, session,
user user,
}: { }: {
req: NextApiRequest; req: NextApiRequest;
res: NextApiResponse; res: NextApiResponse;
@@ -72,7 +72,7 @@ function errorHandler(error: any, response: NextApiResponse) {
function handlePrismaError({ function handlePrismaError({
meta, meta,
code, code,
message message,
}: PrismaClientKnownRequestError) { }: PrismaClientKnownRequestError) {
switch (code) { switch (code) {
case "P2002": case "P2002":

View File

@@ -4,16 +4,24 @@ import { i18n } from "next-i18next";
export async function makeRequest({ export async function makeRequest({
method = "GET", method = "GET",
url, url,
body body,
}: { method?: RequestInit["method"], url: string, body?: object | any[] }): Promise<any> { }: {
method?: RequestInit["method"];
url: string;
body?: object | any[];
}): Promise<any> {
nProgress.start(); nProgress.start();
const request = await fetch(url, { const request = await fetch(url, {
method, body: body ? JSON.stringify(body) : undefined, headers: { method,
"Content-Type": "application/json" body: body ? JSON.stringify(body) : undefined,
} headers: {
"Content-Type": "application/json",
},
}); });
nProgress.done(); nProgress.done();
const data = await request.json(); const data = await request.json();
return request.ok ? data : Promise.reject(data?.error || i18n.t("common:generic-error")); return request.ok
? data
: Promise.reject(data?.error || i18n.t("common:generic-error"));
} }

View File

@@ -5,7 +5,7 @@ export default async function createUser(profile: Profile) {
return await prisma.user.create({ return await prisma.user.create({
data: { data: {
email: profile.email, email: profile.email,
google_id: profile.sub google_id: profile.sub,
} },
}); });
} }

View File

@@ -5,7 +5,7 @@ export default async function getUserByProfileProvider(profile: Profile) {
return await prisma.user.findFirst({ return await prisma.user.findFirst({
where: { where: {
google_id: profile.sub, google_id: profile.sub,
email: profile.email email: profile.email,
} },
}); });
} }

View File

@@ -5,11 +5,11 @@ export default async function updateUser(profile: Profile) {
return await prisma.user.update({ return await prisma.user.update({
where: { where: {
email: profile.email, email: profile.email,
google_id: profile.sub google_id: profile.sub,
}, },
data: { data: {
email: profile.email, email: profile.email,
google_id: profile.sub google_id: profile.sub,
} },
}); });
} }

View File

@@ -6,12 +6,18 @@ import createUser from "lib/user/createUser";
import updateUser from "lib/user/updateUser"; import updateUser from "lib/user/updateUser";
import prisma from "utils/prisma"; import prisma from "utils/prisma";
const authLogger = (profile: Profile, ...args: any[]) => console.log("[AUTH]", profile.email, `(${profile.name} - ${profile.sub})`, ...args); const authLogger = (profile: Profile, ...args: any[]) =>
console.log(
"[AUTH]",
profile.email,
`(${profile.name} - ${profile.sub})`,
...args,
);
const redirectUser = (errorKey: string) => `${PATHS.LOGIN}?error=${errorKey}`; const redirectUser = (errorKey: string) => `${PATHS.LOGIN}?error=${errorKey}`;
const checkProvider = (provider: string) => provider === "google"; const checkProvider = (provider: string) => provider === "google";
const checkAccountDataReceived = (profile: Profile) => !!profile?.sub && !!profile?.email; const checkAccountDataReceived = (profile: Profile) =>
!!profile?.sub && !!profile?.email;
export const authOptions = { export const authOptions = {
providers: [ providers: [
@@ -22,16 +28,16 @@ export const authOptions = {
params: { params: {
prompt: "consent", prompt: "consent",
access_type: "offline", access_type: "offline",
response_type: "code" response_type: "code",
} },
} },
}) }),
], ],
callbacks: { callbacks: {
async session({ session }) { async session({ session }) {
// check if stored in session still exist in db // check if stored in session still exist in db
const user = await prisma.user.findFirst({ const user = await prisma.user.findFirst({
where: { email: session.user.email } where: { email: session.user.email },
}); });
return user ? session : undefined; return user ? session : undefined;
}, },
@@ -62,12 +68,12 @@ export const authOptions = {
console.error(error); console.error(error);
return redirectUser("AUTH_ERROR"); return redirectUser("AUTH_ERROR");
} }
} },
}, },
pages: { pages: {
signIn: PATHS.LOGIN, signIn: PATHS.LOGIN,
error: PATHS.LOGIN, error: PATHS.LOGIN,
signOut: PATHS.LOGOUT signOut: PATHS.LOGOUT,
} },
} as NextAuthOptions; } as NextAuthOptions;
export default NextAuth(authOptions); export default NextAuth(authOptions);

View File

@@ -42,13 +42,17 @@ export default async function handler(
} }
if (isBase64Image(faviconPath)) { if (isBase64Image(faviconPath)) {
console.log("[Favicon]", `[first: ${faviconRequestUrl}]`, "base64, convert it to buffer"); console.log(
"[Favicon]",
`[first: ${faviconRequestUrl}]`,
"base64, convert it to buffer",
);
const buffer = convertBase64ToBuffer(faviconPath); const buffer = convertBase64ToBuffer(faviconPath);
return sendImage(res, { return sendImage(res, {
buffer, buffer,
type: "image/x-icon", type: "image/x-icon",
size: buffer.length, size: buffer.length,
url: faviconPath url: faviconPath,
}); });
} }
@@ -65,7 +69,9 @@ export default async function handler(
const errorMessage = error?.message || "Unable to retrieve favicon"; const errorMessage = error?.message || "Unable to retrieve favicon";
console.log("[Favicon]", `[second: ${faviconRequestUrl}]`, errorMessage); console.log("[Favicon]", `[second: ${faviconRequestUrl}]`, errorMessage);
const readStream = createReadStream(resolve(process.cwd(), "./public/empty-image.png")); const readStream = createReadStream(
resolve(process.cwd(), "./public/empty-image.png"),
);
res.writeHead(206); res.writeHead(206);
readStream.pipe(res); readStream.pipe(res);
} }
@@ -89,15 +95,11 @@ async function downloadImageFromUrl(url: string): Promise<Favicon> {
buffer: Buffer.from(await blob.arrayBuffer()), buffer: Buffer.from(await blob.arrayBuffer()),
url: request.url, url: request.url,
type: blob.type, type: blob.type,
size: blob.size size: blob.size,
}; };
} }
function sendImage(res: NextApiResponse, { function sendImage(res: NextApiResponse, { buffer, type, size }: Favicon) {
buffer,
type,
size
}: Favicon) {
res.setHeader("Content-Type", type); res.setHeader("Content-Type", type);
res.setHeader("Content-Length", size); res.setHeader("Content-Length", size);
res.send(buffer); res.send(buffer);
@@ -110,13 +112,16 @@ const rels = [
"apple-touch-icon-precomposed", "apple-touch-icon-precomposed",
"apple-touch-startup-image", "apple-touch-startup-image",
"mask-icon", "mask-icon",
"fluid-icon" "fluid-icon",
]; ];
function findFaviconPath(text: string) { function findFaviconPath(text: string) {
const document = parse(text); const document = parse(text);
const favicon = Array.from(document.getElementsByTagName("link")).find( const favicon = Array.from(document.getElementsByTagName("link")).find(
(element) => rels.includes(element.getAttribute("rel")) && element.getAttribute("href")); (element) =>
rels.includes(element.getAttribute("rel")) &&
element.getAttribute("href"),
);
if (!favicon) { if (!favicon) {
throw new Error("No link/href attribute found"); throw new Error("No link/href attribute found");

View File

@@ -13,7 +13,7 @@ import { withAuthentication } from "utils/session";
import { makeRequest } from "lib/request"; import { makeRequest } from "lib/request";
export default function PageCreateCategory({ export default function PageCreateCategory({
categoriesCount categoriesCount,
}: { }: {
categoriesCount: number; categoriesCount: number;
}) { }) {
@@ -40,9 +40,11 @@ export default function PageCreateCategory({
makeRequest({ makeRequest({
url: PATHS.API.CATEGORY, url: PATHS.API.CATEGORY,
method: "POST", method: "POST",
body: { name } body: { name },
}) })
.then((data) => router.push(`${PATHS.HOME}?categoryId=${data?.categoryId}`)) .then((data) =>
router.push(`${PATHS.HOME}?categoryId=${data?.categoryId}`),
)
.catch(setError) .catch(setError)
.finally(() => setSubmitted(false)); .finally(() => setSubmitted(false));
}; };
@@ -79,8 +81,8 @@ export const getServerSideProps = withAuthentication(
props: { props: {
session, session,
categoriesCount, categoriesCount,
...(await getServerSideTranslation(locale)) ...(await getServerSideTranslation(locale)),
} },
}; };
}, },
); );

View File

@@ -36,9 +36,11 @@ export default function PageEditCategory({ category }: { category: Category }) {
makeRequest({ makeRequest({
url: `${PATHS.API.CATEGORY}/${category.id}`, url: `${PATHS.API.CATEGORY}/${category.id}`,
method: "PUT", method: "PUT",
body: { name } body: { name },
}) })
.then((data) => router.push(`${PATHS.HOME}?categoryId=${data?.categoryId}`)) .then((data) =>
router.push(`${PATHS.HOME}?categoryId=${data?.categoryId}`),
)
.catch(setError) .catch(setError)
.finally(() => setSubmitted(false)); .finally(() => setSubmitted(false));
}; };
@@ -73,8 +75,8 @@ export const getServerSideProps = withAuthentication(
if (!category) { if (!category) {
return { return {
redirect: { redirect: {
destination: PATHS.HOME destination: PATHS.HOME,
} },
}; };
} }
@@ -82,8 +84,8 @@ export const getServerSideProps = withAuthentication(
props: { props: {
session, session,
category: JSON.parse(JSON.stringify(category)), category: JSON.parse(JSON.stringify(category)),
...(await getServerSideTranslation(locale)) ...(await getServerSideTranslation(locale)),
} },
}; };
}, },
); );

View File

@@ -14,7 +14,7 @@ import { withAuthentication } from "utils/session";
import { makeRequest } from "lib/request"; import { makeRequest } from "lib/request";
export default function PageRemoveCategory({ export default function PageRemoveCategory({
category category,
}: { }: {
category: Category; category: Category;
}) { }) {
@@ -37,7 +37,7 @@ export default function PageRemoveCategory({
makeRequest({ makeRequest({
url: `${PATHS.API.CATEGORY}/${category.id}`, url: `${PATHS.API.CATEGORY}/${category.id}`,
method: "DELETE" method: "DELETE",
}) })
.then((data) => router.push(PATHS.HOME)) .then((data) => router.push(PATHS.HOME))
.catch(setError) .catch(setError)
@@ -90,8 +90,8 @@ export const getServerSideProps = withAuthentication(
if (!category) { if (!category) {
return { return {
redirect: { redirect: {
destination: PATHS.HOME destination: PATHS.HOME,
} },
}; };
} }
@@ -99,8 +99,8 @@ export const getServerSideProps = withAuthentication(
props: { props: {
session, session,
category: JSON.parse(JSON.stringify(category)), category: JSON.parse(JSON.stringify(category)),
...(await getServerSideTranslation(locale)) ...(await getServerSideTranslation(locale)),
} },
}; };
}, },
); );

View File

@@ -17,7 +17,7 @@ import { withAuthentication } from "utils/session";
import { makeRequest } from "lib/request"; import { makeRequest } from "lib/request";
export default function PageCreateLink({ export default function PageCreateLink({
categories categories,
}: { }: {
categories: Category[]; categories: Category[];
}) { }) {
@@ -54,9 +54,11 @@ export default function PageCreateLink({
makeRequest({ makeRequest({
url: PATHS.API.LINK, url: PATHS.API.LINK,
method: "POST", method: "POST",
body: { name, url, favorite, categoryId } body: { name, url, favorite, categoryId },
}) })
.then((data) => router.push(`${PATHS.HOME}?categoryId=${data?.categoryId}`)) .then((data) =>
router.push(`${PATHS.HOME}?categoryId=${data?.categoryId}`),
)
.catch(setError) .catch(setError)
.finally(() => setSubmitted(false)); .finally(() => setSubmitted(false));
}; };
@@ -94,7 +96,7 @@ export default function PageCreateLink({
onChangeCallback={(value: number) => setCategoryId(value)} onChangeCallback={(value: number) => setCategoryId(value)}
options={categories.map(({ id, name }) => ({ options={categories.map(({ id, name }) => ({
label: name, label: name,
value: id value: id,
}))} }))}
/> />
<Checkbox <Checkbox
@@ -114,8 +116,8 @@ export const getServerSideProps = withAuthentication(
if (categories.length === 0) { if (categories.length === 0) {
return { return {
redirect: { redirect: {
destination: PATHS.HOME destination: PATHS.HOME,
} },
}; };
} }
@@ -123,8 +125,8 @@ export const getServerSideProps = withAuthentication(
props: { props: {
session, session,
categories: JSON.parse(JSON.stringify(categories)), categories: JSON.parse(JSON.stringify(categories)),
...(await getServerSideTranslation(locale)) ...(await getServerSideTranslation(locale)),
} },
}; };
}, },
); );

View File

@@ -19,7 +19,7 @@ import { makeRequest } from "lib/request";
export default function PageEditLink({ export default function PageEditLink({
link, link,
categories categories,
}: { }: {
link: Link; link: Link;
categories: Category[]; categories: Category[];
@@ -59,7 +59,7 @@ export default function PageEditLink({
link.url, link.url,
name, name,
submitted, submitted,
url url,
]); ]);
const handleSubmit = async (event: FormEvent<HTMLFormElement>) => { const handleSubmit = async (event: FormEvent<HTMLFormElement>) => {
@@ -70,9 +70,11 @@ export default function PageEditLink({
makeRequest({ makeRequest({
url: `${PATHS.API.LINK}/${link.id}`, url: `${PATHS.API.LINK}/${link.id}`,
method: "PUT", method: "PUT",
body: { name, url, favorite, categoryId } body: { name, url, favorite, categoryId },
}) })
.then((data) => router.push(`${PATHS.HOME}?categoryId=${data?.categoryId}`)) .then((data) =>
router.push(`${PATHS.HOME}?categoryId=${data?.categoryId}`),
)
.catch(setError) .catch(setError)
.finally(() => setSubmitted(false)); .finally(() => setSubmitted(false));
}; };
@@ -109,7 +111,7 @@ export default function PageEditLink({
onChangeCallback={(value: number) => setCategoryId(value)} onChangeCallback={(value: number) => setCategoryId(value)}
options={categories.map(({ id, name }) => ({ options={categories.map(({ id, name }) => ({
label: name, label: name,
value: id value: id,
}))} }))}
/> />
<Checkbox <Checkbox
@@ -132,8 +134,8 @@ export const getServerSideProps = withAuthentication(
if (!link) { if (!link) {
return { return {
redirect: { redirect: {
destination: PATHS.HOME destination: PATHS.HOME,
} },
}; };
} }
@@ -142,8 +144,8 @@ export const getServerSideProps = withAuthentication(
session, session,
link: JSON.parse(JSON.stringify(link)), link: JSON.parse(JSON.stringify(link)),
categories: JSON.parse(JSON.stringify(categories)), categories: JSON.parse(JSON.stringify(categories)),
...(await getServerSideTranslation(locale)) ...(await getServerSideTranslation(locale)),
} },
}; };
}, },
); );

View File

@@ -33,9 +33,11 @@ export default function PageRemoveLink({ link }: { link: Link }) {
makeRequest({ makeRequest({
url: `${PATHS.API.LINK}/${link.id}`, url: `${PATHS.API.LINK}/${link.id}`,
method: "DELETE" method: "DELETE",
}) })
.then((data) => router.push(`${PATHS.HOME}?categoryId=${data?.categoryId}`)) .then((data) =>
router.push(`${PATHS.HOME}?categoryId=${data?.categoryId}`),
)
.catch(setError) .catch(setError)
.finally(() => setSubmitted(false)); .finally(() => setSubmitted(false));
}; };
@@ -97,8 +99,8 @@ export const getServerSideProps = withAuthentication(
if (!link) { if (!link) {
return { return {
redirect: { redirect: {
destination: PATHS.HOME destination: PATHS.HOME,
} },
}; };
} }
@@ -106,8 +108,8 @@ export const getServerSideProps = withAuthentication(
props: { props: {
session, session,
link: JSON.parse(JSON.stringify(link)), link: JSON.parse(JSON.stringify(link)),
...(await getServerSideTranslation(locale)) ...(await getServerSideTranslation(locale)),
} },
}; };
}, },
); );

View File

@@ -13,6 +13,7 @@ import Image from "next/image";
import { FcGoogle } from "react-icons/fc"; import { FcGoogle } from "react-icons/fc";
import styles from "styles/login.module.scss"; import styles from "styles/login.module.scss";
import { getSession } from "utils/session"; import { getSession } from "utils/session";
import { TFunctionParam } from "../types/i18next";
interface SignInProps { interface SignInProps {
providers: Provider[]; providers: Provider[];
@@ -43,7 +44,7 @@ export default function SignIn({ providers }: SignInProps) {
key={id} key={id}
> >
<FcGoogle size={"1.5em"} />{" "} <FcGoogle size={"1.5em"} />{" "}
{t("login:continue-with", { provider: name } as undefined)} {t("login:continue-with", { provider: name } as TFunctionParam)}
</ButtonLink> </ButtonLink>
))} ))}
</div> </div>