Skip to content

Commit

Permalink
feat(web): prettify settlement plan
Browse files Browse the repository at this point in the history
  • Loading branch information
mikonse committed Aug 26, 2023
1 parent 5130ce9 commit f11e114
Show file tree
Hide file tree
Showing 8 changed files with 93 additions and 27 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,17 @@ import { Account, AccountValidator } from "@abrechnung/types";
import { ChevronLeft, Delete, Edit } from "@mui/icons-material";
import { Button, Chip, Divider, Grid, IconButton, LinearProgress, TableCell } from "@mui/material";
import React from "react";
import { Link as RouterLink, useNavigate } from "react-router-dom";
import { useNavigate } from "react-router-dom";
import { toast } from "react-toastify";
import { typeToFlattenedError, z } from "zod";
import { DeleteAccountModal } from "../../../components/accounts/DeleteAccountModal";
import { DateInput } from "../../../components/DateInput";
import { ShareSelect } from "../../../components/ShareSelect";
import { TagSelector } from "../../../components/TagSelector";
import { TextInput } from "../../../components/TextInput";
import { api } from "../../../core/api";
import { selectAccountSlice, selectGroupSlice, useAppDispatch, useAppSelector } from "../../../store";
import { getAccountLink, getAccountListLink } from "../../../utils";
import { DeleteAccountModal } from "@/components/accounts/DeleteAccountModal";
import { DateInput } from "@/components/DateInput";
import { ShareSelect } from "@/components/ShareSelect";
import { TagSelector } from "@/components/TagSelector";
import { TextInput } from "@/components/TextInput";
import { api } from "@/core/api";
import { selectAccountSlice, selectGroupSlice, useAppDispatch, useAppSelector } from "@/store";
import { getAccountLink, getAccountListLink } from "@/utils";

