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} /> +