Skip to content

Commit 18012b8

Browse files
committed
Add records list components and query hooks; implement pagination and data fetching logic
2 parents b1277bc + 14c3d30 commit 18012b8

17 files changed

+238
-18
lines changed

src/modules/records/create/components/step-navigation.component.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import React from 'react';
22
import { Button } from '@mui/material';
33
import { useWithTheme } from '#core/theme/theme.hooks.ts';
4-
import { Steps, useCreateRecordContext } from '#modules/records/common/providers';
4+
import { Steps, useCreateRecordContext } from '#modules/records/core/providers';
55
import * as innerClasses from './step-navigation.styles';
66

77
export const StepNavigation: React.FC = () => {

src/modules/records/create/components/steps/budget-step.component.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import React from 'react';
22
import { Form, Formik } from 'formik';
33
import { TextFieldForm } from '#common/components';
4-
import { useCreateRecordContext, Budget } from '#modules/records/common/providers';
4+
import { useCreateRecordContext, Budget } from '#modules/records/core/providers';
55
import { StepNavigation } from '../step-navigation.component';
66
import { budgetValidation } from '../validations';
77
import * as classes from './steps.styles';

src/modules/records/create/components/steps/general-data-step.component.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import React from 'react';
22
import { Form, Formik } from 'formik';
33
import { TextFieldForm } from '#common/components';
4-
import { GeneralData, useCreateRecordContext } from '#modules/records/common/providers';
4+
import { GeneralData, useCreateRecordContext } from '#modules/records/core/providers';
55
import { generalDataValidation } from '../validations';
66
import { StepNavigation } from '../step-navigation.component';
77
import * as classes from './steps.styles';

src/modules/records/create/components/steps/temporality-step.component.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import React from 'react';
22
import { Form, Formik } from 'formik';
33
import { TextFieldForm } from '#common/components';
4-
import { useCreateRecordContext, Temporality } from '#modules/records/common/providers';
4+
import { useCreateRecordContext, Temporality } from '#modules/records/core/providers';
55
import { StepNavigation } from '../step-navigation.component';
66
import { temporalityValidation } from '../validations';
77
import * as classes from './steps.styles';

src/modules/records/create/create-record.component.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { Dialog, DialogContent, DialogTitle, Step, StepLabel, Stepper } from '@m
33
import { useWithTheme } from '#core/theme';
44
import { BudgetStep, GeneralDataStep, TemporalityStep } from './components';
55
import * as innerClasses from './create-record.styles';
6-
import { useCreateRecordContext } from '../common/providers';
6+
import { useCreateRecordContext } from '../core/providers';
77

88
export const CreateRecord: React.FC = () => {
99
const { activeStep, isOpen, onCancel } = useCreateRecordContext();
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export * from './table.component';
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
import React from 'react';
2+
import { useWithTheme } from '#core/theme';
3+
import { Pagination, Paper, Table, TableBody, TableCell, TableContainer, TableHead, TableRow } from '@mui/material';
4+
import { ColumnDef, flexRender, getCoreRowModel, getPaginationRowModel, useReactTable } from '@tanstack/react-table';
5+
import { Record } from '../records.vm';
6+
import * as innerClasses from './table.styles';
7+
8+
interface Props {
9+
columns: ColumnDef<Record>[];
10+
recordCollection: Record[];
11+
totalItems: number;
12+
currentPage: number;
13+
onPageChange: (event: React.ChangeEvent<unknown>, page: number) => void;
14+
}
15+
16+
export const TableComponent: React.FC<Props> = props => {
17+
const { columns, recordCollection: data, totalItems, currentPage, onPageChange } = props;
18+
const classes = useWithTheme(innerClasses);
19+
const tableInstance = useReactTable({
20+
data,
21+
columns,
22+
getCoreRowModel: getCoreRowModel(),
23+
getPaginationRowModel: getPaginationRowModel(),
24+
rowCount: totalItems,
25+
});
26+
27+
const { getRowModel, getHeaderGroups, getPageCount } = tableInstance;
28+
29+
return (
30+
<TableContainer component={Paper}>
31+
<Table className={classes.table}>
32+
<TableHead>
33+
{getHeaderGroups().map(headerGroup => (
34+
<TableRow key={headerGroup.id}>
35+
{headerGroup.headers.map(header => (
36+
<TableCell key={header.id}>{flexRender(header.column.columnDef.header, header.getContext())}</TableCell>
37+
))}
38+
</TableRow>
39+
))}
40+
</TableHead>
41+
<TableBody>
42+
{getRowModel().rows.map(row => (
43+
<TableRow key={row.id}>
44+
{row.getVisibleCells().map(cell => (
45+
<TableCell key={cell.id}>{flexRender(cell.column.columnDef.cell, cell.getContext())}</TableCell>
46+
))}
47+
</TableRow>
48+
))}
49+
</TableBody>
50+
</Table>
51+
<Pagination
52+
count={getPageCount()}
53+
page={currentPage + 1}
54+
onChange={onPageChange}
55+
className={classes.pagination}
56+
/>
57+
</TableContainer>
58+
);
59+
};
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import { css } from '@emotion/css';
2+
3+
export const table = css`
4+
min-width: 1200px;
5+
`;
6+
7+
export const pagination = css`
8+
display: flex;
9+
justify-content: center;
10+
padding: 10px;
11+
`;
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import { ColumnDef } from '@tanstack/react-table';
2+
import { Link } from '@tanstack/react-router';
3+
import { Chip, Box } from '@mui/material';
4+
import { Edit as EditIcon, Delete as DeleteIcon, Visibility as VisibilityIcon } from '@mui/icons-material';
5+
import { useWithTheme } from '#core/theme';
6+
import { Record } from './records.vm';
7+
import * as innerClasses from './records.styles';
8+
9+
export const useColumns = (): ColumnDef<Record>[] => {
10+
const classes = useWithTheme(innerClasses);
11+
12+
return [
13+
{ accessorKey: 'id', header: 'idv' },
14+
{ accessorKey: 'clase', header: 'Clase', cell: ({ row }) => <Chip label={row.original.clase} /> },
15+
{ accessorKey: 'titulo', header: 'Título' },
16+
{
17+
accessorKey: 'adjudicataria',
18+
header: 'Adjudicataria',
19+
},
20+
{ accessorKey: 'estado', header: 'Estado', cell: ({ row }) => <Chip label={row.original.estado} /> },
21+
{
22+
accessorKey: 'commands',
23+
header: 'Comandos',
24+
cell: ({ row }) => (
25+
<Box display="flex" alignItems="center" gap={2}>
26+
<Link to={`/records/${row.original.id}`} className={classes.link}>
27+
<VisibilityIcon />
28+
</Link>
29+
<Link to={`/edit-record/${row.original.id}`} className={classes.link}>
30+
<EditIcon />
31+
</Link>
32+
<DeleteIcon />
33+
</Box>
34+
),
35+
},
36+
];
37+
};

src/modules/records/list/records.pod.tsx

Lines changed: 25 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,35 @@
11
import React from 'react';
2-
import { NavigationButton } from '#common/components';
2+
import { Button, Typography } from '@mui/material';
3+
import { Spinner } from '#common/components';
4+
import { useWithTheme } from '#core/theme/theme.hooks.ts';
35
import { useCreateRecordContext } from '#modules/records/core/providers';
4-
import { Button } from '@mui/material';
6+
import { usePagination } from './use-pagination-hook';
7+
import { TableComponent } from './components';
8+
import { useColumns } from './records.columns';
59
import { CreateRecordPod } from '../create';
10+
import * as innerClasses from './records.styles';
611

712
export const RecordsPod: React.FC = () => {
13+
const { recordCollection, currentPage, totalPages, isLoading, onPageChange } = usePagination();
814
const { onOpen } = useCreateRecordContext();
15+
const classes = useWithTheme(innerClasses);
16+
const columns = useColumns();
17+
918
return (
10-
<div style={{ display: 'flex', flexDirection: 'column', gap: '1rem' }}>
11-
<Button variant="contained" color="primary" onClick={onOpen}>
12-
Crear expediente
13-
</Button>
14-
<NavigationButton
15-
text="Editar expediente"
16-
path="/edit-record/$id"
17-
params={{
18-
id: '123456',
19-
}}
19+
<div className={classes.root}>
20+
<Spinner isSpinnerShowing={isLoading} />
21+
<div className={classes.header}>
22+
<Typography variant="h4">Expedientes</Typography>
23+
<Button variant="contained" color="primary" onClick={onOpen}>
24+
Nuevo expediente
25+
</Button>
26+
</div>
27+
<TableComponent
28+
columns={columns}
29+
recordCollection={recordCollection.data}
30+
totalItems={totalPages}
31+
currentPage={currentPage}
32+
onPageChange={onPageChange}
2033
/>
2134
<CreateRecordPod />
2235
</div>
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import { useQuery } from '@tanstack/react-query';
2+
import { CollectionQuery, createEmptyCollectionQuery } from '#common/models';
3+
import { getRecordsRepository } from './records.repository';
4+
import { recordsQueryKeys } from '#modules/records/records-keys.ts';
5+
import { RecordQueryFilter, Record } from './records.vm';
6+
7+
interface UseRecordsQueryResult {
8+
recordCollection: CollectionQuery<Record>;
9+
isLoading: boolean;
10+
}
11+
12+
export const useRecordsQuery = (recordFilter: RecordQueryFilter): UseRecordsQueryResult => {
13+
const { page, pageSize } = recordFilter;
14+
15+
const { data: recordCollection = createEmptyCollectionQuery(), isLoading } = useQuery({
16+
queryKey: recordsQueryKeys.recordCollection(page, pageSize),
17+
queryFn: () => getRecordsRepository(),
18+
});
19+
20+
return {
21+
recordCollection,
22+
isLoading,
23+
};
24+
};
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { CollectionQuery } from '#common/models';
2+
import { Record } from './records.vm';
3+
4+
export const getRecordsRepository = async (): Promise<CollectionQuery<Record>> => ({
5+
data: [
6+
{ id: '1', clase: 'Clase A', titulo: 'Título A', adjudicataria: 'Empresa A', estado: 'Activo' },
7+
{ id: '2', clase: 'Clase B', titulo: 'Título 2', adjudicataria: 'Empresa B', estado: 'Pendiente' },
8+
],
9+
pagination: {
10+
totalPages: 1,
11+
},
12+
});
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import { css } from '@emotion/css';
2+
import { Theme } from '@mui/material';
3+
4+
export const root = css`
5+
display: flex;
6+
flex-direction: column;
7+
gap: 30px;
8+
align-items: center;
9+
`;
10+
11+
export const header = (theme: Theme) => css`
12+
display: flex;
13+
justify-content: space-between;
14+
width: 100%;
15+
padding: 0 ${theme.spacing(2)};
16+
`;
17+
18+
export const link = (theme: Theme) => css`
19+
color: ${theme.palette.common.black};
20+
text-decoration: none;
21+
cursor: pointer;
22+
`;
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
export interface Record {
2+
id: string;
3+
clase: string;
4+
titulo: string;
5+
adjudicataria: string;
6+
estado: string;
7+
}
8+
9+
export const createEmptyRecord = (): Record => ({
10+
id: '',
11+
clase: '',
12+
titulo: '',
13+
adjudicataria: '',
14+
estado: '',
15+
});
16+
17+
export interface RecordQueryFilter {
18+
page: number;
19+
pageSize: number;
20+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import React from 'react';
2+
import { useRecordsQuery } from './records.query.hook';
3+
4+
export const usePagination = (initialPage: number = 0, pageSize: number = 10) => {
5+
const [currentPage, setCurrentPage] = React.useState(initialPage);
6+
const { recordCollection, isLoading } = useRecordsQuery({ page: currentPage, pageSize });
7+
8+
const handleChangePage = (_: React.ChangeEvent<unknown>, newPage: number) => setCurrentPage(newPage - 1);
9+
10+
return {
11+
recordCollection,
12+
currentPage,
13+
totalPages: recordCollection.pagination.totalPages,
14+
isLoading,
15+
onPageChange: handleChangePage,
16+
};
17+
};

src/modules/records/records-keys.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
export const recordsQueryKeys = {
2+
all: ['records'],
3+
recordCollection: (page?: number, pageSize?: number) => ['records', page, pageSize],
4+
};

src/scenes/_auth/records/index.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { createFileRoute } from '@tanstack/react-router';
2-
import { CreateRecordProvider } from '#modules/records/common/providers';
2+
import { CreateRecordProvider } from '#modules/records/core/providers';
33
import { RecordsPod } from '#modules/records/list';
44

55
export const Route = createFileRoute('/_auth/records/')({

0 commit comments

Comments
 (0)