show transcripts in a modal instead of a pop-up

This commit is contained in:
2025-07-05 23:39:14 +02:00
parent f8f5df6919
commit 7b86fb9d82

View File

@@ -2,6 +2,12 @@
import { Badge } from '@/components/ui/badge' import { Badge } from '@/components/ui/badge'
import { Button } from '@/components/ui/button' import { Button } from '@/components/ui/button'
import {
Dialog,
DialogContent,
DialogHeader,
DialogTitle,
} from '@/components/ui/dialog'
import { import {
Table, Table,
TableBody, TableBody,
@@ -41,24 +47,8 @@ function getTranscript(gameNumber: number) {
`https://api.neatqueue.com/api/transcript/1226193436521267223/${gameNumber}` `https://api.neatqueue.com/api/transcript/1226193436521267223/${gameNumber}`
).then((res) => res.json()) ).then((res) => res.json())
} }
function openTranscript(gameNumber: number): void { // This function is now moved inside the GamesTable component
getTranscript(gameNumber) const useColumns = (openTranscriptFn?: (gameNumber: number) => void) => {
.then((html: string) => {
const newWindow = window.open('', '_blank')
if (newWindow) {
newWindow.document.write(html)
newWindow.document.close()
} else {
console.error(
'Failed to open new window - popup blocker may be enabled'
)
}
})
.catch((err) => {
console.error('Failed to load transcript:', err)
})
}
const useColumns = () => {
const format = useFormatter() const format = useFormatter()
const timeZone = useTimeZone() const timeZone = useTimeZone()
const session = useSession() const session = useSession()
@@ -186,7 +176,9 @@ const useColumns = () => {
cell: (info) => ( cell: (info) => (
<Button <Button
size={'sm'} size={'sm'}
onClick={() => openTranscript(info.getValue())} onClick={() =>
openTranscriptFn ? openTranscriptFn(info.getValue()) : null
}
type={'button'} type={'button'}
variant={'ghost'} variant={'ghost'}
> >
@@ -204,7 +196,28 @@ const useColumns = () => {
export function GamesTable({ games }: { games: SelectGames[] }) { export function GamesTable({ games }: { games: SelectGames[] }) {
const [sorting, setSorting] = useState<SortingState>([]) const [sorting, setSorting] = useState<SortingState>([])
const columns = useColumns() const [isDialogOpen, setIsDialogOpen] = useState(false)
const [transcriptContent, setTranscriptContent] = useState<string>('')
const [transcriptGameNumber, setTranscriptGameNumber] = useState<
number | null
>(null)
// New openTranscript function that sets state instead of opening a new window
const openTranscript = (gameNumber: number): void => {
setTranscriptGameNumber(gameNumber)
getTranscript(gameNumber)
.then((html: string) => {
setTranscriptContent(html)
setIsDialogOpen(true)
})
.catch((err) => {
console.error('Failed to load transcript:', err)
})
}
// Pass the openTranscript function to useColumns
const columns = useColumns(openTranscript)
const table = useReactTable({ const table = useReactTable({
data: games, data: games,
columns, columns,
@@ -218,6 +231,7 @@ export function GamesTable({ games }: { games: SelectGames[] }) {
}) })
return ( return (
<>
<div className='rounded-md border'> <div className='rounded-md border'>
<Table> <Table>
<TableHeader> <TableHeader>
@@ -281,5 +295,28 @@ export function GamesTable({ games }: { games: SelectGames[] }) {
</TableBody> </TableBody>
</Table> </Table>
</div> </div>
{/* Transcript Dialog */}
<Dialog open={isDialogOpen} onOpenChange={setIsDialogOpen}>
<DialogContent className='max-h-[80vh] w-full overflow-y-auto sm:max-w-[calc(100%-2rem)] '>
<DialogHeader>
<DialogTitle>
{transcriptGameNumber
? `Game Transcript #${transcriptGameNumber}`
: 'Game Transcript'}
</DialogTitle>
</DialogHeader>
{/* Use iframe to isolate the transcript content and prevent style leakage */}
<div className='!h-[60vh] mt-4 w-full'>
<iframe
srcDoc={transcriptContent}
title={`Game Transcript #${transcriptGameNumber || ''}`}
className='h-full w-full border-0'
sandbox='allow-same-origin'
/>
</div>
</DialogContent>
</Dialog>
</>
) )
} }