aboutsummaryrefslogtreecommitdiff
path: root/packages/demobank-ui
diff options
context:
space:
mode:
authorSebastian <sebasjm@gmail.com>2023-03-06 15:12:43 -0300
committerSebastian <sebasjm@gmail.com>2023-03-06 15:18:25 -0300
commit8f32ad272dd319b74e0a4a3d3ecc1472884c87e2 (patch)
treebf6fac4c0dc696dff1364fee94e2256aad593c47 /packages/demobank-ui
parent8743db9e4056dbb656ef269737313ac24c870dff (diff)
downloadwallet-core-8f32ad272dd319b74e0a4a3d3ecc1472884c87e2.tar.xz
centered forms, show balance in accont info
Diffstat (limited to 'packages/demobank-ui')
-rw-r--r--packages/demobank-ui/src/declaration.d.ts13
-rw-r--r--packages/demobank-ui/src/pages/AdminPage.tsx473
2 files changed, 259 insertions, 227 deletions
diff --git a/packages/demobank-ui/src/declaration.d.ts b/packages/demobank-ui/src/declaration.d.ts
index 03ab8f2a8..8dc5fd8b2 100644
--- a/packages/demobank-ui/src/declaration.d.ts
+++ b/packages/demobank-ui/src/declaration.d.ts
@@ -99,6 +99,11 @@ type Amount = string;
type UUID = string;
type Integer = number;
+interface Balance {
+ amount: Amount;
+ credit_debit_indicator: "credit" | "debit";
+}
+
namespace SandboxBackend {
export interface Config {
// Name of this API, always "circuit".
@@ -161,10 +166,7 @@ namespace SandboxBackend {
interface BankAccountBalanceResponse {
// Available balance on the account.
- balance: {
- amount: Amount;
- credit_debit_indicator: "credit" | "debit";
- };
+ balance: Balance;
// payto://-URI of the account. (New)
paytoUri: string;
}
@@ -304,6 +306,9 @@ namespace SandboxBackend {
// Legal subject owning the account.
name: string;
+
+ // current balance of the account
+ balance: Balance;
}
interface CircuitAccountData {
diff --git a/packages/demobank-ui/src/pages/AdminPage.tsx b/packages/demobank-ui/src/pages/AdminPage.tsx
index 3d0c09cbf..58b048b83 100644
--- a/packages/demobank-ui/src/pages/AdminPage.tsx
+++ b/packages/demobank-ui/src/pages/AdminPage.tsx
@@ -230,7 +230,10 @@ export function AdminPage({ onLoadNotOk }: Props): VNode {
</div>
</p>
- <section id="main">
+ <section
+ id="main"
+ style={{ width: 600, marginLeft: "auto", marginRight: "auto" }}
+ >
{!customers.length ? (
<div></div>
) : (
@@ -242,12 +245,18 @@ export function AdminPage({ onLoadNotOk }: Props): VNode {
<tr>
<th>{i18n.str`Username`}</th>
<th>{i18n.str`Name`}</th>
- <th></th>
- <th></th>
+ <th>{i18n.str`Balance`}</th>
+ <th>{i18n.str`Actions`}</th>
</tr>
</thead>
<tbody>
{customers.map((item, idx) => {
+ const balance = !item.balance
+ ? undefined
+ : Amounts.parse(item.balance.amount);
+ const balanceIsDebit =
+ item.balance &&
+ item.balance.credit_debit_indicator == "debit";
return (
<tr key={idx}>
<td>
@@ -263,6 +272,20 @@ export function AdminPage({ onLoadNotOk }: Props): VNode {
</td>
<td>{item.name}</td>
<td>
+ {!balance ? (
+ i18n.str`unknown`
+ ) : (
+ <span class="amount">
+ {balanceIsDebit ? <b>-</b> : null}
+ <span class="value">{`${Amounts.stringifyValue(
+ balance,
+ )}`}</span>
+ &nbsp;
+ <span class="currency">{`${balance.currency}`}</span>
+ </span>
+ )}
+ </td>
+ <td>
<a
href="#"
onClick={(e) => {
@@ -272,8 +295,7 @@ export function AdminPage({ onLoadNotOk }: Props): VNode {
>
change password
</a>
- </td>
- <td>
+ &nbsp;
<a
href="#"
onClick={(e) => {
@@ -283,8 +305,7 @@ export function AdminPage({ onLoadNotOk }: Props): VNode {
>
cashouts
</a>
- </td>
- <td>
+ &nbsp;
<a
href="#"
onClick={(e) => {
@@ -384,82 +405,84 @@ export function UpdateAccountPassword({
<ErrorBannerFloat error={error} onClear={() => saveError(undefined)} />
)}
- <form class="pure-form">
- <fieldset>
- <label>{i18n.str`Password`}</label>
- <input
- type="password"
- value={password ?? ""}
- onChange={(e) => {
- setPassword(e.currentTarget.value);
- }}
- />
- <ShowInputErrorLabel
- message={errors?.password}
- isDirty={password !== undefined}
- />
- </fieldset>
- <fieldset>
- <label>{i18n.str`Repeast password`}</label>
- <input
- type="password"
- value={repeat ?? ""}
- onChange={(e) => {
- setRepeat(e.currentTarget.value);
- }}
- />
- <ShowInputErrorLabel
- message={errors?.repeat}
- isDirty={repeat !== undefined}
- />
- </fieldset>
- </form>
- <p>
- <div style={{ display: "flex", justifyContent: "space-between" }}>
- <div>
+ <div style={{ maxWidth: 600, overflowX: "hidden", margin: "auto" }}>
+ <form class="pure-form">
+ <fieldset>
+ <label>{i18n.str`Password`}</label>
<input
- class="pure-button"
- type="submit"
- value={i18n.str`Close`}
- onClick={async (e) => {
- e.preventDefault();
- onClear();
+ type="password"
+ value={password ?? ""}
+ onChange={(e) => {
+ setPassword(e.currentTarget.value);
}}
/>
- </div>
- <div>
+ <ShowInputErrorLabel
+ message={errors?.password}
+ isDirty={password !== undefined}
+ />
+ </fieldset>
+ <fieldset>
+ <label>{i18n.str`Repeast password`}</label>
<input
- id="select-exchange"
- class="pure-button pure-button-primary content"
- disabled={!!errors}
- type="submit"
- value={i18n.str`Confirm`}
- onClick={async (e) => {
- e.preventDefault();
- if (!!errors || !password) return;
- try {
- const r = await changePassword(account, {
- new_password: password,
- });
- onUpdateSuccess();
- } catch (error) {
- if (error instanceof RequestError) {
- saveError(buildRequestErrorMessage(i18n, error.cause));
- } else {
- saveError({
- title: i18n.str`Operation failed, please report`,
- description:
- error instanceof Error
- ? error.message
- : JSON.stringify(error),
- });
- }
- }
+ type="password"
+ value={repeat ?? ""}
+ onChange={(e) => {
+ setRepeat(e.currentTarget.value);
}}
/>
+ <ShowInputErrorLabel
+ message={errors?.repeat}
+ isDirty={repeat !== undefined}
+ />
+ </fieldset>
+ </form>
+ <p>
+ <div style={{ display: "flex", justifyContent: "space-between" }}>
+ <div>
+ <input
+ class="pure-button"
+ type="submit"
+ value={i18n.str`Close`}
+ onClick={async (e) => {
+ e.preventDefault();
+ onClear();
+ }}
+ />
+ </div>
+ <div>
+ <input
+ id="select-exchange"
+ class="pure-button pure-button-primary content"
+ disabled={!!errors}
+ type="submit"
+ value={i18n.str`Confirm`}
+ onClick={async (e) => {
+ e.preventDefault();
+ if (!!errors || !password) return;
+ try {
+ const r = await changePassword(account, {
+ new_password: password,
+ });
+ onUpdateSuccess();
+ } catch (error) {
+ if (error instanceof RequestError) {
+ saveError(buildRequestErrorMessage(i18n, error.cause));
+ } else {
+ saveError({
+ title: i18n.str`Operation failed, please report`,
+ description:
+ error instanceof Error
+ ? error.message
+ : JSON.stringify(error),
+ });
+ }
+ }
+ }}
+ />
+ </div>
</div>
- </div>
- </p>
+ </p>
+ </div>
</div>
);
}
@@ -488,81 +511,83 @@ function CreateNewAccount({
<ErrorBannerFloat error={error} onClear={() => saveError(undefined)} />
)}
- <AccountForm
- template={undefined}
- purpose="create"
- onChange={(a) => {
- console.log(a);
- setSubmitAccount(a);
- }}
- />
+ <div style={{ maxWidth: 600, overflowX: "hidden", margin: "auto" }}>
+ <AccountForm
+ template={undefined}
+ purpose="create"
+ onChange={(a) => {
+ console.log(a);
+ setSubmitAccount(a);
+ }}
+ />
- <p>
- <div style={{ display: "flex", justifyContent: "space-between" }}>
- <div>
- <input
- class="pure-button"
- type="submit"
- value={i18n.str`Close`}
- onClick={async (e) => {
- e.preventDefault();
- onClose();
- }}
- />
- </div>
- <div>
- <input
- id="select-exchange"
- class="pure-button pure-button-primary content"
- disabled={!submitAccount}
- type="submit"
- value={i18n.str`Confirm`}
- onClick={async (e) => {
- e.preventDefault();
+ <p>
+ <div style={{ display: "flex", justifyContent: "space-between" }}>
+ <div>
+ <input
+ class="pure-button"
+ type="submit"
+ value={i18n.str`Close`}
+ onClick={async (e) => {
+ e.preventDefault();
+ onClose();
+ }}
+ />
+ </div>
+ <div>
+ <input
+ id="select-exchange"
+ class="pure-button pure-button-primary content"
+ disabled={!submitAccount}
+ type="submit"
+ value={i18n.str`Confirm`}
+ onClick={async (e) => {
+ e.preventDefault();
- if (!submitAccount) return;
- try {
- const account: SandboxBackend.Circuit.CircuitAccountRequest =
- {
- cashout_address: submitAccount.cashout_address,
- contact_data: submitAccount.contact_data,
- internal_iban: submitAccount.iban,
- name: submitAccount.name,
- username: submitAccount.username,
- password: randomPassword(),
- };
-
- await createAccount(account);
- onCreateSuccess(account.password);
- } catch (error) {
- if (error instanceof RequestError) {
- saveError(
- buildRequestErrorMessage(i18n, error.cause, {
- onClientError: (status) =>
- status === HttpStatusCode.Forbidden
- ? i18n.str`The rights to perform the operation are not sufficient`
- : status === HttpStatusCode.BadRequest
- ? i18n.str`Input data was invalid`
- : status === HttpStatusCode.Conflict
- ? i18n.str`At least one registration detail was not available`
- : undefined,
- }),
- );
- } else {
- saveError({
- title: i18n.str`Operation failed, please report`,
- description:
- error instanceof Error
- ? error.message
- : JSON.stringify(error),
- });
+ if (!submitAccount) return;
+ try {
+ const account: SandboxBackend.Circuit.CircuitAccountRequest =
+ {
+ cashout_address: submitAccount.cashout_address,
+ contact_data: submitAccount.contact_data,
+ internal_iban: submitAccount.iban,
+ name: submitAccount.name,
+ username: submitAccount.username,
+ password: randomPassword(),
+ };
+
+ await createAccount(account);
+ onCreateSuccess(account.password);
+ } catch (error) {
+ if (error instanceof RequestError) {
+ saveError(
+ buildRequestErrorMessage(i18n, error.cause, {
+ onClientError: (status) =>
+ status === HttpStatusCode.Forbidden
+ ? i18n.str`The rights to perform the operation are not sufficient`
+ : status === HttpStatusCode.BadRequest
+ ? i18n.str`Input data was invalid`
+ : status === HttpStatusCode.Conflict
+ ? i18n.str`At least one registration detail was not available`
+ : undefined,
+ }),
+ );
+ } else {
+ saveError({
+ title: i18n.str`Operation failed, please report`,
+ description:
+ error instanceof Error
+ ? error.message
+ : JSON.stringify(error),
+ });
+ }
}
- }
- }}
- />
+ }}
+ />
+ </div>
</div>
- </div>
- </p>
+ </p>
+ </div>
</div>
);
}
@@ -608,90 +633,92 @@ export function ShowAccountDetails({
{error && (
<ErrorBannerFloat error={error} onClear={() => saveError(undefined)} />
)}
- <AccountForm
- template={result.data}
- purpose={update ? "update" : "show"}
- onChange={(a) => setSubmitAccount(a)}
- />
+ <div style={{ maxWidth: 600, overflowX: "hidden", margin: "auto" }}>
+ <AccountForm
+ template={result.data}
+ purpose={update ? "update" : "show"}
+ onChange={(a) => setSubmitAccount(a)}
+ />
- <p>
- <div style={{ display: "flex", justifyContent: "space-between" }}>
- <div>
- {onClear ? (
- <input
- class="pure-button"
- type="submit"
- value={i18n.str`Close`}
- onClick={async (e) => {
- e.preventDefault();
- onClear();
- }}
- />
- ) : undefined}
- </div>
- <div style={{ display: "flex" }}>
+ <p>
+ <div style={{ display: "flex", justifyContent: "space-between" }}>
<div>
- <input
- id="select-exchange"
- class="pure-button pure-button-primary content"
- disabled={update && !submitAccount}
- type="submit"
- value={i18n.str`Change password`}
- onClick={async (e) => {
- e.preventDefault();
- onChangePassword();
- }}
- />
+ {onClear ? (
+ <input
+ class="pure-button"
+ type="submit"
+ value={i18n.str`Close`}
+ onClick={async (e) => {
+ e.preventDefault();
+ onClear();
+ }}
+ />
+ ) : undefined}
</div>
- <div>
- <input
- id="select-exchange"
- class="pure-button pure-button-primary content"
- disabled={update && !submitAccount}
- type="submit"
- value={update ? i18n.str`Confirm` : i18n.str`Update`}
- onClick={async (e) => {
- e.preventDefault();
-
- if (!update) {
- setUpdate(true);
- } else {
- if (!submitAccount) return;
- try {
- await updateAccount(account, {
- cashout_address: submitAccount.cashout_address,
- contact_data: submitAccount.contact_data,
- });
- onUpdateSuccess();
- } catch (error) {
- if (error instanceof RequestError) {
- saveError(
- buildRequestErrorMessage(i18n, error.cause, {
- onClientError: (status) =>
- status === HttpStatusCode.Forbidden
- ? i18n.str`The rights to change the account are not sufficient`
- : status === HttpStatusCode.NotFound
- ? i18n.str`The username was not found`
- : undefined,
- }),
- );
- } else {
- saveError({
- title: i18n.str`Operation failed, please report`,
- description:
- error instanceof Error
- ? error.message
- : JSON.stringify(error),
+ <div style={{ display: "flex" }}>
+ <div>
+ <input
+ id="select-exchange"
+ class="pure-button pure-button-primary content"
+ disabled={update && !submitAccount}
+ type="submit"
+ value={i18n.str`Change password`}
+ onClick={async (e) => {
+ e.preventDefault();
+ onChangePassword();
+ }}
+ />
+ </div>
+ <div>
+ <input
+ id="select-exchange"
+ class="pure-button pure-button-primary content"
+ disabled={update && !submitAccount}
+ type="submit"
+ value={update ? i18n.str`Confirm` : i18n.str`Update`}
+ onClick={async (e) => {
+ e.preventDefault();
+
+ if (!update) {
+ setUpdate(true);
+ } else {
+ if (!submitAccount) return;
+ try {
+ await updateAccount(account, {
+ cashout_address: submitAccount.cashout_address,
+ contact_data: submitAccount.contact_data,
});
+ onUpdateSuccess();
+ } catch (error) {
+ if (error instanceof RequestError) {
+ saveError(
+ buildRequestErrorMessage(i18n, error.cause, {
+ onClientError: (status) =>
+ status === HttpStatusCode.Forbidden
+ ? i18n.str`The rights to change the account are not sufficient`
+ : status === HttpStatusCode.NotFound
+ ? i18n.str`The username was not found`
+ : undefined,
+ }),
+ );
+ } else {
+ saveError({
+ title: i18n.str`Operation failed, please report`,
+ description:
+ error instanceof Error
+ ? error.message
+ : JSON.stringify(error),
+ });
+ }
}
}
- }
- }}
- />
+ }}
+ />
+ </div>
</div>
</div>
- </div>
- </p>
+ </p>
+ </div>
</div>
);
}