diff options
Diffstat (limited to 'packages/bank-ui/src/components/Cashouts/views.tsx')
-rw-r--r-- | packages/bank-ui/src/components/Cashouts/views.tsx | 218 |
1 files changed, 218 insertions, 0 deletions
diff --git a/packages/bank-ui/src/components/Cashouts/views.tsx b/packages/bank-ui/src/components/Cashouts/views.tsx new file mode 100644 index 000000000..22b8d8c1b --- /dev/null +++ b/packages/bank-ui/src/components/Cashouts/views.tsx @@ -0,0 +1,218 @@ +/* + This file is part of GNU Taler + (C) 2022-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/> + */ + +import { + AbsoluteTime, + Amounts, + HttpStatusCode, + TalerError, + assertUnreachable, +} from "@gnu-taler/taler-util"; +import { + Attention, + Loading, + useTranslationContext, +} from "@gnu-taler/web-util/browser"; +import { format } from "date-fns"; +import { Fragment, VNode, h } from "preact"; +import { useConversionInfo } from "../../hooks/regional.js"; +import { RenderAmount } from "../../pages/PaytoWireTransferForm.js"; +import { ErrorLoadingWithDebug } from "../ErrorLoadingWithDebug.js"; +import { Time } from "../Time.js"; +import { State } from "./index.js"; + +export function FailedView({ error }: State.Failed) { + const { i18n } = useTranslationContext(); + switch (error.case) { + case HttpStatusCode.NotImplemented: { + return ( + <Attention type="danger" title={i18n.str`Cashout are disabled`}> + <i18n.Translate> + Cashout should be enable by configuration and the conversion rate + should be initialized with fee, ratio and rounding mode. + </i18n.Translate> + </Attention> + ); + } + default: + assertUnreachable(error.case); + } +} + +export function ReadyView({ + cashouts, + routeCashoutDetails, +}: State.Ready): VNode { + const { i18n, dateLocale } = useTranslationContext(); + const resp = useConversionInfo(); + if (!resp) { + return <Loading />; + } + if (resp instanceof TalerError) { + return <ErrorLoadingWithDebug error={resp} />; + } + if (resp.type === "fail") { + switch (resp.case) { + case HttpStatusCode.NotImplemented: { + return ( + <Attention type="danger" title={i18n.str`Cashout are disabled`}> + <i18n.Translate> + Cashout should be enable by configuration and the conversion rate + should be initialized with fee, ratio and rounding mode. + </i18n.Translate> + </Attention> + ); + } + default: + assertUnreachable(resp.case); + } + } + + if (!cashouts.length) return <div />; + const txByDate = cashouts.reduce( + (prev, cur) => { + const d = + cur.creation_time.t_s === "never" + ? "" + : format(cur.creation_time.t_s * 1000, "dd/MM/yyyy", { + locale: dateLocale, + }); + if (!prev[d]) { + prev[d] = []; + } + prev[d].push(cur); + return prev; + }, + {} as Record<string, typeof cashouts>, + ); + return ( + <div class="px-4 mt-4"> + <div class="sm:flex sm:items-center"> + <div class="sm:flex-auto"> + <h1 class="text-base font-semibold leading-6 text-gray-900"> + <i18n.Translate>Latest cashouts</i18n.Translate> + </h1> + </div> + </div> + <div class="-mx-4 mt-5 ring-1 ring-gray-300 sm:mx-0 rounded-lg min-w-fit bg-white"> + <table class="min-w-full divide-y divide-gray-300"> + <thead> + <tr> + <th + scope="col" + class=" pl-2 py-3.5 text-left text-sm font-semibold text-gray-900" + >{i18n.str`Created`}</th> + <th + scope="col" + class="hidden sm:table-cell pl-2 py-3.5 text-left text-sm font-semibold text-gray-900" + >{i18n.str`Total debit`}</th> + <th + scope="col" + class="hidden sm:table-cell pl-2 py-3.5 text-left text-sm font-semibold text-gray-900" + >{i18n.str`Total credit`}</th> + <th + scope="col" + class="hidden sm:table-cell pl-2 py-3.5 text-left text-sm font-semibold text-gray-900" + >{i18n.str`Subject`}</th> + </tr> + </thead> + <tbody> + {Object.entries(txByDate).map(([date, txs], idx) => { + return ( + <Fragment key={idx}> + <tr class="border-t border-gray-200"> + <th + colSpan={6} + scope="colgroup" + class="bg-gray-50 py-2 pl-4 pr-3 text-left text-sm font-semibold text-gray-900 sm:pl-3" + > + {date} + </th> + </tr> + {txs.map((item) => { + return ( + <a + name="cashout details" + key={idx} + class="table-row border-b border-gray-200 hover:bg-gray-200 last:border-none" + // class="table-row" + href={routeCashoutDetails.url({ + cid: String(item.id), + })} + > + <td class="relative py-2 pl-2 pr-2 text-sm "> + <div class="font-medium text-gray-900"> + <Time + format="HH:mm:ss" + timestamp={AbsoluteTime.fromProtocolTimestamp( + item.creation_time, + )} + // relative={Duration.fromSpec({ days: 1 })} + /> + </div> + { + //FIXME: implement responsive view + } + {/* <dl class="font-normal sm:hidden"> + <dt class="sr-only sm:hidden"><i18n.Translate>Amount</i18n.Translate></dt> + <dd class="mt-1 truncate text-gray-700"> + {item.negative ? i18n.str`sent` : i18n.str`received`} {item.amount ? ( + <span data-negative={item.negative ? "true" : "false"} class="data-[negative=false]:text-green-600 data-[negative=true]:text-red-600"> + <RenderAmount value={item.amount} /> + </span> + ) : ( + <span style={{ color: "grey" }}><{i18n.str`invalid value`}></span> + )}</dd> + + <dt class="sr-only sm:hidden"><i18n.Translate>Counterpart</i18n.Translate></dt> + <dd class="mt-1 truncate text-gray-500 sm:hidden"> + {item.negative ? i18n.str`to` : i18n.str`from`} {item.counterpart} + </dd> + <dd class="mt-1 text-gray-500 sm:hidden" > + <pre class="break-words w-56 whitespace-break-spaces p-2 rounded-md mx-auto my-2 bg-gray-100"> + {item.subject} + </pre> + </dd> + </dl> */} + </td> + <td class="hidden sm:table-cell px-3 py-3.5 text-sm text-red-600 cursor-pointer"> + <RenderAmount + value={Amounts.parseOrThrow(item.amount_debit)} + spec={resp.body.regional_currency_specification} + /> + </td> + <td class="hidden sm:table-cell px-3 py-3.5 text-sm text-green-600 cursor-pointer"> + <RenderAmount + value={Amounts.parseOrThrow(item.amount_credit)} + spec={resp.body.fiat_currency_specification} + /> + </td> + + <td class="hidden sm:table-cell px-3 py-3.5 text-sm text-gray-500 break-all min-w-md"> + {item.subject} + </td> + </a> + ); + })} + </Fragment> + ); + })} + </tbody> + </table> + </div> + </div> + ); +} |