mirror of
https://github.com/Sonny93/my-links.git
synced 2025-12-09 07:03:25 +00:00
feat: first form field auto focused
This commit is contained in:
@@ -1,57 +1,59 @@
|
||||
import { MutableRefObject, useState } from 'react';
|
||||
import { MutableRefObject, useState } from "react";
|
||||
|
||||
interface SelectorProps {
|
||||
name: string;
|
||||
label?: string;
|
||||
labelComponent?: JSX.Element;
|
||||
disabled?: boolean;
|
||||
innerRef?: MutableRefObject<any>;
|
||||
placeholder?: string;
|
||||
fieldClass?: string;
|
||||
isChecked?: boolean;
|
||||
onChangeCallback?: (value, { target }) => void;
|
||||
name: string;
|
||||
label?: string;
|
||||
labelComponent?: JSX.Element;
|
||||
disabled?: boolean;
|
||||
innerRef?: MutableRefObject<any>;
|
||||
placeholder?: string;
|
||||
fieldClass?: string;
|
||||
isChecked?: boolean;
|
||||
onChangeCallback?: (value, { target }) => void;
|
||||
}
|
||||
|
||||
export default function Selector({
|
||||
name,
|
||||
label,
|
||||
labelComponent,
|
||||
disabled = false,
|
||||
innerRef = null,
|
||||
fieldClass = '',
|
||||
placeholder = 'Type something...',
|
||||
isChecked,
|
||||
onChangeCallback
|
||||
export default function Checkbox({
|
||||
name,
|
||||
label,
|
||||
labelComponent,
|
||||
disabled = false,
|
||||
innerRef = null,
|
||||
fieldClass = "",
|
||||
placeholder = "Type something...",
|
||||
isChecked,
|
||||
onChangeCallback,
|
||||
}: SelectorProps): JSX.Element {
|
||||
const [checkboxValue, setCheckboxValue] = useState<boolean>(isChecked);
|
||||
const [checkboxValue, setCheckboxValue] = useState<boolean>(isChecked);
|
||||
|
||||
function onChange({ target }) {
|
||||
setCheckboxValue(!checkboxValue);
|
||||
if (onChangeCallback) {
|
||||
onChangeCallback(!checkboxValue, { target });
|
||||
}
|
||||
function onChange({ target }) {
|
||||
setCheckboxValue(!checkboxValue);
|
||||
if (onChangeCallback) {
|
||||
onChangeCallback(!checkboxValue, { target });
|
||||
}
|
||||
}
|
||||
|
||||
return (<div className={`checkbox-field ${fieldClass}`}>
|
||||
{label && (
|
||||
<label htmlFor={name} title={`${name} field`}>
|
||||
{label}
|
||||
</label>
|
||||
)}
|
||||
{labelComponent && (
|
||||
<label htmlFor={name} title={`${name} field`}>
|
||||
{labelComponent}
|
||||
</label>
|
||||
)}
|
||||
<input
|
||||
type='checkbox'
|
||||
id={name}
|
||||
name={name}
|
||||
onChange={onChange}
|
||||
checked={checkboxValue}
|
||||
placeholder={placeholder}
|
||||
ref={innerRef}
|
||||
disabled={disabled}
|
||||
/>
|
||||
</div>);
|
||||
}
|
||||
return (
|
||||
<div className={`checkbox-field ${fieldClass}`}>
|
||||
{label && (
|
||||
<label htmlFor={name} title={`${name} field`}>
|
||||
{label}
|
||||
</label>
|
||||
)}
|
||||
{labelComponent && (
|
||||
<label htmlFor={name} title={`${name} field`}>
|
||||
{labelComponent}
|
||||
</label>
|
||||
)}
|
||||
<input
|
||||
type="checkbox"
|
||||
id={name}
|
||||
name={name}
|
||||
onChange={onChange}
|
||||
checked={checkboxValue}
|
||||
placeholder={placeholder}
|
||||
ref={innerRef}
|
||||
disabled={disabled}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -7,6 +7,9 @@ import styles from "../styles/create.module.scss";
|
||||
|
||||
interface FormProps {
|
||||
title: string;
|
||||
|
||||
categoryId?: string;
|
||||
|
||||
errorMessage?: string;
|
||||
successMessage?: string;
|
||||
infoMessage?: string;
|
||||
@@ -21,6 +24,7 @@ interface FormProps {
|
||||
}
|
||||
export default function Form({
|
||||
title,
|
||||
categoryId = undefined,
|
||||
errorMessage,
|
||||
successMessage,
|
||||
infoMessage,
|
||||
@@ -45,7 +49,9 @@ export default function Form({
|
||||
{textBtnConfirm}
|
||||
</button>
|
||||
</form>
|
||||
<Link href="/">← Revenir à l'accueil</Link>
|
||||
<Link href={categoryId ? `/?categoryId=${categoryId}` : "/"}>
|
||||
← Revenir à l'accueil
|
||||
</Link>
|
||||
<MessageManager
|
||||
info={infoMessage}
|
||||
error={errorMessage}
|
||||
|
||||
@@ -3,6 +3,7 @@ import { AiFillDelete, AiFillEdit } from "react-icons/ai";
|
||||
|
||||
import { Category } from "../../../types";
|
||||
|
||||
import { useEffect, useRef } from "react";
|
||||
import styles from "./categories.module.scss";
|
||||
|
||||
interface CategoryItemProps {
|
||||
@@ -11,19 +12,28 @@ interface CategoryItemProps {
|
||||
handleSelectCategory: (category: Category) => void;
|
||||
}
|
||||
|
||||
let rendered = false;
|
||||
export default function CategoryItem({
|
||||
category,
|
||||
categoryActive,
|
||||
handleSelectCategory,
|
||||
}: CategoryItemProps): JSX.Element {
|
||||
const ref = useRef<HTMLLIElement>();
|
||||
const className = `${styles["item"]} ${
|
||||
category.id === categoryActive.id ? styles["active"] : ""
|
||||
}`;
|
||||
const onClick = () => handleSelectCategory(category);
|
||||
|
||||
useEffect(() => {
|
||||
if (category.id === categoryActive.id && !rendered) {
|
||||
rendered = true;
|
||||
ref.current.scrollIntoView({ behavior: "smooth" });
|
||||
}
|
||||
}, [category.id, categoryActive.id]);
|
||||
|
||||
return (
|
||||
<li className={className} onClick={onClick}>
|
||||
<div className={styles["content"]}>
|
||||
<li className={className} ref={ref}>
|
||||
<div className={styles["content"]} onClick={onClick}>
|
||||
<span className={styles["name"]}>{category.name}</span>
|
||||
<span className={styles["links-count"]}>— {category.links.length}</span>
|
||||
</div>
|
||||
@@ -35,12 +45,17 @@ export default function CategoryItem({
|
||||
function MenuOptions({ id }: { id: number }): JSX.Element {
|
||||
return (
|
||||
<div className={styles["menu-item"]}>
|
||||
<LinkTag href={`/category/edit/${id}`} className={styles["option-edit"]}>
|
||||
<LinkTag
|
||||
href={`/category/edit/${id}`}
|
||||
className={styles["option-edit"]}
|
||||
onClick={(event) => event.stopPropagation()}
|
||||
>
|
||||
<AiFillEdit />
|
||||
</LinkTag>
|
||||
<LinkTag
|
||||
href={`/category/remove/${id}`}
|
||||
className={styles["option-remove"]}
|
||||
onClick={(event) => event.stopPropagation()}
|
||||
>
|
||||
<AiFillDelete color="red" />
|
||||
</LinkTag>
|
||||
|
||||
@@ -29,7 +29,7 @@ export default function SideMenu({
|
||||
<BlockWrapper>
|
||||
<Favorites favorites={favorites} />
|
||||
</BlockWrapper>
|
||||
<BlockWrapper style={{ minHeight: "0" }}>
|
||||
<BlockWrapper style={{ minHeight: "0", flex: "1" }}>
|
||||
<Categories
|
||||
categories={categories}
|
||||
categoryActive={categoryActive}
|
||||
|
||||
@@ -1,62 +1,64 @@
|
||||
import { MutableRefObject, useState } from 'react';
|
||||
import { MutableRefObject, useState } from "react";
|
||||
|
||||
interface InputProps {
|
||||
name: string;
|
||||
label?: string;
|
||||
labelComponent?: JSX.Element;
|
||||
disabled?: boolean;
|
||||
type?: string;
|
||||
multiple?: boolean;
|
||||
innerRef?: MutableRefObject<any>;
|
||||
placeholder?: string;
|
||||
fieldClass?: string;
|
||||
value?: string;
|
||||
onChangeCallback?: (value) => void;
|
||||
name: string;
|
||||
label?: string;
|
||||
labelComponent?: JSX.Element;
|
||||
disabled?: boolean;
|
||||
type?: string;
|
||||
multiple?: boolean;
|
||||
innerRef?: MutableRefObject<any> | ((ref: any) => void);
|
||||
placeholder?: string;
|
||||
fieldClass?: string;
|
||||
value?: string;
|
||||
onChangeCallback?: (value) => void;
|
||||
}
|
||||
|
||||
export default function TextBox({
|
||||
name,
|
||||
label,
|
||||
labelComponent,
|
||||
disabled = false,
|
||||
type = 'text',
|
||||
multiple = false,
|
||||
innerRef = null,
|
||||
placeholder = 'Type something...',
|
||||
fieldClass = '',
|
||||
value,
|
||||
onChangeCallback
|
||||
name,
|
||||
label,
|
||||
labelComponent,
|
||||
disabled = false,
|
||||
type = "text",
|
||||
multiple = false,
|
||||
innerRef = null,
|
||||
placeholder = "Type something...",
|
||||
fieldClass = "",
|
||||
value,
|
||||
onChangeCallback,
|
||||
}: InputProps): JSX.Element {
|
||||
const [inputValue, setInputValue] = useState<string>(value);
|
||||
const [inputValue, setInputValue] = useState<string>(value);
|
||||
|
||||
function onChange({ target }) {
|
||||
setInputValue(target.value);
|
||||
if (onChangeCallback) {
|
||||
onChangeCallback(target.value);
|
||||
}
|
||||
function onChange({ target }) {
|
||||
setInputValue(target.value);
|
||||
if (onChangeCallback) {
|
||||
onChangeCallback(target.value);
|
||||
}
|
||||
}
|
||||
|
||||
return (<div className={`input-field ${fieldClass}`}>
|
||||
{label && (
|
||||
<label htmlFor={name} title={`${name} field`}>
|
||||
{label}
|
||||
</label>
|
||||
)}
|
||||
{labelComponent && (
|
||||
<label htmlFor={name} title={`${name} field`}>
|
||||
{labelComponent}
|
||||
</label>
|
||||
)}
|
||||
<input
|
||||
id={name}
|
||||
name={name}
|
||||
type={type}
|
||||
onChange={onChange}
|
||||
value={inputValue}
|
||||
multiple={multiple}
|
||||
placeholder={placeholder}
|
||||
ref={innerRef}
|
||||
disabled={disabled}
|
||||
/>
|
||||
</div>);
|
||||
}
|
||||
return (
|
||||
<div className={`input-field ${fieldClass}`}>
|
||||
{label && (
|
||||
<label htmlFor={name} title={`${name} field`}>
|
||||
{label}
|
||||
</label>
|
||||
)}
|
||||
{labelComponent && (
|
||||
<label htmlFor={name} title={`${name} field`}>
|
||||
{labelComponent}
|
||||
</label>
|
||||
)}
|
||||
<input
|
||||
id={name}
|
||||
name={name}
|
||||
type={type}
|
||||
onChange={onChange}
|
||||
value={inputValue}
|
||||
multiple={multiple}
|
||||
placeholder={placeholder}
|
||||
ref={innerRef}
|
||||
disabled={disabled}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -2,6 +2,11 @@ DB_USER="my_user"
|
||||
DB_PASSWORD=""
|
||||
DB_DATABASE="my-links"
|
||||
|
||||
# Or if you need external Database
|
||||
# DATABASE_IP="localhost"
|
||||
# DATABASE_PORT="3306"
|
||||
# DATABASE_URL="mysql://${MYSQL_USER}:${MYSQL_PASSWORD}@${DATABASE_IP}:${DATABASE_PORT}/${MYSQL_DATABASE}"
|
||||
|
||||
NEXTAUTH_URL=http://localhost:3000
|
||||
NEXTAUTH_URL_INTERNAL=http://localhost:3000
|
||||
|
||||
|
||||
11
hooks/useAutoFocus.tsx
Normal file
11
hooks/useAutoFocus.tsx
Normal file
@@ -0,0 +1,11 @@
|
||||
import { useCallback } from "react";
|
||||
|
||||
export default function useAutoFocus() {
|
||||
const inputRef = useCallback((inputElement: any) => {
|
||||
if (inputElement) {
|
||||
inputElement.focus();
|
||||
}
|
||||
}, []);
|
||||
|
||||
return inputRef;
|
||||
}
|
||||
@@ -1,14 +1,12 @@
|
||||
import { SessionProvider } from "next-auth/react";
|
||||
import { useEffect } from "react";
|
||||
|
||||
import { DefaultSeo } from "next-seo";
|
||||
import { useRouter } from "next/router";
|
||||
|
||||
import nProgress from "nprogress";
|
||||
import "nprogress/nprogress.css";
|
||||
import { useEffect } from "react";
|
||||
|
||||
import AuthRequired from "../components/AuthRequired";
|
||||
|
||||
import { DefaultSeo } from "next-seo";
|
||||
import "nprogress/nprogress.css";
|
||||
import "../styles/globals.scss";
|
||||
|
||||
function MyApp({ Component, pageProps: { session, ...pageProps } }) {
|
||||
@@ -25,7 +23,7 @@ function MyApp({ Component, pageProps: { session, ...pageProps } }) {
|
||||
router.events.off("routeChangeComplete", nProgress.done);
|
||||
router.events.off("routeChangeError", nProgress.done);
|
||||
};
|
||||
});
|
||||
}, [router.events]);
|
||||
|
||||
return (
|
||||
<SessionProvider session={session}>
|
||||
|
||||
@@ -1,33 +1,47 @@
|
||||
import { NextApiRequest, NextApiResponse } from 'next';
|
||||
import { prisma } from '../../../utils/back';
|
||||
import { NextApiRequest, NextApiResponse } from "next";
|
||||
import { prisma } from "../../../utils/back";
|
||||
|
||||
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||
const name = req.body?.name as string;
|
||||
export default async function handler(
|
||||
req: NextApiRequest,
|
||||
res: NextApiResponse
|
||||
) {
|
||||
const name = req.body?.name as string;
|
||||
|
||||
if (!name) {
|
||||
return res.status(400).send({ error: 'Nom de catégorie manquant' });
|
||||
if (!name) {
|
||||
return res.status(400).send({ error: "Nom de catégorie manquant" });
|
||||
}
|
||||
|
||||
try {
|
||||
const category = await prisma.category.findFirst({
|
||||
where: { name },
|
||||
});
|
||||
|
||||
if (category) {
|
||||
return res
|
||||
.status(400)
|
||||
.send({ error: "Une catégorie avec ce nom existe déjà" });
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return res.status(400).send({
|
||||
error:
|
||||
"Une erreur est survenue lors de la création de la catégorie (category/create->findCategory)",
|
||||
});
|
||||
}
|
||||
|
||||
try {
|
||||
const category = await prisma.category.findFirst({
|
||||
where: { name }
|
||||
});
|
||||
|
||||
if (category) {
|
||||
return res.status(400).send({ error: 'Une catégorie avec ce nom existe déjà' });
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return res.status(400).send({ error: 'Une erreur est survenue lors de la création de la catégorie (category/create->findCategory)' });
|
||||
}
|
||||
|
||||
try {
|
||||
await prisma.category.create({
|
||||
data: { name }
|
||||
});
|
||||
return res.status(200).send({ success: 'Catégorie créée avec succès' });
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return res.status(400).send({ error: 'Une erreur est survenue lors de la création de la catégorie (category/create->createCategory)' });
|
||||
}
|
||||
}
|
||||
try {
|
||||
const category = await prisma.category.create({
|
||||
data: { name },
|
||||
});
|
||||
return res.status(200).send({
|
||||
success: "Catégorie créée avec succès",
|
||||
categoryId: category.id,
|
||||
});
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return res.status(400).send({
|
||||
error:
|
||||
"Une erreur est survenue lors de la création de la catégorie (category/create->createCategory)",
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,39 +1,53 @@
|
||||
import { NextApiRequest, NextApiResponse } from 'next';
|
||||
import { prisma } from '../../../../utils/back';
|
||||
import { NextApiRequest, NextApiResponse } from "next";
|
||||
import { prisma } from "../../../../utils/back";
|
||||
|
||||
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||
const { cid } = req.query;
|
||||
export default async function handler(
|
||||
req: NextApiRequest,
|
||||
res: NextApiResponse
|
||||
) {
|
||||
const { cid } = req.query;
|
||||
|
||||
let category;
|
||||
try {
|
||||
category = await prisma.category.findFirst({
|
||||
where: { id: Number(cid) }
|
||||
});
|
||||
let category;
|
||||
try {
|
||||
category = await prisma.category.findFirst({
|
||||
where: { id: Number(cid) },
|
||||
});
|
||||
|
||||
if (!category) {
|
||||
return res.status(400).send({ error: 'Catégorie introuvable' });
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return res.status(400).send({ error: 'Une erreur est survenue lors de l\'édition de la catégorie (category/edit->findCategory)' });
|
||||
if (!category) {
|
||||
return res.status(400).send({ error: "Catégorie introuvable" });
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return res.status(400).send({
|
||||
error:
|
||||
"Une erreur est survenue lors de l'édition de la catégorie (category/edit->findCategory)",
|
||||
});
|
||||
}
|
||||
|
||||
const name = req.body?.name as string;
|
||||
if (!name) {
|
||||
return res.status(400).send({ error: 'Nom de la catégorie manquante' });
|
||||
} else if (name === category.name) {
|
||||
return res.status(400).send({ error: 'Le nom de la catégorie doit être différent du nom actuel' });
|
||||
}
|
||||
const name = req.body?.name as string;
|
||||
if (!name) {
|
||||
return res.status(400).send({ error: "Nom de la catégorie manquante" });
|
||||
} else if (name === category.name) {
|
||||
return res.status(400).send({
|
||||
error: "Le nom de la catégorie doit être différent du nom actuel",
|
||||
});
|
||||
}
|
||||
|
||||
try {
|
||||
await prisma.category.update({
|
||||
where: { id: Number(cid) },
|
||||
data: { name }
|
||||
});
|
||||
try {
|
||||
const category = await prisma.category.update({
|
||||
where: { id: Number(cid) },
|
||||
data: { name },
|
||||
});
|
||||
|
||||
return res.status(200).send({ success: 'Catégorie mise à jour avec succès' });
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return res.status(400).send({ error: 'Une erreur est survenue lors de l\'édition de la catégorie (category/edit->updateCategory)' });
|
||||
}
|
||||
}
|
||||
return res.status(200).send({
|
||||
success: "Catégorie mise à jour avec succès",
|
||||
categoryId: category.id,
|
||||
});
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return res.status(400).send({
|
||||
error:
|
||||
"Une erreur est survenue lors de l'édition de la catégorie (category/edit->updateCategory)",
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,16 +39,16 @@ export default async function handler(
|
||||
|
||||
const faviconPath = findFaviconPath(text);
|
||||
if (!faviconPath) {
|
||||
throw new Error("Unable to find favicon path");
|
||||
throw new Error("[Favicon] Unable to find favicon path");
|
||||
}
|
||||
|
||||
if (isBase64Image(faviconPath)) {
|
||||
console.log("base64, convert it to buffer");
|
||||
console.log("[Favicon] base64, convert it to buffer");
|
||||
const buffer = convertBase64ToBuffer(faviconPath);
|
||||
return sendImage({
|
||||
content: buffer,
|
||||
res,
|
||||
type: "image/vnd.microsoft.icon",
|
||||
type: "image/x-icon",
|
||||
size: buffer.length,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,62 +1,78 @@
|
||||
import { NextApiRequest, NextApiResponse } from 'next';
|
||||
import { prisma } from '../../../utils/back';
|
||||
import { NextApiRequest, NextApiResponse } from "next";
|
||||
import { prisma } from "../../../utils/back";
|
||||
|
||||
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||
const name = req.body?.name as string;
|
||||
const url = req.body?.url as string;
|
||||
const favorite = Boolean(req.body?.favorite) || false;
|
||||
const categoryId = Number(req.body?.categoryId);
|
||||
export default async function handler(
|
||||
req: NextApiRequest,
|
||||
res: NextApiResponse
|
||||
) {
|
||||
const name = req.body?.name as string;
|
||||
const url = req.body?.url as string;
|
||||
const favorite = Boolean(req.body?.favorite) || false;
|
||||
const categoryId = Number(req.body?.categoryId);
|
||||
|
||||
if (!name) {
|
||||
return res.status(400).send({ error: 'Nom du lien manquant' });
|
||||
if (!name) {
|
||||
return res.status(400).send({ error: "Nom du lien manquant" });
|
||||
}
|
||||
|
||||
if (!url) {
|
||||
return res.status(400).send({ error: "URL du lien manquant" });
|
||||
}
|
||||
|
||||
if (!categoryId) {
|
||||
return res.status(400).send({ error: "Catégorie du lien manquante" });
|
||||
}
|
||||
|
||||
try {
|
||||
const link = await prisma.link.findFirst({
|
||||
where: { name, categoryId },
|
||||
});
|
||||
|
||||
if (link) {
|
||||
return res.status(400).send({
|
||||
error: "Un lien avec ce nom existe déjà dans cette catégorie",
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return res.status(400).send({
|
||||
error:
|
||||
"Une erreur est survenue lors de la création du lien (link/create->findLink)",
|
||||
});
|
||||
}
|
||||
|
||||
if (!url) {
|
||||
return res.status(400).send({ error: 'URL du lien manquant' });
|
||||
try {
|
||||
const category = await prisma.category.findFirst({
|
||||
where: { id: categoryId },
|
||||
});
|
||||
|
||||
if (!category) {
|
||||
return res.status(400).send({ error: "Cette catégorie n'existe pas" });
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return res.status(400).send({
|
||||
error:
|
||||
"Une erreur est survenue lors de la création du lien (link/create->findCategory)",
|
||||
});
|
||||
}
|
||||
|
||||
if (!categoryId) {
|
||||
return res.status(400).send({ error: 'Catégorie du lien manquante' });
|
||||
}
|
||||
|
||||
try {
|
||||
const link = await prisma.link.findFirst({
|
||||
where: { name, categoryId }
|
||||
});
|
||||
|
||||
if (link) {
|
||||
return res.status(400).send({ error: 'Un lien avec ce nom existe déjà dans cette catégorie' });
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return res.status(400).send({ error: 'Une erreur est survenue lors de la création du lien (link/create->findLink)' });
|
||||
}
|
||||
|
||||
try {
|
||||
const category = await prisma.category.findFirst({
|
||||
where: { id: categoryId }
|
||||
});
|
||||
|
||||
if (!category) {
|
||||
return res.status(400).send({ error: 'Cette catégorie n\'existe pas' });
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return res.status(400).send({ error: 'Une erreur est survenue lors de la création du lien (link/create->findCategory)' });
|
||||
}
|
||||
|
||||
try {
|
||||
await prisma.link.create({
|
||||
data: {
|
||||
name,
|
||||
url,
|
||||
categoryId,
|
||||
favorite
|
||||
}
|
||||
});
|
||||
return res.status(200).send({ success: 'Lien créé avec succès' });
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return res.status(400).send({ error: 'Une erreur est survenue lors de la création du lien (link/create->createLink)' });
|
||||
}
|
||||
}
|
||||
try {
|
||||
await prisma.link.create({
|
||||
data: {
|
||||
name,
|
||||
url,
|
||||
categoryId,
|
||||
favorite,
|
||||
},
|
||||
});
|
||||
return res
|
||||
.status(200)
|
||||
.send({ success: "Lien créé avec succès", categoryId });
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return res.status(400).send({
|
||||
error:
|
||||
"Une erreur est survenue lors de la création du lien (link/create->createLink)",
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,54 +1,65 @@
|
||||
import { NextApiRequest, NextApiResponse } from 'next';
|
||||
import { prisma } from '../../../../utils/back';
|
||||
import { NextApiRequest, NextApiResponse } from "next";
|
||||
import { prisma } from "../../../../utils/back";
|
||||
|
||||
// TODO: Ajouter vérification -> l'utilisateur doit changer au moins un champ
|
||||
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||
const { lid } = req.query;
|
||||
export default async function handler(
|
||||
req: NextApiRequest,
|
||||
res: NextApiResponse
|
||||
) {
|
||||
const { lid } = req.query;
|
||||
|
||||
try {
|
||||
const link = await prisma.link.findFirst({
|
||||
where: { id: Number(lid) }
|
||||
});
|
||||
try {
|
||||
const link = await prisma.link.findFirst({
|
||||
where: { id: Number(lid) },
|
||||
});
|
||||
|
||||
if (!link) {
|
||||
return res.status(400).send({ error: 'Lien introuvable' });
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return res.status(400).send({ error: 'Une erreur est survenue lors de l\'édition du lien (link/edit->findLink)' });
|
||||
if (!link) {
|
||||
return res.status(400).send({ error: "Lien introuvable" });
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return res.status(400).send({
|
||||
error:
|
||||
"Une erreur est survenue lors de l'édition du lien (link/edit->findLink)",
|
||||
});
|
||||
}
|
||||
|
||||
const name = req.body?.name as string;
|
||||
const url = req.body?.url as string;
|
||||
const favorite = Boolean(req.body?.favorite) || false;
|
||||
const categoryId = Number(req.body?.categoryId);
|
||||
const name = req.body?.name as string;
|
||||
const url = req.body?.url as string;
|
||||
const favorite = Boolean(req.body?.favorite) || false;
|
||||
const categoryId = Number(req.body?.categoryId);
|
||||
|
||||
if (!name) {
|
||||
return res.status(400).send({ error: 'Nom du lien manquant' });
|
||||
}
|
||||
if (!name) {
|
||||
return res.status(400).send({ error: "Nom du lien manquant" });
|
||||
}
|
||||
|
||||
if (!url) {
|
||||
return res.status(400).send({ error: 'URL du lien manquant' });
|
||||
}
|
||||
if (!url) {
|
||||
return res.status(400).send({ error: "URL du lien manquant" });
|
||||
}
|
||||
|
||||
if (!categoryId) {
|
||||
return res.status(400).send({ error: 'Catégorie du lien manquante' });
|
||||
}
|
||||
if (!categoryId) {
|
||||
return res.status(400).send({ error: "Catégorie du lien manquante" });
|
||||
}
|
||||
|
||||
try {
|
||||
await prisma.link.update({
|
||||
where: { id: Number(lid) },
|
||||
data: {
|
||||
name,
|
||||
url,
|
||||
favorite,
|
||||
categoryId
|
||||
}
|
||||
});
|
||||
try {
|
||||
await prisma.link.update({
|
||||
where: { id: Number(lid) },
|
||||
data: {
|
||||
name,
|
||||
url,
|
||||
favorite,
|
||||
categoryId,
|
||||
},
|
||||
});
|
||||
|
||||
return res.status(200).send({ success: 'Lien mis à jour avec succès' });
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return res.status(400).send({ error: 'Une erreur est survenue lors de l\'édition du lien (link/remove->updateLink)' });
|
||||
}
|
||||
}
|
||||
return res
|
||||
.status(200)
|
||||
.send({ success: "Lien mis à jour avec succès", categoryId });
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return res.status(400).send({
|
||||
error:
|
||||
"Une erreur est survenue lors de l'édition du lien (link/remove->updateLink)",
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,30 +1,42 @@
|
||||
import { NextApiRequest, NextApiResponse } from 'next';
|
||||
import { prisma } from '../../../../utils/back';
|
||||
import { NextApiRequest, NextApiResponse } from "next";
|
||||
import { prisma } from "../../../../utils/back";
|
||||
|
||||
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||
const { lid } = req.query;
|
||||
export default async function handler(
|
||||
req: NextApiRequest,
|
||||
res: NextApiResponse
|
||||
) {
|
||||
const { lid } = req.query;
|
||||
|
||||
try {
|
||||
const link = await prisma.link.findFirst({
|
||||
where: { id: Number(lid) }
|
||||
});
|
||||
try {
|
||||
const link = await prisma.link.findFirst({
|
||||
where: { id: Number(lid) },
|
||||
});
|
||||
|
||||
if (!link) {
|
||||
return res.status(400).send({ error: 'Lien introuvable' });
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return res.status(400).send({ error: 'Une erreur est survenue lors de la suppression du lien (link/remove->findLink)' });
|
||||
if (!link) {
|
||||
return res.status(400).send({ error: "Lien introuvable" });
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return res.status(400).send({
|
||||
error:
|
||||
"Une erreur est survenue lors de la suppression du lien (link/remove->findLink)",
|
||||
});
|
||||
}
|
||||
|
||||
try {
|
||||
await prisma.link.delete({
|
||||
where: { id: Number(lid) }
|
||||
});
|
||||
try {
|
||||
const link = await prisma.link.delete({
|
||||
where: { id: Number(lid) },
|
||||
});
|
||||
|
||||
return res.status(200).send({ success: 'Le lien a été supprimé avec succès' });
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return res.status(400).send({ error: 'Une erreur est survenue lors de la suppression du lien (link/remove->deleteLink)' });
|
||||
}
|
||||
}
|
||||
return res.status(200).send({
|
||||
success: "Le lien a été supprimé avec succès",
|
||||
categoryId: link.categoryId,
|
||||
});
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return res.status(400).send({
|
||||
error:
|
||||
"Une erreur est survenue lors de la suppression du lien (link/remove->deleteLink)",
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,64 +1,68 @@
|
||||
import axios from 'axios';
|
||||
import { useRouter } from 'next/router';
|
||||
import nProgress from 'nprogress';
|
||||
import { useMemo, useState } from 'react';
|
||||
import axios from "axios";
|
||||
import { useRouter } from "next/router";
|
||||
import nProgress from "nprogress";
|
||||
import { useMemo, useState } from "react";
|
||||
|
||||
import { redirectWithoutClientCache } from '../../utils/client';
|
||||
import { HandleAxiosError } from '../../utils/front';
|
||||
import FormLayout from "../../components/FormLayout";
|
||||
import TextBox from "../../components/TextBox";
|
||||
|
||||
import FormLayout from '../../components/FormLayout';
|
||||
import TextBox from '../../components/TextBox';
|
||||
import { redirectWithoutClientCache } from "../../utils/client";
|
||||
import { HandleAxiosError } from "../../utils/front";
|
||||
|
||||
import styles from '../../styles/create.module.scss';
|
||||
import styles from "../../styles/create.module.scss";
|
||||
|
||||
function CreateCategory() {
|
||||
const router = useRouter();
|
||||
const info = useRouter().query?.info as string;
|
||||
const [name, setName] = useState<string>('');
|
||||
const router = useRouter();
|
||||
const info = useRouter().query?.info as string;
|
||||
const [name, setName] = useState<string>("");
|
||||
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
const [success, setSuccess] = useState<string | null>(null);
|
||||
const [submitted, setSubmitted] = useState<boolean>(false);
|
||||
const canSubmit = useMemo<boolean>(() => name.length !== 0 && !submitted, [name.length, submitted]);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
const [submitted, setSubmitted] = useState<boolean>(false);
|
||||
|
||||
const handleSubmit = async (event) => {
|
||||
event.preventDefault();
|
||||
setSuccess(null);
|
||||
setError(null);
|
||||
setSubmitted(false);
|
||||
nProgress.start();
|
||||
const canSubmit = useMemo<boolean>(
|
||||
() => name.length !== 0 && !submitted,
|
||||
[name.length, submitted]
|
||||
);
|
||||
|
||||
try {
|
||||
await axios.post('/api/category/create', { name });
|
||||
redirectWithoutClientCache(router, '');
|
||||
router.push('/')
|
||||
} catch (error) {
|
||||
setError(HandleAxiosError(error));
|
||||
setSubmitted(true);
|
||||
} finally {
|
||||
nProgress.done();
|
||||
}
|
||||
const handleSubmit = async (event) => {
|
||||
event.preventDefault();
|
||||
setError(null);
|
||||
setSubmitted(true);
|
||||
nProgress.start();
|
||||
|
||||
try {
|
||||
const { data } = await axios.post("/api/category/create", { name });
|
||||
redirectWithoutClientCache(router, "");
|
||||
router.push(`/?categoryId=${data?.categoryId}`);
|
||||
setSubmitted(true);
|
||||
} catch (error) {
|
||||
setError(HandleAxiosError(error));
|
||||
setSubmitted(false);
|
||||
} finally {
|
||||
nProgress.done();
|
||||
}
|
||||
};
|
||||
|
||||
return (<>
|
||||
<FormLayout
|
||||
title='Créer une catégorie'
|
||||
errorMessage={error}
|
||||
successMessage={success}
|
||||
infoMessage={info}
|
||||
canSubmit={canSubmit}
|
||||
handleSubmit={handleSubmit}
|
||||
>
|
||||
<TextBox
|
||||
name='name'
|
||||
label='Nom de la catégorie'
|
||||
onChangeCallback={(value) => setName(value)}
|
||||
value={name}
|
||||
fieldClass={styles['input-field']}
|
||||
placeholder='Nom...'
|
||||
/>
|
||||
</FormLayout>
|
||||
</>);
|
||||
return (
|
||||
<>
|
||||
<FormLayout
|
||||
title="Créer une catégorie"
|
||||
errorMessage={error}
|
||||
infoMessage={info}
|
||||
canSubmit={canSubmit}
|
||||
handleSubmit={handleSubmit}
|
||||
>
|
||||
<TextBox
|
||||
name="name"
|
||||
label="Nom de la catégorie"
|
||||
onChangeCallback={(value) => setName(value)}
|
||||
value={name}
|
||||
fieldClass={styles["input-field"]}
|
||||
placeholder="Nom..."
|
||||
/>
|
||||
</FormLayout>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
CreateCategory.authRequired = true;
|
||||
|
||||
@@ -1,92 +1,99 @@
|
||||
import axios, { AxiosResponse } from 'axios';
|
||||
import nProgress from 'nprogress';
|
||||
import { useEffect, useState } from 'react';
|
||||
import axios from "axios";
|
||||
import { useRouter } from "next/router";
|
||||
import nProgress from "nprogress";
|
||||
import { useMemo, useState } from "react";
|
||||
|
||||
import FormLayout from '../../../components/FormLayout';
|
||||
import TextBox from '../../../components/TextBox';
|
||||
import FormLayout from "../../../components/FormLayout";
|
||||
import TextBox from "../../../components/TextBox";
|
||||
|
||||
import { Category } from '../../../types';
|
||||
import { prisma } from '../../../utils/back';
|
||||
import { BuildCategory, HandleAxiosError } from '../../../utils/front';
|
||||
import useAutoFocus from "../../../hooks/useAutoFocus";
|
||||
|
||||
import styles from '../../../styles/create.module.scss';
|
||||
import { Category } from "../../../types";
|
||||
import { prisma } from "../../../utils/back";
|
||||
import { BuildCategory, HandleAxiosError } from "../../../utils/front";
|
||||
|
||||
function EditCategory({ category }: { category: Category; }) {
|
||||
const [name, setName] = useState<string>(category.name);
|
||||
import styles from "../../../styles/create.module.scss";
|
||||
|
||||
const [canSubmit, setCanSubmit] = useState<boolean>(false);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
const [success, setSuccess] = useState<string | null>(null);
|
||||
function EditCategory({ category }: { category: Category }) {
|
||||
const autoFocusRef = useAutoFocus();
|
||||
const router = useRouter();
|
||||
|
||||
useEffect(() => {
|
||||
if (name !== category.name && name !== '') {
|
||||
setCanSubmit(true);
|
||||
} else {
|
||||
setCanSubmit(false);
|
||||
}
|
||||
}, [category, name]);
|
||||
const [name, setName] = useState<string>(category.name);
|
||||
|
||||
const handleSubmit = async (event) => {
|
||||
event.preventDefault();
|
||||
setSuccess(null);
|
||||
setError(null);
|
||||
setCanSubmit(false);
|
||||
nProgress.start();
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
const [submitted, setSubmitted] = useState<boolean>(false);
|
||||
|
||||
try {
|
||||
const payload = { name };
|
||||
const { data }: AxiosResponse<any> = await axios.put(`/api/category/edit/${category.id}`, payload);
|
||||
setSuccess(data?.success || 'Catégorie modifiée avec succès');
|
||||
} catch (error) {
|
||||
setError(HandleAxiosError(error));
|
||||
} finally {
|
||||
setCanSubmit(true);
|
||||
nProgress.done();
|
||||
}
|
||||
const canSubmit = useMemo<boolean>(
|
||||
() => name !== category.name && name !== "" && !submitted,
|
||||
[category.name, name, submitted]
|
||||
);
|
||||
|
||||
const handleSubmit = async (event) => {
|
||||
event.preventDefault();
|
||||
setError(null);
|
||||
setSubmitted(true);
|
||||
nProgress.start();
|
||||
|
||||
try {
|
||||
const payload = { name };
|
||||
const { data } = await axios.put(
|
||||
`/api/category/edit/${category.id}`,
|
||||
payload
|
||||
);
|
||||
router.push(`/?categoryId=${data?.categoryId}`);
|
||||
setSubmitted(true);
|
||||
} catch (error) {
|
||||
setError(HandleAxiosError(error));
|
||||
setSubmitted(false);
|
||||
} finally {
|
||||
nProgress.done();
|
||||
}
|
||||
};
|
||||
|
||||
return (<>
|
||||
<FormLayout
|
||||
title='Modifier une catégorie'
|
||||
errorMessage={error}
|
||||
successMessage={success}
|
||||
canSubmit={canSubmit}
|
||||
handleSubmit={handleSubmit}
|
||||
>
|
||||
<TextBox
|
||||
name='name'
|
||||
label='Nom'
|
||||
onChangeCallback={(value) => setName(value)}
|
||||
value={name}
|
||||
fieldClass={styles['input-field']}
|
||||
placeholder={`Nom original : ${category.name}`}
|
||||
/>
|
||||
</FormLayout>
|
||||
</>);
|
||||
return (
|
||||
<>
|
||||
<FormLayout
|
||||
title="Modifier une catégorie"
|
||||
errorMessage={error}
|
||||
canSubmit={canSubmit}
|
||||
handleSubmit={handleSubmit}
|
||||
>
|
||||
<TextBox
|
||||
name="name"
|
||||
label="Nom"
|
||||
onChangeCallback={(value) => setName(value)}
|
||||
value={name}
|
||||
fieldClass={styles["input-field"]}
|
||||
placeholder={`Nom original : ${category.name}`}
|
||||
innerRef={autoFocusRef}
|
||||
/>
|
||||
</FormLayout>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
EditCategory.authRequired = true;
|
||||
export default EditCategory;
|
||||
|
||||
export async function getServerSideProps({ query }) {
|
||||
const { cid } = query;
|
||||
const categoryDB = await prisma.category.findFirst({
|
||||
where: { id: Number(cid) },
|
||||
include: { links: true }
|
||||
});
|
||||
const { cid } = query;
|
||||
const categoryDB = await prisma.category.findFirst({
|
||||
where: { id: Number(cid) },
|
||||
include: { links: true },
|
||||
});
|
||||
|
||||
if (!categoryDB) {
|
||||
return {
|
||||
redirect: {
|
||||
destination: '/'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const category = BuildCategory(categoryDB);
|
||||
if (!categoryDB) {
|
||||
return {
|
||||
props: {
|
||||
category: JSON.parse(JSON.stringify(category))
|
||||
}
|
||||
}
|
||||
}
|
||||
redirect: {
|
||||
destination: "/",
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
const category = BuildCategory(categoryDB);
|
||||
return {
|
||||
props: {
|
||||
category: JSON.parse(JSON.stringify(category)),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,96 +1,103 @@
|
||||
import axios, { AxiosResponse } from 'axios';
|
||||
import nProgress from 'nprogress';
|
||||
import { useEffect, useState } from 'react';
|
||||
import axios from "axios";
|
||||
import { useRouter } from "next/router";
|
||||
import nProgress from "nprogress";
|
||||
import { useMemo, useState } from "react";
|
||||
|
||||
import FormLayout from '../../../components/FormLayout';
|
||||
import TextBox from '../../../components/TextBox';
|
||||
import Checkbox from "../../../components/Checkbox";
|
||||
import FormLayout from "../../../components/FormLayout";
|
||||
import TextBox from "../../../components/TextBox";
|
||||
|
||||
import { Category } from '../../../types';
|
||||
import { BuildCategory, HandleAxiosError } from '../../../utils/front';
|
||||
import { prisma } from '../../../utils/back';
|
||||
import { Category } from "../../../types";
|
||||
import { prisma } from "../../../utils/back";
|
||||
import { BuildCategory, HandleAxiosError } from "../../../utils/front";
|
||||
|
||||
import styles from '../../../styles/create.module.scss';
|
||||
import styles from "../../../styles/create.module.scss";
|
||||
|
||||
function RemoveCategory({ category }: { category: Category; }) {
|
||||
const [canSubmit, setCanSubmit] = useState<boolean>(false);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
const [success, setSuccess] = useState<string | null>(null);
|
||||
function RemoveCategory({ category }: { category: Category }) {
|
||||
const router = useRouter();
|
||||
const [error, setError] = useState<string | null>(
|
||||
category.links.length > 0
|
||||
? "Vous devez supprimer tous les liens de cette catégorie avant de pouvoir supprimer cette catégorie"
|
||||
: null
|
||||
);
|
||||
const [confirmDelete, setConfirmDelete] = useState<boolean>(false);
|
||||
const [submitted, setSubmitted] = useState<boolean>(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (category.links.length > 0) {
|
||||
setError('Vous devez supprimer tous les liens de cette catégorie avant de pouvoir supprimer cette catégorie')
|
||||
setCanSubmit(false);
|
||||
} else {
|
||||
setCanSubmit(true);
|
||||
}
|
||||
}, [category]);
|
||||
const canSubmit = useMemo<boolean>(
|
||||
() => category.links.length === 0 && confirmDelete && !submitted,
|
||||
[category.links.length, confirmDelete, submitted]
|
||||
);
|
||||
|
||||
if (status === 'loading') {
|
||||
return (<p>Chargement de la session en cours</p>)
|
||||
const handleSubmit = async (event) => {
|
||||
event.preventDefault();
|
||||
setError(null);
|
||||
setSubmitted(true);
|
||||
nProgress.start();
|
||||
|
||||
try {
|
||||
await axios.delete(`/api/category/remove/${category.id}`);
|
||||
router.push("/");
|
||||
setSubmitted(true);
|
||||
} catch (error) {
|
||||
setError(HandleAxiosError(error));
|
||||
setSubmitted(false);
|
||||
} finally {
|
||||
nProgress.done();
|
||||
}
|
||||
};
|
||||
|
||||
const handleSubmit = async (event) => {
|
||||
event.preventDefault();
|
||||
setSuccess(null);
|
||||
setError(null);
|
||||
setCanSubmit(false);
|
||||
nProgress.start();
|
||||
|
||||
try {
|
||||
const { data }: AxiosResponse<any> = await axios.delete(`/api/category/remove/${category.id}`);
|
||||
setSuccess(data?.success || 'Categorie supprimée avec succès');
|
||||
setCanSubmit(false);
|
||||
} catch (error) {
|
||||
setError(HandleAxiosError(error));
|
||||
setCanSubmit(true);
|
||||
} finally {
|
||||
nProgress.done();
|
||||
}
|
||||
}
|
||||
|
||||
return (<>
|
||||
<FormLayout
|
||||
title='Supprimer une catégorie'
|
||||
errorMessage={error}
|
||||
successMessage={success}
|
||||
canSubmit={canSubmit}
|
||||
handleSubmit={handleSubmit}
|
||||
classBtnConfirm='red-btn'
|
||||
textBtnConfirm='Supprimer'
|
||||
>
|
||||
<TextBox
|
||||
name='name'
|
||||
label='Nom'
|
||||
value={category.name}
|
||||
fieldClass={styles['input-field']}
|
||||
disabled={true}
|
||||
/>
|
||||
</FormLayout>
|
||||
</>);
|
||||
return (
|
||||
<>
|
||||
<FormLayout
|
||||
title="Supprimer une catégorie"
|
||||
categoryId={category.id.toString()}
|
||||
errorMessage={error}
|
||||
canSubmit={canSubmit}
|
||||
handleSubmit={handleSubmit}
|
||||
classBtnConfirm="red-btn"
|
||||
textBtnConfirm="Supprimer"
|
||||
>
|
||||
<TextBox
|
||||
name="name"
|
||||
label="Nom"
|
||||
value={category.name}
|
||||
fieldClass={styles["input-field"]}
|
||||
disabled={true}
|
||||
/>
|
||||
<Checkbox
|
||||
name="confirm-delete"
|
||||
label="Confirmer la suppression ?"
|
||||
isChecked={confirmDelete}
|
||||
disabled={!!error}
|
||||
onChangeCallback={(checked) => setConfirmDelete(checked)}
|
||||
/>
|
||||
</FormLayout>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
RemoveCategory.authRequired = true;
|
||||
export default RemoveCategory;
|
||||
|
||||
export async function getServerSideProps({ query }) {
|
||||
const { cid } = query;
|
||||
const categoryDB = await prisma.category.findFirst({
|
||||
where: { id: Number(cid) },
|
||||
include: { links: true }
|
||||
});
|
||||
const { cid } = query;
|
||||
const categoryDB = await prisma.category.findFirst({
|
||||
where: { id: Number(cid) },
|
||||
include: { links: true },
|
||||
});
|
||||
|
||||
if (!categoryDB) {
|
||||
return {
|
||||
redirect: {
|
||||
destination: '/'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const category = BuildCategory(categoryDB);
|
||||
if (!categoryDB) {
|
||||
return {
|
||||
props: {
|
||||
category: JSON.parse(JSON.stringify(category))
|
||||
}
|
||||
}
|
||||
}
|
||||
redirect: {
|
||||
destination: "/",
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
const category = BuildCategory(categoryDB);
|
||||
return {
|
||||
props: {
|
||||
category: JSON.parse(JSON.stringify(category)),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
@@ -6,22 +6,28 @@ import SideMenu from "../components/SideMenu/SideMenu";
|
||||
|
||||
import { Category, Link } from "../types";
|
||||
|
||||
import { useRouter } from "next/router";
|
||||
import { prisma } from "../utils/back";
|
||||
import { BuildCategory } from "../utils/front";
|
||||
|
||||
interface HomeProps {
|
||||
categories: Category[];
|
||||
favorites: Link[];
|
||||
currentCategory: Category | undefined;
|
||||
}
|
||||
|
||||
function Home({ categories, favorites }: HomeProps) {
|
||||
function Home({ categories, favorites, currentCategory }: HomeProps) {
|
||||
const router = useRouter();
|
||||
const { data } = useSession({ required: true });
|
||||
|
||||
const [categoryActive, setCategoryActive] = useState<Category | null>(
|
||||
categories?.[0]
|
||||
currentCategory || categories?.[0]
|
||||
);
|
||||
|
||||
const handleSelectCategory = (category: Category) =>
|
||||
const handleSelectCategory = (category: Category) => {
|
||||
setCategoryActive(category);
|
||||
router.push(`/?categoryId=${category.id}`);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="App">
|
||||
@@ -37,7 +43,9 @@ function Home({ categories, favorites }: HomeProps) {
|
||||
);
|
||||
}
|
||||
|
||||
export async function getServerSideProps() {
|
||||
export async function getServerSideProps({ query }) {
|
||||
const queryCategoryId = (query?.categoryId as string) || "";
|
||||
|
||||
const categoriesDB = await prisma.category.findMany({
|
||||
include: { links: true },
|
||||
});
|
||||
@@ -57,10 +65,17 @@ export async function getServerSideProps() {
|
||||
};
|
||||
}
|
||||
|
||||
const currentCategory = categories.find(
|
||||
(c) => c.id === Number(queryCategoryId)
|
||||
);
|
||||
|
||||
return {
|
||||
props: {
|
||||
categories: JSON.parse(JSON.stringify(categories)),
|
||||
favorites: JSON.parse(JSON.stringify(favorites)),
|
||||
currentCategory: currentCategory
|
||||
? JSON.parse(JSON.stringify(currentCategory))
|
||||
: null,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,108 +1,132 @@
|
||||
import axios, { AxiosResponse } from 'axios';
|
||||
import { useRouter } from 'next/router';
|
||||
import nProgress from 'nprogress';
|
||||
import { useMemo, useState } from 'react';
|
||||
import axios from "axios";
|
||||
import { useRouter } from "next/router";
|
||||
import nProgress from "nprogress";
|
||||
import { useMemo, useState } from "react";
|
||||
|
||||
import Checkbox from '../../components/Checkbox';
|
||||
import FormLayout from '../../components/FormLayout';
|
||||
import Selector from '../../components/Selector';
|
||||
import TextBox from '../../components/TextBox';
|
||||
import Checkbox from "../../components/Checkbox";
|
||||
import FormLayout from "../../components/FormLayout";
|
||||
import Selector from "../../components/Selector";
|
||||
import TextBox from "../../components/TextBox";
|
||||
|
||||
import { Category, Link } from '../../types';
|
||||
import { BuildCategory, HandleAxiosError, IsValidURL } from '../../utils/front';
|
||||
import useAutoFocus from "../../hooks/useAutoFocus";
|
||||
|
||||
import { prisma } from '../../utils/back';
|
||||
import { Category, Link } from "../../types";
|
||||
import { prisma } from "../../utils/back";
|
||||
import { BuildCategory, HandleAxiosError, IsValidURL } from "../../utils/front";
|
||||
|
||||
import styles from '../../styles/create.module.scss';
|
||||
import styles from "../../styles/create.module.scss";
|
||||
|
||||
function CreateLink({ categories }: { categories: Category[]; }) {
|
||||
const { query } = useRouter();
|
||||
const categoryIdQuery = Number(query.categoryId?.[0]);
|
||||
function CreateLink({ categories }: { categories: Category[] }) {
|
||||
const autoFocusRef = useAutoFocus();
|
||||
const router = useRouter();
|
||||
const categoryIdQuery = router.query?.categoryId as string;
|
||||
|
||||
const [name, setName] = useState<Link['name']>('');
|
||||
const [url, setUrl] = useState<Link['url']>('');
|
||||
const [favorite, setFavorite] = useState<Link['favorite']>(false);
|
||||
const [categoryId, setCategoryId] = useState<Link['category']['id']>(categoryIdQuery || categories?.[0].id || null);
|
||||
const [name, setName] = useState<Link["name"]>("");
|
||||
const [url, setUrl] = useState<Link["url"]>("");
|
||||
const [favorite, setFavorite] = useState<Link["favorite"]>(false);
|
||||
const [categoryId, setCategoryId] = useState<Link["category"]["id"]>(
|
||||
Number(categoryIdQuery) || categories?.[0].id || null
|
||||
);
|
||||
|
||||
const [error, setError] = useState<string>(null);
|
||||
const [success, setSuccess] = useState<string>(null);
|
||||
const [submitted, setSubmitted] = useState<boolean>(false);
|
||||
const [error, setError] = useState<string>(null);
|
||||
const [submitted, setSubmitted] = useState<boolean>(false);
|
||||
|
||||
const canSubmit = useMemo<boolean>(
|
||||
() => name !== '' && IsValidURL(url) && favorite !== null && categoryId !== null && !submitted,
|
||||
[name, url, favorite, categoryId, submitted]
|
||||
);
|
||||
const canSubmit = useMemo<boolean>(
|
||||
() =>
|
||||
name !== "" &&
|
||||
IsValidURL(url) &&
|
||||
favorite !== null &&
|
||||
categoryId !== null &&
|
||||
!submitted,
|
||||
[name, url, favorite, categoryId, submitted]
|
||||
);
|
||||
|
||||
const handleSubmit = async (event) => {
|
||||
event.preventDefault();
|
||||
setSuccess(null);
|
||||
setError(null);
|
||||
setSubmitted(false);
|
||||
nProgress.start();
|
||||
const handleSubmit = async (event) => {
|
||||
event.preventDefault();
|
||||
setError(null);
|
||||
setSubmitted(true);
|
||||
nProgress.start();
|
||||
|
||||
try {
|
||||
const payload = { name, url, favorite, categoryId };
|
||||
const { data }: AxiosResponse<any> = await axios.post('/api/link/create', payload);
|
||||
setSuccess(data?.success || 'Lien modifié avec succès');
|
||||
} catch (error) {
|
||||
setError(HandleAxiosError(error));
|
||||
} finally {
|
||||
setSubmitted(true);
|
||||
nProgress.done();
|
||||
}
|
||||
try {
|
||||
const payload = { name, url, favorite, categoryId };
|
||||
const { data } = await axios.post("/api/link/create", payload);
|
||||
router.push(`/?categoryId=${data?.categoryId}`);
|
||||
setSubmitted(true);
|
||||
} catch (error) {
|
||||
setError(HandleAxiosError(error));
|
||||
} finally {
|
||||
setSubmitted(true);
|
||||
nProgress.done();
|
||||
}
|
||||
};
|
||||
|
||||
return (<>
|
||||
<FormLayout
|
||||
title='Créer un lien'
|
||||
errorMessage={error}
|
||||
successMessage={success}
|
||||
canSubmit={canSubmit}
|
||||
handleSubmit={handleSubmit}
|
||||
>
|
||||
<TextBox
|
||||
name='name'
|
||||
label='Nom'
|
||||
onChangeCallback={(value) => setName(value)}
|
||||
value={name}
|
||||
fieldClass={styles['input-field']}
|
||||
placeholder='Nom du lien'
|
||||
/>
|
||||
<TextBox
|
||||
name='url'
|
||||
label='URL'
|
||||
onChangeCallback={(value) => setUrl(value)}
|
||||
value={url}
|
||||
fieldClass={styles['input-field']}
|
||||
placeholder='https://www.example.org/'
|
||||
/>
|
||||
<Selector
|
||||
name='category'
|
||||
label='Catégorie'
|
||||
value={categoryId}
|
||||
onChangeCallback={(value: number) => setCategoryId(value)}
|
||||
options={categories.map(({ id, name }) => ({ label: name, value: id }))}
|
||||
/>
|
||||
<Checkbox
|
||||
name='favorite'
|
||||
isChecked={favorite}
|
||||
onChangeCallback={(value) => setFavorite(value)}
|
||||
label='Favoris'
|
||||
/>
|
||||
</FormLayout>
|
||||
</>);
|
||||
return (
|
||||
<>
|
||||
<FormLayout
|
||||
title="Créer un lien"
|
||||
categoryId={categoryIdQuery}
|
||||
errorMessage={error}
|
||||
canSubmit={canSubmit}
|
||||
handleSubmit={handleSubmit}
|
||||
>
|
||||
<TextBox
|
||||
name="name"
|
||||
label="Nom"
|
||||
onChangeCallback={(value) => setName(value)}
|
||||
value={name}
|
||||
fieldClass={styles["input-field"]}
|
||||
placeholder="Nom du lien"
|
||||
innerRef={autoFocusRef}
|
||||
/>
|
||||
<TextBox
|
||||
name="url"
|
||||
label="URL"
|
||||
onChangeCallback={(value) => setUrl(value)}
|
||||
value={url}
|
||||
fieldClass={styles["input-field"]}
|
||||
placeholder="https://www.example.org/"
|
||||
/>
|
||||
<Selector
|
||||
name="category"
|
||||
label="Catégorie"
|
||||
value={categoryId}
|
||||
onChangeCallback={(value: number) => setCategoryId(value)}
|
||||
options={categories.map(({ id, name }) => ({
|
||||
label: name,
|
||||
value: id,
|
||||
}))}
|
||||
/>
|
||||
<Checkbox
|
||||
name="favorite"
|
||||
isChecked={favorite}
|
||||
onChangeCallback={(value) => setFavorite(value)}
|
||||
label="Favoris"
|
||||
/>
|
||||
</FormLayout>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
CreateLink.authRequired = true;
|
||||
export default CreateLink;
|
||||
|
||||
export async function getServerSideProps() {
|
||||
const categoriesDB = await prisma.category.findMany();
|
||||
const categories = categoriesDB.map((categoryDB) => BuildCategory(categoryDB));
|
||||
const categoriesDB = await prisma.category.findMany();
|
||||
const categories = categoriesDB.map((categoryDB) =>
|
||||
BuildCategory(categoryDB)
|
||||
);
|
||||
|
||||
if (categories.length === 0) {
|
||||
return {
|
||||
props: {
|
||||
categories: JSON.parse(JSON.stringify(categories))
|
||||
}
|
||||
}
|
||||
}
|
||||
redirect: {
|
||||
destination: "/",
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
props: {
|
||||
categories: JSON.parse(JSON.stringify(categories)),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,129 +1,167 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import axios from "axios";
|
||||
import { useRouter } from "next/router";
|
||||
import nProgress from "nprogress";
|
||||
import { useMemo, useState } from "react";
|
||||
|
||||
import axios, { AxiosResponse } from 'axios';
|
||||
import nProgress from 'nprogress';
|
||||
import Checkbox from "../../../components/Checkbox";
|
||||
import FormLayout from "../../../components/FormLayout";
|
||||
import Selector from "../../../components/Selector";
|
||||
import TextBox from "../../../components/TextBox";
|
||||
|
||||
import FormLayout from '../../../components/FormLayout';
|
||||
import TextBox from '../../../components/TextBox';
|
||||
import Selector from '../../../components/Selector';
|
||||
import Checkbox from '../../../components/Checkbox';
|
||||
import useAutoFocus from "../../../hooks/useAutoFocus";
|
||||
|
||||
import styles from '../../../styles/create.module.scss';
|
||||
import { Category, Link } from "../../../types";
|
||||
import { prisma } from "../../../utils/back";
|
||||
import {
|
||||
BuildCategory,
|
||||
BuildLink,
|
||||
HandleAxiosError,
|
||||
IsValidURL,
|
||||
} from "../../../utils/front";
|
||||
|
||||
import { Category, Link } from '../../../types';
|
||||
import { BuildCategory, BuildLink, HandleAxiosError, IsValidURL } from '../../../utils/front';
|
||||
import styles from "../../../styles/create.module.scss";
|
||||
|
||||
import { prisma } from '../../../utils/back';
|
||||
function EditLink({
|
||||
link,
|
||||
categories,
|
||||
}: {
|
||||
link: Link;
|
||||
categories: Category[];
|
||||
}) {
|
||||
const autoFocusRef = useAutoFocus();
|
||||
const router = useRouter();
|
||||
|
||||
function EditLink({ link, categories }: { link: Link; categories: Category[]; }) {
|
||||
const [name, setName] = useState<string>(link.name);
|
||||
const [url, setUrl] = useState<string>(link.url);
|
||||
const [favorite, setFavorite] = useState<boolean>(link.favorite);
|
||||
const [categoryId, setCategoryId] = useState<number | null>(link.category?.id || null);
|
||||
const [name, setName] = useState<string>(link.name);
|
||||
const [url, setUrl] = useState<string>(link.url);
|
||||
const [favorite, setFavorite] = useState<boolean>(link.favorite);
|
||||
const [categoryId, setCategoryId] = useState<number | null>(
|
||||
link.category?.id || null
|
||||
);
|
||||
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
const [success, setSuccess] = useState<string | null>(null);
|
||||
const [canSubmit, setCanSubmit] = useState<boolean>(false);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
const [submitted, setSubmitted] = useState<boolean>(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (name !== link.name || url !== link.url || favorite !== link.favorite || categoryId !== link.category.id) {
|
||||
if (name !== '' && IsValidURL(url) && favorite !== null && categoryId !== null) {
|
||||
setCanSubmit(true);
|
||||
} else {
|
||||
setCanSubmit(false);
|
||||
}
|
||||
} else {
|
||||
setCanSubmit(false);
|
||||
}
|
||||
}, [name, url, favorite, categoryId, link]);
|
||||
const canSubmit = useMemo<boolean>(() => {
|
||||
const isFormEdited =
|
||||
name !== link.name ||
|
||||
url !== link.url ||
|
||||
favorite !== link.favorite ||
|
||||
categoryId !== link.category.id;
|
||||
const isFormValid =
|
||||
name !== "" &&
|
||||
IsValidURL(url) &&
|
||||
favorite !== null &&
|
||||
categoryId !== null;
|
||||
return isFormEdited && isFormValid && !submitted;
|
||||
}, [
|
||||
categoryId,
|
||||
favorite,
|
||||
link.category.id,
|
||||
link.favorite,
|
||||
link.name,
|
||||
link.url,
|
||||
name,
|
||||
submitted,
|
||||
url,
|
||||
]);
|
||||
|
||||
const handleSubmit = async (event) => {
|
||||
event.preventDefault();
|
||||
setSuccess(null);
|
||||
setError(null);
|
||||
setCanSubmit(false);
|
||||
nProgress.start();
|
||||
const handleSubmit = async (event) => {
|
||||
event.preventDefault();
|
||||
setError(null);
|
||||
setSubmitted(true);
|
||||
nProgress.start();
|
||||
|
||||
try {
|
||||
const payload = { name, url, favorite, categoryId };
|
||||
const { data }: AxiosResponse<any> = await axios.put(`/api/link/edit/${link.id}`, payload);
|
||||
setSuccess(data?.success || 'Lien modifié avec succès');
|
||||
} catch (error) {
|
||||
setError(HandleAxiosError(error));
|
||||
} finally {
|
||||
setCanSubmit(true);
|
||||
nProgress.done();
|
||||
}
|
||||
try {
|
||||
const payload = { name, url, favorite, categoryId };
|
||||
const { data } = await axios.put(`/api/link/edit/${link.id}`, payload);
|
||||
router.push(`/?categoryId=${data?.categoryId}`);
|
||||
setSubmitted(true);
|
||||
} catch (error) {
|
||||
setError(HandleAxiosError(error));
|
||||
setSubmitted(false);
|
||||
} finally {
|
||||
nProgress.done();
|
||||
}
|
||||
};
|
||||
|
||||
return (<>
|
||||
<FormLayout
|
||||
title='Modifier un lien'
|
||||
errorMessage={error}
|
||||
successMessage={success}
|
||||
canSubmit={canSubmit}
|
||||
handleSubmit={handleSubmit}
|
||||
>
|
||||
<TextBox
|
||||
name='name'
|
||||
label='Nom'
|
||||
onChangeCallback={(value) => setName(value)}
|
||||
value={name}
|
||||
fieldClass={styles['input-field']}
|
||||
placeholder={`Nom original : ${link.name}`}
|
||||
/>
|
||||
<TextBox
|
||||
name='url'
|
||||
label='URL'
|
||||
onChangeCallback={(value) => setUrl(value)}
|
||||
value={url}
|
||||
fieldClass={styles['input-field']}
|
||||
placeholder={`URL original : ${link.url}`}
|
||||
/>
|
||||
<Selector
|
||||
name='category'
|
||||
label='Catégorie'
|
||||
value={categoryId}
|
||||
onChangeCallback={(value: number) => setCategoryId(value)}
|
||||
options={categories.map(({ id, name }) => ({ label: name, value: id }))}
|
||||
/>
|
||||
<Checkbox
|
||||
name='favorite'
|
||||
isChecked={favorite}
|
||||
onChangeCallback={(value) => setFavorite(value)}
|
||||
label='Favoris'
|
||||
/>
|
||||
</FormLayout>
|
||||
</>);
|
||||
return (
|
||||
<>
|
||||
<FormLayout
|
||||
title="Modifier un lien"
|
||||
errorMessage={error}
|
||||
canSubmit={canSubmit}
|
||||
handleSubmit={handleSubmit}
|
||||
>
|
||||
<TextBox
|
||||
name="name"
|
||||
label="Nom"
|
||||
onChangeCallback={(value) => setName(value)}
|
||||
value={name}
|
||||
fieldClass={styles["input-field"]}
|
||||
placeholder={`Nom original : ${link.name}`}
|
||||
innerRef={autoFocusRef}
|
||||
/>
|
||||
<TextBox
|
||||
name="url"
|
||||
label="URL"
|
||||
onChangeCallback={(value) => setUrl(value)}
|
||||
value={url}
|
||||
fieldClass={styles["input-field"]}
|
||||
placeholder={`URL original : ${link.url}`}
|
||||
/>
|
||||
<Selector
|
||||
name="category"
|
||||
label="Catégorie"
|
||||
value={categoryId}
|
||||
onChangeCallback={(value: number) => setCategoryId(value)}
|
||||
options={categories.map(({ id, name }) => ({
|
||||
label: name,
|
||||
value: id,
|
||||
}))}
|
||||
/>
|
||||
<Checkbox
|
||||
name="favorite"
|
||||
isChecked={favorite}
|
||||
onChangeCallback={(value) => setFavorite(value)}
|
||||
label="Favoris"
|
||||
/>
|
||||
</FormLayout>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
EditLink.authRequired = true;
|
||||
export default EditLink;
|
||||
|
||||
export async function getServerSideProps({ query }) {
|
||||
const { lid } = query;
|
||||
const { lid } = query;
|
||||
|
||||
const categoriesDB = await prisma.category.findMany();
|
||||
const categories = categoriesDB.map((categoryDB) => BuildCategory(categoryDB));
|
||||
const categoriesDB = await prisma.category.findMany();
|
||||
const categories = categoriesDB.map((categoryDB) =>
|
||||
BuildCategory(categoryDB)
|
||||
);
|
||||
|
||||
const linkDB = await prisma.link.findFirst({
|
||||
where: { id: Number(lid) },
|
||||
include: { category: true }
|
||||
});
|
||||
const linkDB = await prisma.link.findFirst({
|
||||
where: { id: Number(lid) },
|
||||
include: { category: true },
|
||||
});
|
||||
|
||||
if (!linkDB) {
|
||||
return {
|
||||
redirect: {
|
||||
destination: '/'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const link = BuildLink(linkDB, { categoryId: linkDB.categoryId, categoryName: linkDB.category.name });
|
||||
if (!linkDB) {
|
||||
return {
|
||||
props: {
|
||||
link: JSON.parse(JSON.stringify(link)),
|
||||
categories: JSON.parse(JSON.stringify(categories))
|
||||
}
|
||||
}
|
||||
}
|
||||
redirect: {
|
||||
destination: "/",
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
const link = BuildLink(linkDB, {
|
||||
categoryId: linkDB.categoryId,
|
||||
categoryName: linkDB.category.name,
|
||||
});
|
||||
return {
|
||||
props: {
|
||||
link: JSON.parse(JSON.stringify(link)),
|
||||
categories: JSON.parse(JSON.stringify(categories)),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,104 +1,120 @@
|
||||
import axios, { AxiosResponse } from 'axios';
|
||||
import nProgress from 'nprogress';
|
||||
import { useState } from 'react';
|
||||
import axios from "axios";
|
||||
import { useRouter } from "next/router";
|
||||
import nProgress from "nprogress";
|
||||
import { useMemo, useState } from "react";
|
||||
|
||||
import Checkbox from '../../../components/Checkbox';
|
||||
import FormLayout from '../../../components/FormLayout';
|
||||
import TextBox from '../../../components/TextBox';
|
||||
import Checkbox from "../../../components/Checkbox";
|
||||
import FormLayout from "../../../components/FormLayout";
|
||||
import TextBox from "../../../components/TextBox";
|
||||
|
||||
import { Link } from '../../../types';
|
||||
import { BuildLink, HandleAxiosError } from '../../../utils/front';
|
||||
import { prisma } from '../../../utils/back';
|
||||
import { Link } from "../../../types";
|
||||
import { prisma } from "../../../utils/back";
|
||||
import { BuildLink, HandleAxiosError } from "../../../utils/front";
|
||||
|
||||
import styles from '../../../styles/create.module.scss';
|
||||
import styles from "../../../styles/create.module.scss";
|
||||
|
||||
function RemoveLink({ link }: { link: Link; }) {
|
||||
const [canSubmit, setCanSubmit] = useState<boolean>(true);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
const [success, setSuccess] = useState<string | null>(null);
|
||||
function RemoveLink({ link }: { link: Link }) {
|
||||
const router = useRouter();
|
||||
|
||||
const handleSubmit = async (event) => {
|
||||
event.preventDefault();
|
||||
setSuccess(null);
|
||||
setError(null);
|
||||
setCanSubmit(false);
|
||||
nProgress.start();
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
const [confirmDelete, setConfirmDelete] = useState<boolean>(false);
|
||||
const [submitted, setSubmitted] = useState<boolean>(false);
|
||||
|
||||
try {
|
||||
const { data }: AxiosResponse<any> = await axios.delete(`/api/link/remove/${link.id}`);
|
||||
setSuccess(data?.success || 'Lien supprimé avec succès');
|
||||
setCanSubmit(false);
|
||||
} catch (error) {
|
||||
setError(HandleAxiosError(error));
|
||||
setCanSubmit(true);
|
||||
} finally {
|
||||
nProgress.done();
|
||||
}
|
||||
const canSubmit = useMemo<boolean>(
|
||||
() => confirmDelete && !submitted,
|
||||
[confirmDelete, submitted]
|
||||
);
|
||||
|
||||
const handleSubmit = async (event) => {
|
||||
event.preventDefault();
|
||||
setError(null);
|
||||
nProgress.start();
|
||||
|
||||
try {
|
||||
const { data } = await axios.delete(`/api/link/remove/${link.id}`);
|
||||
router.push(`/?categoryId=${data?.categoryId}`);
|
||||
setSubmitted(true);
|
||||
} catch (error) {
|
||||
setError(HandleAxiosError(error));
|
||||
} finally {
|
||||
nProgress.done();
|
||||
}
|
||||
};
|
||||
|
||||
return (<>
|
||||
<FormLayout
|
||||
title='Supprimer un lien'
|
||||
errorMessage={error}
|
||||
successMessage={success}
|
||||
canSubmit={canSubmit}
|
||||
handleSubmit={handleSubmit}
|
||||
classBtnConfirm='red-btn'
|
||||
textBtnConfirm='Supprimer'
|
||||
>
|
||||
<TextBox
|
||||
name='name'
|
||||
label='Nom'
|
||||
value={link.name}
|
||||
fieldClass={styles['input-field']}
|
||||
disabled={true}
|
||||
/>
|
||||
<TextBox
|
||||
name='url'
|
||||
label='URL'
|
||||
value={link.url}
|
||||
fieldClass={styles['input-field']}
|
||||
disabled={true}
|
||||
/>
|
||||
<TextBox
|
||||
name='category'
|
||||
label='Catégorie'
|
||||
value={link.category.name}
|
||||
fieldClass={styles['input-field']}
|
||||
disabled={true}
|
||||
/>
|
||||
<Checkbox
|
||||
name='favorite'
|
||||
label='Favoris'
|
||||
isChecked={link.favorite}
|
||||
disabled={true}
|
||||
/>
|
||||
</FormLayout>
|
||||
</>);
|
||||
return (
|
||||
<>
|
||||
<FormLayout
|
||||
title="Supprimer un lien"
|
||||
categoryId={link.category.id.toString()}
|
||||
errorMessage={error}
|
||||
canSubmit={canSubmit}
|
||||
handleSubmit={handleSubmit}
|
||||
classBtnConfirm="red-btn"
|
||||
textBtnConfirm="Supprimer"
|
||||
>
|
||||
<TextBox
|
||||
name="name"
|
||||
label="Nom"
|
||||
value={link.name}
|
||||
fieldClass={styles["input-field"]}
|
||||
disabled={true}
|
||||
/>
|
||||
<TextBox
|
||||
name="url"
|
||||
label="URL"
|
||||
value={link.url}
|
||||
fieldClass={styles["input-field"]}
|
||||
disabled={true}
|
||||
/>
|
||||
<TextBox
|
||||
name="category"
|
||||
label="Catégorie"
|
||||
value={link.category.name}
|
||||
fieldClass={styles["input-field"]}
|
||||
disabled={true}
|
||||
/>
|
||||
<Checkbox
|
||||
name="favorite"
|
||||
label="Favoris"
|
||||
isChecked={link.favorite}
|
||||
disabled={true}
|
||||
/>
|
||||
<Checkbox
|
||||
name="confirm-delete"
|
||||
label="Confirmer la suppression ?"
|
||||
isChecked={confirmDelete}
|
||||
onChangeCallback={(checked) => setConfirmDelete(checked)}
|
||||
/>
|
||||
</FormLayout>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
RemoveLink.authRequired = true;
|
||||
export default RemoveLink;
|
||||
|
||||
export async function getServerSideProps({ query }) {
|
||||
const { lid } = query;
|
||||
const linkDB = await prisma.link.findFirst({
|
||||
where: { id: Number(lid) },
|
||||
include: { category: true }
|
||||
});
|
||||
const { lid } = query;
|
||||
const linkDB = await prisma.link.findFirst({
|
||||
where: { id: Number(lid) },
|
||||
include: { category: true },
|
||||
});
|
||||
|
||||
if (!linkDB) {
|
||||
return {
|
||||
redirect: {
|
||||
destination: '/'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const link = BuildLink(linkDB, { categoryId: linkDB.categoryId, categoryName: linkDB.category.name });
|
||||
if (!linkDB) {
|
||||
return {
|
||||
props: {
|
||||
link: JSON.parse(JSON.stringify(link))
|
||||
}
|
||||
}
|
||||
}
|
||||
redirect: {
|
||||
destination: "/",
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
const link = BuildLink(linkDB, {
|
||||
categoryId: linkDB.categoryId,
|
||||
categoryName: linkDB.category.name,
|
||||
});
|
||||
return {
|
||||
props: {
|
||||
link: JSON.parse(JSON.stringify(link)),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user