2024-02-02 23:50:24 +00:00
'use client'
2024-05-27 22:20:58 +00:00
import React from 'react'
import ReactDOM from 'react-dom/client'
import Link from 'next/link'
2024-12-12 07:23:46 +00:00
import { defaultImageBlur } from '../lib/constants'
2024-02-02 23:50:24 +00:00
import {
2024-05-27 22:20:58 +00:00
keepPreviousData ,
QueryClient ,
useQuery ,
} from '@tanstack/react-query'
2024-06-04 23:06:47 +00:00
import { format } from 'date-fns'
2024-06-13 02:54:44 +00:00
import Image from "next/legacy/image"
2024-05-27 22:20:58 +00:00
import {
PaginationState ,
useReactTable ,
getCoreRowModel ,
ColumnDef ,
flexRender ,
} from '@tanstack/react-table'
2024-07-06 08:49:51 +00:00
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import { faSpinner } from '@fortawesome/free-solid-svg-icons'
2024-02-02 23:50:24 +00:00
2024-07-10 22:11:18 +00:00
import { fetchStreamData } from '@/app/lib/streams'
2024-07-15 16:07:04 +00:00
import { IStream } from '@futureporn/types'
2024-02-02 23:50:24 +00:00
2024-05-27 22:20:58 +00:00
const queryClient = new QueryClient ( )
2024-02-02 23:50:24 +00:00
2024-05-27 22:20:58 +00:00
function getStatusClass ( value : string ) {
switch ( value ) {
case 'issue' :
return 'is-warning' ;
case 'missing' :
return 'is-danger' ;
case 'good' :
return 'is-success' ;
default :
return '' ;
}
}
2024-02-02 23:50:24 +00:00
2024-05-27 22:20:58 +00:00
export default function StreamsTable() {
const rerender = React . useReducer ( ( ) = > ( { } ) , { } ) [ 1 ]
2024-02-02 23:50:24 +00:00
2024-06-04 23:06:47 +00:00
// image & name
2024-05-27 22:20:58 +00:00
// title
// platform
2024-06-04 23:06:47 +00:00
// date & time
2024-05-27 22:20:58 +00:00
// archiveStatus
const columns = React . useMemo < ColumnDef < IStream > [ ] > (
( ) = > [
2024-12-16 20:39:23 +00:00
{
header : 'VTuber' ,
accessorFn : d = > ( {
displayName : d.vtuber.display_name ,
image : d.vtuber.image ,
imageBlur : d.vtuber.image_blur
} ) ,
cell : info = > {
const { displayName , image , imageBlur } = info . getValue < { displayName : string , image : string , imageBlur : string } > ( ) ;
return (
< >
< div className = "columns is-mobile" >
< div className = "column mr-0 is-flex-grow-0" >
< figure className = "image is-24x24" >
< Image
className = "is-rounded"
src = { image }
alt = { displayName }
placeholder = "blur"
objectFit = 'cover'
blurDataURL = { imageBlur || defaultImageBlur }
width = { 32 }
height = { 32 }
/ >
< / figure >
2024-06-04 23:06:47 +00:00
< / div >
2024-12-16 20:39:23 +00:00
< div className = "column ml-0" >
< span > { displayName } < / span >
< / div >
< / div >
< / >
)
}
} ,
{
header : 'Date' ,
accessorFn : d = > format ( new Date ( d . date ) , 'yyyy-MM-dd HH:mm' ) ,
sortingFn : 'datetime' ,
sortDescFirst : true ,
cell : info = > ( < Link href = { ` /archive/ ${ info . row . original . uuid } ` } > { info . getValue ( ) as string } < / Link > )
} ,
{
header : 'Platform' ,
accessorFn : d = > [
( d . is_chaturbate_stream && 'CB' ) ,
( d . is_fansly_stream && 'Fansly' )
] . filter ( Boolean ) . join ( ', ' ) || '???'
} ,
{
header : 'Status' ,
accessorFn : d = > {
if ( ! d . archive_status ) return 'missing' ;
return d . archive_status
}
} ,
// {
// header: 'Name',
// footer: props => props.column.id,
// columns: [
// {
// accessorKey: 'firstName',
// cell: info => info.getValue(),
// footer: props => props.column.id,
// },
// {
// accessorFn: row => row.lastName,
// id: 'lastName',
// cell: info => info.getValue(),
// header: () => <span>Last Name</span>,
// footer: props => props.column.id,
// },
// ],
// },
2024-05-27 22:20:58 +00:00
] ,
[ ]
)
const [ pagination , setPagination ] = React . useState < PaginationState > ( {
pageIndex : 0 ,
pageSize : 50 ,
} )
2024-07-06 08:49:51 +00:00
const { data , error , isPending } = useQuery ( {
2024-05-27 22:20:58 +00:00
queryKey : [ 'streams' , pagination . pageIndex , pagination . pageSize ] ,
queryFn : ( ) = > fetchStreamData ( pagination ) ,
placeholderData : keepPreviousData , // don't have 0 rows flash while changing pages/loading next page,
2024-07-06 08:49:51 +00:00
staleTime : 1000 ,
2024-05-27 22:20:58 +00:00
} , queryClient )
const defaultData = React . useMemo ( ( ) = > [ ] , [ ] )
const table = useReactTable ( {
2024-07-06 08:49:51 +00:00
data : data?.rows ? ? defaultData ,
2024-05-27 22:20:58 +00:00
columns ,
// pageCount: dataQuery.data?.pageCount ?? -1, //you can now pass in `rowCount` instead of pageCount and `pageCount` will be calculated internally (new in v8.13.0)
2024-07-06 08:49:51 +00:00
rowCount : data?.rowCount , // new in v8.13.0 - alternatively, just pass in `pageCount` directly
2024-05-27 22:20:58 +00:00
state : {
pagination ,
} ,
onPaginationChange : setPagination ,
getCoreRowModel : getCoreRowModel ( ) ,
manualPagination : true , //we're doing manual "server-side" pagination
// getPaginationRowModel: getPaginationRowModel(), // If only doing manual pagination, you don't need this
debugTable : true ,
} )
return (
< div className = "p-2" >
< div className = "h-2" / >
2024-12-16 20:39:23 +00:00
{ isPending && < FontAwesomeIcon className = "mt-5 fa-spin-pulse" icon = { faSpinner } > < / FontAwesomeIcon > }
2024-07-06 08:49:51 +00:00
{ ! isPending && < >
< table className = 'table is-hoverable is-fullwidth' >
< thead >
{ table . getHeaderGroups ( ) . map ( headerGroup = > (
< tr key = { headerGroup . id } >
{ headerGroup . headers . map ( header = > {
2024-05-27 22:20:58 +00:00
return (
2024-07-06 08:49:51 +00:00
< th key = { header . id } colSpan = { header . colSpan } >
{ header . isPlaceholder ? null : (
< div >
{ flexRender (
header . column . columnDef . header ,
header . getContext ( )
) }
< / div >
2024-05-27 22:20:58 +00:00
) }
2024-07-06 08:49:51 +00:00
< / th >
2024-05-27 22:20:58 +00:00
)
} ) }
< / tr >
2024-07-06 08:49:51 +00:00
) ) }
< / thead >
< tbody >
{ table . getRowModel ( ) . rows . map ( row = > {
return (
< tr key = { row . id } >
{ row . getVisibleCells ( ) . map ( cell = > {
return (
2024-12-16 20:39:23 +00:00
< td
className = { getStatusClass ( cell . getValue ( ) as string ) }
2024-07-06 08:49:51 +00:00
key = { cell . id }
>
{ flexRender (
cell . column . columnDef . cell ,
cell . getContext ( )
) }
< / td >
)
} ) }
< / tr >
)
} ) }
< / tbody >
< / table >
2024-12-16 20:39:23 +00:00
< div className = "columns is-mobile is-vcentered" >
< div className = 'column is-half' >
< button
className = "button border rounded mx-1"
onClick = { ( ) = > table . firstPage ( ) }
disabled = { ! table . getCanPreviousPage ( ) }
>
{ '<<' }
< / button >
< button
className = "button border rounded mx-1"
onClick = { ( ) = > table . previousPage ( ) }
disabled = { ! table . getCanPreviousPage ( ) }
>
{ '<' }
< / button >
< button
className = "button border rounded mx-1"
onClick = { ( ) = > table . nextPage ( ) }
disabled = { ! table . getCanNextPage ( ) }
>
{ '>' }
< / button >
< button
className = "button border rounded mx-1"
onClick = { ( ) = > table . lastPage ( ) }
disabled = { ! table . getCanNextPage ( ) }
>
{ '>>' }
< / button >
< / div >
< div className = 'column is-half' >
< span > Page < / span >
2024-05-27 22:20:58 +00:00
< strong >
2024-12-16 20:39:23 +00:00
{ table . getState ( ) . pagination . pageIndex + 1 } of { ' ' } { table . getPageCount ( ) . toLocaleString ( ) }
2024-05-27 22:20:58 +00:00
< / strong >
2024-12-16 20:39:23 +00:00
< / div >
2024-05-27 22:20:58 +00:00
< / div >
2024-12-16 20:39:23 +00:00
{ /* second row with page number input and pages-per-screen select */ }
< div className = 'columns is-mobile is-vcentered' >
< div className = 'column is-2 ' >
< span className = 'is-text-centered' > Go to page : < / span >
< / div >
< div className = 'column is-3' >
< input
type = "number"
defaultValue = { table . getState ( ) . pagination . pageIndex + 1 }
2024-05-27 22:20:58 +00:00
onChange = { e = > {
2024-12-16 20:39:23 +00:00
const page = e . target . value ? Number ( e . target . value ) - 1 : 0
table . setPageIndex ( page )
2024-05-27 22:20:58 +00:00
} }
2024-12-16 20:39:23 +00:00
className = "input"
/ >
< / div >
< div className = 'column is-5' >
< div className = "select" >
< select
value = { table . getState ( ) . pagination . pageSize }
onChange = { e = > {
table . setPageSize ( Number ( e . target . value ) )
} }
>
{ [ 20 , 50 , 100 ] . map ( pageSize = > (
< option key = { pageSize } value = { pageSize } >
Show { pageSize }
< / option >
) ) }
< / select >
< / div >
2024-05-27 22:20:58 +00:00
< / div >
< / div >
2024-12-16 20:39:23 +00:00
< / > }
2024-05-27 22:20:58 +00:00
2024-12-16 20:39:23 +00:00
< / div >
2024-05-27 22:20:58 +00:00
)
2024-02-02 23:50:24 +00:00
}