-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Share bookmark component between lists (#14)
* Share bookmark component between lists * Fix delete btn click inside Link * Fix align content un bookmark
- Loading branch information
Showing
12 changed files
with
356 additions
and
302 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
import useAddAndRemoveBlockOnDigest from '@/hooks/useAddAndRemoveBlockOnDigest'; | ||
import { getTeamBookmarksNotInDigest } from '@/lib/queries'; | ||
import Link from 'next/link'; | ||
import React from 'react'; | ||
import BookmarkImage from '../bookmark/BookmarkImage'; | ||
import { AiOutlineLoading3Quarters as LoadingIcon } from '@react-icons/all-files/ai/AiOutlineLoading3Quarters'; | ||
import { PlusCircleIcon } from '@heroicons/react/24/solid'; | ||
import { getRelativeDate } from '@/utils/date'; | ||
import { getDomainFromUrl } from '@/utils/url'; | ||
import { BookmarkDigestStyle, DigestBlockType } from '@prisma/client'; | ||
import { getEnvHost } from '@/lib/server'; | ||
import { isTwitterLink } from '@/utils/link'; | ||
|
||
interface Props { | ||
bookmark: Awaited< | ||
ReturnType<typeof getTeamBookmarksNotInDigest> | ||
>['bookmarks'][0]; | ||
teamId: string; | ||
digestId: string; | ||
} | ||
|
||
/** | ||
* Bookmark item with an add to a (specific) digest button | ||
*/ | ||
export default function BookmarkAddButton({ | ||
bookmark, | ||
teamId, | ||
digestId, | ||
}: Props) { | ||
const { add, isRefreshing } = useAddAndRemoveBlockOnDigest({ | ||
teamId, | ||
digestId, | ||
}); | ||
|
||
return ( | ||
<div className="flex h-full items-center w-16"> | ||
<button | ||
className="group-hover color-black w-full" | ||
onClick={(e) => { | ||
e.preventDefault(); | ||
add.mutate({ | ||
bookmarkId: bookmark.id, | ||
type: DigestBlockType.BOOKMARK, | ||
style: isTwitterLink(bookmark.link.url) | ||
? BookmarkDigestStyle.TWEET_EMBED | ||
: BookmarkDigestStyle.BLOCK, | ||
}); | ||
}} | ||
disabled={add.isLoading || isRefreshing} | ||
aria-label="Add" | ||
> | ||
{add.isLoading || isRefreshing ? ( | ||
<LoadingIcon | ||
className="animate-spin h-6 w-6 m-auto text-gray-400" | ||
aria-hidden="true" | ||
/> | ||
) : ( | ||
<span className="h-8 w-8 block m-auto text-gray-400 group-hover:text-gray-500 group-hover:scale-[110%] transition-[transform] duration-400"> | ||
<PlusCircleIcon /> | ||
</span> | ||
)} | ||
</button> | ||
</div> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,178 @@ | ||
'use client'; | ||
|
||
import { | ||
TeamBookmarksNotInDigestResult, | ||
TeamBookmarksResult, | ||
} from '@/lib/queries'; | ||
import { getRelativeDate } from '@/utils/date'; | ||
import { getDomainFromUrl } from '@/utils/url'; | ||
import clsx from 'clsx'; | ||
import BookmarkImage from './BookmarkImage'; | ||
import { DeletePopover } from '../Popover'; | ||
import { getEnvHost } from '@/lib/server'; | ||
|
||
import api from '@/lib/api'; | ||
import { ApiBookmarkResponseSuccess } from '@/pages/api/teams/[teamId]/bookmark'; | ||
|
||
import { AxiosError, AxiosResponse } from 'axios'; | ||
|
||
import { useMutation } from 'react-query'; | ||
|
||
import message from '../../messages/en'; | ||
import useCustomToast from '@/hooks/useCustomToast'; | ||
import useTransitionRefresh from '@/hooks/useTransitionRefresh'; | ||
import BookmarkAddButton from './BookmarkAddButton'; | ||
import Link from 'next/link'; | ||
|
||
type Props = { | ||
bookmark: | ||
| TeamBookmarksResult | ||
| TeamBookmarksNotInDigestResult['bookmarks'][0]; | ||
teamSlug: string; | ||
teamId: string; | ||
digestId?: string; | ||
nbOfTimesUsed?: number; | ||
editMode?: boolean; | ||
}; | ||
|
||
export const BookmarkItem = ({ | ||
bookmark, | ||
teamSlug, | ||
teamId, | ||
digestId, | ||
nbOfTimesUsed, | ||
editMode, | ||
}: Props) => { | ||
const { successToast, errorToast } = useCustomToast(); | ||
const { isRefreshing, refresh } = useTransitionRefresh(); | ||
|
||
const { mutate: deleteBookmark, isLoading: isDeleting } = useMutation< | ||
AxiosResponse<ApiBookmarkResponseSuccess>, | ||
AxiosError<ErrorResponse>, | ||
{ bookmarkId: string } | ||
>( | ||
'delete-bookmarks', | ||
({ bookmarkId }) => { | ||
console.log(bookmarkId, teamId); | ||
return api.delete(`/teams/${teamId}/bookmark/${bookmarkId}`); | ||
}, | ||
{ | ||
onSuccess: () => { | ||
successToast(message.bookmark.delete.success); | ||
refresh(); | ||
}, | ||
onError: (error: AxiosError<ErrorResponse>) => { | ||
errorToast( | ||
error.response?.data?.error || | ||
error.response?.statusText || | ||
error.message | ||
); | ||
}, | ||
} | ||
); | ||
|
||
const isLoading = isRefreshing || isDeleting; | ||
const isUsed = !!nbOfTimesUsed && !editMode; | ||
|
||
return ( | ||
<div | ||
key={bookmark.id} | ||
className={clsx( | ||
'group relative flex w-full rounded-md p-2 hover:bg-gray-50 flex-col', | ||
{ 'opacity-60': isRefreshing } | ||
)} | ||
> | ||
{isUsed && ( | ||
<a | ||
className="absolute bottom-0 right-2 items-center rounded-md bg-gray-50 px-2 py-1 text-xs font-medium text-gray-600 ring-1 ring-inset ring-gray-500/10 hover:bg-gray-100 hover:text-gray-700 z-20" | ||
href={`/teams/${teamSlug}/digests/${digestId}/edit`} | ||
target="_blank" | ||
title="Used in digest. Click to edit the digest." | ||
> | ||
Bookmarked {nbOfTimesUsed > 1 ? nbOfTimesUsed : ''}{' '} | ||
</a> | ||
)} | ||
<div | ||
className={clsx('flex w-full justify-between', { | ||
'opacity-60': isUsed, | ||
})} | ||
> | ||
<div className="flex gap-2 overflow-hidden w-[100%] justify-start"> | ||
<div className="relative w-16 h-16 overflow-hidden rounded-md border max-w-[4rem]"> | ||
<BookmarkImage | ||
link={bookmark.link} | ||
fallbackSrc={`${getEnvHost()}/api/bookmark-og?bookmark=${ | ||
bookmark.id | ||
}`} | ||
/> | ||
</div> | ||
<div className="flex flex-col items-start max-w-[100%] overflow-hidden flex-1"> | ||
<div className="flex flex-col overflow-hidden max-w-[100%]"> | ||
<span className="truncate font-semibold whitespace-nowrap"> | ||
{bookmark.link.title || bookmark.link.url} | ||
</span> | ||
|
||
<div className="flex items-center text-sm text-gray-500"> | ||
{bookmark.membership ? ( | ||
<div className="whitespace-nowrap max-w-[33%] sm:max-w-none truncate"> | ||
{bookmark.membership.user?.name || | ||
bookmark.membership.user?.email?.split('@')[0]}{' '} | ||
{bookmark.createdAt && getRelativeDate(bookmark.createdAt)} | ||
</div> | ||
) : ( | ||
<div className="whitespace-nowrap max-w-[33%] sm:max-w-none truncate"> | ||
{bookmark.provider === 'SLACK' && ( | ||
<> | ||
From Slack{' '} | ||
{bookmark.createdAt && | ||
getRelativeDate(bookmark.createdAt)} | ||
</> | ||
)} | ||
</div> | ||
)} | ||
<div className="mx-1">-</div> | ||
<div className="whitespace-nowrap max-w-[33%] sm:max-w-none truncate"> | ||
{editMode ? ( | ||
<Link | ||
href={bookmark.link.url} | ||
target="_blank" | ||
className="text-gray-400 whitespace-nowrap overflow-hidden text-ellipsis underline underline-offset-2" | ||
> | ||
{getDomainFromUrl(bookmark.link.url)} | ||
</Link> | ||
) : ( | ||
getDomainFromUrl(bookmark.link.url) | ||
)} | ||
</div> | ||
<div className="mx-1">-</div> | ||
<div | ||
className="relative z-20" | ||
onClick={(e) => e.preventDefault()} | ||
> | ||
<DeletePopover | ||
handleDelete={() => | ||
deleteBookmark({ bookmarkId: bookmark?.id }) | ||
} | ||
isLoading={isLoading} | ||
/> | ||
</div> | ||
</div> | ||
</div> | ||
{bookmark.link.description && ( | ||
<p className={clsx('pt-2 text-sm', { 'opacity-60': isUsed })}> | ||
{bookmark.link.description} | ||
</p> | ||
)} | ||
</div> | ||
</div> | ||
{editMode && digestId && ( | ||
<BookmarkAddButton | ||
bookmark={bookmark} | ||
teamId={teamId} | ||
digestId={digestId} | ||
/> | ||
)} | ||
</div> | ||
</div> | ||
); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
2ab0e28
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Successfully deployed to the following URLs:
digestclub – ./
digestclub-premieroctet.vercel.app
digestclub-git-main-premieroctet.vercel.app
digestclub.vercel.app