diff options
Diffstat (limited to 'packages/auditor-backoffice-ui/src/paths')
14 files changed, 1281 insertions, 433 deletions
diff --git a/packages/auditor-backoffice-ui/src/paths/default/Table.tsx b/packages/auditor-backoffice-ui/src/paths/default/Table.tsx new file mode 100644 index 000000000..9bb75907d --- /dev/null +++ b/packages/auditor-backoffice-ui/src/paths/default/Table.tsx @@ -0,0 +1,155 @@ +/* + This file is part of GNU Taler + (C) 2021-2023 Taler Systems S.A. + + GNU Taler is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> + */ + +/** + * + * @author Sebastian Javier Marchano (sebasjm) + */ + +import { useTranslationContext } from "@gnu-taler/web-util/browser"; +import { ComponentChildren, Fragment, h, VNode } from "preact"; +import { StateUpdater, useState } from "preact/hooks"; +import { useEntityContext, useEntityDataContext } from "../../context/entity.js"; + +interface Props { + onSuppress: (id: any) => void; +} + +export function CardTable({onSuppress}: Props): any { + + const data = useEntityDataContext(); + const [rowSelection, rowSelectionHandler] = useState<string | undefined>( + undefined, + ); + const { i18n } = useTranslationContext(); + const { title, endpoint, entity } = useEntityContext(); + + return ( + <div class="card has-table"> + <header class="card-header"> + <p class="card-header-title"> + <span class="icon"> + <i class="mdi mdi-shopping" /> + </span> + <i18n.Translate>{title}</i18n.Translate> + </p> + <div class="card-header-icon" aria-label="more options"> + </div> + </header> + <div class="card-content"> + <div class="b-table has-pagination"> + <div class="table-wrapper has-mobile-cards"> + {(data.data[0][endpoint] !== undefined && data.data[0][endpoint].length != 0) ? ( + <Table + data={data.data[0][endpoint]} + onSuppress={onSuppress} + /> + ) : ( + <EmptyTable /> + )} + </div> + </div> + </div> + </div> + ); +} + +interface TableProps { + data: any; + onSuppress: (id: any) => void; +} + +function Table({ + data, + onSuppress, + }: TableProps): VNode { + const { i18n } = useTranslationContext(); + const { entity } = useEntityContext(); + type Entity = typeof entity; + let count = 0; + + return ( + <div class="table-container"> + <table class="table is-fullwidth is-striped is-hoverable is-fullwidth"> + <thead> + <tr> + {Object.keys(data[0]).map((i: Entity) => { + const paramName = i[0].toUpperCase() + i.replace("_", " ").slice(1, i.count); + return ( + <Fragment key={count.toString() + i}> + <th> + <i18n.Translate>{paramName}</i18n.Translate> + </th> + </Fragment>); + })} + </tr> + </thead> + <tbody> + {data.map((key: Entity, value: string) => { + return ( + <tr> + {Object.keys(data[0]).map((i: Entity) => { + return ( + <Fragment> + <td> + {(key[i] == false) ? "false" : key[i]} + </td> + </Fragment> + ); + })} + <td class="is-actions-cell right-sticky"> + <div class="buttons is-right"> + <span + class="has-tooltip-bottom" + data-tooltip={i18n.str`suppress`} + > + <button + class="button is-small is-success " + type="button" + onClick={(): void => onSuppress(key["row_id"])} + > + {<i18n.Translate>Suppress</i18n.Translate>} + </button> + </span> + </div> + </td> + </tr> + ); + }) + } + </tbody> + </table> + </div> + ); +} + +function EmptyTable(): VNode { + const { i18n } = useTranslationContext(); + return ( + <div class="content has-text-grey has-text-centered"> + <p> + <span class="icon is-large"> + <i class="mdi mdi-emoticon-happy mdi-48px" /> + </span> + </p> + <p> + <i18n.Translate> + There are no entries yet + </i18n.Translate> + </p> + </div> + ); +}
\ No newline at end of file diff --git a/packages/auditor-backoffice-ui/src/paths/default/index.tsx b/packages/auditor-backoffice-ui/src/paths/default/index.tsx new file mode 100644 index 000000000..1b7758190 --- /dev/null +++ b/packages/auditor-backoffice-ui/src/paths/default/index.tsx @@ -0,0 +1,130 @@ +/* + This file is part of GNU Taler + (C) 2021-2023 Taler Systems S.A. + + GNU Taler is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> + */ + +/** + * @author Nic Eigel + * @author Sebastian Javier Marchano (sebasjm) + */ + +import { + ErrorType, + HttpError, + useTranslationContext, +} from "@gnu-taler/web-util/browser"; +import { h, VNode } from "preact"; +import { useState } from "preact/hooks"; +import { Loading } from "../../components/exception/loading.js"; +import { NotificationCard } from "../../components/menu/index.js"; +import { AuditorBackend, WithId } from "../../declaration.js"; +import { Notification } from "../../utils/types.js"; +import { CardTable } from "./Table.js"; +import { HttpStatusCode } from "@gnu-taler/taler-util"; +import { EntityDataContextProvider, useEntityContext } from "../../context/entity.js"; +import { getEntityList, useEntityAPI } from "../../hooks/entity.js"; +import { useMemo } from "preact/hooks"; +import { ConfirmModal, DeleteModal } from "../../components/modal/index.js"; +import { route } from "preact-router"; +import { Paths } from "../../InstanceRoutes.js"; + + +interface Props { + onNotFound: () => VNode; + onLoadError: (e: HttpError<AuditorBackend.ErrorDetail>) => VNode; +} + +export default function DefaultList({ + onLoadError, + onNotFound, + }: Props): VNode { + const { endpoint, entity } = useEntityContext(); + const result = getEntityList({ endpoint, entity }); + const { updateEntity } = useEntityAPI(); + const [suppressing, setSuppressing] = + useState<typeof entity & WithId | null>(null); + const [notif, setNotif] = useState<Notification | undefined>(undefined); + const { i18n } = useTranslationContext(); + + if (result.loading) return <Loading />; + if (!result.ok) { + if ( + result.type === ErrorType.CLIENT && + result.status === HttpStatusCode.Unauthorized + ) + return onNotFound(); + return onLoadError(result); + } + + let data = result.data; + const value = useMemo( + () => ({ data }), + [data], + ); + + function onReturn(): void { + route(Paths.detail_view); + } + + return ( + + <section class="section is-main-section"> + <button + class="button is-fullwidth" + onClick={onReturn} + >Back + </button><br /> + + <NotificationCard notification={notif} /> + + <EntityDataContextProvider value={value}> + <CardTable + onSuppress={(e: typeof entity & WithId) => + setSuppressing(e) + } + /> + </EntityDataContextProvider> + + {suppressing && ( + <ConfirmModal + label={`Suppress row`} + description={`Suppress the row`} + danger + active + onCancel={() => setSuppressing(null)} + onConfirm={async (): Promise<void> => { + try { + await updateEntity(suppressing); + setNotif({ + message: i18n.str`Entity row with id: ${suppressing} has been suppressed`, + type: "SUCCESS", + }); + } catch (error) { + setNotif({ + message: i18n.str`Failed to suppress row`, + type: "ERROR", + description: error instanceof Error ? error.message : undefined, + }); + } + setSuppressing(null); + }} + > + <p class="warning"> + Suppressing a row <b>cannot be undone</b> in this GUI. + </p> + </ConfirmModal> + )} + </section> + ); +} diff --git a/packages/auditor-backoffice-ui/src/paths/details/ListPage.tsx b/packages/auditor-backoffice-ui/src/paths/details/ListPage.tsx new file mode 100644 index 000000000..60ae7b578 --- /dev/null +++ b/packages/auditor-backoffice-ui/src/paths/details/ListPage.tsx @@ -0,0 +1,346 @@ +/* + This file is part of GNU Taler + (C) 2021-2023 Taler Systems S.A. + + GNU Taler is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> + */ + +/** + * + * @author Sebastian Javier Marchano (sebasjm) + */ + +import { useTranslationContext } from "@gnu-taler/web-util/browser"; +import { h, VNode, Fragment } from "preact"; +import { route, Route } from "preact-router"; +import { Paths, Redirect } from "../../InstanceRoutes.js"; +import { AuditorBackend } from "../../declaration.js"; + +export interface ListPageProps { + onShowAll: () => void; + onShowNotPaid: () => void; + onShowPaid: () => void; + onShowRefunded: () => void; + onShowNotWired: () => void; + onShowWired: () => void; + onCopyURL: (id: string) => void; + isAllActive: string; + isPaidActive: string; + isNotPaidActive: string; + isRefundedActive: string; + isNotWiredActive: string; + isWiredActive: string; + + jumpToDate?: Date; + onSelectDate: (date?: Date) => void; + + onLoadMoreBefore?: () => void; + hasMoreBefore?: boolean; + hasMoreAfter?: boolean; + onLoadMoreAfter?: () => void; + + onCreate: () => void; +} + +export function ListPage(): VNode { + const { i18n } = useTranslationContext(); + + return ( + <Fragment> + + <div class="columns"> + <div class="column"> + <div class="card"> + <div class="card-body"> + <button + class="button is-fullwidth" + onClick={(e) => route(Paths.amount_arithmethic_inconsistency_list) } + value={"Amount arithmetic inconsistencies"} + >Amount arithmetic inconsistencies + </button> + </div> + </div> + </div> + <div class="column"> + <div class="card"> + <div class="card-body"> + <button + class="button is-fullwidth" + onClick={(e) => route(Paths.bad_sig_losses_list) } + value={"Bad signature losses"} + >Bad signature losses + </button> + </div> + </div> + </div> + <div class="column"> + <div class="card"> + <div class="card-body"> + <button + class="button is-fullwidth" + onClick={(e) => route(Paths.closure_lag_list) } + >Closure Lags + </button> + </div> + </div> + </div> + <div class="column"> + <div class="card"> + <div class="card-body"> + <button + class="button is-fullwidth" + onClick={(e) => route(Paths.coin_inconsistency_list) } + >Coin inconsistencies + </button> + </div> + </div> + </div> + </div> + + <div class="columns"> + <div class="column"> + <div class="card"> + <div class="card-body"> + <button + class="button is-fullwidth" + onClick={(e) => route(Paths.denomination_key_validity_withdraw_inconsistency_list) } + >Denominations key validity + </button> + </div> + </div> + </div> + <div class="column"> + <div class="card"> + <div class="card-body"> + <button + class="button is-fullwidth" + onClick={(e) => route(Paths.denomination_without_sig_list) } + >Denominations without signature + </button> + </div> + </div> + </div> + <div class="column"> + <div class="card"> + <div class="card-body"> + <button + class="button is-fullwidth" + onClick={(e) => route(Paths.denomination_pending_list) } + >Denominations pending + </button> + </div> + </div> + </div> + <div class="column"> + <div class="card"> + <div class="card-body"> + <button + class="button is-fullwidth" + onClick={(e) => route(Paths.deposit_confirmation_list) } + >Deposit confirmations + </button> + </div> + </div> + </div> + </div> + + <div class="columns"> + <div class="column"> + <div class="card"> + <div class="card-body"> + <button + class="button is-fullwidth" + onClick={(e) => route(Paths.emergency_list) } + >Emergencies + </button> + </div> + </div> + </div> + <div class="column"> + <div class="card"> + <div class="card-body"> + <button + class="button is-fullwidth" + onClick={(e) => route(Paths.emergency_by_count_list) } + >Emergencies by count + </button> + </div> + </div> + </div> + <div class="column"> + <div class="card"> + <div class="card-body"> + <button + class="button is-fullwidth" + onClick={(e) => route(Paths.fee_time_inconsistency_list) } + >Fee time inconsistencies + </button> + </div> + </div> + </div> + <div class="column"> + <div class="card"> + <div class="card-body"> + <button + class="button is-fullwidth" + onClick={(e) => route(Paths.misattribution_in_inconsistency_list) } + >Misattribution in inconsistencies + </button> + </div> + </div> + </div> + </div> + + <div class="columns"> + <div class="column"> + <div class="card"> + <div class="card-body"> + <button + class="button is-fullwidth" + onClick={(e) => route(Paths.purse_not_closed_inconsistency_list) } + >Purses not closed + </button> + </div> + </div> + </div> + <div class="column"> + <div class="card"> + <div class="card-body"> + <button + class="button is-fullwidth" + onClick={(e) => route(Paths.purse_list) } + >Purses + </button> + </div> + </div> + </div> + <div class="column"> + <div class="card"> + <div class="card-body"> + <button + class="button is-fullwidth" + onClick={(e) => route(Paths.refresh_hanging_list) } + >Refreshes hanging + </button> + </div> + </div> + </div> + <div class="column"> + <div class="card"> + <div class="card-body"> + <button + class="button is-fullwidth" + onClick={(e) => route(Paths.reserve_balance_insufficient_inconsistency_list) } + >Reserve balances insufficient + </button> + </div> + </div> + </div> + </div> + + <div class="columns"> + <div class="column"> + <div class="card"> + <div class="card-body"> + <button + class="button is-fullwidth" + onClick={(e) => route(Paths.reserve_balance_summary_wrong_inconsistency_list) } + >Reserve balances summary wrong + </button> + </div> + </div> + </div> + <div class="column"> + <div class="card"> + <div class="card-body"> + <button + class="button is-fullwidth" + onClick={(e) => route(Paths.reserve_in_inconsistency_list) } + >Reserves in + </button> + </div> + </div> + </div> + <div class="column"> + <div class="card"> + <div class="card-body"> + <button + class="button is-fullwidth" + onClick={(e) => route(Paths.reserve_not_closed_inconsistency_list) } + >Reserves not closed + </button> + </div> + </div> + </div> + <div class="column"> + <div class="card"> + <div class="card-body"> + <button + class="button is-fullwidth" + onClick={(e) => route(Paths.reserves_list) } + >Reserves + </button> + </div> + </div> + </div> + </div> + + <div class="columns"> + <div class="column"> + <div class="card"> + <div class="card-body"> + <button + class="button is-fullwidth" + onClick={(e) => route(Paths.row_inconsistency_list) } + >Row inconsistencies + </button> + </div> + </div> + </div> + <div class="column"> + <div class="card"> + <div class="card-body"> + <button + class="button is-fullwidth" + onClick={(e) => route(Paths.row_minor_inconsistency_list) } + >Row minor inconsistencies + </button> + </div> + </div> + </div> + <div class="column"> + <div class="card"> + <div class="card-body"> + <button + class="button is-fullwidth" + onClick={(e) => route(Paths.wire_format_inconsistency_list) } + >Wire format inconsistencies + </button> + </div> + </div> + </div> + <div class="column"> + <div class="card"> + <div class="card-body"> + <button + class="button is-fullwidth" + onClick={(e) => route(Paths.wire_out_inconsistency_list) } + >Wire out inconsistencies + </button> + </div> + </div> + </div> + </div> + + </Fragment> + ); +} diff --git a/packages/auditor-backoffice-ui/src/paths/instance/transfers/update/index.tsx b/packages/auditor-backoffice-ui/src/paths/details/index.tsx index 719f99209..f99dae7e5 100644 --- a/packages/auditor-backoffice-ui/src/paths/instance/transfers/update/index.tsx +++ b/packages/auditor-backoffice-ui/src/paths/details/index.tsx @@ -16,11 +16,24 @@ /** * + * @author Nic Eigel * @author Sebastian Javier Marchano (sebasjm) */ import { h, VNode } from "preact"; +import { useState } from "preact/hooks"; +import { NotificationCard } from "../../components/menu/index.js"; +import { Notification } from "../../utils/types.js"; +import { ListPage } from "./ListPage.js"; -export default function UpdateTransfer(): VNode { - return <div>order transfer page</div>; -} +export default function DetailsDashboard(): VNode { + + const [notif, setNotif] = useState<Notification | undefined>(undefined); + + return ( + <section class="section is-main-section"> + <NotificationCard notification={notif} /> + <ListPage /> + </section> + ); +}
\ No newline at end of file diff --git a/packages/auditor-backoffice-ui/src/paths/finance/ListPage.tsx b/packages/auditor-backoffice-ui/src/paths/finance/ListPage.tsx new file mode 100644 index 000000000..88ca6bcfd --- /dev/null +++ b/packages/auditor-backoffice-ui/src/paths/finance/ListPage.tsx @@ -0,0 +1,214 @@ +/* + This file is part of GNU Taler + (C) 2021-2023 Taler Systems S.A. + + GNU Taler is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> + */ + +/** + * + * @author Nic Eigel + * @author Sebastian Javier Marchano (sebasjm) + */ + +import { useTranslationContext } from "@gnu-taler/web-util/browser"; +import { h, VNode, Fragment } from "preact"; + +export function ListPage(data: any): VNode { + const { i18n } = useTranslationContext(); + + let balances = data.data.data[0][4].data.balances; + let coinBalances = [ + "Total recoup loss", + "Coin refund fee revenue", + "Coin deposit fee revenue", + "Coin melt fee revenue", + "Coin irregular loss", + "Coins reported emergency risk by amount", + "Coins emergencies loss by count", + "Coins emergencies loss", + "Coins total arithmetic delta minus", + "Coins total arithmetic delta plus", + "Total escrowed", + "Total refresh hanging", + ]; + let reserveBalances = [ + "Total balance summary delta minus", + "Total balance reserve not closed", + "Reserves total arithmetic delta minus", + "Reserves total arithmetic delta plus", + "Reserves total bad signature loss", + "Reserves history fee revenue", + "Reserves open fee revenue", + ]; + let i = 0; + + return ( + <Fragment> + <div class="columns"> + <div class="column is-half"> + <div class="columns"> + <div class="column"> + <div class="card"> + <div class="card-content"> + <table class="table is-striped is-fullwidth is-dark"> + <tbody> + <tr> + <th>Finding</th> + <td class="has-text-right"><b>Count</b></td> + <td class="has-text-right"><b>Gain/Loss</b></td> + </tr> + { + data["data"]["data"][0].map((x: any) => { + const key = Object.keys(x.data)[0]; + let value = Object.values(x.data)[0]; + const paramName = key[0].toUpperCase() + key.split("_").join(" ").split("-").join(" ").slice(1, key.length); + if (key == "balances") { + //TODO fix + let gains = 0; + if (value == null) + value = 0; + else + value = Object.keys(value).length; + + return ( + <tr class="is-link"> + <td>{paramName}</td> + <td class="has-text-right"><p + class={value == 0 ? "text-success" : "text-danger"}>{String(value)}</p></td> + <td class="has-text-right"><p + class={gains == 0 ? "text-success" : "text-danger"}>{String(gains)}</p></td> + </tr> + ); + } else { + <tr class="is-link"> + <td>{paramName}</td> + <td class="has-text-right"><p + class={value == 0 ? "text-success" : "text-danger"}>{String(value)}</p></td> + <td class="has-text-right"><p>{ + //TODO + }</p></td> + </tr>; + } + }) + } + </tbody> + </table> + </div> + </div> + <div class="card"> + <div class="card-content"> + <table class="table is-striped is-fullwidth is-dark"> + <tbody> + <tr> + <th>Summary</th> + <td class="has-text-right"><b>Value</b></td> + </tr> + <tr> + <td>Total gain/loss</td> + <td class="has-text-right">{ + //TODO fix + }</td> + </tr> + <tr> + <td>Pending gain/loss</td> + <td class="has-text-right">{ + //TODO fix + }</td> + </tr> + <tr> + <td>Transaction count</td> + <td class="has-text-right">{ + //TODO fix + }</td> + </tr> + <tr> + <td>Transactions pending</td> + <td class="has-text-right">{ + //TODO fix + }</td> + </tr> + </tbody> + </table> + </div> + </div> + </div> + </div> + </div> + <div class="column is-half"> + <div class="card"> + <div class="card-content"> + <p class="has-text-weight-bold">Helper coin</p> + <table class="table is-striped is-fullwidth is-dark"> + <tbody> + <tr> + <th>Balance</th> + <td><b>Value</b></td> + </tr> + { + balances.map((x: any) => { + let key = x.balance_key; + let balanceName = key[0].toUpperCase() + key.split("_").join(" ").split("-").join(" ").slice(1, key.length); + + if(coinBalances.includes(balanceName)) + { + let value = balances[i].balance_value.replace(":", " "); + i=i+1; + return ( + <tr class="is-link"> + <td>{balanceName}</td> + <td><p>{value}</p></td> + </tr> + ); + } else { + return null; + } + }) + } + </tbody> + </table> + <p class="has-text-weight-bold">Helper reserve</p> + <table class="table is-striped is-fullwidth is-dark"> + <tbody> + <tr> + <th>Balance</th> + <td><b>Value</b></td> + </tr> + { + balances.map((x: any) => { + let key = x.balance_key; + let balanceName = key[0].toUpperCase() + key.split("_").join(" ").split("-").join(" ").slice(1, key.length); + + if(reserveBalances.includes(balanceName)) + { + let value = balances[i].balance_value.replace(":", " "); + i = i+1; + return ( + <tr class="is-link"> + <td>{balanceName}</td> + <td><p>{value}</p></td> + </tr> + ); + } else { + return null; + } + }) + } + </tbody> + </table> + </div> + </div> + </div> + </div> + </Fragment> + ); +} diff --git a/packages/auditor-backoffice-ui/src/paths/instance/deposit_confirmations/update/index.tsx b/packages/auditor-backoffice-ui/src/paths/finance/index.tsx index 2d3e7bd6b..b0d07aa0f 100644 --- a/packages/auditor-backoffice-ui/src/paths/instance/deposit_confirmations/update/index.tsx +++ b/packages/auditor-backoffice-ui/src/paths/finance/index.tsx @@ -16,43 +16,41 @@ /** * + * @author Nic Eigel * @author Sebastian Javier Marchano (sebasjm) */ import { ErrorType, - HttpError, useTranslationContext, } from "@gnu-taler/web-util/browser"; -import { Fragment, h, VNode } from "preact"; +import { h, VNode } from "preact"; import { useState } from "preact/hooks"; -import { Loading } from "../../../../components/exception/loading.js"; -import { NotificationCard } from "../../../../components/menu/index.js"; -import { MerchantBackend } from "../../../../declaration.js"; -import { useProductAPI, useProductDetails } from "../../../../hooks/product.js"; -import { Notification } from "../../../../utils/types.js"; -import { UpdatePage } from "./UpdatePage.js"; +import { Loading } from "../../components/exception/loading.js"; +import { NotificationCard } from "../../components/menu/index.js"; +import { Notification } from "../../utils/types.js"; +import { ListPage } from "./ListPage.js"; import { HttpStatusCode } from "@gnu-taler/taler-util"; +import { getKeyFiguresData } from "../../hooks/finance.js"; + -export type Entity = MerchantBackend.Products.ProductAddDetail; interface Props { - onBack?: () => void; - onConfirm: () => void; onUnauthorized: () => VNode; onNotFound: () => VNode; - onLoadError: (e: HttpError<MerchantBackend.ErrorDetail>) => VNode; - pid: string; + onSelect: (id: string) => void; + onCreate: () => void; } -export default function UpdateProduct({ - pid, - onConfirm, - onBack, - onUnauthorized, - onNotFound, - onLoadError, -}: Props): VNode { - const { updateProduct } = useProductAPI(); - const result = useProductDetails(pid); + +export default function FinanceDashboard({ + onUnauthorized, + // onLoadError, + onCreate, + onSelect, + onNotFound, + }: Props): VNode { + + const result = getKeyFiguresData(); + const [notif, setNotif] = useState<Notification | undefined>(undefined); const { i18n } = useTranslationContext(); @@ -69,27 +67,14 @@ export default function UpdateProduct({ result.status === HttpStatusCode.NotFound ) return onNotFound(); - return onLoadError(result); + else + return onNotFound(); } return ( - <Fragment> + <section class="section is-main-section"> <NotificationCard notification={notif} /> - <UpdatePage - product={{ ...result.data, product_id: pid }} - onBack={onBack} - onUpdate={(data) => { - return updateProduct(pid, data) - .then(onConfirm) - .catch((error) => { - setNotif({ - message: i18n.str`could not create product`, - type: "ERROR", - description: error.message, - }); - }); - }} - /> - </Fragment> + <ListPage data={result} /> + </section> ); -} +}
\ No newline at end of file diff --git a/packages/auditor-backoffice-ui/src/paths/instance/deposit_confirmations/list/index.tsx b/packages/auditor-backoffice-ui/src/paths/instance/deposit_confirmations/list/index.tsx deleted file mode 100644 index a99cfd2ef..000000000 --- a/packages/auditor-backoffice-ui/src/paths/instance/deposit_confirmations/list/index.tsx +++ /dev/null @@ -1,126 +0,0 @@ -/* - This file is part of GNU Taler - (C) 2021-2024 Taler Systems S.A. - - GNU Taler is free software; you can redistribute it and/or modify it under the - terms of the GNU General Public License as published by the Free Software - Foundation; either version 3, or (at your option) any later version. - - GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along with - GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> - */ - -/** - * - * @author Sebastian Javier Marchano (sebasjm) - * @author Nic Eigel - */ - -import { - ErrorType, - HttpError, - useTranslationContext, -} from "@gnu-taler/web-util/browser"; -import { h, VNode } from "preact"; -import { useState } from "preact/hooks"; -import { Loading } from "../../../../components/exception/loading.js"; -import { NotificationCard } from "../../../../components/menu/index.js"; -import { AuditorBackend, WithId } from "../../../../declaration.js"; -import { - useDepositConfirmation, - useDepositConfirmationAPI, -} from "../../../../hooks/deposit_confirmations.js"; -import { Notification } from "../../../../utils/types.js"; -import { CardTable } from "./Table.js"; -import { HttpStatusCode } from "@gnu-taler/taler-util"; -import { ConfirmModal, DeleteModal } from "../../../../components/modal/index.js"; -import { JumpToElementById } from "../../../../components/form/JumpToElementById.js"; - -interface Props { - onUnauthorized: () => VNode; - onNotFound: () => VNode; - onCreate: () => void; - onSelect: (id: string) => void; - onLoadError: (e: HttpError<AuditorBackend.ErrorDetail>) => VNode; -} -export default function DepositConfirmationList({ - onUnauthorized, - onLoadError, - onCreate, - onSelect, - onNotFound, -}: Props): VNode { - const result = useDepositConfirmation(); - const { deleteDepositConfirmation, updateDepositConfirmation, getDepositConfirmation } = useDepositConfirmationAPI(); - const [deleting, setDeleting] = - useState<AuditorBackend.DepositConfirmation.DepositConfirmationDetail & WithId | null>(null); - const [notif, setNotif] = useState<Notification | undefined>(undefined); - - const { i18n } = useTranslationContext(); - - if (result.loading) return <Loading />; - if (!result.ok) { - if ( - result.type === ErrorType.CLIENT && - result.status === HttpStatusCode.Unauthorized - ) - return onUnauthorized(); - if ( - result.type === ErrorType.CLIENT && - result.status === HttpStatusCode.NotFound - ) - return onNotFound(); - return onLoadError(result); - } - - return ( - <section class="section is-main-section"> - <NotificationCard notification={notif} /> - - <JumpToElementById - testIfExist={getDepositConfirmation} - onSelect={onSelect} - description={i18n.str`jump to deposit_confirmation with the given serial ID`} - placeholder={i18n.str`serial id`} - /> - - {deleting && ( - <ConfirmModal - label={`Delete deposit-confirmation`} - description={`Delete the deposit-cofirmation "${deleting.serial_id}"`} - danger - active - onCancel={() => setDeleting(null)} - onConfirm={async (): Promise<void> => { - try { - await deleteDepositConfirmation(deleting.serial_id); - setNotif({ - message: i18n.str`Deposit-confirmation "${deleting.serial_id}" (ID: ${deleting.serial_id}) has been deleted`, - type: "SUCCESS", - }); - } catch (error) { - setNotif({ - message: i18n.str`Failed to delete deposit-confirmation`, - type: "ERROR", - description: error instanceof Error ? error.message : undefined, - }); - } - setDeleting(null); - }} - > - <p> - If you delete the deposit-confirmation (ID:{" "} - <b>{deleting.serial_id}</b>), the stock and related information will be lost - </p> - <p class="warning"> - Deleting a deposit-confirmation <b>cannot be undone</b>. - </p> - </ConfirmModal> - )} - </section> - ); -} diff --git a/packages/auditor-backoffice-ui/src/paths/login/index.tsx b/packages/auditor-backoffice-ui/src/paths/login/index.tsx index f8990d377..c99dc6050 100644 --- a/packages/auditor-backoffice-ui/src/paths/login/index.tsx +++ b/packages/auditor-backoffice-ui/src/paths/login/index.tsx @@ -16,187 +16,198 @@ /** * + * @author Nic Eigel * @author Sebastian Javier Marchano (sebasjm) */ import { useTranslationContext } from "@gnu-taler/web-util/browser"; -import { ComponentChildren, h, VNode } from "preact"; -import { useCallback, useEffect, useState } from "preact/hooks"; -import { useBackendContext } from "../../context/backend.js"; -import { useInstanceContext } from "../../context/instance.js"; -import { AccessToken, LoginToken } from "../../declaration.js"; -import { useCredentialsChecker } from "../../hooks/backend.js"; - -interface Props { - onConfirm: (token: LoginToken | undefined) => void; -} - -function normalizeToken(r: string): AccessToken { - return `secret-token:${r}` as AccessToken; -} - -export function LoginPage({ onConfirm }: Props): VNode { - const { url: backendURL } = useBackendContext(); - const { admin, id } = useInstanceContext(); - const { requestNewLoginToken } = useCredentialsChecker(); +import { ComponentChildren, Fragment, h, VNode } from "preact"; +import { useCallback, useState } from "preact/hooks"; +import { useBackendContext, useBackendTokenContext } from "../../context/backend.js"; +import { NotificationCard } from "../../components/menu/index.js"; +import { Notification } from "../../utils/types.js"; +import { useBackendToken } from "../../hooks/backend.js"; +import { Route } from "preact-router"; +import { Paths, Redirect } from "../../InstanceRoutes.js"; + +export function LoginPage(): VNode { const [token, setToken] = useState(""); - + const [notif, setNotif] = useState<Notification | undefined>(undefined); const { i18n } = useTranslationContext(); - - const doLogin = useCallback(async function doLoginImpl() { - const secretToken = normalizeToken(token); - const baseUrl = id === undefined ? backendURL : `${backendURL}/instances/${id}` - const result = await requestNewLoginToken(baseUrl, secretToken); - if (result.valid) { - const { token, expiration } = result - onConfirm({ token, expiration }); + + const result = useBackendToken(); + if (!result.ok) { + } + if (result.ok) { + //TODO fixme + const { token } = useBackendTokenContext(); + /* return ( + <Route path="/" component={Redirect} to={Paths.key_figures}/> + );*/ } else { - onConfirm(undefined); + setNotif({ + message: "Your password is incorrect", + type: "ERROR", + }); } - }, [id, token]) - - if (admin && id !== "default") { - //admin trying to access another instance - return (<div class="columns is-centered" style={{ margin: "auto" }}> - <div class="column is-two-thirds "> - <div class="modal-card" style={{ width: "100%", margin: 0 }}> - <header - class="modal-card-head" - style={{ border: "1px solid", borderBottom: 0 }} - > - <p class="modal-card-title">{i18n.str`Login required`}</p> - </header> - <section - class="modal-card-body" - style={{ border: "1px solid", borderTop: 0, borderBottom: 0 }} - > - <p> - <i18n.Translate>Need the access token for the instance.</i18n.Translate> - </p> - <div class="field is-horizontal"> - <div class="field-label is-normal"> - <label class="label"> - <i18n.Translate>Access Token</i18n.Translate> - </label> - </div> - <div class="field-body"> - <div class="field"> - <p class="control is-expanded"> - <input - class="input" - type="password" - placeholder={"current access token"} - name="token" - onKeyPress={(e) => - e.keyCode === 13 - ? doLogin() - : null - } - value={token} - onInput={(e): void => setToken(e?.currentTarget.value)} - /> - </p> - </div> + }, [token]); + + return ( + <Route path="/" component={Redirect} to={Paths.key_figures}/> + ); + + return ( + <div class="columns is-centered" style={{ margin: "auto" }}> + <div class="column is-two-thirds "> + <div class="modal-card" style={{ width: "100%", margin: 0 }}> + <header + class="modal-card-head" + style={{ border: "1px solid", borderBottom: 0 }} + > + <p class="modal-card-title">{i18n.str`Token required`}</p> + </header> + <section + class="modal-card-body" + style={{ border: "1px solid", borderTop: 0, borderBottom: 0 }} + > + + <p> + <i18n.Translate>Need the access token for the API.</i18n.Translate> + </p> + <div class="field is-horizontal"> + <div class="field-label is-normal"> + <label class="label"> + <i18n.Translate>Access Token</i18n.Translate> + </label> + </div> + <div class="field-body"> + <div class="field"> + <p class="control is-expanded"> + <input + class="input" + type="password" + placeholder={"current access token"} + name="token" + onKeyPress={(e) => + e.keyCode === 13 + ? doLogin() + : null + } + value={token} + onInput={(e): void => setToken(e?.currentTarget.value)} + /> + </p> </div> </div> - </section> - <footer - class="modal-card-foot " - style={{ - justifyContent: "flex-end", - border: "1px solid", - borderTop: 0, - }} + </div> + </section> + <footer + class="modal-card-foot " + style={{ + justifyContent: "flex-end", + border: "1px solid", + borderTop: 0, + }} + > + <AsyncButton + onClick={() => doLogin()} > - <AsyncButton - onClick={doLogin} - > - <i18n.Translate>Confirm</i18n.Translate> - </AsyncButton> - </footer> - </div> + <i18n.Translate>Confirm</i18n.Translate> + </AsyncButton> + </footer> </div> - </div>) - } + </div> + </div>); - return ( - <div class="columns is-centered" style={{ margin: "auto" }}> - <div class="column is-two-thirds "> - <div class="modal-card" style={{ width: "100%", margin: 0 }}> - <header - class="modal-card-head" - style={{ border: "1px solid", borderBottom: 0 }} - > - <p class="modal-card-title">{i18n.str`Login required`}</p> - </header> - <section - class="modal-card-body" - style={{ border: "1px solid", borderTop: 0, borderBottom: 0 }} - > - <i18n.Translate>Please enter your access token.</i18n.Translate> - <div class="field is-horizontal"> - <div class="field-label is-normal"> - <label class="label"> - <i18n.Translate>Access Token</i18n.Translate> - </label> - </div> - <div class="field-body"> - <div class="field"> - <p class="control is-expanded"> - <input - class="input" - type="password" - placeholder={"current access token"} - name="token" - onKeyPress={(e) => - e.keyCode === 13 - ? doLogin() - : null - } - value={token} - onInput={(e): void => setToken(e?.currentTarget.value)} - /> - </p> + return (<Fragment> + <NotificationCard notification={notif} /> + <div class="columns is-centered" style={{ margin: "auto" }}> + <div class="column is-two-thirds "> + <div class="modal-card" style={{ width: "100%", margin: 0 }}> + <header + class="modal-card-head" + style={{ border: "1px solid", borderBottom: 0 }} + > + <p class="modal-card-title">{i18n.str`Login required`}</p> + </header> + <section + class="modal-card-body" + style={{ border: "1px solid", borderTop: 0, borderBottom: 0 }} + > + <i18n.Translate>Please enter your access token.</i18n.Translate> + + <div class="field is-horizontal"> + <div class="field-label is-normal"> + <label class="label"> + <i18n.Translate>Access Token</i18n.Translate> + </label> + </div> + <div class="field-body"> + + <div class="field"> + <p class="control is-expanded"> + <input + class="input" + type="password" + placeholder={"current access token"} + name="token" + onKeyPress={(e) => + e.keyCode === 13 + ? doLogin() + : null + } + value={token} + onInput={(e): void => setToken(e?.currentTarget.value)} + /> + </p> + </div> </div> </div> - </div> - </section> - <footer - class="modal-card-foot " - style={{ - justifyContent: "space-between", - border: "1px solid", - borderTop: 0, - }} - > - <div /> - <AsyncButton - type="is-info" - onClick={doLogin} + </section> + <footer + class="modal-card-foot " + style={{ + justifyContent: "space-between", + border: "1px solid", + borderTop: 0, + }} > - <i18n.Translate>Confirm</i18n.Translate> - </AsyncButton> - </footer> + <div /> + <AsyncButton + type="is-info" + onClick={doLogin} + > + <i18n.Translate>Confirm</i18n.Translate> + </AsyncButton> + + </footer> + </div> </div> </div> - </div> + </Fragment> + ); } -function AsyncButton({ onClick, disabled, type = "", children }: { type?: string, disabled?: boolean, onClick: () => Promise<void>, children: ComponentChildren }): VNode { - const [running, setRunning] = useState(false) +function AsyncButton({ onClick, disabled, type = "", children }: { + type?: string, + disabled?: boolean, + onClick: () => Promise<void>, + children: ComponentChildren +}): VNode { + const [running, setRunning] = useState(false); return <button class={"button " + type} disabled={disabled || running} onClick={() => { - setRunning(true) + setRunning(true); onClick().then(() => { - setRunning(false) + setRunning(false); }).catch(() => { - setRunning(false) - }) + setRunning(false); + }); }}> {children} - </button> + </button>; } diff --git a/packages/auditor-backoffice-ui/src/paths/notfound/index.tsx b/packages/auditor-backoffice-ui/src/paths/notfound/index.tsx index 68adb79bf..114b95219 100644 --- a/packages/auditor-backoffice-ui/src/paths/notfound/index.tsx +++ b/packages/auditor-backoffice-ui/src/paths/notfound/index.tsx @@ -23,12 +23,12 @@ import { h, VNode } from "preact"; import { Link } from "preact-router"; export default function NotFoundPage(): VNode { - return ( - <div> - <p>That page doesn't exist.</p> - <Link href="/"> - <h4>Back to Home</h4> - </Link> - </div> - ); + return ( + <div> + <p>That page doesn't exist.</p> + <Link href="/"> + <h4>Back to Home</h4> + </Link> + </div> + ); } diff --git a/packages/auditor-backoffice-ui/src/paths/operations/ListPage.tsx b/packages/auditor-backoffice-ui/src/paths/operations/ListPage.tsx new file mode 100644 index 000000000..7f0579b2b --- /dev/null +++ b/packages/auditor-backoffice-ui/src/paths/operations/ListPage.tsx @@ -0,0 +1,72 @@ +/* + This file is part of GNU Taler + (C) 2021-2023 Taler Systems S.A. + + GNU Taler is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> + */ + +/** + * + * @author Nic Eigel + * @author Sebastian Javier Marchano (sebasjm) + */ + +import { useTranslationContext } from "@gnu-taler/web-util/browser"; +import { h, VNode, Fragment } from "preact"; + +export function ListPage(data: any): VNode { + const { i18n } = useTranslationContext(); + + return ( + <Fragment> + <div class="columns is-fullwidth"> + <div class="column is-fullwidth"> + <div class="card"> + <div class="card-content"> + <table class="table is-striped is-fullwidth"> + <tbody> + <tr> + <th>Finding</th> + <td class="has-text-right"><b>Count</b></td> + <td class="has-text-right"><b>Time difference (s)</b></td> + <td class="has-text-right"><b>Diagnostic</b></td> + </tr> + { + data["data"]["data"][0].map((x: any) => { + const key = Object.keys(x.data)[0]; + let value = Object.values(x.data)[0]; + console.log(value); + if (!!value) + value = 0; + const paramName = key[0].toUpperCase() + key.split("_").join(" ").split("-").join(" ").slice(1, key.length); + return ( + <tr class="is-link"> + <td>{paramName}</td> + <td className="has-text-right"><p + class={value == 0 ? "text-success" : "text-danger"}>{String(value)}</p></td> + <td className="has-text-right">{//TODO + }</td> + <td>{//TODO + }</td> + </tr> + ); + }) + } + </tbody> + </table> + </div> + </div> + </div> + </div> + </Fragment> + ); +}
\ No newline at end of file diff --git a/packages/auditor-backoffice-ui/src/paths/instance/products/update/index.tsx b/packages/auditor-backoffice-ui/src/paths/operations/index.tsx index 2d3e7bd6b..c05b271fe 100644 --- a/packages/auditor-backoffice-ui/src/paths/instance/products/update/index.tsx +++ b/packages/auditor-backoffice-ui/src/paths/operations/index.tsx @@ -16,43 +16,41 @@ /** * + * @author Nic Eigel * @author Sebastian Javier Marchano (sebasjm) */ import { ErrorType, - HttpError, useTranslationContext, } from "@gnu-taler/web-util/browser"; -import { Fragment, h, VNode } from "preact"; +import { h, VNode } from "preact"; import { useState } from "preact/hooks"; -import { Loading } from "../../../../components/exception/loading.js"; -import { NotificationCard } from "../../../../components/menu/index.js"; -import { MerchantBackend } from "../../../../declaration.js"; -import { useProductAPI, useProductDetails } from "../../../../hooks/product.js"; -import { Notification } from "../../../../utils/types.js"; -import { UpdatePage } from "./UpdatePage.js"; +import { Loading } from "../../components/exception/loading.js"; +import { NotificationCard } from "../../components/menu/index.js"; +import { Notification } from "../../utils/types.js"; +import { ListPage } from "./ListPage.js"; import { HttpStatusCode } from "@gnu-taler/taler-util"; +import { getOperationData } from "../../hooks/operational.js"; + -export type Entity = MerchantBackend.Products.ProductAddDetail; interface Props { - onBack?: () => void; - onConfirm: () => void; onUnauthorized: () => VNode; onNotFound: () => VNode; - onLoadError: (e: HttpError<MerchantBackend.ErrorDetail>) => VNode; - pid: string; + onSelect: (id: string) => void; + onCreate: () => void; } -export default function UpdateProduct({ - pid, - onConfirm, - onBack, - onUnauthorized, - onNotFound, - onLoadError, -}: Props): VNode { - const { updateProduct } = useProductAPI(); - const result = useProductDetails(pid); + +export default function OperationsDashboard({ + onUnauthorized, + // onLoadError, + onCreate, + onSelect, + onNotFound, + }: Props): VNode { + + const result = getOperationData(); + const [notif, setNotif] = useState<Notification | undefined>(undefined); const { i18n } = useTranslationContext(); @@ -69,27 +67,14 @@ export default function UpdateProduct({ result.status === HttpStatusCode.NotFound ) return onNotFound(); - return onLoadError(result); + else + return onNotFound(); } return ( - <Fragment> + <section class="section is-main-section"> <NotificationCard notification={notif} /> - <UpdatePage - product={{ ...result.data, product_id: pid }} - onBack={onBack} - onUpdate={(data) => { - return updateProduct(pid, data) - .then(onConfirm) - .catch((error) => { - setNotif({ - message: i18n.str`could not create product`, - type: "ERROR", - description: error.message, - }); - }); - }} - /> - </Fragment> + <ListPage data={result} /> + </section> ); -} +}
\ No newline at end of file diff --git a/packages/auditor-backoffice-ui/src/paths/security/ListPage.tsx b/packages/auditor-backoffice-ui/src/paths/security/ListPage.tsx new file mode 100644 index 000000000..74f83bd4a --- /dev/null +++ b/packages/auditor-backoffice-ui/src/paths/security/ListPage.tsx @@ -0,0 +1,70 @@ +/* + This file is part of GNU Taler + (C) 2021-2023 Taler Systems S.A. + + GNU Taler is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> + */ + +/** + * + * @author Nic Eigel + * @author Sebastian Javier Marchano (sebasjm) + */ + +import { useTranslationContext } from "@gnu-taler/web-util/browser"; +import { h, VNode, Fragment } from "preact"; + +export function ListPage(data: any): VNode { + const { i18n } = useTranslationContext(); + + return ( + <Fragment> + <div class="columns is-fullwidth"> + <div class="column is-fullwidth"> + <div class="card"> + <div class="card-content"> + <table class="table is-striped is-fullwidth"> + <tbody> + <tr> + <th>Finding</th> + <td class="has-text-right"><b>Count</b></td> + <td class="has-text-right"><b>Expiration dates</b></td> + </tr> + { + data["data"]["data"][0].map((x: any) => { + const key = Object.keys(x.data)[0]; + let value = Object.values(x.data)[0]; + console.log(value); + if (!!value) + value = 0; + const paramName = key[0].toUpperCase() + key.split("_").join(" ").split("-").join(" ").slice(1, key.length); + return ( + <tr class="is-link"> + <td>{paramName}</td> + <td class="has-text-right"><p + class={value == 0 ? "text-success" : "text-danger"}>{String(value)}</p></td> + <td class="has-text-right">{ + //TODO + }</td> + </tr> + ); + }) + } + </tbody> + </table> + </div> + </div> + </div> + </div> + </Fragment> + ); +} diff --git a/packages/auditor-backoffice-ui/src/paths/instance/templates/qr/index.tsx b/packages/auditor-backoffice-ui/src/paths/security/index.tsx index 65ccc2dcc..99c98a5e7 100644 --- a/packages/auditor-backoffice-ui/src/paths/instance/templates/qr/index.tsx +++ b/packages/auditor-backoffice-ui/src/paths/security/index.tsx @@ -16,46 +16,43 @@ /** * + * @author Nic Eigel * @author Sebastian Javier Marchano (sebasjm) */ import { ErrorType, - HttpError, useTranslationContext, } from "@gnu-taler/web-util/browser"; -import { Fragment, h, VNode } from "preact"; +import { h, VNode } from "preact"; import { useState } from "preact/hooks"; -import { Loading } from "../../../../components/exception/loading.js"; -import { NotificationCard } from "../../../../components/menu/index.js"; -import { MerchantBackend } from "../../../../declaration.js"; -import { - useTemplateAPI, - useTemplateDetails, -} from "../../../../hooks/templates.js"; -import { Notification } from "../../../../utils/types.js"; -import { QrPage } from "./QrPage.js"; +import { Loading } from "../../components/exception/loading.js"; +import { NotificationCard } from "../../components/menu/index.js"; +import { Notification } from "../../utils/types.js"; +import { ListPage } from "./ListPage.js"; import { HttpStatusCode } from "@gnu-taler/taler-util"; - -export type Entity = MerchantBackend.Transfers.TransferInformation; +import { getCriticalData } from "../../hooks/critical.js"; interface Props { - onBack?: () => void; onUnauthorized: () => VNode; onNotFound: () => VNode; - onLoadError: (e: HttpError<MerchantBackend.ErrorDetail>) => VNode; - tid: string; + onSelect: (id: string) => void; + onCreate: () => void; } -export default function TemplateQrPage({ - tid, - onBack, - onLoadError, - onNotFound, - onUnauthorized, -}: Props): VNode { - const result = useTemplateDetails(tid); +export default function SecurityDashboard({ + onUnauthorized, + // onLoadError, + onCreate, + onSelect, + onNotFound, + }: Props): VNode { + + const result = getCriticalData(); + const [notif, setNotif] = useState<Notification | undefined>(undefined); + const { i18n } = useTranslationContext(); + if (result.loading) return <Loading />; if (!result.ok) { if ( @@ -68,13 +65,14 @@ export default function TemplateQrPage({ result.status === HttpStatusCode.NotFound ) return onNotFound(); - return onLoadError(result); + else + return onNotFound(); } return ( - <> + <section class="section is-main-section"> <NotificationCard notification={notif} /> - <QrPage contract={result.data.template_contract} id={tid} onBack={onBack} /> - </> + <ListPage data={result} /> + </section> ); -} +}
\ No newline at end of file diff --git a/packages/auditor-backoffice-ui/src/paths/settings/index.tsx b/packages/auditor-backoffice-ui/src/paths/settings/index.tsx index 093c3d09d..77a56a794 100644 --- a/packages/auditor-backoffice-ui/src/paths/settings/index.tsx +++ b/packages/auditor-backoffice-ui/src/paths/settings/index.tsx @@ -1,8 +1,28 @@ +/* + This file is part of GNU Taler + (C) 2021-2024 Taler Systems S.A. + + GNU Taler is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> + */ + +/** + * + * @author Sebastian Javier Marchano (sebasjm) + * @author Nic Eigel + */ + import { useLang, useTranslationContext } from "@gnu-taler/web-util/browser"; import { VNode, h } from "preact"; -import { FormErrors, FormProvider } from "../../components/form/FormProvider.js"; -import { InputSelector } from "../../components/form/InputSelector.js"; -import { InputToggle } from "../../components/form/InputToggle.js"; +import { FormErrors, FormProvider } from "../../components/forms/FormProvider.js"; import { LangSelector } from "../../components/menu/LangSelector.js"; import { Settings, useSettings } from "../../hooks/useSettings.js"; @@ -16,7 +36,7 @@ function getBrowserLang(): string | undefined { export function Settings({ onClose }: { onClose?: () => void }): VNode { const { i18n } = useTranslationContext() const borwserLang = getBrowserLang() - //const { update } = useLang() + const { update } = useLang(undefined, {}) const [value, updateValue] = useSettings() const errors: FormErrors<Settings> = { @@ -60,38 +80,13 @@ export function Settings({ onClose }: { onClose?: () => void }): VNode { data-tooltip={i18n.str`generate random secret key`} class="button is-info mr-2" onClick={(e) => { - //update(borwserLang.substring(0, 2)) + update(borwserLang.substring(0, 2)) }} > <i18n.Translate>Set default</i18n.Translate> </button>} </div> </div> - <InputToggle<Settings> - label={i18n.str`Advance order creation`} - tooltip={i18n.str`Shows more options in the order creation form`} - name="advanceOrderMode" - /> - <InputSelector<Settings> - name="dateFormat" - label={i18n.str`Date format`} - expand={true} - help={ - value.dateFormat === "dmy" ? "31/12/2001" : value.dateFormat === "mdy" ? "12/31/2001" : value.dateFormat === "ymd" ? "2001/12/31" : "" - } - toStr={(e) => { - if (e === "ymd") return "year month day" - if (e === "mdy") return "month day year" - if (e === "dmy") return "day month year" - return "choose one" - }} - values={[ - "ymd", - "mdy", - "dmy", - ]} - tooltip={i18n.str`how the date is going to be displayed`} - /> </FormProvider> </div> </div> |