Skip to content

Commit

Permalink
Merge pull request #102 from BudgetBuddyDE/dev
Browse files Browse the repository at this point in the history
dev
  • Loading branch information
tklein1801 authored Jan 19, 2024
2 parents 35f28f6 + 25fb736 commit 0585a50
Show file tree
Hide file tree
Showing 25 changed files with 781 additions and 658 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/build-application.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ jobs:
strategy:
matrix:
os: [ubuntu-latest]
node-version: [14.x, 16.x, 18.x, 20.x]
node-version: [16.x, 18.x, 20.x]
env:
REACT_APP_SUPABASE_URL: ${{ secrets.SUPABASE_URL }}
REACT_APP_SUPABASE_ANON: ${{ secrets.SUPABASE_ANON_KEY }}
Expand Down
8 changes: 4 additions & 4 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
"preview": "vite preview"
},
"dependencies": {
"@budgetbuddyde/types": "^1.0.1",
"@budgetbuddyde/types": "^1.0.4",
"@emotion/react": "^11.11.1",
"@emotion/styled": "^11.11.0",
"@mui/icons-material": "^5.14.15",
Expand Down
2 changes: 1 addition & 1 deletion src/components/Base/Pagination/Pagination.component.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export type TPaginationProps = Pick<
onRowsPerPageChange: (rowsPerPage: number) => void;
};

