diff --git a/prisma/migrations/20240409202205_add_link_description/migration.sql b/prisma/migrations/20240409202205_add_link_description/migration.sql
new file mode 100644
index 0000000..c0cef23
--- /dev/null
+++ b/prisma/migrations/20240409202205_add_link_description/migration.sql
@@ -0,0 +1,2 @@
+-- AlterTable
+ALTER TABLE `link` ADD COLUMN `description` VARCHAR(255) NULL;
diff --git a/prisma/schema.prisma b/prisma/schema.prisma
index d2d4df1..449a587 100644
--- a/prisma/schema.prisma
+++ b/prisma/schema.prisma
@@ -45,9 +45,10 @@ model Category {
}
model Link {
- id Int @id @default(autoincrement())
- name String @db.VarChar(255)
- url String @db.Text
+ id Int @id @default(autoincrement())
+ name String @db.VarChar(255)
+ description String? @db.VarChar(255)
+ url String @db.Text
category Category @relation(fields: [categoryId], references: [id])
categoryId Int
diff --git a/public/locales/en/common.json b/public/locales/en/common.json
index c08eafc..8b28e2f 100644
--- a/public/locales/en/common.json
+++ b/public/locales/en/common.json
@@ -8,6 +8,7 @@
"links": "Links",
"link": "Link",
"name": "Link name",
+ "description": "Link description",
"create": "Create a link",
"edit": "Edit a link",
"remove": "Delete a link",
diff --git a/public/locales/fr/common.json b/public/locales/fr/common.json
index bf524ad..3a312ac 100644
--- a/public/locales/fr/common.json
+++ b/public/locales/fr/common.json
@@ -8,6 +8,7 @@
"links": "Liens",
"link": "Lien",
"name": "Nom du lien",
+ "description": "Description du lien",
"create": "Créer un lien",
"edit": "Modifier un lien",
"remove": "Supprimer un lien",
diff --git a/src/components/Links/LinkItem.tsx b/src/components/Links/LinkItem.tsx
index 9a157b6..d1357e1 100644
--- a/src/components/Links/LinkItem.tsx
+++ b/src/components/Links/LinkItem.tsx
@@ -1,3 +1,4 @@
+import ExternalLink from 'components/ExternalLink';
import EditItem from 'components/QuickActions/EditItem';
import FavoriteItem from 'components/QuickActions/FavoriteItem';
import RemoveItem from 'components/QuickActions/RemoveItem';
@@ -5,7 +6,6 @@ import PATHS from 'constants/paths';
import { motion } from 'framer-motion';
import useCategories from 'hooks/useCategories';
import { makeRequest } from 'lib/request';
-import LinkTag from 'next/link';
import { useCallback } from 'react';
import { AiFillStar } from 'react-icons/ai';
import { LinkWithCategory } from 'types';
@@ -19,7 +19,7 @@ export default function LinkItem({
link: LinkWithCategory;
index: number;
}) {
- const { id, name, url, favorite } = link;
+ const { id, name, url, description, favorite } = link;
const { categories, setCategories } = useCategories();
const toggleFavorite = useCallback(
@@ -73,32 +73,35 @@ export default function LinkItem({
delay: index * 0.05,
}}
>
-
-
-
- {name} {favorite && }
-
-
-
-
-
-
-
+
+
+
+
+ {name} {favorite && }
+
+
+
+
+
+
+
+
+ {description && (
+
{description}
+ )}
);
}
diff --git a/src/components/Links/links.module.scss b/src/components/Links/links.module.scss
index be78665..c5e5b26 100644
--- a/src/components/Links/links.module.scss
+++ b/src/components/Links/links.module.scss
@@ -91,8 +91,18 @@
border: 1px solid $lightest-grey;
border-radius: 3px;
outline: 3px solid transparent;
- display: flex;
- align-items: center;
+
+ & .link-header {
+ display: flex;
+ align-items: center;
+ }
+
+ & .link-description {
+ margin-top: 0.5em;
+ color: $black;
+ font-size: 0.8em;
+ word-wrap: break-word;
+ }
&:hover {
border: 1px solid transparent;
@@ -109,7 +119,7 @@
}
}
-.link > a {
+.link-header > a {
height: 100%;
max-width: calc(100% - 125px); // TODO: faut fix ça, c'est pas beau
text-decoration: none;
diff --git a/src/lib/link/linkValidationSchema.ts b/src/lib/link/linkValidationSchema.ts
index 0bb9515..56a279d 100644
--- a/src/lib/link/linkValidationSchema.ts
+++ b/src/lib/link/linkValidationSchema.ts
@@ -6,6 +6,7 @@ const LinkBodySchema = object({
.trim()
.required('Link name is required')
.max(128, 'Link name is too long'),
+ description: string().trim().max(255, 'Link description is too long'),
url: string()
.trim()
.required('URl is required')
diff --git a/src/pages/api/link/[lid].ts b/src/pages/api/link/[lid].ts
index f6a1584..512b998 100644
--- a/src/pages/api/link/[lid].ts
+++ b/src/pages/api/link/[lid].ts
@@ -10,9 +10,8 @@ export default apiHandler({
async function editLink({ req, res, user }) {
const { lid } = await LinkQuerySchema.validate(req.query);
- const { name, url, favorite, categoryId } = await LinkBodySchema.validate(
- req.body,
- );
+ const { name, url, description, favorite, categoryId } =
+ await LinkBodySchema.validate(req.body);
const link = await getUserLink(user, lid);
if (!link) {
@@ -22,6 +21,7 @@ async function editLink({ req, res, user }) {
if (
link.name === name &&
link.url === url &&
+ link.description === description &&
link.favorite === favorite &&
link.categoryId === categoryId
) {
@@ -33,6 +33,7 @@ async function editLink({ req, res, user }) {
data: {
name,
url,
+ description,
favorite,
categoryId,
},
diff --git a/src/pages/api/link/index.ts b/src/pages/api/link/index.ts
index ea8e383..cf300fe 100644
--- a/src/pages/api/link/index.ts
+++ b/src/pages/api/link/index.ts
@@ -10,9 +10,8 @@ export default apiHandler({
});
async function createLink({ req, res, user }) {
- const { name, url, favorite, categoryId } = await LinkBodySchema.validate(
- req.body,
- );
+ const { name, url, description, favorite, categoryId } =
+ await LinkBodySchema.validate(req.body);
const link = await getUserLinkByName(user, name, categoryId);
if (link) {
@@ -28,6 +27,7 @@ async function createLink({ req, res, user }) {
data: {
name,
url,
+ description,
categoryId,
favorite,
authorId: user.id,
diff --git a/src/pages/link/create.tsx b/src/pages/link/create.tsx
index fc6ced8..4991e1b 100644
--- a/src/pages/link/create.tsx
+++ b/src/pages/link/create.tsx
@@ -28,6 +28,8 @@ export default function PageCreateLink({
const [name, setName] = useState
('');
const [url, setUrl] = useState('');
+ const [description, setDescription] =
+ useState('');
const [favorite, setFavorite] = useState(false);
const [categoryId, setCategoryId] = useState<
LinkWithCategory['category']['id']
@@ -54,7 +56,7 @@ export default function PageCreateLink({
makeRequest({
url: PATHS.API.LINK,
method: 'POST',
- body: { name, url, favorite, categoryId },
+ body: { name, url, description, favorite, categoryId },
})
.then((data) =>
router.push(`${PATHS.HOME}?categoryId=${data?.categoryId}`),
@@ -75,19 +77,29 @@ export default function PageCreateLink({
setName(value)}
+ onChangeCallback={setName}
value={name}
fieldClass={styles['input-field']}
placeholder={t('common:link.name')}
innerRef={autoFocusRef}
+ required
/>
setUrl(value)}
+ onChangeCallback={setUrl}
value={url}
fieldClass={styles['input-field']}
placeholder='https://www.example.com/'
+ required
+ />
+
setFavorite(value)}
+ onChangeCallback={setFavorite}
label={t('common:favorite')}
/>
diff --git a/src/pages/link/edit/[lid].tsx b/src/pages/link/edit/[lid].tsx
index dfc62d3..394b94b 100644
--- a/src/pages/link/edit/[lid].tsx
+++ b/src/pages/link/edit/[lid].tsx
@@ -30,6 +30,7 @@ export default function PageEditLink({
const [name, setName] = useState(link.name);
const [url, setUrl] = useState(link.url);
+ const [description, setDescription] = useState(link.description);
const [favorite, setFavorite] = useState(link.favorite);
const [categoryId, setCategoryId] = useState(
link.category?.id || null,
@@ -42,6 +43,7 @@ export default function PageEditLink({
const isFormEdited =
name !== link.name ||
url !== link.url ||
+ description !== link.description ||
favorite !== link.favorite ||
categoryId !== link.category.id;
const isFormValid =
@@ -50,17 +52,7 @@ export default function PageEditLink({
favorite !== null &&
categoryId !== null;
return isFormEdited && isFormValid && !submitted;
- }, [
- categoryId,
- favorite,
- link.category.id,
- link.favorite,
- link.name,
- link.url,
- name,
- submitted,
- url,
- ]);
+ }, [categoryId, description, favorite, link, name, submitted, url]);
const handleSubmit = async (event: FormEvent) => {
event.preventDefault();
@@ -70,7 +62,7 @@ export default function PageEditLink({
makeRequest({
url: `${PATHS.API.LINK}/${link.id}`,
method: 'PUT',
- body: { name, url, favorite, categoryId },
+ body: { name, url, description, favorite, categoryId },
})
.then((data) =>
router.push(`${PATHS.HOME}?categoryId=${data?.categoryId}`),
@@ -90,19 +82,29 @@ export default function PageEditLink({
setName(value)}
+ onChangeCallback={setName}
value={name}
fieldClass={styles['input-field']}
placeholder={`${t('common:link.name')} : ${link.name}`}
innerRef={autoFocusRef}
+ required
/>
setUrl(value)}
+ onChangeCallback={setUrl}
value={url}
fieldClass={styles['input-field']}
placeholder='https://example.com/'
+ required
+ />
+
setFavorite(value)}
+ onChangeCallback={setFavorite}
label={t('common:favorite')}
/>
diff --git a/src/pages/link/remove/[lid].tsx b/src/pages/link/remove/[lid].tsx
index 8908506..1924774 100644
--- a/src/pages/link/remove/[lid].tsx
+++ b/src/pages/link/remove/[lid].tsx
@@ -69,6 +69,13 @@ export default function PageRemoveLink({
fieldClass={styles['input-field']}
disabled={true}
/>
+