@@ -1,7 +1,26 @@
'use client'
import { useGetReferralPayments } from '@/app/hooks/react-query/useGetReferralPayments' ;
import { useEffect } from 'react' ;
import { useEffect , useState , useMemo } from 'react' ;
import { useReactTable , getCoreRowModel , getSortedRowModel , getPaginationRowModel , getFilteredRowModel , ColumnDef , SortingState , ColumnFiltersState } from '@tanstack/react-table' ;
import { IconDoubleArrowRight , IconArrowRight , IconDoubleArrowLeft , IconArrowLeft , IconArrowUp , IconArrowDown , IconFilter } from '@/app/ui/icons/icons' ;
import { useTranslations , useLocale } from 'next-intl' ;
import DropDownList from '@/app/components/DropDownList' ;
import { useQueryClient , useQuery } from '@tanstack/react-query' ;
import { pluralize } from '@/app/lib/pluralize' ;
import { fetchReferralInvitees } from '@/app/actions/referralsActions' ;
type InviteesType = {
status? : string ;
email? : string ;
registrationData : string ;
} ;
type InviteType = {
active? : string ;
email? : string ;
regDate : string ;
} ;
export default function PaymentsHistory() {
@@ -9,44 +28,524 @@ export default function PaymentsHistory() {
useEffect ( ( ) = > {
console . log ( paymentsData ) ;
} , [ paymentsData ] )
} , [ paymentsData ] ) ;
const {
data : referralInvitees ,
isLoading ,
isError ,
error ,
} = useQuery < InviteType [ ] , Error , InviteesType [ ] , [ 'referralInvitees' ] > ( {
queryKey : [ 'referralInvitees' ] ,
queryFn : ( ) = > {
return fetchReferralInvitees ( ) ;
} ,
select : ( data : InviteType [ ] ) : InviteesType [ ] = > {
if ( ! data ) return [
] ;
return data . map ( ( item : InviteType ) = > {
return {
status : item?.active ? 'active' : 'not-active' ,
email : item?.email ,
registrationData : item?.regDate
} ;
} ) ;
} ,
} ) ;
const queryClient = useQueryClient ( ) ;
// Состояния
const [ sorting , setSorting ] = useState < SortingState > ( [ ] ) ;
const [ columnFilters , setColumnFilters ] = useState < ColumnFiltersState > ( [ ] ) ;
const [ dateFilter , setDateFilter ] = useState < string > ( 'all' ) ;
const [ statusFilter , setStatusFilter ] = useState < string > ( 'all' ) ;
const [ pagination , setPagination ] = useState ( {
pageIndex : 0 ,
pageSize : 10 ,
} ) ;
const t = useTranslations ( "Global" ) ;
const locale = useLocale ( ) ;
// Определение колонок
const columns = useMemo < ColumnDef < InviteesType > [ ] > (
( ) = > [
{
accessorKey : 'amount' ,
header : ( { column } ) = > (
< div className = "column" >
< span >
{ t ( 'amount' ) }
< / span >
< button
onClick = { ( ) = > column . toggleSorting ( column . getIsSorted ( ) === 'asc' ) }
className = "sort-button"
>
{
column . getIsSorted ( ) === 'asc' ?
< span >
< IconArrowUp / >
< / span >
: column . getIsSorted ( ) === 'desc' ?
< span >
< IconArrowDown / >
< / span >
: < span >
< IconFilter / >
< / span >
}
< / button >
< / div >
) ,
cell : ( { row } ) = > (
< div className = "text-center table-item" >
{ /* {row.original.size !== undefined ? convertBytes(row.original.size) : '-'} */ }
{ /* {row.original.email} */ }
-- -
< / div >
) ,
} ,
{
accessorKey : 'method' ,
header : ( { column } ) = > (
< div className = "column" >
< span >
{ t ( 'method' ) }
< / span >
< button
onClick = { ( ) = > column . toggleSorting ( column . getIsSorted ( ) === 'asc' ) }
className = "sort-button"
>
{
column . getIsSorted ( ) === 'asc' ?
< span >
< IconArrowUp / >
< / span >
: column . getIsSorted ( ) === 'desc' ?
< span >
< IconArrowDown / >
< / span >
: < span >
< IconFilter / >
< / span >
}
< / button >
< / div >
) ,
cell : ( { row } ) = > (
< div className = "text-center table-item" >
{ /* {row.original.size !== undefined ? convertBytes(row.original.size) : '-'} */ }
{ /* {row.original.email} */ }
-- -
< / div >
) ,
} ,
{
accessorKey : 'status' ,
header : ( { column } ) = > (
< div className = "column" >
< span >
{ t ( 'status' ) }
< / span >
< button
onClick = { ( ) = > column . toggleSorting ( column . getIsSorted ( ) === 'asc' ) }
className = "sort-button"
>
{
column . getIsSorted ( ) === 'asc' ?
< span >
< IconArrowUp / >
< / span >
: column . getIsSorted ( ) === 'desc' ?
< span >
< IconArrowDown / >
< / span >
: < span >
< IconFilter / >
< / span >
}
< / button >
< / div >
) ,
cell : ( { row } ) = > {
return (
< div className = "text-center font-semibold table-item" >
< span className = "table-item-status" >
{ row . original . status }
< / span >
< / div >
)
} ,
} ,
{
accessorKey : 'request-date' ,
header : ( { column } ) = > (
< div className = "column" >
< span >
{ t ( 'request-date' ) }
< / span >
< button
onClick = { ( ) = > column . toggleSorting ( column . getIsSorted ( ) === 'asc' ) }
className = "sort-button"
>
{
column . getIsSorted ( ) === 'asc' ?
< span >
< IconArrowUp / >
< / span >
: column . getIsSorted ( ) === 'desc' ?
< span >
< IconArrowDown / >
< / span >
: < span >
< IconFilter / >
< / span >
}
< / button >
< / div >
) ,
cell : ( { row } ) = > {
return (
< div className = "text-center table-item" >
{ row . original . registrationData ? . split ( 'T' ) [ 0 ] }
< / div >
)
} ,
enableColumnFilter : false ,
} ,
{
accessorKey : 'processed' ,
header : ( { column } ) = > (
< div className = "column" >
< span >
{ t ( 'processed' ) }
< / span >
< button
onClick = { ( ) = > column . toggleSorting ( column . getIsSorted ( ) === 'asc' ) }
className = "sort-button"
>
{
column . getIsSorted ( ) === 'asc' ?
< span >
< IconArrowUp / >
< / span >
: column . getIsSorted ( ) === 'desc' ?
< span >
< IconArrowDown / >
< / span >
: < span >
< IconFilter / >
< / span >
}
< / button >
< / div >
) ,
cell : ( { row } ) = > {
return (
< div className = "text-center table-item" >
{ row . original . registrationData ? . split ( 'T' ) [ 0 ] }
< / div >
)
} ,
enableColumnFilter : false ,
}
] ,
[ ]
) ;
// Фильтрация по типу файла и дате
const filteredData = useMemo ( ( ) = > {
let result = referralInvitees ;
if ( ! result ) {
return [ ] ;
}
// Фильтр по типу файла
if ( statusFilter !== 'all' ) {
result = result . filter ( item = > item . status === statusFilter ) ;
}
// Фильтр по дате
/* if (dateFilter !== 'all') {
const now = Date.now();
const oneDay = 24 * 60 * 60 * 1000;
const sevenDays = 7 * oneDay;
const thirtyDays = 30 * oneDay;
switch (dateFilter) {
case 'today':
const todayStart = new Date().setHours(0, 0, 0, 0);
result = result.filter(item => {
if (item.registrationData) {
return item.registrationData >= todayStart
} else {
return 0
}
});
break;
case 'week':
const weekAgo = now - sevenDays;
result = result.filter(item => {
if (item.registrationData) {
return item.registrationData >= weekAgo;
}
});
break;
case 'month':
const monthAgo = now - thirtyDays;
result = result.filter(item => {
if (item.registrationData) {
return item.registrationData >= monthAgo;
}
});
break;
case 'older':
const monthAgo2 = now - thirtyDays;
result = result.filter(item => {
if (item.registrationData) {
return item.registrationData < monthAgo2;
}
});
break;
}
} */
return result ;
} , [ referralInvitees , statusFilter , dateFilter ] ) ;
useEffect ( ( ) = > {
const currentPageRows = table . getRowModel ( ) . rows ;
const pageCount = table . getPageCount ( ) ;
if ( currentPageRows . length === 0 && pagination . pageIndex > 0 && pageCount > 0 ) {
table . setPageIndex ( pagination . pageIndex - 1 ) ;
}
} , [ filteredData , pagination . pageIndex ] ) ;
// Создание таблицы
const table = useReactTable ( {
data : filteredData ,
columns ,
state : {
sorting ,
columnFilters ,
pagination
} ,
autoResetPageIndex : false ,
onPaginationChange : setPagination ,
onSortingChange : setSorting ,
onColumnFiltersChange : setColumnFilters ,
getCoreRowModel : getCoreRowModel ( ) ,
getSortedRowModel : getSortedRowModel ( ) ,
getPaginationRowModel : getPaginationRowModel ( ) ,
getFilteredRowModel : getFilteredRowModel ( ) ,
initialState : {
pagination : {
pageSize : 10 ,
} ,
} ,
} ) ;
const pluralizeFiles = ( number : number ) = > {
const translate = [ t ( 'file' ) , t ( 'files-few' ) , t ( 'files' ) ] ;
return pluralize ( number , translate [ 0 ] , translate [ 1 ] , translate [ 2 ] , locale ) ;
} ;
return (
< >
< h4 className = "mt-[30px]" > 📊 И с т о р и я в ы п л а т < / h4 >
< div className = "stats-grid" >
< div className = "stats-item left-top-corner stats-header" >
С у м м а
< / div >
< div className = "stats-item stats-header" >
С п о с о б
< / div >
< div className = "s tats-item stats-header " >
С т а т у с
< / div >
< div className = "stats-item stats-header" >
Д а т а з а п р о с а
< / div >
< div className = "stats-item last-column right-top-corner stats-header" >
О б р а б о т а н о
< div className = "tanstak-table-wrapper" >
< h3
className = "tanstak-table-title"
>
И с т о р и я в ы п л а т
< / h3 >
{ /* Фильтры */ }
< div className = "tanstak-table-filtres" style = { { display : "none" } } >
< div className = "table-filtres-wrapper" >
< div className = "table-filtres-item " >
< div className = "table-filtres-label" > { t ( 'date-filter' ) } : < / div >
< DropDownList
value = { dateFilter }
translatedValue = { ( ( ) = > {
switch ( dateFilter ) {
case 'all' :
return t ( 'all-dates' )
case 'week' :
return t ( 'for-a-week' )
case 'month' :
return t ( 'for-a-month' )
case 'older' :
return t ( 'older-than-a-month' )
default :
return t ( 'today' )
}
} ) ( ) }
callBack = { setDateFilter }
>
< li value = "all" >
{ t ( 'all-dates' ) }
< / li >
< li value = "today" >
{ t ( 'today' ) }
< / li >
< li value = "week" >
{ t ( 'for-a-week' ) }
< / li >
< li value = "month" >
{ t ( 'for-a-month' ) }
< / li >
< li value = "older" >
{ t ( 'older-than-a-month' ) }
< / li >
< / DropDownList >
< / div >
< / div >
< div className = "s tats-item first-column left-bottom-corner " >
0
< / div >
< div className = "stats-item second-row" >
0
< / div >
< div className = "stats-item second-row" >
0
< / div >
< div className = "stats-item second-row" >
0
< / div >
< div className = "stats-item last-column right-bottom-corner" >
0
< div className = "table-filtres-item " >
< div className = "table-filtres-label" > { t ( 'items-per-page' ) } : < / div >
< DropDownList
value = { table . getState ( ) . pagination . pageSize }
//@ts-ignore сделал так потому что для table.setPageSize нужна цифра
callBack = { table . setPageSize }
>
{ [ 5 , 10 , 20 , 50 , 100 ] . map ( pageSize = > (
< li key = { pageSize } value = { pageSize } >
{ t ( 'show' ) } { pageSize }
< / li >
) ) }
< / DropDownList >
< / div >
< / div >
< / >
)
{ /* Таблица */ }
< div className = "tanstak-table-block" >
< table className = "tanstak-table" >
< thead className = "tanstak-table-head" >
{ table . getHeaderGroups ( ) . map ( headerGroup = > (
< tr key = { headerGroup . id } >
{ headerGroup . headers . map ( header = > (
< th
key = { header . id }
>
{ header . isPlaceholder
? null
: typeof header . column . columnDef . header === 'function'
? header . column . columnDef . header ( header . getContext ( ) )
: header . column . columnDef . header as string }
< / th >
) ) }
< / tr >
) ) }
< / thead >
< tbody className = "tanstak-table-body" >
{ table . getRowModel ( ) . rows . length > 0 ? (
table . getRowModel ( ) . rows . map ( row = > (
< tr key = { row . id } >
{ row . getVisibleCells ( ) . map ( cell = > (
< td key = { cell . id } >
{ typeof cell . column . columnDef . cell === 'function'
? cell . column . columnDef . cell ( cell . getContext ( ) )
: cell . getValue ( ) as string }
< / td >
) ) }
< / tr >
) )
) : (
< tr >
< td colSpan = { columns . length } className = "text-center" >
{ t ( 'no-data-for-selected-filters' ) }
< / td >
< / tr >
) }
< / tbody >
< / table >
< / div >
{ /* Пагинация */ }
< div className = "tanstak-table-pagination" >
< div className = "pagination-info" >
{ /* <span className="pagination-info-pages">
{t('page')}{' '}
<strong>
{table.getState().pagination.pageIndex + 1} {t('out-of')} {table.getPageCount() ? table.getPageCount() : 1}
</strong>
</span>
<span className="pagination-info-files">
| {t('shown')} {table.getRowModel().rows.length} {t('out-of')} {filteredData.length} {pluralizeFiles(filteredData.length || 0)}
</span> */ }
< / div >
< div className = "pagination-controls" >
{ table . getCanPreviousPage ( ) && (
< button
className = "arrow"
onClick = { ( ) = > table . firstPage ( ) }
disabled = { ! table . getCanPreviousPage ( ) }
>
< IconDoubleArrowLeft / >
< / button >
) }
{ table . getCanPreviousPage ( ) && (
< button
className = "arrow"
onClick = { ( ) = > table . previousPage ( ) }
disabled = { ! table . getCanPreviousPage ( ) }
>
< IconArrowLeft / >
< / button >
) }
< div className = "pagination-controls-pages" >
{ Array . from ( { length : Math.min ( 5 , table . getPageCount ( ) ) } , ( _ , i ) = > {
const pageIndex = Math . max (
0 ,
Math . min (
table . getPageCount ( ) - 5 ,
table . getState ( ) . pagination . pageIndex - 2
)
) + i ;
if ( pageIndex < table . getPageCount ( ) ) {
return (
< button
key = { pageIndex }
className = { ` ${ table . getState ( ) . pagination . pageIndex === pageIndex
? 'current'
: 'other'
} ` }
onClick = { ( ) = > table . setPageIndex ( pageIndex ) }
>
{ pageIndex + 1 }
< / button >
) ;
}
return null ;
} ) }
< / div >
{ table . getCanNextPage ( ) && (
< button
className = "arrow"
onClick = { ( ) = > table . nextPage ( ) }
disabled = { ! table . getCanNextPage ( ) }
>
< IconArrowRight / >
< / button >
) }
{ table . getCanNextPage ( ) && (
< button
className = "arrow"
onClick = { ( ) = > table . lastPage ( ) }
disabled = { ! table . getCanNextPage ( ) }
>
< IconDoubleArrowRight / >
< / button >
) }
< / div >
< / div >
< / d i v >
) ;
}