/* 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 */ /** * * @author Sebastian Javier Marchano (sebasjm) */ import { ErrorType, HttpError, useTranslationContext, } from "@gnu-taler/web-util/browser"; import { Fragment, 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 { InstanceOrderFilter, useInstanceOrders, useOrderAPI, useOrderDetails, } from "../../../../hooks/order.js"; import { Notification } from "../../../../utils/types.js"; import { ListPage } from "./ListPage.js"; import { RefundModal } from "./Table.js"; import { HttpStatusCode } from "@gnu-taler/taler-util"; import { JumpToElementById } from "../../../../components/form/JumpToElementById.js"; interface Props { onUnauthorized: () => VNode; onLoadError: (error: HttpError) => VNode; onNotFound: () => VNode; onSelect: (id: string) => void; onCreate: () => void; } export default function OrderList({ onUnauthorized, onLoadError, onCreate, onSelect, onNotFound, }: Props): VNode { const [filter, setFilter] = useState({ paid: "no" }); const [orderToBeRefunded, setOrderToBeRefunded] = useState< MerchantBackend.Orders.OrderHistoryEntry | undefined >(undefined); const setNewDate = (date?: Date): void => setFilter((prev) => ({ ...prev, date })); const result = useInstanceOrders(filter, setNewDate); const { refundOrder, getPaymentURL } = useOrderAPI(); const [notif, setNotif] = useState(undefined); const { i18n } = useTranslationContext(); if (result.loading) return ; 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); } const isNotPaidActive = filter.paid === "no" ? "is-active" : ""; const isPaidActive = filter.paid === "yes" && filter.wired === undefined ? "is-active" : ""; const isRefundedActive = filter.refunded === "yes" ? "is-active" : ""; const isNotWiredActive = filter.wired === "no" && filter.paid === "yes" ? "is-active" : ""; const isWiredActive = filter.wired === "yes" ? "is-active" : ""; const isAllActive = filter.paid === undefined && filter.refunded === undefined && filter.wired === undefined ? "is-active" : ""; return (
({ ...o, id: o.order_id }))} onLoadMoreBefore={result.loadMorePrev} hasMoreBefore={!result.isReachingStart} onLoadMoreAfter={result.loadMore} hasMoreAfter={!result.isReachingEnd} onSelectOrder={(order) => onSelect(order.id)} onRefundOrder={(value) => setOrderToBeRefunded(value)} isAllActive={isAllActive} isNotWiredActive={isNotWiredActive} isWiredActive={isWiredActive} isPaidActive={isPaidActive} isNotPaidActive={isNotPaidActive} isRefundedActive={isRefundedActive} jumpToDate={filter.date} onCopyURL={(id) => getPaymentURL(id).then((resp) => copyToClipboard(resp.data)) } onCreate={onCreate} onSelectDate={setNewDate} onShowAll={() => setFilter({})} onShowNotPaid={() => setFilter({ paid: "no" })} onShowPaid={() => setFilter({ paid: "yes" })} onShowRefunded={() => setFilter({ refunded: "yes" })} onShowNotWired={() => setFilter({ wired: "no", paid: "yes" })} onShowWired={() => setFilter({ wired: "yes" })} /> {orderToBeRefunded && ( setOrderToBeRefunded(undefined)} onConfirm={(value) => refundOrder(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)) } onLoadError={(error) => { setNotif({ message: i18n.str`could not create the refund`, type: "ERROR", description: error.message, }); setOrderToBeRefunded(undefined); return
; }} onUnauthorized={onUnauthorized} onNotFound={() => { setNotif({ message: i18n.str`could not get the order to refund`, type: "ERROR", // description: error.message }); setOrderToBeRefunded(undefined); return
; }} /> )}
); } interface RefundProps { id: string; onUnauthorized: () => VNode; onLoadError: (error: HttpError) => VNode; onNotFound: () => VNode; onCancel: () => void; onConfirm: (m: MerchantBackend.Orders.RefundRequest) => void; } function RefundModalForTable({ id, onUnauthorized, onLoadError, onNotFound, onConfirm, onCancel, }: RefundProps): VNode { const result = useOrderDetails(id); if (result.loading) return ; 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 ( ); } async function copyToClipboard(text: string): Promise { return navigator.clipboard.writeText(text); }