diff options
Diffstat (limited to 'packages/demobank-ui/src/pages/AdminPage.tsx')
-rw-r--r-- | packages/demobank-ui/src/pages/AdminPage.tsx | 150 |
1 files changed, 149 insertions, 1 deletions
diff --git a/packages/demobank-ui/src/pages/AdminPage.tsx b/packages/demobank-ui/src/pages/AdminPage.tsx index f8efddd80..d15ac02c4 100644 --- a/packages/demobank-ui/src/pages/AdminPage.tsx +++ b/packages/demobank-ui/src/pages/AdminPage.tsx @@ -14,7 +14,11 @@ GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> */ -import { parsePaytoUri, TranslatedString } from "@gnu-taler/taler-util"; +import { + Amounts, + parsePaytoUri, + TranslatedString, +} from "@gnu-taler/taler-util"; import { HttpResponsePaginated, RequestError, @@ -22,7 +26,9 @@ import { } from "@gnu-taler/web-util/lib/index.browser"; import { Fragment, h, VNode } from "preact"; import { useState } from "preact/hooks"; +import { Cashouts } from "../components/Cashouts/index.js"; import { ErrorMessage, usePageContext } from "../context/pageState.js"; +import { useAccountDetails } from "../hooks/access.js"; import { useBusinessAccountDetails, useBusinessAccounts, @@ -60,7 +66,10 @@ interface Props { export function AdminPage({ onLoadNotOk }: Props): VNode { const [account, setAccount] = useState<string | undefined>(); const [showDetails, setShowDetails] = useState<string | undefined>(); + const [showCashouts, setShowCashouts] = useState<string | undefined>(); const [updatePassword, setUpdatePassword] = useState<string | undefined>(); + const [removeAccount, setRemoveAccount] = useState<string | undefined>(); + const [createAccount, setCreateAccount] = useState(false); const { pageStateSetter } = usePageContext(); @@ -81,6 +90,23 @@ export function AdminPage({ onLoadNotOk }: Props): VNode { const { customers } = result.data; + if (showCashouts) { + return ( + <div> + <Cashouts account={showCashouts} /> + <input + class="pure-button" + type="submit" + value={i18n.str`Close`} + onClick={async (e) => { + e.preventDefault(); + setShowCashouts(undefined); + }} + /> + </div> + ); + } + if (showDetails) { return ( <ShowAccountDetails @@ -100,6 +126,21 @@ export function AdminPage({ onLoadNotOk }: Props): VNode { /> ); } + if (removeAccount) { + return ( + <RemoveAccount + account={removeAccount} + onLoadNotOk={onLoadNotOk} + onUpdateSuccess={() => { + showInfoMessage(i18n.str`Account removed`); + setRemoveAccount(undefined); + }} + onClear={() => { + setRemoveAccount(undefined); + }} + /> + ); + } if (updatePassword) { return ( <UpdateAccountPassword @@ -164,6 +205,7 @@ export function AdminPage({ onLoadNotOk }: Props): VNode { <th>{i18n.str`Username`}</th> <th>{i18n.str`Name`}</th> <th></th> + <th></th> </tr> </thead> <tbody> @@ -193,6 +235,28 @@ export function AdminPage({ onLoadNotOk }: Props): VNode { change password </a> </td> + <td> + <a + href="#" + onClick={(e) => { + e.preventDefault(); + setShowCashouts(item.username); + }} + > + cashouts + </a> + </td> + <td> + <a + href="#" + onClick={(e) => { + e.preventDefault(); + setRemoveAccount(item.username); + }} + > + remove + </a> + </td> </tr> ); })} @@ -536,6 +600,90 @@ export function ShowAccountDetails({ ); } +function RemoveAccount({ + account, + onClear, + onUpdateSuccess, + onLoadNotOk, +}: { + onLoadNotOk: <T, E>(error: HttpResponsePaginated<T, E>) => VNode; + onClear: () => void; + onUpdateSuccess: () => void; + account: string; +}): VNode { + const { i18n } = useTranslationContext(); + const result = useAccountDetails(account); + const { deleteAccount } = useAdminAccountAPI(); + const [error, saveError] = useState<ErrorMessage | undefined>(); + + if (result.clientError) { + if (result.isNotfound) return <div>account not found</div>; + } + if (!result.ok) { + return onLoadNotOk(result); + } + + const balance = Amounts.parse(result.data.balance.amount); + if (!balance) { + return <div>there was an error reading the balance</div>; + } + const isBalanceEmpty = Amounts.isZero(balance); + return ( + <div> + <div> + <h1 class="nav welcome-text"> + <i18n.Translate>Remove account: {account}</i18n.Translate> + </h1> + </div> + {!isBalanceEmpty && ( + <ErrorBanner + error={{ + title: i18n.str`Can't delete the account`, + description: i18n.str`Balance is not empty`, + }} + /> + )} + {error && ( + <ErrorBanner error={error} onClear={() => saveError(undefined)} /> + )} + + <p> + <div style={{ display: "flex", justifyContent: "space-between" }}> + <div> + <input + class="pure-button" + type="submit" + value={i18n.str`Cancel`} + onClick={async (e) => { + e.preventDefault(); + onClear(); + }} + /> + </div> + <div> + <input + id="select-exchange" + class="pure-button pure-button-primary content" + disabled={!isBalanceEmpty} + type="submit" + value={i18n.str`Confirm`} + onClick={async (e) => { + e.preventDefault(); + try { + const r = await deleteAccount(account); + onUpdateSuccess(); + } catch (error) { + handleError(error, saveError, i18n); + } + }} + /> + </div> + </div> + </p> + </div> + ); +} + /** * Create valid account object to update or create * Take template as initial values for the form |