Skip to content

Commit

Permalink
Merge pull request #208 from SFTtech/milo/add-transaction-from-accoun…
Browse files Browse the repository at this point in the history
…t-detail

feat(web): add purchase for account from account detail page
  • Loading branch information
mikonse authored Feb 11, 2024
2 parents 3b1acbc + 14501ec commit 17fba1c
Show file tree
Hide file tree
Showing 5 changed files with 109 additions and 57 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

[Compare the full difference.](https://github.com/SFTtech/abrechnung/compare/v0.13.2...HEAD)

- web: add button to add a new purchase for an account from the account detail page

## 0.13.1 (2024-02-11)

[Compare the full difference.](https://github.com/SFTtech/abrechnung/compare/v0.13.1...v0.13.2)
Expand Down
112 changes: 80 additions & 32 deletions frontend/apps/web/src/components/accounts/AccountTransactionList.tsx
Original file line number Diff line number Diff line change
@@ -1,60 +1,108 @@
import { selectClearingAccountsInvolvingAccounts, selectTransactionsInvolvingAccount } from "@abrechnung/redux";
import {
createTransaction,
selectClearingAccountsInvolvingAccounts,
selectTransactionsInvolvingAccount,
} from "@abrechnung/redux";
import { Add as AddIcon } from "@mui/icons-material";
import { Account, Transaction } from "@abrechnung/types";
import { Alert, List } from "@mui/material";
import { Alert, Box, IconButton, List, Tooltip, Typography } from "@mui/material";
import { DateTime } from "luxon";
import * as React from "react";
import { selectAccountSlice, selectTransactionSlice, useAppSelector } from "@/store";
import { selectAccountSlice, selectTransactionSlice, useAppDispatch, useAppSelector } from "@/store";
import { AccountClearingListEntry } from "./AccountClearingListEntry";
import { AccountTransactionListEntry } from "./AccountTransactionListEntry";
import { useTranslation } from "react-i18next";
import { toast } from "react-toastify";
import { useNavigate } from "react-router-dom";
import { PurchaseIcon } from "../style/AbrechnungIcons";

type ArrayAccountsAndTransactions = Array<Transaction | Account>;

interface Props {
groupId: number;
accountId: number;
account: Account;
}

export const AccountTransactionList: React.FC<Props> = ({ groupId, accountId }) => {
export const AccountTransactionList: React.FC<Props> = ({ groupId, account }) => {
const { t } = useTranslation();
const dispatch = useAppDispatch();
const navigate = useNavigate();
const transactions = useAppSelector((state) =>
selectTransactionsInvolvingAccount({ state: selectTransactionSlice(state), groupId, accountId })
selectTransactionsInvolvingAccount({ state: selectTransactionSlice(state), groupId, accountId: account.id })
);
const clearingAccounts = useAppSelector((state) =>
selectClearingAccountsInvolvingAccounts({ state: selectAccountSlice(state), groupId, accountId })
selectClearingAccountsInvolvingAccounts({ state: selectAccountSlice(state), groupId, accountId: account.id })
);

const combinedList: ArrayAccountsAndTransactions = (transactions as ArrayAccountsAndTransactions)
.concat(clearingAccounts)
.sort((f1, f2) => DateTime.fromISO(f2.last_changed).toMillis() - DateTime.fromISO(f1.last_changed).toMillis());

const createTransactionForAccount = () => {
dispatch(
createTransaction({
groupId,
type: "purchase",
data: {
debitor_shares: {
[account.id]: 1,
},
},
})
)
.unwrap()
.then(({ transaction }) => {
navigate(`/groups/${groupId}/transactions/${transaction.id}?no-redirect=true`);
})
.catch(() => toast.error("Creating a transaction failed"));
};

return (
<List>
{combinedList.length === 0 && <Alert severity="info">None so far.</Alert>}
{combinedList.map((entry) => {
if (entry.type === "clearing") {
<>
<Box sx={{ display: "grid", gridTemplateColumns: "auto min-content", justifyContent: "space-between" }}>
<Typography variant="h6">{t("accounts.transactionsInvolving", "", { account })}</Typography>
<Tooltip
title={t("transactions.createPurchaseForAccount", "", {
accountName: account.name,
})}
>
<Box sx={{ display: "flex", flexDirection: "row", alignItems: "center" }}>
<AddIcon color="primary" />
<IconButton color="primary" onClick={createTransactionForAccount}>
<PurchaseIcon />
</IconButton>
</Box>
</Tooltip>
</Box>
<List>
{combinedList.length === 0 && <Alert severity="info">None so far.</Alert>}
{combinedList.map((entry) => {
if (entry.type === "clearing") {
return (
<AccountClearingListEntry
key={`clearing-${entry.id}`}
accountId={account.id}
groupId={groupId}
clearingAccountId={entry.id}
/>
);
}
if (entry.type === "personal") {
return null;
}

// we need to case "entry" to Transaction as typescript cant deduce that it
// has to be a transaction even though we handled all other "type" cases before
return (
<AccountClearingListEntry
key={`clearing-${entry.id}`}
accountId={accountId}
<AccountTransactionListEntry
key={`transaction-${entry.id}`}
accountId={account.id}
groupId={groupId}
clearingAccountId={entry.id}
transactionId={entry.id}
/>
);
}
if (entry.type === "personal") {
return null;
}

// we need to case "entry" to Transaction as typescript cant deduce that it
// has to be a transaction even though we handled all other "type" cases before
return (
<AccountTransactionListEntry
key={`transaction-${entry.id}`}
accountId={accountId}
groupId={groupId}
transactionId={entry.id}
/>
);
})}
</List>
})}
</List>
</>
);
};
47 changes: 25 additions & 22 deletions frontend/apps/web/src/components/accounts/ClearingAccountDetail.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { selectAccountBalances, selectAccountById, selectGroupCurrencySymbol } from "@abrechnung/redux";
import { TableCell } from "@mui/material";
import { TableCell, Typography } from "@mui/material";
import React from "react";
import { selectAccountSlice, selectGroupSlice, useAppSelector } from "@/store";
import { ShareSelect } from "../ShareSelect";
Expand All @@ -26,26 +26,29 @@ export const ClearingAccountDetail: React.FC<Props> = ({ groupId, accountId }) =
}

return (
<ShareSelect
groupId={groupId}
label={t("accounts.participated")}
value={account.clearing_shares}
additionalShareInfoHeader={
<TableCell width="100px" align="right">
{t("common.shared")}
</TableCell>
}
excludeAccounts={[account.id]}
renderAdditionalShareInfo={({ account: participatingAccount }) => (
<TableCell width="100px" align="right">
{formatCurrency(
balances[account.id]?.clearingResolution[participatingAccount.id] ?? 0,
currency_symbol
)}
</TableCell>
)}
onChange={(value) => undefined}
editable={false}
/>
<>
<Typography variant="h6">{t("accounts.clearingDistributionOf", "", { account })}</Typography>
<ShareSelect
groupId={groupId}
label={t("accounts.participated")}
value={account.clearing_shares}
additionalShareInfoHeader={
<TableCell width="100px" align="right">
{t("common.shared")}
</TableCell>
}
excludeAccounts={[account.id]}
renderAdditionalShareInfo={({ account: participatingAccount }) => (
<TableCell width="100px" align="right">
{formatCurrency(
balances[account.id]?.clearingResolution[participatingAccount.id] ?? 0,
currency_symbol
)}
</TableCell>
)}
onChange={(value) => undefined}
editable={false}
/>
</>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -76,15 +76,13 @@ export const AccountDetail: React.FC<Props> = ({ groupId }) => {
{account.type === "clearing" && (
<Grid item xs={12}>
<MobilePaper>
<Typography variant="h6">{t("accounts.clearingDistributionOf", "", { account })}</Typography>
<ClearingAccountDetail groupId={groupId} accountId={accountId} />
</MobilePaper>
</Grid>
)}
<Grid item xs={12}>
<MobilePaper>
<Typography variant="h6">{t("accounts.transactionsInvolving", "", { account })}</Typography>
<AccountTransactionList groupId={groupId} accountId={accountId} />
<AccountTransactionList groupId={groupId} account={account} />
</MobilePaper>
</Grid>
</Grid>
Expand Down
1 change: 1 addition & 0 deletions frontend/libs/translations/src/lib/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ const translations = {
transactions: {
createTransaction: "Create Transaction",
createPurchase: "Create Purchase",
createPurchaseForAccount: "Create purchase with {{accountName}} as participant",
createTransfer: "Create Transfer",
noTransactions: "No Transactions",
purchase: "Purchase",
Expand Down

0 comments on commit 17fba1c

Please sign in to comment.