export interface PaginationHandler {
export interface IPaginationHandler {
onPageChange: TPaginationProps['onPageChange'];
onRowsPerPageChange: TPaginationProps['onRowsPerPageChange'];
}
Expand Down
33 changes: 33 additions & 0 deletions src/components/Base/Select/SelectAll.component.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import React from 'react';
import {
Checkbox as MuiCheckbox,
type CheckboxProps,
TableCell,
type TableCellProps,
} from '@mui/material';
import { AppConfig } from '@/app.config';

export type TSelectAllProps = CheckboxProps &
(
| { wrapWithTableCell: true; tableCellProps?: TableCellProps }
| { wrapWithTableCell?: false; tableCellProps?: undefined }
);

export const SelectAll: React.FC<TSelectAllProps> = ({
wrapWithTableCell,
tableCellProps,
...checkboxProps
}) => {
const Checkbox = () => <MuiCheckbox {...checkboxProps} />;
return wrapWithTableCell ? (
<TableCell
size={AppConfig.table.cellSize}
{...tableCellProps}
sx={{ width: '1%', whiteSpace: 'nowrap', ...tableCellProps?.sx }}
>
<Checkbox />
</TableCell>
) : (
<Checkbox />
);
};
8 changes: 8 additions & 0 deletions src/components/Base/Select/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
export * from './SelectAll.component';

export interface ISelectionHandler<T> {
onSelectAll: (shouldSelectAll: boolean) => void;
onSelect: (entity: T) => void;
isSelected: (entity: T) => boolean;
onDeleteMultiple?: () => void;
}
181 changes: 167 additions & 14 deletions src/components/Base/Table/Table.component.tsx
Original file line number Diff line number Diff line change
@@ -1,22 +1,175 @@
import React from 'react';
import {
TableContainer,
type TableContainerProps,
Table as MuiTable,
type TableProps as MuiTableProps,
Box,
Button,
Skeleton,
TableBody,
TableCell,
TableHead,
TableRow,
Typography,
} from '@mui/material';
import { ActionPaper, Card, NoResults } from '../index';
import {
type IPaginationHandler,
InitialPaginationState,
Pagination,
usePagination,
PaginationReducer,
} from '../Pagination';
import { TableContainer } from './TableContainer.component';
import { CircularProgress } from '@/components/Loading';
import { type ISelectionHandler, SelectAll } from '../Select';
import { DeleteRounded } from '@mui/icons-material';

export type TTableProps<T> = {
title?: string;
subtitle?: string;
headerCells: string[];
renderHeaderCell?: (headerCell: string) => React.ReactNode;
data: T[];
renderRow: (row: T) => React.ReactNode;
tableActions?: React.ReactNode;
isLoading?: boolean;
} & (
| {
withSelection: true;
onSelectAll: ISelectionHandler<T>['onSelectAll'];
onDelete?: () => void;
amountOfSelectedEntities: number;
}
| { withSelection?: false }
);

interface ITableHandler {
pagination: IPaginationHandler;
}

export const Table = <T,>({
title,
subtitle,
headerCells,
renderHeaderCell,
data,
renderRow,
tableActions,
isLoading = false,
...props
}: TTableProps<T>) => {
const [state, dispatch] = React.useReducer(PaginationReducer, InitialPaginationState);
const [checked, setChecked] = React.useState(false);
const currentPageData = usePagination(data, state);

export type TTable = React.PropsWithChildren<{
tableContainerProps?: TableContainerProps;
tableProps?: MuiTableProps;
}>;
const handler: ITableHandler = {
pagination: {
onPageChange(newPage) {
dispatch({ type: 'CHANGE_PAGE', page: newPage });
},
onRowsPerPageChange(rowsPerPage) {
dispatch({ type: 'CHANGE_ROWS_PER_PAGE', rowsPerPage: rowsPerPage });
},
},
};

React.useLayoutEffect(() => {
setChecked(false);
if (!props.withSelection) return;
if (props.amountOfSelectedEntities === data.length) {
setChecked(true);
}
}, [props, data]);

export const Table: React.FC<TTable> = ({ tableProps, tableContainerProps, children }) => {
return (
<TableContainer {...tableContainerProps}>
<MuiTable aria-label="Table" {...tableProps} sx={{ minWidth: 650, ...tableProps?.sx }}>
{children}
</MuiTable>
</TableContainer>
<Card sx={{ p: 0 }}>
{(title || subtitle) && (
<Card.Header sx={{ px: 2, pt: 2 }}>
<Box>
{title && <Card.Title>{title || 'Table'}</Card.Title>}
{subtitle && <Card.Subtitle>{subtitle}</Card.Subtitle>}
</Box>
{tableActions && (
<Card.HeaderActions sx={{ mt: { xs: 1, md: 0 }, width: { md: 'unset' } }}>
<ActionPaper sx={{ display: 'flex', flexDirection: 'row' }}>
{isLoading ? (
<Skeleton
variant="rounded"
sx={{ width: { xs: '5rem', md: '10rem' }, height: '2.3rem' }}
/>
) : (
tableActions
)}
</ActionPaper>
</Card.HeaderActions>
)}
</Card.Header>
)}
<Card.Body sx={{ px: 0 }}>
{isLoading ? (
<CircularProgress />
) : currentPageData.length > 0 ? (
<React.Fragment>
{props.withSelection && props.amountOfSelectedEntities > 0 && (
<Box sx={{ px: 2, pt: 1.5 }}>
{props.onDelete && (
<Button
startIcon={<DeleteRounded />}
onClick={() => {
if (props.onDelete) props.onDelete();
}}
sx={{ mr: 1 }}
>
Delete
</Button>
)}
</Box>
)}

<TableContainer>
<TableHead>
<TableRow>
{props.withSelection && (
<SelectAll
checked={checked}
indeterminate={
props.amountOfSelectedEntities > 0 &&
props.amountOfSelectedEntities < data.length
}
onChange={(_event, checked) => {
const indeterminate =
props.amountOfSelectedEntities > 0 &&
props.amountOfSelectedEntities < data.length;
props.onSelectAll(indeterminate ? false : checked);
}}
wrapWithTableCell
/>
)}

{headerCells.map((headerCell) =>
renderHeaderCell ? (
renderHeaderCell(headerCell)
) : (
<TableCell key={headerCell.replaceAll(' ', '_').toLowerCase()}>
<Typography fontWeight={'bold'}>{headerCell}</Typography>
</TableCell>
)
)}
</TableRow>
</TableHead>
<TableBody>{currentPageData.map(renderRow)}</TableBody>
</TableContainer>
</React.Fragment>
) : (
<NoResults sx={{ mx: 2, mt: 2 }} />
)}
</Card.Body>
<Card.Footer sx={{ p: 2 }}>
<Pagination
{...state}
count={currentPageData.length}
onPageChange={handler.pagination.onPageChange}
onRowsPerPageChange={handler.pagination.onRowsPerPageChange}
/>
</Card.Footer>
</Card>
);
};
26 changes: 26 additions & 0 deletions src/components/Base/Table/TableContainer.component.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import React from 'react';
import {
TableContainer as MuiTableContainer,
type TableContainerProps,
Table as MuiTable,
type TableProps as MuiTableProps,
} from '@mui/material';

export type TTableContainerProps = React.PropsWithChildren<{
tableContainerProps?: TableContainerProps;
tableProps?: MuiTableProps;
}>;

export const TableContainer: React.FC<TTableContainerProps> = ({
tableProps,
tableContainerProps,
children,
}) => {
return (
<MuiTableContainer {...tableContainerProps}>
<MuiTable aria-label="Table" {...tableProps} sx={{ width: '100%', ...tableProps?.sx }}>
{children}
</MuiTable>
</MuiTableContainer>
);
};
1 change: 1 addition & 0 deletions src/components/Base/Table/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export * from './TableContainer.component';
export * from './Table.component';
36 changes: 18 additions & 18 deletions src/components/DashboardStatsWrapper.component.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Grid } from '@mui/material';
import React from 'react';
import { StatsCard, StatsIconStyle, TStatsCardProps } from './StatsCard.component';
import { StatsCard, TStatsCardProps } from './StatsCard.component';
import {
AddRounded,
BalanceRounded,
Expand Down Expand Up @@ -65,29 +65,29 @@ export const DashboardStatsWrapper: React.FC<TDashboardStatsWrapperProps> = () =
const stats: TStatsCardProps[] = React.useMemo(() => {
return [
{
title: formatBalance(fetchedStats.earnings),
subtitle: 'Earnings',
icon: <AddRounded sx={StatsIconStyle} />,
value: formatBalance(fetchedStats.earnings),
label: 'Earnings',
icon: <AddRounded />,
},
{
title: formatBalance(fetchedStats.upcoming_earnings),
subtitle: 'Upcoming Earnings',
icon: <ScheduleSendRounded sx={StatsIconStyle} />,
value: formatBalance(fetchedStats.upcoming_earnings),
label: 'Upcoming Earnings',
icon: <ScheduleSendRounded />,
},
{
title: formatBalance(fetchedStats.expenses),
subtitle: 'Expenses',
icon: <RemoveRounded sx={StatsIconStyle} />,
value: formatBalance(fetchedStats.expenses),
label: 'Expenses',
icon: <RemoveRounded />,
},
{
title: formatBalance(fetchedStats.upcoming_expenses),
subtitle: 'Upcoming Expenses',
icon: <ScheduleSendRounded sx={StatsIconStyle} />,
value: formatBalance(fetchedStats.upcoming_expenses),
label: 'Upcoming Expenses',
icon: <ScheduleSendRounded />,
},
{
title: formatBalance(fetchedStats.balance),
subtitle: 'Balance',
icon: <BalanceRounded sx={StatsIconStyle} />,
value: formatBalance(fetchedStats.balance),
label: 'Balance',
icon: <BalanceRounded />,
},
];
}, [fetchedStats]);
Expand Down Expand Up @@ -128,12 +128,12 @@ export const DashboardStatsWrapper: React.FC<TDashboardStatsWrapperProps> = () =
<Grid container item xs={12} md={12} columns={10} spacing={3}>
{stats.map((props, idx, list) => (
<Grid
key={props.subtitle.toString().toLowerCase().replace(' ', '_')}
key={props.label.toString().toLowerCase().replace(' ', '_')}
item
xs={idx == list.length - 1 ? 10 : 5}
md={2}
>
<StatsCard loading={loading} {...props} />
<StatsCard isLoading={loading} {...props} />
</Grid>
))}
</Grid>
Expand Down
3 changes: 0 additions & 3 deletions src/components/DataTable/DataTable.component.tsx

This file was deleted.

1 change: 0 additions & 1 deletion src/components/DataTable/index.ts

This file was deleted.

Loading

0 comments on commit 0585a50

Please sign in to comment.