Skip to content

Commit

Permalink
feat (session): optimistic updates for lip dnd
Browse files Browse the repository at this point in the history
  • Loading branch information
glencoden committed Jan 12, 2025
1 parent 286c483 commit a4f7557
Show file tree
Hide file tree
Showing 10 changed files with 302 additions and 93 deletions.
30 changes: 25 additions & 5 deletions apps/cloud/app/components/AddDemoLipButton.tsx
Original file line number Diff line number Diff line change
@@ -1,33 +1,53 @@
import { api } from '@repo/api/client'
import { Session } from '@repo/db'
import Button from '@repo/ui/components/Button'
import { cn } from '@repo/ui/helpers'
import { CirclePlus } from 'lucide-react'
import { useEffect, useState } from 'react'

export default function AddDemoLipButton({
session,
}: Readonly<{ session: Session }>) {
const { isFetching } = api.lip.getBySessionId.useQuery({
id: session.id,
})

const utils = api.useUtils()

const { mutate: createDemoLip, isPending } = api.lip.createDemo.useMutation(
{
const { mutate: createDemoLip, isPending: isCreateDemoPending } =
api.lip.createDemo.useMutation({
onSettled: () => {
void utils.lip.getBySessionId.invalidate({ id: session.id })
},
},
)
})

const handleAddButtonClick = () => {
void createDemoLip({ id: session.id })
}

const [isPending, setIsPending] = useState(false)

useEffect(() => {
if (!isFetching && !isCreateDemoPending) {
setIsPending(false)
}
if (isCreateDemoPending) {
setIsPending(true)
}
}, [isFetching, isCreateDemoPending])

return (
<Button
variant='ghost'
title='Add demo lip'
disabled={isPending}
onClick={handleAddButtonClick}
>
<CirclePlus className='h-12 w-12 fill-pink-600 text-black' />
<CirclePlus
className={cn('h-12 w-12 fill-pink-600 text-black', {
'animate-spin': isPending,
})}
/>
</Button>
)
}
4 changes: 3 additions & 1 deletion apps/cloud/app/components/DragDropList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,11 @@ const DragDropList = forwardRef<
scale: SpringValue<number>
}[]
bind: (...args: any[]) => ReactDOMAttributes
isLocked: boolean
fixTop: number | null
header: ReactNode
}
>(({ lips, q, springs, bind, fixTop, header }, ref) => {
>(({ lips, q, springs, bind, isLocked, fixTop, header }, ref) => {
return (
<div
ref={ref}
Expand Down Expand Up @@ -56,6 +57,7 @@ const DragDropList = forwardRef<
q={q}
spring={spring}
bind={bind}
isLocked={isLocked}
/>
)
})}
Expand Down
10 changes: 9 additions & 1 deletion apps/cloud/app/components/DragDropListItem.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
import { animated, SpringValue } from '@react-spring/web'
import { LipDTO } from '@repo/api'
import SongLip from '@repo/ui/components/SongLip'
import { cn } from '@repo/ui/helpers'
import { ReactDOMAttributes } from '@use-gesture/react/dist/declarations/src/types'

export default function DragDropListItem({
lip,
q,
spring: { zIndex, shadow, x, y, scale },
bind,
isLocked,
}: {
lip: LipDTO
q?: string
Expand All @@ -19,6 +21,7 @@ export default function DragDropListItem({
scale: SpringValue<number>
}
bind: (...args: any[]) => ReactDOMAttributes
isLocked: boolean
}) {
return (
<animated.div
Expand All @@ -37,7 +40,12 @@ export default function DragDropListItem({
<SongLip lip={lip} q={q} />
<div
{...bind(lip.id)}
className='absolute left-1/2 top-1/2 h-24 w-24 -translate-x-1/2 -translate-y-1/2 cursor-grab touch-none select-none active:cursor-grabbing'
className={cn(
'absolute left-1/2 top-1/2 h-24 w-24 -translate-x-1/2 -translate-y-1/2 cursor-grab touch-none select-none active:cursor-grabbing',
{
hidden: isLocked,
},
)}
/>
</>
}
Expand Down
31 changes: 20 additions & 11 deletions apps/cloud/app/components/SessionMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,19 @@ import { CircleDollarSign, House, Lock, LockOpen, Star } from 'lucide-react'

export default function SessionMenu({
session,
}: Readonly<{ session: Session }>) {
isSessionPending,
}: Readonly<{
session: Session
isSessionPending: boolean
}>) {
const utils = api.useUtils()

const { mutate: updateSession, isPending } = api.session.update.useMutation(
{
const { mutate: updateSession, isPending: isUpdatePending } =
api.session.update.useMutation({
onSettled: () => {
void utils.session.get.invalidate({ id: session.id })
},
},
)
})

const handleLockButtonClick = () => {
void updateSession({ id: session.id, isLocked: !session.isLocked })
Expand Down Expand Up @@ -57,9 +60,11 @@ export default function SessionMenu({
)
}

const isPending = isSessionPending || isUpdatePending

return (
<div className='flex justify-between'>
<section className='flex gap-4'>
<section className='flex items-center gap-4'>
<Button
variant='ghost'
size='icon'
Expand Down Expand Up @@ -111,11 +116,15 @@ export default function SessionMenu({
</Button>
</section>

<Button asChild variant='ghost' size='icon'>
<Link to='/'>
<House className='h-6 w-6 text-white' />
</Link>
</Button>
<section className='flex items-center gap-7'>
{isPending && <Spinner light />}

<Button asChild variant='ghost' size='icon'>
<Link to='/'>
<House className='h-6 w-6 text-white' />
</Link>
</Button>
</section>
</div>
)
}
21 changes: 12 additions & 9 deletions apps/cloud/app/root.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,11 @@ import BoxMain from '@repo/ui/components/BoxMain'
import Spinner from '@repo/ui/components/Spinner'
import { FONT_SANS_URL, FONT_SERIF_URL } from '@repo/ui/constants'
import '@repo/ui/styles.css'
import H1 from '@repo/ui/typography/H1'
import { useEffectEvent } from '@repo/utils/hooks'
import { ReactNode, useEffect } from 'react'
import { handleBeforeUnload } from '~/helpers/handle-before-unload'
import { hasAccess } from '~/helpers/has-access'
import { useUserSession } from '~/hooks/useUserSession'
import { supabase } from '~/lib/supabase.client'
import './tailwind.css'
Expand Down Expand Up @@ -113,20 +115,21 @@ export default function App() {
}

if (
userSession?.expires_at &&
new Date(userSession.expires_at * 1000) < new Date()
!userSession ||
(userSession.expires_at &&
new Date(userSession.expires_at * 1000) < new Date())
) {
navigate('/signin')
return null
}

// if (!hasAccess(userSession?.user.accessRole)) {
// return (
// <BoxMain className='flex items-center justify-center'>
// <H1>Unauthorized</H1>
// </BoxMain>
// )
// }
if (!hasAccess(userSession?.user.accessRole)) {
return (
<BoxMain className='flex items-center justify-center'>
<H1>Unauthorized</H1>
</BoxMain>
)
}

return <Outlet />
}
Loading

0 comments on commit a4f7557

Please sign in to comment.