/* 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 */ /** * * @author Sebastian Javier Marchano (sebasjm) */ import { AbsoluteTime, HttpStatusCode, TalerError, TalerMerchantApi, assertUnreachable, } from "@gnu-taler/taler-util"; import { useTranslationContext } from "@gnu-taler/web-util/browser"; import { VNode, h } from "preact"; import { useState } from "preact/hooks"; import { ErrorLoadingMerchant } from "../../../../components/ErrorLoadingMerchant.js"; import { Loading } from "../../../../components/exception/loading.js"; import { JumpToElementById } from "../../../../components/form/JumpToElementById.js"; import { NotificationCard } from "../../../../components/menu/index.js"; import { useSessionContext } from "../../../../context/session.js"; import { InstanceOrderFilter, useInstanceOrders, useOrderDetails, } from "../../../../hooks/order.js"; import { Notification } from "../../../../utils/types.js"; import { LoginPage } from "../../../login/index.js"; import { NotFoundPageOrAdminCreate } from "../../../notfound/index.js"; import { ListPage } from "./ListPage.js"; import { RefundModal } from "./Table.js"; interface Props { onSelect: (id: string) => void; onCreate: () => void; } export default function OrderList({ onCreate, onSelect }: Props): VNode { const [filter, setFilter] = useState({ paid: false }); const [orderToBeRefunded, setOrderToBeRefunded] = useState< TalerMerchantApi.OrderHistoryEntry | undefined >(undefined); const setNewDate = (date?: AbsoluteTime): void => setFilter((prev) => ({ ...prev, date })); const result = useInstanceOrders(filter, (d) => setFilter({ ...filter, position: d }), ); const { lib } = useSessionContext(); const [notif, setNotif] = useState(undefined); const { i18n } = useTranslationContext(); const { state } = useSessionContext(); if (!result) return ; if (result instanceof TalerError) { return ; } if (result.type === "fail") { switch(result.case) { case HttpStatusCode.NotFound: { return ; } case HttpStatusCode.Unauthorized: { return } default: { assertUnreachable(result) } } } const isNotPaidActive = filter.paid === false ? "is-active" : ""; const isPaidActive = filter.paid === true && filter.wired === undefined ? "is-active" : ""; const isRefundedActive = filter.refunded === true ? "is-active" : ""; const isNotWiredActive = filter.wired === false && filter.paid === true ? "is-active" : ""; const isWiredActive = filter.wired === true ? "is-active" : ""; const isAllActive = filter.paid === undefined && filter.refunded === undefined && filter.wired === undefined ? "is-active" : ""; return (
{ const resp = await lib.instance.getOrderDetails(state.token, order); return resp.type === "ok"; }} onSelect={onSelect} description={i18n.str`jump to order with the given product ID`} placeholder={i18n.str`order id`} /> ({ ...o, id: o.order_id }))} onLoadMoreBefore={result.isFirstPage ? undefined : result.loadFirst} onLoadMoreAfter={result.isLastPage ? undefined : result.loadNext} onSelectOrder={(order) => onSelect(order.id)} onRefundOrder={(value) => setOrderToBeRefunded(value)} isAllActive={isAllActive} isNotWiredActive={isNotWiredActive} isWiredActive={isWiredActive} isPaidActive={isPaidActive} isNotPaidActive={isNotPaidActive} isRefundedActive={isRefundedActive} jumpToDate={filter.date} onSelectDate={setNewDate} onCopyURL={async (id) => { const resp = await lib.instance.getOrderDetails(state.token, id); if (resp.type === "ok") { if (resp.body.order_status === "unpaid") { copyToClipboard(resp.body.taler_pay_uri); } else { if (resp.body.contract_terms.fulfillment_url) { copyToClipboard(resp.body.contract_terms.fulfillment_url); } } copyToClipboard(resp.body.order_status); } }} onCreate={onCreate} onShowAll={() => setFilter({})} onShowNotPaid={() => setFilter({ paid: false })} onShowPaid={() => setFilter({ paid: true })} onShowRefunded={() => setFilter({ refunded: true })} onShowNotWired={() => setFilter({ wired: false, paid: true })} onShowWired={() => setFilter({ wired: true })} /> {orderToBeRefunded && ( setOrderToBeRefunded(undefined)} onConfirm={(value) => { lib.instance .addRefund(state.token, orderToBeRefunded.order_id, value) .then(() => setNotif({ message: i18n.str`refund created successfully`, type: "SUCCESS", }), ) .catch((error) => setNotif({ message: i18n.str`could not create the refund`, type: "ERROR", description: error.message, }), ) .then(() => setOrderToBeRefunded(undefined)); }} /> )}
); } interface RefundProps { id: string; onCancel: () => void; onConfirm: (m: TalerMerchantApi.RefundRequest) => void; } function RefundModalForTable({ id, onConfirm, onCancel }: RefundProps): VNode { const result = useOrderDetails(id); if (!result) return ; if (result instanceof TalerError) { return ; } if (result.type === "fail") { switch (result.case) { case HttpStatusCode.NotFound: { return ; } case HttpStatusCode.BadGateway: { return
Failed to obtain a response from the exchange
; } case HttpStatusCode.GatewayTimeout: { return (
The merchant's interaction with the exchange took too long
); } case HttpStatusCode.Unauthorized: { return } default: { assertUnreachable(result); } } } return ( ); } async function copyToClipboard(text: string): Promise { return navigator.clipboard.writeText(text); }