Fixed issue with transactions table

This commit is contained in:
Umar Adilov 2025-05-16 17:46:51 +05:00
parent 06b886ca5d
commit bf134a99d5
8 changed files with 181 additions and 90 deletions

View File

@ -1,11 +1,10 @@
import {
TransactionRequest,
TransactionResponse,
} from '@/entities/transactions/model/types';
import { baseAPI } from '@/shared/api/base-api'; import { baseAPI } from '@/shared/api/base-api';
import { ClientInfo } from '../model/types/bonus-client-info.type'; import { ClientInfo } from '../model/types/bonus-client-info.type';
import {
BonusTransactionRequest,
BonusTransactionResponse,
} from '../model/types/bonus-transactions.type';
export const bonusApi = baseAPI.injectEndpoints({ export const bonusApi = baseAPI.injectEndpoints({
endpoints: (builder) => ({ endpoints: (builder) => ({
@ -17,8 +16,8 @@ export const bonusApi = baseAPI.injectEndpoints({
}, },
}), }),
fetchBonusTransactions: builder.query< fetchBonusTransactions: builder.query<
TransactionResponse, BonusTransactionResponse,
TransactionRequest BonusTransactionRequest
>({ >({
query: (request) => { query: (request) => {
return { return {

View File

@ -1,23 +1,22 @@
export interface TransactionResponse { export interface BonusTransactionResponse {
transactions: Transaction[]; transactions: BonusTransaction[];
current_page: number; current_page: number;
limit: number; limit: number;
total_records: number; total_records: number;
total_pages: number; total_pages: number;
} }
export interface Transaction { export interface BonusTransaction {
id: number; id: number;
date_create: string; date_create: string;
station?: string; station?: string;
station_name?: string;
product_name: string; product_name: string;
amount: string; amount: string;
price_real: string; price_real: string;
sum_real: string; sum_real: string;
} }
export interface TransactionRequest { export interface BonusTransactionRequest {
start_date?: string; start_date?: string;
end_date?: string; end_date?: string;
page: number; page: number;

View File

@ -1,11 +1,10 @@
import {
TransactionRequest,
TransactionResponse,
} from '@/entities/transactions/model/types';
import { baseAPI } from '@/shared/api/base-api'; import { baseAPI } from '@/shared/api/base-api';
import { CorporateInfoResponse } from '../model/types/corporate-client-info.type'; import { CorporateInfoResponse } from '../model/types/corporate-client-info.type';
import {
CorporateTransactionRequest,
CorporateTransactionResponse,
} from '../model/types/corporate-transactions.type';
export const corporateApi = baseAPI.injectEndpoints({ export const corporateApi = baseAPI.injectEndpoints({
endpoints: (builder) => ({ endpoints: (builder) => ({
@ -17,8 +16,8 @@ export const corporateApi = baseAPI.injectEndpoints({
}, },
}), }),
fetchCorporateTransactions: builder.query< fetchCorporateTransactions: builder.query<
TransactionResponse, CorporateTransactionResponse,
TransactionRequest CorporateTransactionRequest
>({ >({
query: (request) => { query: (request) => {
return { return {

View File

@ -0,0 +1,24 @@
export interface CorporateTransactionResponse {
transactions: CorporateTransaction[];
current_page: number;
limit: number;
total_records: number;
total_pages: number;
}
export interface CorporateTransaction {
date_create: string;
station_name?: string;
product_name: string;
amount: string;
price_real: string;
sum_real: string;
uid: string;
}
export interface CorporateTransactionRequest {
start_date?: string;
end_date?: string;
page: number;
limit: number;
}

View File

@ -1,6 +1,7 @@
'use client'; 'use client';
import { deleteCookie } from 'cookies-next'; import { deleteCookie } from 'cookies-next';
import { format } from 'date-fns';
import { Building2, LogOut, Wallet } from 'lucide-react'; import { Building2, LogOut, Wallet } from 'lucide-react';
import { useEffect, useState } from 'react'; import { useEffect, useState } from 'react';
@ -8,7 +9,7 @@ import {
useFetchCorporateTransactionsQuery, useFetchCorporateTransactionsQuery,
useFetchMyCorporateInfoQuery, useFetchMyCorporateInfoQuery,
} from '@/entities/corporate/api/corporate.api'; } from '@/entities/corporate/api/corporate.api';
import { TransactionRequest } from '@/entities/transactions/model/types'; import { CorporateTransactionRequest } from '@/entities/corporate/model/types/corporate-transactions.type';
import { useTextController } from '@/shared/language/hooks/use-text-controller'; import { useTextController } from '@/shared/language/hooks/use-text-controller';
import { Button } from '@/shared/shadcn-ui/button'; import { Button } from '@/shared/shadcn-ui/button';
@ -19,6 +20,7 @@ import {
CardHeader, CardHeader,
CardTitle, CardTitle,
} from '@/shared/shadcn-ui/card'; } from '@/shared/shadcn-ui/card';
import { TableCell, TableHead, TableRow } from '@/shared/shadcn-ui/table';
import { TransactionsTable } from '@/widgets/transactions-table'; import { TransactionsTable } from '@/widgets/transactions-table';
@ -27,10 +29,11 @@ export function CorporateDashboard() {
const { data } = useFetchMyCorporateInfoQuery({}); const { data } = useFetchMyCorporateInfoQuery({});
const [request, setTransactionFetchRequest] = useState<TransactionRequest>({ const [request, setTransactionFetchRequest] =
limit: 10, useState<CorporateTransactionRequest>({
page: 1, limit: 10,
}); page: 1,
});
const { const {
data: transactionsResponse, data: transactionsResponse,
@ -164,6 +167,53 @@ export function CorporateDashboard() {
<TransactionsTable <TransactionsTable
isLoading={isFetching} isLoading={isFetching}
renderHeaders={() => (
<TableRow>
<TableHead>
{t('corporate.transactions.tableHeaders.date')}
</TableHead>
<TableHead>
{t('corporate.transactions.tableHeaders.card')}
</TableHead>
<TableHead>
{t('corporate.transactions.tableHeaders.station')}
</TableHead>
<TableHead>
{t('corporate.transactions.tableHeaders.product')}
</TableHead>
<TableHead className='text-right'>
{t('corporate.transactions.tableHeaders.quantity')}
</TableHead>
<TableHead className='text-right'>
{t('corporate.transactions.tableHeaders.price')}
</TableHead>
<TableHead className='text-right'>
{t('corporate.transactions.tableHeaders.total')}
</TableHead>
</TableRow>
)}
renderRow={(transaction, index) => (
<TableRow key={index}>
<TableCell>
{format(
new Date(transaction.date_create),
'dd.MM.yyyy HH:mm',
)}
</TableCell>
<TableCell>{transaction.uid}</TableCell>
<TableCell>{transaction.station_name}</TableCell>
<TableCell>{transaction.product_name}</TableCell>
<TableCell className='text-right'>
{transaction.amount}
</TableCell>
<TableCell className='text-right'>
{transaction.price_real} {t('corporate.currency')}
</TableCell>
<TableCell className='text-right font-medium'>
{transaction.sum_real} {t('corporate.currency')}
</TableCell>
</TableRow>
)}
data={ data={
transactionsResponse || { transactionsResponse || {
limit: 10, limit: 10,

View File

@ -1,6 +1,7 @@
'use client'; 'use client';
import { deleteCookie } from 'cookies-next'; import { deleteCookie } from 'cookies-next';
import { format } from 'date-fns';
import { ArrowUpRight, Clock, CreditCard, LogOut, User } from 'lucide-react'; import { ArrowUpRight, Clock, CreditCard, LogOut, User } from 'lucide-react';
import { useEffect, useState } from 'react'; import { useEffect, useState } from 'react';
@ -8,7 +9,7 @@ import {
useFetchBonusTransactionsQuery, useFetchBonusTransactionsQuery,
useFetchMyBonusInfoQuery, useFetchMyBonusInfoQuery,
} from '@/entities/bonus/api/bonus.api'; } from '@/entities/bonus/api/bonus.api';
import { TransactionRequest } from '@/entities/transactions/model/types'; import { BonusTransactionRequest } from '@/entities/bonus/model/types/bonus-transactions.type';
import Loader from '@/shared/components/loader'; import Loader from '@/shared/components/loader';
import { useTextController } from '@/shared/language/hooks/use-text-controller'; import { useTextController } from '@/shared/language/hooks/use-text-controller';
@ -20,16 +21,18 @@ import {
CardHeader, CardHeader,
CardTitle, CardTitle,
} from '@/shared/shadcn-ui/card'; } from '@/shared/shadcn-ui/card';
import { TableCell, TableHead, TableRow } from '@/shared/shadcn-ui/table';
import { TransactionsTable } from '@/widgets/transactions-table'; import { TransactionsTable } from '@/widgets/transactions-table';
export function CustomerDashboard() { export function CustomerDashboard() {
const { t } = useTextController(); const { t } = useTextController();
const [request, setTransactionFetchRequest] = useState<TransactionRequest>({ const [request, setTransactionFetchRequest] =
limit: 10, useState<BonusTransactionRequest>({
page: 1, limit: 10,
}); page: 1,
});
const { data, isLoading } = useFetchMyBonusInfoQuery({}); const { data, isLoading } = useFetchMyBonusInfoQuery({});
@ -162,6 +165,49 @@ export function CustomerDashboard() {
transactions: [], transactions: [],
} }
} }
renderHeaders={() => (
<TableRow>
<TableHead>
{t('corporate.transactions.tableHeaders.date')}
</TableHead>
<TableHead>
{t('corporate.transactions.tableHeaders.station')}
</TableHead>
<TableHead>
{t('corporate.transactions.tableHeaders.product')}
</TableHead>
<TableHead className='text-right'>
{t('corporate.transactions.tableHeaders.quantity')}
</TableHead>
<TableHead className='text-right'>
{t('corporate.transactions.tableHeaders.price')}
</TableHead>
<TableHead className='text-right'>
{t('corporate.transactions.tableHeaders.total')}
</TableHead>
</TableRow>
)}
renderRow={(transaction) => (
<TableRow key={transaction.id}>
<TableCell>
{format(
new Date(transaction.date_create),
'dd.MM.yyyy HH:mm',
)}
</TableCell>
<TableCell>{transaction.station}</TableCell>
<TableCell>{transaction.product_name}</TableCell>
<TableCell className='text-right'>
{transaction.amount}
</TableCell>
<TableCell className='text-right'>
{transaction.price_real} {t('corporate.currency')}
</TableCell>
<TableCell className='text-right font-medium'>
{transaction.sum_real} {t('corporate.currency')}
</TableCell>
</TableRow>
)}
onChange={setTransactionFetchRequest} onChange={setTransactionFetchRequest}
/> />
</div> </div>

View File

@ -5,11 +5,6 @@ import { ru } from 'date-fns/locale';
import { CalendarIcon, X } from 'lucide-react'; import { CalendarIcon, X } from 'lucide-react';
import { useEffect, useState } from 'react'; import { useEffect, useState } from 'react';
import {
TransactionRequest,
TransactionResponse,
} from '@/entities/transactions/model/types';
import TableLoadingOverlay from '@/shared/components/table-loading-overlay'; import TableLoadingOverlay from '@/shared/components/table-loading-overlay';
import { useTextController } from '@/shared/language/hooks/use-text-controller'; import { useTextController } from '@/shared/language/hooks/use-text-controller';
import { Button } from '@/shared/shadcn-ui/button'; import { Button } from '@/shared/shadcn-ui/button';
@ -24,7 +19,6 @@ import {
Table, Table,
TableBody, TableBody,
TableCell, TableCell,
TableHead,
TableHeader, TableHeader,
TableRow, TableRow,
} from '@/shared/shadcn-ui/table'; } from '@/shared/shadcn-ui/table';
@ -38,23 +32,40 @@ import {
PaginationPrevious, PaginationPrevious,
} from './pagination'; } from './pagination';
export interface TransactionsTableProps { export interface TransactionRequest {
onChange: (request: TransactionRequest) => void; start_date?: string;
isLoading: boolean; end_date?: string;
data: TransactionResponse; page: number;
limit: number;
} }
export const TransactionsTable = ({ export interface TransactionsTableProps<T> {
data: {
transactions: T[];
total_pages: number;
total_records: number;
};
isLoading: boolean;
onChange: (request: TransactionRequest) => void;
renderHeaders: () => React.ReactNode;
renderRow: (transaction: T, index: number) => React.ReactNode;
itemsPerPageOptions?: number[];
}
export const TransactionsTable = <T,>({
data, data,
isLoading, isLoading,
onChange, onChange,
}: TransactionsTableProps) => { renderHeaders,
renderRow,
itemsPerPageOptions = [5, 10, 20, 50],
}: TransactionsTableProps<T>) => {
const [startDate, setStartDate] = useState<Date | undefined>( const [startDate, setStartDate] = useState<Date | undefined>(
new Date(new Date().setMonth(new Date().getMonth() - 1)), new Date(new Date().setMonth(new Date().getMonth() - 1)),
); );
const [endDate, setEndDate] = useState<Date | undefined>(new Date()); const [endDate, setEndDate] = useState<Date | undefined>(new Date());
const [currentPage, setCurrentPage] = useState(1); const [currentPage, setCurrentPage] = useState(1);
const [itemsPerPage, setItemsPerPage] = useState(10); const [itemsPerPage, setItemsPerPage] = useState(itemsPerPageOptions[0]);
const handlePageChange = (page: number) => { const handlePageChange = (page: number) => {
if (page < 1 || page > data.total_pages) return; if (page < 1 || page > data.total_pages) return;
@ -175,57 +186,19 @@ export const TransactionsTable = ({
<div className='relative rounded-md border'> <div className='relative rounded-md border'>
<Table> <Table>
<TableHeader> <TableHeader>{renderHeaders()}</TableHeader>
<TableRow>
<TableHead>
{t('corporate.transactions.tableHeaders.date')}
</TableHead>
<TableHead>
{t('corporate.transactions.tableHeaders.station')}
</TableHead>
<TableHead>
{t('corporate.transactions.tableHeaders.product')}
</TableHead>
<TableHead className='text-right'>
{t('corporate.transactions.tableHeaders.quantity')}
</TableHead>
<TableHead className='text-right'>
{t('corporate.transactions.tableHeaders.price')}
</TableHead>
<TableHead className='text-right'>
{t('corporate.transactions.tableHeaders.total')}
</TableHead>
</TableRow>
</TableHeader>
<TableBody> <TableBody>
{data.transactions.length > 0 ? ( {data.transactions.length > 0 ? (
data.transactions.map((transaction) => ( data.transactions.map((transaction, index) =>
<TableRow key={transaction.id}> renderRow(transaction, index),
<TableCell> )
{format(new Date(transaction.date_create), 'dd.MM.yyyy')}
</TableCell>
<TableCell>
{transaction.station || transaction.station_name}
</TableCell>
<TableCell>{transaction.product_name}</TableCell>
<TableCell className='text-right'>
{transaction.amount}
</TableCell>
<TableCell className='text-right'>
{transaction.price_real} {t('corporate.currency')}
</TableCell>
<TableCell className='text-right font-medium'>
{transaction.sum_real} {t('corporate.currency')}
</TableCell>
</TableRow>
))
) : ( ) : (
<TableRow> <TableRow>
<TableCell <TableCell
colSpan={6} colSpan={6}
className='py-6 text-center text-gray-500' className='py-6 text-center text-gray-500'
> >
{t('corporate.transactions.noTransactions')} {t('corporate.transactions.no-data')}
</TableCell> </TableCell>
</TableRow> </TableRow>
)} )}
@ -286,10 +259,11 @@ export const TransactionsTable = ({
setCurrentPage(1); // Reset to first page when changing items per page setCurrentPage(1); // Reset to first page when changing items per page
}} }}
> >
<option value={5}>5</option> {itemsPerPageOptions.map((option) => (
<option value={10}>10</option> <option key={option} value={option}>
<option value={20}>20</option> {option}
<option value={50}>50</option> </option>
))}
</select> </select>
</div> </div>
</div> </div>

View File

@ -29,5 +29,5 @@
} }
}, },
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
"exclude": ["node_modules"], "exclude": ["node_modules"]
} }