interface Props {
groupId: number;
Expand Down
9 changes: 6 additions & 3 deletions frontend/apps/web/src/pages/accounts/Balances.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -87,9 +87,6 @@ export const Balances: React.FC<Props> = ({ groupId }) => {

return (
<MobilePaper>
<Button component={RouterLink} to={`/groups/${group.id}/settlement-plan`}>
Settle up
</Button>
<TabContext value={selectedTab}>
<Box sx={{ borderBottom: 1, borderColor: "divider" }}>
<TabList onChange={(event, idx) => setSelectedTab(idx)} centered>
Expand Down Expand Up @@ -206,6 +203,12 @@ export const Balances: React.FC<Props> = ({ groupId }) => {
<BalanceTable groupId={groupId} />
</TabPanel>
</TabContext>
<Divider />
<Box sx={{ display: "flex", justifyContent: "center" }}>
<Button component={RouterLink} to={`/groups/${group.id}/settlement-plan`}>
Settle up
</Button>
</Box>
</MobilePaper>
);
};
Expand Down
39 changes: 34 additions & 5 deletions frontend/apps/web/src/pages/accounts/SettlementPlanDisplay.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,23 @@
import { selectAccountIdToAccountMap, selectGroupCurrencySymbol, selectSettlementPlan } from "@abrechnung/redux";
import { Button, List, ListItem, ListItemSecondaryAction, ListItemText } from "@mui/material";
import { MobilePaper } from "@/components/style/mobile";
import { selectAccountSlice, selectGroupSlice, useAppDispatch, useAppSelector } from "@/store";
import {
createTransaction,
selectAccountIdToAccountMap,
selectGroupCurrencySymbol,
selectSettlementPlan,
} from "@abrechnung/redux";
import { Button, List, ListItem, ListItemSecondaryAction, ListItemText, Typography } from "@mui/material";
import * as React from "react";
import { MobilePaper } from "../../components/style/mobile";
import { selectAccountSlice, selectGroupSlice, useAppSelector } from "../../store";
import { SettlementPlanItem } from "@abrechnung/core";
import { useNavigate } from "react-router-dom";

interface Props {
groupId: number;
}

export const SettlementPlanDisplay: React.FC<Props> = ({ groupId }) => {
const dispatch = useAppDispatch();
const navigate = useNavigate();
const settlementPlan = useAppSelector((state) => selectSettlementPlan({ state, groupId }));
const currencySymbol = useAppSelector((state) =>
selectGroupCurrencySymbol({ state: selectGroupSlice(state), groupId })
Expand All @@ -17,8 +26,28 @@ export const SettlementPlanDisplay: React.FC<Props> = ({ groupId }) => {
selectAccountIdToAccountMap({ state: selectAccountSlice(state), groupId })
);

const onSettleClicked = (planItem: SettlementPlanItem) => {
dispatch(
createTransaction({
type: "transfer",
groupId,
data: {
name: "Settlement",
value: planItem.paymentAmount,
creditorShares: { [planItem.creditorId]: 1 },
debitorShares: { [planItem.debitorId]: 1 },
},
})
)
.unwrap()
.then(({ transaction }) => {
navigate(`/groups/${groupId}/transactions/${transaction.id}?no-redirect=true`);
});
};

return (
<MobilePaper>
<Typography variant="h5">Settle this groups balances</Typography>
<List>
{settlementPlan.map((planItem) => (
<ListItem key={`${planItem.creditorId}-${planItem.debitorId}`}>
Expand All @@ -32,7 +61,7 @@ export const SettlementPlanDisplay: React.FC<Props> = ({ groupId }) => {
}
/>
<ListItemSecondaryAction>
<Button>Settled</Button>
<Button onClick={() => onSettleClicked(planItem)}>Settle</Button>
</ListItemSecondaryAction>
</ListItem>
))}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,11 @@ import * as React from "react";
import { Navigate, useNavigate, useParams } from "react-router-dom";
import { toast } from "react-toastify";
import { typeToFlattenedError, z } from "zod";
import Loading from "../../../components/style/Loading";
import { MobilePaper } from "../../../components/style/mobile";
import { api } from "../../../core/api";
import { useQuery, useTitle } from "../../../core/utils";
import { selectGroupSlice, selectTransactionSlice, useAppDispatch, useAppSelector } from "../../../store";
import Loading from "@/components/style/Loading";
import { MobilePaper } from "@/components/style/mobile";
import { api } from "@/core/api";
import { useQuery, useTitle } from "@/core/utils";
import { selectGroupSlice, selectTransactionSlice, useAppDispatch, useAppSelector } from "@/store";
import { TransactionPositions, ValidationErrors as PositionValidationErrors } from "./purchase/TransactionPositions";
import { TransactionActions } from "./TransactionActions";
import { TransactionMetadata } from "./TransactionMetadata";
Expand Down
11 changes: 10 additions & 1 deletion frontend/apps/web/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,16 @@
"noPropertyAccessFromIndexSignature": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true,
"resolveJsonModule": true
"resolveJsonModule": true,
"baseUrl": ".",
"paths": {
"@abrechnung/api": ["../../libs/api/src/index.ts"],
"@abrechnung/core": ["../../libs/core/src/index.ts"],
"@abrechnung/redux": ["../../libs/redux/src/index.ts"],
"@abrechnung/types": ["../../libs/types/src/index.ts"],
"@abrechnung/utils": ["../../libs/utils/src/index.ts"],
"@/*": ["src/*"]
}
},
"files": [],
"include": [],
Expand Down
5 changes: 3 additions & 2 deletions frontend/libs/core/src/lib/accounts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -248,7 +248,8 @@ export const computeAccountBalanceHistory = (
return accumulatedBalanceChanges;
};

export type SettlementPlan = Array<{ creditorId: number; debitorId: number; paymentAmount: number }>;
export type SettlementPlanItem = { creditorId: number; debitorId: number; paymentAmount: number };
export type SettlementPlan = Array<SettlementPlanItem>;
type SimplifiedBalances = Array<[number, number]>; // map of account ids to balances

const balanceSortCompareFn = (a: [number, number], b: [number, number]) => {
Expand Down Expand Up @@ -322,5 +323,5 @@ export const computeGroupSettlement = (balances: AccountBalanceMap): SettlementP
}
}

return result;
return result.filter((planItem) => Math.round((planItem.paymentAmount + Number.EPSILON) * 100) / 100 !== 0);
};
23 changes: 21 additions & 2 deletions frontend/libs/redux/src/lib/transactions/transactionSlice.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
TransactionContainer,
TransactionPosition,
TransactionType,
TransactionTypeMap,
} from "@abrechnung/types";
import { toISODateString } from "@abrechnung/utils";
import { createAsyncThunk, createSlice, Draft, PayloadAction } from "@reduxjs/toolkit";
Expand Down Expand Up @@ -417,9 +418,26 @@ export const fetchTransaction = createAsyncThunk<

export const createTransaction = createAsyncThunk<
{ transaction: Transaction },
{ groupId: number; type: TransactionType },
{
groupId: number;
type: TransactionType;
data?: Partial<
Omit<
Transaction,
| "id"
| "type"
| "positions"
| "groupId"
| "hasLocalChanges"
| "isWip"
| "lastChanged"
| "deleted"
| "attachments"
>
>;
},
{ state: ITransactionRootState }
>("createPurchase", async ({ groupId, type }, { getState, dispatch }) => {
>("createPurchase", async ({ groupId, type, data }, { getState, dispatch }) => {
const state = getState();
const transactionId = state.transactions.nextLocalTransactionId;
const transactionBase = {
Expand All @@ -440,6 +458,7 @@ export const createTransaction = createAsyncThunk<
hasLocalChanges: true,
isWip: true,
lastChanged: new Date().toISOString(),
...data,
};
let transaction: Transaction;
if (type === "purchase") {
Expand Down
5 changes: 5 additions & 0 deletions frontend/libs/types/src/lib/transactions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,11 @@ interface TransactionMetadata {
export type Purchase = PurchaseBase & TransactionMetadata;
export type Transfer = TransferBase & TransactionMetadata;

export type TransactionTypeMap = {
purchase: Purchase;
transfer: Transfer;
};

export type Transaction = Purchase | Transfer;

/**
Expand Down

0 comments on commit f11e114

Please sign in to comment.