diff --git a/app/controllers/shared_collections_controller.ts b/app/controllers/shared_collections_controller.ts index fd2d971..8ee8899 100644 --- a/app/controllers/shared_collections_controller.ts +++ b/app/controllers/shared_collections_controller.ts @@ -1,27 +1,61 @@ import { Visibility } from '#enums/visibility'; import Collection from '#models/collection'; +import Link from '#models/link'; +import User from '#models/user'; import { getSharedCollectionValidator } from '#validators/shared_collection'; import type { HttpContext } from '@adonisjs/core/http'; +class LinkWithoutFavoriteDto { + constructor(private link: Link) {} + + toJson = () => ({ + id: this.link.id, + name: this.link.name, + description: this.link.description, + url: this.link.url, + collectionId: this.link.collectionId, + createdAt: this.link.createdAt.toString(), + updatedAt: this.link.updatedAt.toString(), + }); +} + +class UserWithoutEmailDto { + constructor(private user: User) {} + + toJson = () => ({ + id: this.user.id, + fullname: this.user.name, + avatarUrl: this.user.avatarUrl, + isAdmin: this.user.isAdmin, + createdAt: this.user.createdAt.toString(), + updatedAt: this.user.updatedAt.toString(), + }); +} + export default class SharedCollectionsController { - async index({ request, response }: HttpContext) { + async index({ request, inertia }: HttpContext) { const { params } = await request.validateUsing( getSharedCollectionValidator ); const collection = await this.getSharedCollectionById(params.id); - console.log('shared page', collection); - // TODO: return view - return response.json(collection); - // return inertia.render('shared', { collection }); + return inertia.render('shared', { collection }); } private async getSharedCollectionById(id: Collection['id']) { - return await Collection.query() + const collection = await Collection.query() .where('id', id) .andWhere('visibility', Visibility.PUBLIC) .preload('links') .preload('author') .firstOrFail(); + + return { + ...collection.serialize(), + links: collection.links.map((link) => + new LinkWithoutFavoriteDto(link).toJson() + ), + author: new UserWithoutEmailDto(collection.author).toJson(), + }; } } diff --git a/inertia/components/dashboard/favorite/item/favorite_item.tsx b/inertia/components/dashboard/favorite/item/favorite_item.tsx index e85121e..17e0aec 100644 --- a/inertia/components/dashboard/favorite/item/favorite_item.tsx +++ b/inertia/components/dashboard/favorite/item/favorite_item.tsx @@ -1,7 +1,7 @@ import { Card, Group, Text } from '@mantine/core'; import { ExternalLinkStyled } from '~/components/common/external_link_styled'; -import LinkControls from '~/components/dashboard/link/link_controls'; -import LinkFavicon from '~/components/dashboard/link/link_favicon'; +import LinkFavicon from '~/components/dashboard/link/item/favicon/link_favicon'; +import LinkControls from '~/components/dashboard/link/item/link_controls'; import { LinkWithCollection } from '~/types/app'; import styles from './favorite_item.module.css'; diff --git a/inertia/components/dashboard/link/link_favicon.module.css b/inertia/components/dashboard/link/item/favicon/link_favicon.module.css similarity index 100% rename from inertia/components/dashboard/link/link_favicon.module.css rename to inertia/components/dashboard/link/item/favicon/link_favicon.module.css diff --git a/inertia/components/dashboard/link/link_favicon.tsx b/inertia/components/dashboard/link/item/favicon/link_favicon.tsx similarity index 100% rename from inertia/components/dashboard/link/link_favicon.tsx rename to inertia/components/dashboard/link/item/favicon/link_favicon.tsx diff --git a/inertia/components/dashboard/link/link.module.css b/inertia/components/dashboard/link/item/link.module.css similarity index 100% rename from inertia/components/dashboard/link/link.module.css rename to inertia/components/dashboard/link/item/link.module.css diff --git a/inertia/components/dashboard/link/link_controls.tsx b/inertia/components/dashboard/link/item/link_controls.tsx similarity index 81% rename from inertia/components/dashboard/link/link_controls.tsx rename to inertia/components/dashboard/link/item/link_controls.tsx index d73debd..8a257ad 100644 --- a/inertia/components/dashboard/link/link_controls.tsx +++ b/inertia/components/dashboard/link/item/link_controls.tsx @@ -10,10 +10,10 @@ import { MdFavorite, MdFavoriteBorder } from 'react-icons/md'; import { onFavorite } from '~/lib/favorite'; import { appendCollectionId, appendLinkId } from '~/lib/navigation'; import { useFavorites } from '~/stores/collection_store'; -import { Link } from '~/types/app'; +import { Link, PublicLink } from '~/types/app'; interface LinksControlsProps { - link: Link; + link: Link | PublicLink; showGoToCollection?: boolean; } export default function LinkControls({ @@ -42,15 +42,17 @@ export default function LinkControls({ {t('go-to-collection')} )} - - onFavorite(link.id, !link.favorite, onFavoriteCallback) - } - leftSection={link.favorite ? : } - color="var(--mantine-color-yellow-7)" - > - {link.favorite ? t('remove-favorite') : t('add-favorite')} - + {'favorite' in link && ( + + onFavorite(link.id, !link.favorite, onFavoriteCallback) + } + leftSection={link.favorite ? : } + color="var(--mantine-color-yellow-7)" + > + {link.favorite ? t('remove-favorite') : t('add-favorite')} + + )} @@ -21,13 +21,12 @@ export default function LinkItem({
- {name}{' '} - {showUserControls && favorite && } + {name} {showFavoriteIcon && }
- {showUserControls && } + {!hideMenu && }
{description && ( diff --git a/inertia/components/dashboard/link/list/link_list.tsx b/inertia/components/dashboard/link/list/link_list.tsx new file mode 100644 index 0000000..3195a76 --- /dev/null +++ b/inertia/components/dashboard/link/list/link_list.tsx @@ -0,0 +1,24 @@ +import { Stack } from '@mantine/core'; +import { LinkItem } from '~/components/dashboard/link/item/link_item'; +import { NoLink } from '~/components/dashboard/link/no_link/no_link'; +import { useActiveCollection } from '~/stores/collection_store'; + +export interface LinkListProps { + hideMenu?: boolean; +} + +export function LinkList({ hideMenu = false }: LinkListProps) { + const { activeCollection } = useActiveCollection(); + + if (!activeCollection?.links || activeCollection.links.length === 0) { + return ; + } + + return ( + + {activeCollection?.links.map((link) => ( + + ))} + + ); +} diff --git a/inertia/components/dashboard/link/no_link.module.css b/inertia/components/dashboard/link/no_link/no_link.module.css similarity index 100% rename from inertia/components/dashboard/link/no_link.module.css rename to inertia/components/dashboard/link/no_link/no_link.module.css diff --git a/inertia/components/dashboard/link/no_link.tsx b/inertia/components/dashboard/link/no_link/no_link.tsx similarity index 66% rename from inertia/components/dashboard/link/no_link.tsx rename to inertia/components/dashboard/link/no_link/no_link.tsx index 98c4b47..a216aab 100644 --- a/inertia/components/dashboard/link/no_link.tsx +++ b/inertia/components/dashboard/link/no_link/no_link.tsx @@ -2,11 +2,14 @@ import { Link } from '@inertiajs/react'; import { route } from '@izzyjs/route/client'; import { Anchor, Box, Text } from '@mantine/core'; import { useTranslation } from 'react-i18next'; +import type { LinkListProps } from '~/components/dashboard/link/list/link_list'; import { appendCollectionId } from '~/lib/navigation'; import { useActiveCollection } from '~/stores/collection_store'; import styles from './no_link.module.css'; -export function NoLink() { +interface NoLinkProps extends LinkListProps {} + +export function NoLink({ hideMenu }: NoLinkProps) { const { t } = useTranslation('common'); const { activeCollection } = useActiveCollection(); return ( @@ -23,15 +26,17 @@ export function NoLink() { ), }} /> - - {t('link.create')} - + {!hideMenu && ( + + {t('link.create')} + + )} ); } diff --git a/inertia/i18n/locales/en/admin.json b/inertia/i18n/locales/en/admin.json index 33ac3bc..7b3f6ac 100644 --- a/inertia/i18n/locales/en/admin.json +++ b/inertia/i18n/locales/en/admin.json @@ -2,8 +2,6 @@ "role": "Role", "created_at": "Created at", "last_seen_at": "Last seen at", - "admin": "Administrator", - "user": "User", "users": "Users", "stats": "Statistics" } \ No newline at end of file diff --git a/inertia/i18n/locales/en/common.json b/inertia/i18n/locales/en/common.json index af39f58..9614bce 100644 --- a/inertia/i18n/locales/en/common.json +++ b/inertia/i18n/locales/en/common.json @@ -27,7 +27,8 @@ "edit": "Edit a collection", "delete": "Delete a collection", "delete-confirm": "Confirm deletion?", - "delete-description": "You must delete all links in this collection before you can delete this collection." + "delete-description": "You must delete all links in this collection before you can delete this collection.", + "managed-by": "Collection managed by {{name}}" }, "form": { "name": "Name", @@ -55,6 +56,7 @@ "go-to-collection": "Go to collection", "no-item-found": "No item found", "admin": "Administrator", + "user": "User", "search": "Search", "search-with": "Search with", "avatar": "{{name}}'s avatar", diff --git a/inertia/i18n/locales/fr/admin.json b/inertia/i18n/locales/fr/admin.json index 0811c1e..635350c 100644 --- a/inertia/i18n/locales/fr/admin.json +++ b/inertia/i18n/locales/fr/admin.json @@ -2,8 +2,6 @@ "role": "Rôle", "created_at": "Création", "last_seen_at": "Dernière connexion", - "admin": "Administrateur", - "user": "Utilisateur", "users": "Utilisateurs", "stats": "Statistiques" } \ No newline at end of file diff --git a/inertia/i18n/locales/fr/common.json b/inertia/i18n/locales/fr/common.json index f68e0ba..5967b9a 100644 --- a/inertia/i18n/locales/fr/common.json +++ b/inertia/i18n/locales/fr/common.json @@ -27,7 +27,8 @@ "edit": "Modifier une collection", "delete": "Supprimer une collection", "delete-confirm": "Confirmer la suppression ?", - "delete-description": "Vous devez supprimer tous les liens de cette collection avant de pouvoir supprimer cette collection" + "delete-description": "Vous devez supprimer tous les liens de cette collection avant de pouvoir supprimer cette collection", + "managed-by": "Collection gérée par {{name}}" }, "form": { "name": "Nom", @@ -54,7 +55,8 @@ "favorites-appears-here": "Vos favoris apparaîtront ici", "go-to-collection": "Voir la collection", "no-item-found": "Aucun élément trouvé", - "admin": "Administrateur", + "admin": "Administrateur", + "user": "Utilisateur", "search": "Rechercher", "search-with": "Rechercher avec", "avatar": "Avatar de {{name}}", diff --git a/inertia/pages/dashboard.tsx b/inertia/pages/dashboard.tsx index be945b7..6f5f3bc 100644 --- a/inertia/pages/dashboard.tsx +++ b/inertia/pages/dashboard.tsx @@ -1,13 +1,12 @@ import { router } from '@inertiajs/react'; import { route } from '@izzyjs/route/client'; -import { AppShell, ScrollArea, Stack } from '@mantine/core'; +import { AppShell, ScrollArea } from '@mantine/core'; import { useDisclosure } from '@mantine/hooks'; import { useEffect } from 'react'; import { DashboardAside } from '~/components/dashboard/dashboard_aside'; import { DashboardHeader } from '~/components/dashboard/dashboard_header'; import { DashboardNavbar } from '~/components/dashboard/dashboard_navbar'; -import LinkItem from '~/components/dashboard/link/link_item'; -import { NoLink } from '~/components/dashboard/link/no_link'; +import { LinkList } from '~/components/dashboard/link/list/link_list'; import { MantineFooter } from '~/components/footer/footer'; import { useDisableOverflow } from '~/hooks/use_disable_overflow'; import useShortcut from '~/hooks/use_shortcut'; @@ -69,16 +68,16 @@ export default function MantineDashboard(props: Readonly) { } ); + const headerHeight = !!activeCollection?.description + ? HEADER_SIZE_WITH_DESCRIPTION + : HEADER_SIZE_WITHOUT_DESCRIPTION; + const footerHeight = 45; return (
) { breakpoint: 'md', collapsed: { mobile: !openedAside }, }} + footer={{ height: footerHeight }} classNames={{ aside: classes.ml_custom_class, footer: classes.ml_custom_class, @@ -103,20 +103,12 @@ export default function MantineDashboard(props: Readonly) { /> - {activeCollection?.links && activeCollection.links.length > 0 ? ( - - - {activeCollection?.links.map((link) => ( - - ))} - - - ) : ( - - )} + + + diff --git a/inertia/pages/shared.tsx b/inertia/pages/shared.tsx new file mode 100644 index 0000000..f3b43fa --- /dev/null +++ b/inertia/pages/shared.tsx @@ -0,0 +1,48 @@ +import { Flex, Text } from '@mantine/core'; +import { ReactNode, useEffect } from 'react'; +import { useTranslation } from 'react-i18next'; +import { LinkList } from '~/components/dashboard/link/list/link_list'; +import { ContentLayout } from '~/layouts/content_layout'; +import { useCollectionsSetter } from '~/stores/collection_store'; +import type { CollectionWithLinks, PublicUser } from '~/types/app'; + +interface SharedPageProps { + collection: CollectionWithLinks & { author: PublicUser }; +} + +function SharedPage({ collection }: SharedPageProps) { + const { t } = useTranslation('common'); + const { setActiveCollection } = useCollectionsSetter(); + + useEffect(() => { + setActiveCollection(collection); + }, []); + + return ( + <> + + {collection.name} + + {collection.description} + + + + + + + + ); +} + +SharedPage.layout = (page: ReactNode) => {page}; +export default SharedPage; diff --git a/inertia/types/app.d.ts b/inertia/types/app.d.ts index 4bafdba..79d716e 100644 --- a/inertia/types/app.d.ts +++ b/inertia/types/app.d.ts @@ -14,6 +14,8 @@ type User = CommonBase & { lastSeenAt: string; }; +type PublicUser = Omit; + type Users = User[]; type UserWithCollections = User & { @@ -42,6 +44,9 @@ type LinkWithCollection = Link & { collection: Collection; }; +type PublicLink = Omit; +type PublicLinkWithCollection = Omit; + type Collection = CommonBase & { name: string; description: string | null;