Skip to content

Commit

Permalink
add delete from watching section button (#26)
Browse files Browse the repository at this point in the history
  • Loading branch information
iswilljr authored Dec 9, 2024
1 parent 331e2a9 commit 05ced21
Show file tree
Hide file tree
Showing 4 changed files with 126 additions and 42 deletions.
15 changes: 15 additions & 0 deletions src/actions/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { getTrending, multiSearch } from '@/utils/tmdb'
import { deleteItemFromWatching } from '@/utils/watching'
import { defineAction } from 'astro:actions'
import { z } from 'astro:schema'

Expand Down Expand Up @@ -27,4 +28,18 @@ export const server = {
}
},
}),
deleteItemFromWatching: defineAction({
input: z.object({ id: z.number().or(z.string()) }),
handler: async ({ id }, context) => {
try {
await deleteItemFromWatching({
headers: context.request.headers,
id,
})
return true
} catch (e) {
return false
}
},
}),
}
34 changes: 34 additions & 0 deletions src/components/Media/DeleteWatchingButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { useCallback } from 'react'
import { actions } from 'astro:actions'
import { Button } from '../ui/button'
import { XIcon } from 'lucide-react'

export function DeleteWatchingButton({
id,
mediaTitle,
}: {
id: string | number
mediaTitle: string
}) {
const handleClick = useCallback(async () => {
const element = document.querySelector<HTMLElement>(
`[data-watching-id="${id}"]`
)
if (element) {
element.remove()
}

await actions.deleteItemFromWatching({ id })
}, [id])

return (
<Button
size='icon'
onClick={handleClick}
className='pointer-events-auto flex items-center justify-center gap-2 rounded-lg bg-opacity-20 px-4 py-1 text-sm text-white dark:bg-primary-500/70'
>
<XIcon />
<span className='sr-only'>Delete {mediaTitle} from watching</span>
</Button>
)
}
95 changes: 54 additions & 41 deletions src/components/Media/MediaCard.astro
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { Image } from 'astro:assets'
import { formatDate, getImagePath } from '@/utils'
import { getTvOrMovieUrl } from '@/utils/url'
import { Progress } from '@/components/ui/progress'
import { DeleteWatchingButton } from './DeleteWatchingButton'
export interface Props {
media: 'tv' | 'movie'
Expand Down Expand Up @@ -38,54 +39,66 @@ const percentageWatched = isWatching
: 0
---

<a
<div
data-watching-id={isWatching ? id : undefined}
class='swiper-item group relative flex aspect-[2/1] h-fit w-full flex-shrink-0 flex-col gap-2 overflow-hidden rounded-2xl xs:w-8/12 sm:w-80'
href={getTvOrMovieUrl(
media,
id,
title,
watching?.season,
watching?.episode,
watching?.sourceId
)}
>
<div class='z-0'>
{
image && (
<Image
width='780'
height='440'
loading='lazy'
alt={title}
src={getImagePath(image, 'w780')}
class='h-full w-full object-cover object-center duration-150 group-hover:scale-[1.03] group-focus:scale-[1.03]'
/>
)
}
</div>
<div
class='gradient-opacity absolute inset-0 flex h-full w-full flex-col justify-end gap-1 rounded-2xl p-3 ring-inset ring-primary-500 duration-150 group-hover:ring-2 group-focus:ring-2 md:gap-2'
<a
class=''
href={getTvOrMovieUrl(
media,
id,
title,
watching?.season,
watching?.episode,
watching?.sourceId
)}
>
<p
class='line-clamp-2 text-sm font-bold uppercase !leading-none tracking-wide text-white sm:text-base'
>
{mediaTitle}
</p>
<div class='z-0'>
{
image && (
<Image
width='780'
height='440'
loading='lazy'
alt={title}
src={getImagePath(image, 'w780')}
class='h-full w-full object-cover object-center duration-150 group-hover:scale-[1.03] group-focus:scale-[1.03]'
/>
)
}
</div>
<div
class='flex flex-wrap gap-1 text-xs font-normal !leading-tight tracking-wider text-primary-400'
class='gradient-opacity absolute inset-0 flex h-full w-full flex-col justify-end gap-1 rounded-2xl p-3 ring-inset ring-primary-500 duration-150 group-hover:ring-2 group-focus:ring-2 md:gap-2'
>
<p>Rating: {rating.toFixed(1)}</p>
<span>•</span>
<p>{formatDate(releaseDate)}</p>
<span>•</span>
<p class='uppercase'>{language}</p>
<p
class='line-clamp-2 text-sm font-bold uppercase !leading-none tracking-wide text-white sm:text-base'
>
{mediaTitle}
</p>
<div
class='flex flex-wrap gap-1 text-xs font-normal !leading-tight tracking-wider text-primary-400'
>
<p>Rating: {rating.toFixed(1)}</p>
<span>•</span>
<p>{formatDate(releaseDate)}</p>
<span>•</span>
<p class='uppercase'>{language}</p>
</div>
</div>
</div>
{
percentageWatched > 0 && (
<div class='absolute bottom-0 left-0 w-full duration-300 group-hover:opacity-20'>
<Progress className='h-1' value={percentageWatched} />
</div>
)
}
</a>
{
percentageWatched > 0 && (
<div class='absolute bottom-0 left-0 w-full duration-300 group-hover:opacity-20'>
<Progress className='h-1' value={percentageWatched} />
isWatching && (
<div class='absolute right-2 top-2 opacity-0 group-hover:opacity-100 group-focus:opacity-100'>
<DeleteWatchingButton client:idle id={id} mediaTitle={mediaTitle} />
</div>
)
}
</a>
</div>
24 changes: 23 additions & 1 deletion src/utils/watching.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { db, desc, eq, Watching } from 'astro:db'
import { db, desc, and, eq, Watching } from 'astro:db'
import { auth } from './auth/server'
import type { MovieWithMediaType, TVWithMediaType } from 'tmdb-ts'
import type { Session, User } from 'better-auth'
Expand Down Expand Up @@ -92,3 +92,25 @@ export async function linkWatching({

await Promise.allSettled([...insertPromises, ...deletePromises])
}

export async function deleteItemFromWatching({
headers,
id,
}: {
headers: Headers
id: string | number
}) {
const session = await auth.api.getSession({
headers,
})

if (!session) {
throw new Error('Not authenticated')
}

await db
.delete(Watching)
.where(and(eq(Watching.userId, session.user.id), eq(Watching.mediaId, +id)))

console.log('Deleted watching')
}

0 comments on commit 05ced21

Please sign in to comment.