diff options
Diffstat (limited to 'packages/merchant-backoffice-ui/src/paths/instance')
23 files changed, 531 insertions, 649 deletions
diff --git a/packages/merchant-backoffice-ui/src/paths/instance/accounts/list/index.tsx b/packages/merchant-backoffice-ui/src/paths/instance/accounts/list/index.tsx index ab63d0d5f..1d5c523a4 100644 --- a/packages/merchant-backoffice-ui/src/paths/instance/accounts/list/index.tsx +++ b/packages/merchant-backoffice-ui/src/paths/instance/accounts/list/index.tsx @@ -19,37 +19,30 @@ * @author Sebastian Javier Marchano (sebasjm) */ -import { HttpStatusCode, TalerError, TalerErrorDetail, TalerMerchantApi } from "@gnu-taler/taler-util"; +import { HttpStatusCode, TalerError, TalerMerchantApi, assertUnreachable } from "@gnu-taler/taler-util"; import { - ErrorType, - HttpError, useMerchantApiContext, - useTranslationContext, + useTranslationContext } from "@gnu-taler/web-util/browser"; import { Fragment, VNode, h } from "preact"; import { useState } from "preact/hooks"; +import { ErrorLoadingMerchant } from "../../../../components/ErrorLoadingMerchant.js"; import { Loading } from "../../../../components/exception/loading.js"; import { NotificationCard } from "../../../../components/menu/index.js"; +import { useSessionContext } from "../../../../context/session.js"; import { useInstanceBankAccounts } from "../../../../hooks/bank.js"; import { Notification } from "../../../../utils/types.js"; +import { NotFoundPageOrAdminCreate } from "../../../notfound/index.js"; import { ListPage } from "./ListPage.js"; -import { useSessionContext } from "../../../../context/session.js"; -import { ErrorLoadingMerchant } from "../../../../components/ErrorLoadingMerchant.js"; interface Props { - onUnauthorized: () => VNode; - onLoadError: (error: HttpError<TalerErrorDetail>) => VNode; - onNotFound: () => VNode; onCreate: () => void; onSelect: (id: string) => void; } export default function ListOtpDevices({ - onUnauthorized, - onLoadError, onCreate, onSelect, - onNotFound, }: Props): VNode { const { i18n } = useTranslationContext(); const [notif, setNotif] = useState<Notification | undefined>(undefined); @@ -61,11 +54,21 @@ export default function ListOtpDevices({ if (result instanceof TalerError) { return <ErrorLoadingMerchant error={result} /> } + if (result.type === "fail") { + switch(result.case) { + case HttpStatusCode.NotFound: { + return <NotFoundPageOrAdminCreate /> + } + default: { + assertUnreachable(result.case) + } + } + } return ( <Fragment> <NotificationCard notification={notif} /> - {result.result.length < 1 && + {result.body.length < 1 && <NotificationCard notification={{ type: "WARN", message: i18n.str`You need to associate a bank account to receive revenue.`, @@ -73,17 +76,17 @@ export default function ListOtpDevices({ }} /> } <ListPage - devices={result.result} + devices={result.body} onLoadMoreBefore={ - result.isReachingStart ? result.loadMorePrev : undefined + result.isFirstPage ? undefined: result.loadFirst } - onLoadMoreAfter={result.isReachingEnd ? result.loadMore : undefined} + onLoadMoreAfter={result.isLastPage ? undefined : result.loadNext} onCreate={onCreate} onSelect={(e) => { onSelect(e.h_wire); }} onDelete={(e: TalerMerchantApi.BankAccountEntry) => { - return api.management.deleteAccount(state.token, e.h_wire) + return api.management.deleteBankAccount(state.token, e.h_wire) .then(() => setNotif({ message: i18n.str`bank account delete successfully`, diff --git a/packages/merchant-backoffice-ui/src/paths/instance/accounts/update/index.tsx b/packages/merchant-backoffice-ui/src/paths/instance/accounts/update/index.tsx index f83020ed1..f5b7436d4 100644 --- a/packages/merchant-backoffice-ui/src/paths/instance/accounts/update/index.tsx +++ b/packages/merchant-backoffice-ui/src/paths/instance/accounts/update/index.tsx @@ -19,39 +19,33 @@ * @author Sebastian Javier Marchano (sebasjm) */ -import { HttpStatusCode, TalerErrorDetail, TalerMerchantApi } from "@gnu-taler/taler-util"; +import { HttpStatusCode, TalerError, TalerMerchantApi, assertUnreachable } from "@gnu-taler/taler-util"; import { - ErrorType, - HttpError, useMerchantApiContext, - useTranslationContext, + useTranslationContext } from "@gnu-taler/web-util/browser"; import { Fragment, VNode, h } from "preact"; import { useState } from "preact/hooks"; +import { ErrorLoadingMerchant } from "../../../../components/ErrorLoadingMerchant.js"; import { Loading } from "../../../../components/exception/loading.js"; import { NotificationCard } from "../../../../components/menu/index.js"; +import { useSessionContext } from "../../../../context/session.js"; import { useBankAccountDetails } from "../../../../hooks/bank.js"; import { Notification } from "../../../../utils/types.js"; +import { NotFoundPageOrAdminCreate } from "../../../notfound/index.js"; import { UpdatePage } from "./UpdatePage.js"; -import { useSessionContext } from "../../../../context/session.js"; export type Entity = TalerMerchantApi.AccountPatchDetails & WithId; interface Props { onBack?: () => void; onConfirm: () => void; - onUnauthorized: () => VNode; - onNotFound: () => VNode; - onLoadError: (e: HttpError<TalerErrorDetail>) => VNode; bid: string; } export default function UpdateValidator({ bid, onConfirm, onBack, - onUnauthorized, - onNotFound, - onLoadError, }: Props): VNode { const { lib: api } = useMerchantApiContext(); const { state } = useSessionContext(); @@ -60,29 +54,29 @@ export default function UpdateValidator({ 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); + if (!result) return <Loading />; + if (result instanceof TalerError) { + return <ErrorLoadingMerchant error={result} />; + } + if (result.type === "fail") { + switch (result.case) { + case HttpStatusCode.NotFound: { + return <NotFoundPageOrAdminCreate />; + } + default: { + assertUnreachable(result.case); + } + } } return ( <Fragment> <NotificationCard notification={notif} /> <UpdatePage - account={{ ...result.data, id: bid }} + account={{ ...result.body, id: bid }} onBack={onBack} onUpdate={(data) => { - return api.management.updateAccount(state.token, bid, data) + return api.management.updateBankAccount(state.token, bid, data) .then(onConfirm) .catch((error) => { setNotif({ diff --git a/packages/merchant-backoffice-ui/src/paths/instance/orders/create/OrderCreatedSuccessfully.tsx b/packages/merchant-backoffice-ui/src/paths/instance/orders/create/OrderCreatedSuccessfully.tsx index be631c1e0..d7abc4fbe 100644 --- a/packages/merchant-backoffice-ui/src/paths/instance/orders/create/OrderCreatedSuccessfully.tsx +++ b/packages/merchant-backoffice-ui/src/paths/instance/orders/create/OrderCreatedSuccessfully.tsx @@ -13,52 +13,55 @@ 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 { ErrorType, HttpError, Loading, useTranslationContext } from "@gnu-taler/web-util/browser"; -import { h, VNode } from "preact"; -import { useEffect, useState } from "preact/hooks"; +import { HttpStatusCode, TalerError, assertUnreachable } from "@gnu-taler/taler-util"; +import { Loading, useTranslationContext } from "@gnu-taler/web-util/browser"; +import { VNode, h } from "preact"; +import { ErrorLoadingMerchant } from "../../../../components/ErrorLoadingMerchant.js"; import { CreatedSuccessfully } from "../../../../components/notifications/CreatedSuccessfully.js"; -import { Entity } from "./index.js"; import { useOrderDetails } from "../../../../hooks/order.js"; -import { HttpStatusCode, TalerErrorDetail } from "@gnu-taler/taler-util"; +import { NotFoundPageOrAdminCreate } from "../../../notfound/index.js"; +import { Entity } from "./index.js"; interface Props { entity: Entity; onConfirm: () => void; onCreateAnother?: () => void; - onUnauthorized: () => VNode; - onNotFound: () => VNode; - onLoadError: (error: HttpError<TalerErrorDetail>) => VNode; } export function OrderCreatedSuccessfully({ entity, onConfirm, onCreateAnother, - onLoadError, - onNotFound, - onUnauthorized, }: Props): VNode { const result = useOrderDetails(entity.response.order_id) 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); + if (!result) return <Loading /> + if (result instanceof TalerError) { + return <ErrorLoadingMerchant error={result} /> + } + if (result.type === "fail") { + switch(result.case) { + case HttpStatusCode.NotFound: { + return <NotFoundPageOrAdminCreate /> + } + case HttpStatusCode.BadGateway: { + return <div>Failed to obtain a response from the exchange</div>; + } + case HttpStatusCode.GatewayTimeout: { + return ( + <div>The merchant's interaction with the exchange took too long</div> + ); + } + default: { + assertUnreachable(result) + } + } } - const url = result.data.order_status === "unpaid" ? - result.data.taler_pay_uri : - result.data.contract_terms.fulfillment_url + const url = result.body.order_status === "unpaid" ? + result.body.taler_pay_uri : + result.body.contract_terms.fulfillment_url return ( <CreatedSuccessfully diff --git a/packages/merchant-backoffice-ui/src/paths/instance/orders/create/index.tsx b/packages/merchant-backoffice-ui/src/paths/instance/orders/create/index.tsx index 54d8c7b47..e40e766dd 100644 --- a/packages/merchant-backoffice-ui/src/paths/instance/orders/create/index.tsx +++ b/packages/merchant-backoffice-ui/src/paths/instance/orders/create/index.tsx @@ -19,18 +19,19 @@ * @author Sebastian Javier Marchano (sebasjm) */ -import { HttpStatusCode, TalerError, TalerErrorDetail, TalerMerchantApi } from "@gnu-taler/taler-util"; -import { ErrorType, HttpError, useMerchantApiContext } from "@gnu-taler/web-util/browser"; +import { HttpStatusCode, TalerError, TalerMerchantApi, assertUnreachable } from "@gnu-taler/taler-util"; +import { useMerchantApiContext } from "@gnu-taler/web-util/browser"; import { Fragment, VNode, h } from "preact"; import { useState } from "preact/hooks"; +import { ErrorLoadingMerchant } from "../../../../components/ErrorLoadingMerchant.js"; import { Loading } from "../../../../components/exception/loading.js"; import { NotificationCard } from "../../../../components/menu/index.js"; +import { useSessionContext } from "../../../../context/session.js"; import { useInstanceDetails } from "../../../../hooks/instance.js"; import { useInstanceProducts } from "../../../../hooks/product.js"; import { Notification } from "../../../../utils/types.js"; import { CreatePage } from "./CreatePage.js"; -import { useSessionContext } from "../../../../context/session.js"; -import { ErrorLoadingMerchant } from "../../../../components/ErrorLoadingMerchant.js"; +import { NotFoundPageOrAdminCreate } from "../../../notfound/index.js"; export type Entity = { request: TalerMerchantApi.PostOrderRequest; @@ -39,16 +40,10 @@ export type Entity = { interface Props { onBack?: () => void; onConfirm: (id: string) => void; - onUnauthorized: () => VNode; - onNotFound: () => VNode; - onLoadError: (error: HttpError<TalerErrorDetail>) => VNode; } export default function OrderCreate({ onConfirm, onBack, - onLoadError, - onNotFound, - onUnauthorized, }: Props): VNode { const { lib } = useMerchantApiContext(); const [notif, setNotif] = useState<Notification | undefined>(undefined); @@ -60,36 +55,19 @@ export default function OrderCreate({ if (detailsResult instanceof TalerError) { return <ErrorLoadingMerchant error={detailsResult} /> } - - // if (detailsResult.loading) return <Loading />; - if (inventoryResult.loading) return <Loading />; - - // if (!detailsResult.ok) { - // if ( - // detailsResult.type === ErrorType.CLIENT && - // detailsResult.status === HttpStatusCode.Unauthorized - // ) - // return onUnauthorized(); - // if ( - // detailsResult.type === ErrorType.CLIENT && - // detailsResult.status === HttpStatusCode.NotFound - // ) - // return onNotFound(); - // return onLoadError(detailsResult); - // } - - if (!inventoryResult.ok) { - if ( - inventoryResult.type === ErrorType.CLIENT && - inventoryResult.status === HttpStatusCode.Unauthorized - ) - return onUnauthorized(); - if ( - inventoryResult.type === ErrorType.CLIENT && - inventoryResult.status === HttpStatusCode.NotFound - ) - return onNotFound(); - return onLoadError(inventoryResult); + if (!inventoryResult) return <Loading /> + if (inventoryResult instanceof TalerError) { + return <ErrorLoadingMerchant error={inventoryResult} /> + } + if (inventoryResult.type === "fail") { + switch (inventoryResult.case) { + case HttpStatusCode.NotFound: { + return <NotFoundPageOrAdminCreate />; + } + default: { + assertUnreachable(inventoryResult.case); + } + } } return ( @@ -119,7 +97,7 @@ export default function OrderCreate({ }); }} instanceConfig={detailsResult.body} - instanceInventory={inventoryResult.data} + instanceInventory={inventoryResult.body} /> </Fragment> ); diff --git a/packages/merchant-backoffice-ui/src/paths/instance/orders/details/index.tsx b/packages/merchant-backoffice-ui/src/paths/instance/orders/details/index.tsx index c0c4862a1..1c8ceb90e 100644 --- a/packages/merchant-backoffice-ui/src/paths/instance/orders/details/index.tsx +++ b/packages/merchant-backoffice-ui/src/paths/instance/orders/details/index.tsx @@ -13,58 +13,60 @@ 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 { HttpStatusCode, TalerErrorDetail } from "@gnu-taler/taler-util"; import { - ErrorType, - HttpError, + HttpStatusCode, + TalerError, + assertUnreachable, +} from "@gnu-taler/taler-util"; +import { useMerchantApiContext, useTranslationContext, } from "@gnu-taler/web-util/browser"; import { Fragment, VNode, h } from "preact"; import { useState } from "preact/hooks"; +import { ErrorLoadingMerchant } from "../../../../components/ErrorLoadingMerchant.js"; import { Loading } from "../../../../components/exception/loading.js"; import { NotificationCard } from "../../../../components/menu/index.js"; +import { useSessionContext } from "../../../../context/session.js"; import { useOrderDetails } from "../../../../hooks/order.js"; import { Notification } from "../../../../utils/types.js"; +import { NotFoundPageOrAdminCreate } from "../../../notfound/index.js"; import { DetailPage } from "./DetailPage.js"; -import { useSessionContext } from "../../../../context/session.js"; export interface Props { oid: string; - onBack: () => void; - onUnauthorized: () => VNode; - onNotFound: () => VNode; - onLoadError: (error: HttpError<TalerErrorDetail>) => VNode; } -export default function Update({ - oid, - onBack, - onLoadError, - onNotFound, - onUnauthorized, -}: Props): VNode { +export default function Update({ oid, onBack }: Props): VNode { const result = useOrderDetails(oid); const [notif, setNotif] = useState<Notification | undefined>(undefined); - const { lib: api } = useMerchantApiContext() + const { lib: api } = useMerchantApiContext(); const { state } = useSessionContext(); 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); + if (!result) return <Loading />; + if (result instanceof TalerError) { + return <ErrorLoadingMerchant error={result} />; + } + if (result.type === "fail") { + switch (result.case) { + case HttpStatusCode.NotFound: { + return <NotFoundPageOrAdminCreate />; + } + case HttpStatusCode.BadGateway: { + return <div>Failed to obtain a response from the exchange</div>; + } + case HttpStatusCode.GatewayTimeout: { + return ( + <div>The merchant's interaction with the exchange took too long</div> + ); + } + default: { + assertUnreachable(result); + } + } } return ( @@ -78,7 +80,8 @@ export default function Update({ if (state.status !== "loggedIn") { return; } - api.management.addRefund(state.token, id, value) + api.management + .addRefund(state.token, id, value) .then(() => setNotif({ message: i18n.str`refund created successfully`, @@ -91,10 +94,9 @@ export default function Update({ type: "ERROR", description: error.message, }), - ) - } - } - selected={result.data} + ); + }} + selected={result.body} /> </Fragment> ); diff --git a/packages/merchant-backoffice-ui/src/paths/instance/orders/list/ListPage.tsx b/packages/merchant-backoffice-ui/src/paths/instance/orders/list/ListPage.tsx index 7b88985dc..12762c3b3 100644 --- a/packages/merchant-backoffice-ui/src/paths/instance/orders/list/ListPage.tsx +++ b/packages/merchant-backoffice-ui/src/paths/instance/orders/list/ListPage.tsx @@ -19,7 +19,7 @@ * @author Sebastian Javier Marchano (sebasjm) */ -import { TalerMerchantApi } from "@gnu-taler/taler-util"; +import { AbsoluteTime, TalerMerchantApi } from "@gnu-taler/taler-util"; import { useTranslationContext } from "@gnu-taler/web-util/browser"; import { format } from "date-fns"; import { Fragment, VNode, h } from "preact"; @@ -43,8 +43,8 @@ export interface ListPageProps { isNotWiredActive: string; isWiredActive: string; - jumpToDate?: Date; - onSelectDate: (date?: Date) => void; + jumpToDate?: AbsoluteTime; + onSelectDate: (date?: AbsoluteTime) => void; orders: (TalerMerchantApi.OrderHistoryEntry & WithId)[]; onLoadMoreBefore?: () => void; @@ -177,7 +177,7 @@ export function ListPage({ class="input" type="text" readonly - value={!jumpToDate ? "" : format(jumpToDate, dateFormatForSettings(settings))} + value={!jumpToDate || jumpToDate.t_ms === "never" ? "" : format(jumpToDate.t_ms, dateFormatForSettings(settings))} placeholder={i18n.str`date (${dateFormatForSettings(settings)})`} onClick={() => { setPickDate(true); @@ -207,7 +207,9 @@ export function ListPage({ <DatePicker opened={pickDate} closeFunction={() => setPickDate(false)} - dateReceiver={onSelectDate} + dateReceiver={(d) => { + onSelectDate(AbsoluteTime.fromMilliseconds(d.getTime())) + }} /> <CardTable diff --git a/packages/merchant-backoffice-ui/src/paths/instance/orders/list/index.tsx b/packages/merchant-backoffice-ui/src/paths/instance/orders/list/index.tsx index a50f02a2d..7a3fb2d22 100644 --- a/packages/merchant-backoffice-ui/src/paths/instance/orders/list/index.tsx +++ b/packages/merchant-backoffice-ui/src/paths/instance/orders/list/index.tsx @@ -19,83 +19,84 @@ * @author Sebastian Javier Marchano (sebasjm) */ -import { HttpStatusCode, TalerErrorDetail, TalerMerchantApi, stringifyPayUri } from "@gnu-taler/taler-util"; import { - ErrorType, - HttpError, + AbsoluteTime, + HttpStatusCode, + TalerError, + TalerMerchantApi, + assertUnreachable, +} from "@gnu-taler/taler-util"; +import { useMerchantApiContext, useTranslationContext, } from "@gnu-taler/web-util/browser"; -import { Fragment, VNode, h } from "preact"; +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 { NotFoundPageOrAdminCreate } from "../../../notfound/index.js"; import { ListPage } from "./ListPage.js"; import { RefundModal } from "./Table.js"; -import { useSessionContext } from "../../../../context/session.js"; interface Props { - onUnauthorized: () => VNode; - onLoadError: (error: HttpError<TalerErrorDetail>) => VNode; - onNotFound: () => VNode; onSelect: (id: string) => void; onCreate: () => void; } -export default function OrderList({ - onUnauthorized, - onLoadError, - onCreate, - onSelect, - onNotFound, -}: Props): VNode { - const [filter, setFilter] = useState<InstanceOrderFilter>({ paid: "no" }); +export default function OrderList({ onCreate, onSelect }: Props): VNode { + const [filter, setFilter] = useState<InstanceOrderFilter>({ paid: false }); const [orderToBeRefunded, setOrderToBeRefunded] = useState< TalerMerchantApi.OrderHistoryEntry | undefined >(undefined); - const setNewDate = (date?: Date): void => + const setNewDate = (date?: AbsoluteTime): void => setFilter((prev) => ({ ...prev, date })); - const result = useInstanceOrders(filter, setNewDate); + const result = useInstanceOrders(filter, (d) => + setFilter({ ...filter, position: d }), + ); const { lib } = useMerchantApiContext(); const [notif, setNotif] = useState<Notification | undefined>(undefined); const { i18n } = useTranslationContext(); - const { state } = useSessionContext() - - 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); - } + const { state } = useSessionContext(); - 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" : ""; + if (!result) return <Loading />; + if (result instanceof TalerError) { + return <ErrorLoadingMerchant error={result} />; + } + // if (result.type === "fail") { + // switch (result.case) { + // case HttpStatusCode.NotFound: { + // return <NotFoundPageOrAdminCreate />; + // } + // default: { + // assertUnreachable(result.case); + // } + // } + // } + + 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 + filter.refunded === undefined && + filter.wired === undefined ? "is-active" : ""; @@ -105,11 +106,8 @@ export default function OrderList({ <JumpToElementById testIfExist={async (order) => { - if (state.status !== "loggedIn") { - return false; - } - const resp = await lib.management.getOrder(state.token, order) - return resp.type === "ok" + const resp = await lib.management.getOrderDetails(state.token, order); + return resp.type === "ok"; }} onSelect={onSelect} description={i18n.str`jump to order with the given product ID`} @@ -117,11 +115,11 @@ export default function OrderList({ /> <ListPage - orders={result.data.orders.map((o) => ({ ...o, id: o.order_id }))} - onLoadMoreBefore={result.loadMorePrev} - hasMoreBefore={!result.isReachingStart} - onLoadMoreAfter={result.loadMore} - hasMoreAfter={!result.isReachingEnd} + orders={result.body.map((o) => ({ ...o, id: o.order_id }))} + onLoadMoreBefore={result.loadFirst} + hasMoreBefore={!result.isFirstPage} + onLoadMoreAfter={result.loadNext} + hasMoreAfter={!result.isLastPage} onSelectOrder={(order) => onSelect(order.id)} onRefundOrder={(value) => setOrderToBeRefunded(value)} isAllActive={isAllActive} @@ -131,30 +129,27 @@ export default function OrderList({ isNotPaidActive={isNotPaidActive} isRefundedActive={isRefundedActive} jumpToDate={filter.date} + onSelectDate={setNewDate} onCopyURL={async (id) => { - if (state.status !== "loggedIn") { - return false; - } - const resp = await lib.management.getOrder(state.token, id) + const resp = await lib.management.getOrderDetails(state.token, id); if (resp.type === "ok") { if (resp.body.order_status === "unpaid") { - copyToClipboard(resp.body.taler_pay_uri) + copyToClipboard(resp.body.taler_pay_uri); } else { if (resp.body.contract_terms.fulfillment_url) { - copyToClipboard(resp.body.contract_terms.fulfillment_url) + copyToClipboard(resp.body.contract_terms.fulfillment_url); } } - copyToClipboard(resp.body.order_status) + copyToClipboard(resp.body.order_status); } }} 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" })} + onShowNotPaid={() => setFilter({ paid: false })} + onShowPaid={() => setFilter({ paid: true })} + onShowRefunded={() => setFilter({ refunded: true })} + onShowNotWired={() => setFilter({ wired: false, paid: true })} + onShowWired={() => setFilter({ wired: true })} /> {orderToBeRefunded && ( @@ -162,7 +157,8 @@ export default function OrderList({ id={orderToBeRefunded.order_id} onCancel={() => setOrderToBeRefunded(undefined)} onConfirm={(value) => { - lib.management.addRefund(state.token, orderToBeRefunded.order_id, value) + lib.management + .addRefund(state.token, orderToBeRefunded.order_id, value) .then(() => setNotif({ message: i18n.str`refund created successfully`, @@ -176,27 +172,7 @@ export default function OrderList({ 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 <div />; - }} - onUnauthorized={onUnauthorized} - onNotFound={() => { - setNotif({ - message: i18n.str`could not get the order to refund`, - type: "ERROR", - // description: error.message - }); - setOrderToBeRefunded(undefined); - return <div />; + .then(() => setOrderToBeRefunded(undefined)); }} /> )} @@ -206,41 +182,39 @@ export default function OrderList({ interface RefundProps { id: string; - onUnauthorized: () => VNode; - onLoadError: (error: HttpError<TalerErrorDetail>) => VNode; - onNotFound: () => VNode; onCancel: () => void; onConfirm: (m: TalerMerchantApi.RefundRequest) => void; } -function RefundModalForTable({ - id, - onUnauthorized, - onLoadError, - onNotFound, - onConfirm, - onCancel, -}: RefundProps): VNode { +function RefundModalForTable({ id, onConfirm, onCancel }: RefundProps): VNode { const result = useOrderDetails(id); - 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); + if (!result) return <Loading />; + if (result instanceof TalerError) { + return <ErrorLoadingMerchant error={result} />; + } + if (result.type === "fail") { + switch (result.case) { + case HttpStatusCode.NotFound: { + return <NotFoundPageOrAdminCreate />; + } + case HttpStatusCode.BadGateway: { + return <div>Failed to obtain a response from the exchange</div>; + } + case HttpStatusCode.GatewayTimeout: { + return ( + <div>The merchant's interaction with the exchange took too long</div> + ); + } + default: { + assertUnreachable(result); + } + } } return ( <RefundModal - order={result.data} + order={result.body} onCancel={onCancel} onConfirm={onConfirm} /> diff --git a/packages/merchant-backoffice-ui/src/paths/instance/otp_devices/list/index.tsx b/packages/merchant-backoffice-ui/src/paths/instance/otp_devices/list/index.tsx index 06a9f4a55..c240b99cb 100644 --- a/packages/merchant-backoffice-ui/src/paths/instance/otp_devices/list/index.tsx +++ b/packages/merchant-backoffice-ui/src/paths/instance/otp_devices/list/index.tsx @@ -19,57 +19,53 @@ * @author Sebastian Javier Marchano (sebasjm) */ -import { HttpStatusCode, TalerErrorDetail, TalerMerchantApi } from "@gnu-taler/taler-util"; import { - ErrorType, - HttpError, + HttpStatusCode, + TalerError, + TalerMerchantApi, + assertUnreachable +} from "@gnu-taler/taler-util"; +import { useMerchantApiContext, - useTranslationContext, + useTranslationContext } from "@gnu-taler/web-util/browser"; import { Fragment, VNode, h } from "preact"; import { useState } from "preact/hooks"; +import { ErrorLoadingMerchant } from "../../../../components/ErrorLoadingMerchant.js"; import { Loading } from "../../../../components/exception/loading.js"; import { NotificationCard } from "../../../../components/menu/index.js"; import { useSessionContext } from "../../../../context/session.js"; import { useInstanceOtpDevices } from "../../../../hooks/otp.js"; import { Notification } from "../../../../utils/types.js"; +import { NotFoundPageOrAdminCreate } from "../../../notfound/index.js"; import { ListPage } from "./ListPage.js"; interface Props { - onUnauthorized: () => VNode; - onLoadError: (error: HttpError<TalerErrorDetail>) => VNode; - onNotFound: () => VNode; onCreate: () => void; onSelect: (id: string) => void; } -export default function ListOtpDevices({ - onUnauthorized, - onLoadError, - onCreate, - onSelect, - onNotFound, -}: Props): VNode { - const [position, setPosition] = useState<string | undefined>(undefined); +export default function ListOtpDevices({ onCreate, onSelect }: Props): VNode { + // const [position, setPosition] = useState<string | undefined>(undefined); const { i18n } = useTranslationContext(); const [notif, setNotif] = useState<Notification | undefined>(undefined); const { lib } = useMerchantApiContext(); const { state } = useSessionContext(); - const result = useInstanceOtpDevices({ position }, (id) => setPosition(id)); + const result = useInstanceOtpDevices(); - 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); + if (!result) return <Loading />; + if (result instanceof TalerError) { + return <ErrorLoadingMerchant error={result} />; + } + if (result.type === "fail") { + switch (result.case) { + case HttpStatusCode.NotFound: { + return <NotFoundPageOrAdminCreate />; + } + default: { + assertUnreachable(result.case); + } + } } return ( @@ -77,17 +73,16 @@ export default function ListOtpDevices({ <NotificationCard notification={notif} /> <ListPage - devices={result.data.otp_devices} - onLoadMoreBefore={ - result.isReachingStart ? result.loadMorePrev : undefined - } - onLoadMoreAfter={result.isReachingEnd ? result.loadMore : undefined} + devices={result.body} + onLoadMoreBefore={result.isFirstPage ? undefined : result.loadFirst} + onLoadMoreAfter={result.isLastPage ? undefined : result.loadNext} onCreate={onCreate} onSelect={(e) => { onSelect(e.otp_device_id); }} onDelete={(e: TalerMerchantApi.OtpDeviceEntry) => { - return lib.management.deleteOtpDevice(state.token, e.otp_device_id) + return lib.management + .deleteOtpDevice(state.token, e.otp_device_id) .then(() => setNotif({ message: i18n.str`validator delete successfully`, @@ -100,7 +95,7 @@ export default function ListOtpDevices({ type: "ERROR", description: error.message, }), - ) + ); }} /> </Fragment> diff --git a/packages/merchant-backoffice-ui/src/paths/instance/otp_devices/update/index.tsx b/packages/merchant-backoffice-ui/src/paths/instance/otp_devices/update/index.tsx index 6b9970eab..43adbe253 100644 --- a/packages/merchant-backoffice-ui/src/paths/instance/otp_devices/update/index.tsx +++ b/packages/merchant-backoffice-ui/src/paths/instance/otp_devices/update/index.tsx @@ -19,20 +19,25 @@ * @author Sebastian Javier Marchano (sebasjm) */ -import { HttpStatusCode, TalerErrorDetail, TalerMerchantApi } from "@gnu-taler/taler-util"; import { - ErrorType, - HttpError, + HttpStatusCode, + TalerError, + TalerMerchantApi, + assertUnreachable +} from "@gnu-taler/taler-util"; +import { useMerchantApiContext, - useTranslationContext, + useTranslationContext } from "@gnu-taler/web-util/browser"; import { Fragment, VNode, h } from "preact"; import { useState } from "preact/hooks"; +import { ErrorLoadingMerchant } from "../../../../components/ErrorLoadingMerchant.js"; import { Loading } from "../../../../components/exception/loading.js"; import { NotificationCard } from "../../../../components/menu/index.js"; import { useSessionContext } from "../../../../context/session.js"; import { useOtpDeviceDetails } from "../../../../hooks/otp.js"; import { Notification } from "../../../../utils/types.js"; +import { NotFoundPageOrAdminCreate } from "../../../notfound/index.js"; import { CreatedSuccessfully } from "../create/CreatedSuccessfully.js"; import { UpdatePage } from "./UpdatePage.js"; @@ -41,44 +46,39 @@ export type Entity = TalerMerchantApi.OtpDevicePatchDetails & WithId; interface Props { onBack?: () => void; onConfirm: () => void; - onUnauthorized: () => VNode; - onNotFound: () => VNode; - onLoadError: (e: HttpError<TalerErrorDetail>) => VNode; vid: string; } export default function UpdateValidator({ vid, onConfirm, onBack, - onUnauthorized, - onNotFound, - onLoadError, }: Props): VNode { const result = useOtpDeviceDetails(vid); const [notif, setNotif] = useState<Notification | undefined>(undefined); - const [keyUpdated, setKeyUpdated] = useState<TalerMerchantApi.OtpDeviceAddDetails | null>(null) + const [keyUpdated, setKeyUpdated] = + useState<TalerMerchantApi.OtpDeviceAddDetails | null>(null); const { lib } = useMerchantApiContext(); const { state } = useSessionContext(); 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); + if (!result) return <Loading />; + if (result instanceof TalerError) { + return <ErrorLoadingMerchant error={result} />; + } + if (result.type === "fail") { + switch (result.case) { + case HttpStatusCode.NotFound: { + return <NotFoundPageOrAdminCreate />; + } + default: { + assertUnreachable(result.case); + } + } } if (keyUpdated) { - return <CreatedSuccessfully entity={keyUpdated} onConfirm={onConfirm} /> + return <CreatedSuccessfully entity={keyUpdated} onConfirm={onConfirm} />; } return ( @@ -87,25 +87,47 @@ export default function UpdateValidator({ <UpdatePage device={{ id: vid, - otp_algorithm: result.data.otp_algorithm, - otp_device_description: result.data.device_description, + otp_algorithm: result.body.otp_algorithm, + otp_device_description: result.body.device_description, otp_key: "", - otp_ctr: result.data.otp_ctr + otp_ctr: result.body.otp_ctr, }} onBack={onBack} onUpdate={async (newInfo) => { - return lib.management.updateOtpDevice(state.token, vid, newInfo) + return lib.management + .updateOtpDevice(state.token, vid, newInfo) .then((d) => { - if (newInfo.otp_key) { - setKeyUpdated({ - otp_algorithm: newInfo.otp_algorithm, - otp_device_description: newInfo.otp_device_description, - otp_device_id: newInfo.id, - otp_key: newInfo.otp_key, - otp_ctr: newInfo.otp_ctr, - }) + if (d.type === "ok") { + if (newInfo.otp_key) { + setKeyUpdated({ + otp_algorithm: newInfo.otp_algorithm, + otp_device_description: newInfo.otp_device_description, + otp_device_id: newInfo.id, + otp_key: newInfo.otp_key, + otp_ctr: newInfo.otp_ctr, + }); + } else { + onConfirm(); + } } else { - onConfirm() + switch(d.case) { + case HttpStatusCode.NotFound: { + setNotif({ + message: i18n.str`Could not update template`, + type: "ERROR", + description: i18n.str`Template id is unknown`, + }); + break; + } + case HttpStatusCode.Conflict: { + setNotif({ + message: i18n.str`Could not update template`, + type: "ERROR", + description: i18n.str`The provided information is inconsistent with the current state of the template`, + }); + break; + } + } } }) .catch((error) => { diff --git a/packages/merchant-backoffice-ui/src/paths/instance/products/list/index.tsx b/packages/merchant-backoffice-ui/src/paths/instance/products/list/index.tsx index ff54c487a..eb38f25d9 100644 --- a/packages/merchant-backoffice-ui/src/paths/instance/products/list/index.tsx +++ b/packages/merchant-backoffice-ui/src/paths/instance/products/list/index.tsx @@ -19,15 +19,14 @@ * @author Sebastian Javier Marchano (sebasjm) */ -import { HttpStatusCode, TalerErrorDetail, TalerMerchantApi } from "@gnu-taler/taler-util"; +import { HttpStatusCode, TalerError, TalerMerchantApi, assertUnreachable } from "@gnu-taler/taler-util"; import { - ErrorType, - HttpError, useMerchantApiContext, - useTranslationContext, + 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"; @@ -37,21 +36,16 @@ import { useInstanceProducts } from "../../../../hooks/product.js"; import { Notification } from "../../../../utils/types.js"; +import { NotFoundPageOrAdminCreate } from "../../../notfound/index.js"; import { CardTable } from "./Table.js"; interface Props { - onUnauthorized: () => VNode; - onNotFound: () => VNode; onCreate: () => void; onSelect: (id: string) => void; - onLoadError: (e: HttpError<TalerErrorDetail>) => VNode; } export default function ProductList({ - onUnauthorized, - onLoadError, onCreate, onSelect, - onNotFound, }: Props): VNode { const result = useInstanceProducts(); const { lib } = useMerchantApiContext(); @@ -62,19 +56,19 @@ export default function ProductList({ 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); + if (!result) return <Loading />; + if (result instanceof TalerError) { + return <ErrorLoadingMerchant error={result} />; + } + if (result.type === "fail") { + switch (result.case) { + case HttpStatusCode.NotFound: { + return <NotFoundPageOrAdminCreate />; + } + default: { + assertUnreachable(result.case); + } + } } return ( @@ -92,7 +86,7 @@ export default function ProductList({ /> <CardTable - instances={result.data} + instances={result.body} onCreate={onCreate} onUpdate={async (id, prod) => { try { diff --git a/packages/merchant-backoffice-ui/src/paths/instance/products/update/index.tsx b/packages/merchant-backoffice-ui/src/paths/instance/products/update/index.tsx index b9470ddac..9de632218 100644 --- a/packages/merchant-backoffice-ui/src/paths/instance/products/update/index.tsx +++ b/packages/merchant-backoffice-ui/src/paths/instance/products/update/index.tsx @@ -19,38 +19,32 @@ * @author Sebastian Javier Marchano (sebasjm) */ -import { HttpStatusCode, TalerErrorDetail, TalerMerchantApi } from "@gnu-taler/taler-util"; +import { HttpStatusCode, TalerError, TalerMerchantApi, assertUnreachable } from "@gnu-taler/taler-util"; import { - ErrorType, - HttpError, useMerchantApiContext, - useTranslationContext, + useTranslationContext } from "@gnu-taler/web-util/browser"; import { Fragment, VNode, h } from "preact"; import { useState } from "preact/hooks"; +import { ErrorLoadingMerchant } from "../../../../components/ErrorLoadingMerchant.js"; import { Loading } from "../../../../components/exception/loading.js"; import { NotificationCard } from "../../../../components/menu/index.js"; +import { useSessionContext } from "../../../../context/session.js"; import { useProductDetails } from "../../../../hooks/product.js"; import { Notification } from "../../../../utils/types.js"; +import { NotFoundPageOrAdminCreate } from "../../../notfound/index.js"; import { UpdatePage } from "./UpdatePage.js"; -import { useSessionContext } from "../../../../context/session.js"; export type Entity = TalerMerchantApi.ProductAddDetail; interface Props { onBack?: () => void; onConfirm: () => void; - onUnauthorized: () => VNode; - onNotFound: () => VNode; - onLoadError: (e: HttpError<TalerErrorDetail>) => VNode; pid: string; } export default function UpdateProduct({ pid, onConfirm, onBack, - onUnauthorized, - onNotFound, - onLoadError, }: Props): VNode { const result = useProductDetails(pid); const [notif, setNotif] = useState<Notification | undefined>(undefined); @@ -59,26 +53,26 @@ export default function UpdateProduct({ 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); + if (!result) return <Loading />; + if (result instanceof TalerError) { + return <ErrorLoadingMerchant error={result} />; + } + if (result.type === "fail") { + switch (result.case) { + case HttpStatusCode.NotFound: { + return <NotFoundPageOrAdminCreate />; + } + default: { + assertUnreachable(result.case); + } + } } return ( <Fragment> <NotificationCard notification={notif} /> <UpdatePage - product={{ ...result.data, product_id: pid }} + product={{ ...result.body, product_id: pid }} onBack={onBack} onUpdate={(data) => { return lib.management.updateProduct(state.token, pid, data) diff --git a/packages/merchant-backoffice-ui/src/paths/instance/templates/create/CreatePage.tsx b/packages/merchant-backoffice-ui/src/paths/instance/templates/create/CreatePage.tsx index 31e525226..82c0d0e53 100644 --- a/packages/merchant-backoffice-ui/src/paths/instance/templates/create/CreatePage.tsx +++ b/packages/merchant-backoffice-ui/src/paths/instance/templates/create/CreatePage.tsx @@ -23,6 +23,7 @@ import { AmountString, Amounts, Duration, + TalerError, TalerMerchantApi, assertUnreachable, } from "@gnu-taler/taler-util"; @@ -126,7 +127,7 @@ export function CreatePage({ onCreate, onBack }: Props): VNode { }; const hasErrors = Object.keys(errors).some( - (k) => (errors as any)[k] !== undefined, + (k) => (errors as Record<string,unknown>)[k] !== undefined, ); const submitForm = () => { @@ -185,7 +186,7 @@ export function CreatePage({ onCreate, onBack }: Props): VNode { // return onCreate(state); } }; - const deviceList = !devices.ok ? [] : devices.data.otp_devices; + const deviceList = !devices || devices instanceof TalerError || devices.type === "fail" ? [] : devices.body; return ( <div> diff --git a/packages/merchant-backoffice-ui/src/paths/instance/templates/list/index.tsx b/packages/merchant-backoffice-ui/src/paths/instance/templates/list/index.tsx index adbfb93cd..5a8be71b0 100644 --- a/packages/merchant-backoffice-ui/src/paths/instance/templates/list/index.tsx +++ b/packages/merchant-backoffice-ui/src/paths/instance/templates/list/index.tsx @@ -19,15 +19,14 @@ * @author Sebastian Javier Marchano (sebasjm) */ -import { HttpStatusCode, TalerErrorDetail, TalerMerchantApi } from "@gnu-taler/taler-util"; +import { HttpStatusCode, TalerError, TalerMerchantApi, assertUnreachable } from "@gnu-taler/taler-util"; import { - ErrorType, - HttpError, useMerchantApiContext, - useTranslationContext, + useTranslationContext } from "@gnu-taler/web-util/browser"; -import { Fragment, VNode, h } from "preact"; +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"; @@ -37,12 +36,10 @@ import { useInstanceTemplates } from "../../../../hooks/templates.js"; import { Notification } from "../../../../utils/types.js"; +import { NotFoundPageOrAdminCreate } from "../../../notfound/index.js"; import { ListPage } from "./ListPage.js"; interface Props { - onUnauthorized: () => VNode; - onLoadError: (error: HttpError<TalerErrorDetail>) => VNode; - onNotFound: () => VNode; onCreate: () => void; onSelect: (id: string) => void; onNewOrder: (id: string) => void; @@ -50,36 +47,32 @@ interface Props { } export default function ListTemplates({ - onUnauthorized, - onLoadError, onCreate, onQR, onSelect, onNewOrder, - onNotFound, }: Props): VNode { - const [position, setPosition] = useState<string | undefined>(undefined); const { i18n } = useTranslationContext(); const [notif, setNotif] = useState<Notification | undefined>(undefined); const { lib } = useMerchantApiContext(); - const result = useInstanceTemplates({ position }, (id) => setPosition(id)); + const result = useInstanceTemplates(); const [deleting, setDeleting] = useState<TalerMerchantApi.TemplateEntry | null>(null); const { state } = useSessionContext(); - 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); + if (!result) return <Loading /> + if (result instanceof TalerError) { + return <ErrorLoadingMerchant error={result} /> + } + if (result.type === "fail") { + switch(result.case) { + case HttpStatusCode.NotFound: { + return <NotFoundPageOrAdminCreate /> + } + default: { + assertUnreachable(result.case) + } + } } return ( @@ -88,7 +81,7 @@ export default function ListTemplates({ <JumpToElementById testIfExist={async (id) => { - const resp = await lib.management.getTemplate(state.token, id) + const resp = await lib.management.getTemplateDetails(state.token, id) return resp.type === "ok" }} onSelect={onSelect} @@ -97,11 +90,11 @@ export default function ListTemplates({ /> <ListPage - templates={result.data.templates} + templates={result.body} onLoadMoreBefore={ - result.isReachingStart ? result.loadMorePrev : undefined + result.isFirstPage ? undefined: result.loadFirst } - onLoadMoreAfter={result.isReachingEnd ? result.loadMore : undefined} + onLoadMoreAfter={result.isLastPage ? undefined : result.loadNext} onCreate={onCreate} onSelect={(e) => { onSelect(e.template_id); diff --git a/packages/merchant-backoffice-ui/src/paths/instance/templates/qr/index.tsx b/packages/merchant-backoffice-ui/src/paths/instance/templates/qr/index.tsx index 37f0e5c74..3464fb04e 100644 --- a/packages/merchant-backoffice-ui/src/paths/instance/templates/qr/index.tsx +++ b/packages/merchant-backoffice-ui/src/paths/instance/templates/qr/index.tsx @@ -19,59 +19,44 @@ * @author Sebastian Javier Marchano (sebasjm) */ -import { HttpStatusCode, TalerErrorDetail, TalerMerchantApi } from "@gnu-taler/taler-util"; -import { - ErrorType, - HttpError -} from "@gnu-taler/web-util/browser"; -import { Fragment, VNode, h } from "preact"; -import { useState } from "preact/hooks"; +import { HttpStatusCode, TalerError, TalerMerchantApi, assertUnreachable } from "@gnu-taler/taler-util"; +import { VNode, h } from "preact"; +import { ErrorLoadingMerchant } from "../../../../components/ErrorLoadingMerchant.js"; import { Loading } from "../../../../components/exception/loading.js"; -import { NotificationCard } from "../../../../components/menu/index.js"; import { useTemplateDetails } from "../../../../hooks/templates.js"; -import { Notification } from "../../../../utils/types.js"; +import { NotFoundPageOrAdminCreate } from "../../../notfound/index.js"; import { QrPage } from "./QrPage.js"; export type Entity = TalerMerchantApi.TransferInformation; interface Props { onBack?: () => void; - onUnauthorized: () => VNode; - onNotFound: () => VNode; - onLoadError: (e: HttpError<TalerErrorDetail>) => VNode; tid: string; } export default function TemplateQrPage({ tid, onBack, - onLoadError, - onNotFound, - onUnauthorized, }: Props): VNode { const result = useTemplateDetails(tid); - const [notif, setNotif] = useState<Notification | undefined>(undefined); - - 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); + if (!result) return <Loading /> + if (result instanceof TalerError) { + return <ErrorLoadingMerchant error={result} /> } + if (result.type === "fail") { + switch(result.case) { + case HttpStatusCode.NotFound: { + return <NotFoundPageOrAdminCreate /> + } + default: { + assertUnreachable(result.case) + } + } + } + return ( - <> - <NotificationCard notification={notif} /> - <QrPage contract={result.data.template_contract} id={tid} onBack={onBack} /> - </> + <QrPage contract={result.body.template_contract} id={tid} onBack={onBack} /> ); } diff --git a/packages/merchant-backoffice-ui/src/paths/instance/templates/update/UpdatePage.tsx b/packages/merchant-backoffice-ui/src/paths/instance/templates/update/UpdatePage.tsx index f4092b61b..cf1c13fc4 100644 --- a/packages/merchant-backoffice-ui/src/paths/instance/templates/update/UpdatePage.tsx +++ b/packages/merchant-backoffice-ui/src/paths/instance/templates/update/UpdatePage.tsx @@ -23,6 +23,7 @@ import { AmountString, Amounts, Duration, + TalerError, TalerMerchantApi, assertUnreachable } from "@gnu-taler/taler-util"; @@ -91,7 +92,7 @@ export function UpdatePage({ template, onUpdate, onBack }: Props): VNode { type: intialStep, }); const devices = useInstanceOtpDevices() - const deviceList = !devices.ok ? [] : devices.data.otp_devices + const deviceList = !devices || devices instanceof TalerError || devices.type === "fail" ? [] : devices.body const parsedPrice = !state.amount ? undefined @@ -129,7 +130,7 @@ export function UpdatePage({ template, onUpdate, onBack }: Props): VNode { }; const hasErrors = Object.keys(errors).some( - (k) => (errors as any)[k] !== undefined, + (k) => (errors as Record<string,unknown>)[k] !== undefined, ); const submitForm = () => { diff --git a/packages/merchant-backoffice-ui/src/paths/instance/templates/update/index.tsx b/packages/merchant-backoffice-ui/src/paths/instance/templates/update/index.tsx index fc436056a..1ff4b56cf 100644 --- a/packages/merchant-backoffice-ui/src/paths/instance/templates/update/index.tsx +++ b/packages/merchant-backoffice-ui/src/paths/instance/templates/update/index.tsx @@ -19,41 +19,35 @@ * @author Sebastian Javier Marchano (sebasjm) */ -import { HttpStatusCode, TalerErrorDetail, TalerMerchantApi } from "@gnu-taler/taler-util"; +import { HttpStatusCode, TalerError, TalerMerchantApi, assertUnreachable } from "@gnu-taler/taler-util"; import { - ErrorType, - HttpError, useMerchantApiContext, - useTranslationContext, + useTranslationContext } from "@gnu-taler/web-util/browser"; import { Fragment, VNode, h } from "preact"; import { useState } from "preact/hooks"; +import { ErrorLoadingMerchant } from "../../../../components/ErrorLoadingMerchant.js"; import { Loading } from "../../../../components/exception/loading.js"; import { NotificationCard } from "../../../../components/menu/index.js"; +import { useSessionContext } from "../../../../context/session.js"; import { useTemplateDetails, } from "../../../../hooks/templates.js"; import { Notification } from "../../../../utils/types.js"; +import { NotFoundPageOrAdminCreate } from "../../../notfound/index.js"; import { UpdatePage } from "./UpdatePage.js"; -import { useSessionContext } from "../../../../context/session.js"; export type Entity = TalerMerchantApi.TemplatePatchDetails & WithId; interface Props { onBack?: () => void; onConfirm: () => void; - onUnauthorized: () => VNode; - onNotFound: () => VNode; - onLoadError: (e: HttpError<TalerErrorDetail>) => VNode; tid: string; } export default function UpdateTemplate({ tid, onConfirm, onBack, - onUnauthorized, - onNotFound, - onLoadError, }: Props): VNode { const { lib } = useMerchantApiContext(); const { state } = useSessionContext(); @@ -62,26 +56,26 @@ export default function UpdateTemplate({ 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); + if (!result) return <Loading /> + if (result instanceof TalerError) { + return <ErrorLoadingMerchant error={result} /> + } + if (result.type === "fail") { + switch(result.case) { + case HttpStatusCode.NotFound: { + return <NotFoundPageOrAdminCreate /> + } + default: { + assertUnreachable(result.case) + } + } } return ( <Fragment> <NotificationCard notification={notif} /> <UpdatePage - template={{ ...result.data }} + template={result.body} onBack={onBack} onUpdate={(data) => { return lib.management.updateTemplate(state.token, tid, data) diff --git a/packages/merchant-backoffice-ui/src/paths/instance/templates/use/index.tsx b/packages/merchant-backoffice-ui/src/paths/instance/templates/use/index.tsx index dd5d4aea3..0073ca574 100644 --- a/packages/merchant-backoffice-ui/src/paths/instance/templates/use/index.tsx +++ b/packages/merchant-backoffice-ui/src/paths/instance/templates/use/index.tsx @@ -19,31 +19,27 @@ * @author Sebastian Javier Marchano (sebasjm) */ -import { HttpStatusCode, TalerErrorDetail, TalerMerchantApi } from "@gnu-taler/taler-util"; +import { HttpStatusCode, TalerError, TalerMerchantApi, assertUnreachable } from "@gnu-taler/taler-util"; import { - ErrorType, - HttpError, useMerchantApiContext, - useTranslationContext, + useTranslationContext } from "@gnu-taler/web-util/browser"; import { Fragment, VNode, h } from "preact"; import { useState } from "preact/hooks"; +import { ErrorLoadingMerchant } from "../../../../components/ErrorLoadingMerchant.js"; import { Loading } from "../../../../components/exception/loading.js"; import { NotificationCard } from "../../../../components/menu/index.js"; import { useTemplateDetails } from "../../../../hooks/templates.js"; import { Notification } from "../../../../utils/types.js"; +import { NotFoundPageOrAdminCreate } from "../../../notfound/index.js"; import { UsePage } from "./UsePage.js"; -import { useSessionContext } from "../../../../context/session.js"; export type Entity = TalerMerchantApi.TransferInformation; interface Props { onBack?: () => void; onOrderCreated: (id: string) => void; - onUnauthorized: () => VNode; - onNotFound: () => VNode; - onLoadError: (e: HttpError<TalerErrorDetail>) => VNode; tid: string; } @@ -51,36 +47,32 @@ export default function TemplateUsePage({ tid, onOrderCreated, onBack, - onLoadError, - onNotFound, - onUnauthorized, }: Props): VNode { const { lib } = useMerchantApiContext(); - const { state } = useSessionContext(); const result = useTemplateDetails(tid); 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); + if (!result) return <Loading /> + if (result instanceof TalerError) { + return <ErrorLoadingMerchant error={result} /> + } + if (result.type === "fail") { + switch(result.case) { + case HttpStatusCode.NotFound: { + return <NotFoundPageOrAdminCreate /> + } + default: { + assertUnreachable(result.case) + } + } } return ( <> <NotificationCard notification={notif} /> <UsePage - template={result.data} + template={result.body} id={tid} onBack={onBack} onCreateOrder={( diff --git a/packages/merchant-backoffice-ui/src/paths/instance/token/index.tsx b/packages/merchant-backoffice-ui/src/paths/instance/token/index.tsx index 16a4bda22..444283b13 100644 --- a/packages/merchant-backoffice-ui/src/paths/instance/token/index.tsx +++ b/packages/merchant-backoffice-ui/src/paths/instance/token/index.tsx @@ -13,38 +13,31 @@ 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 { HttpStatusCode, TalerError, TalerErrorDetail } from "@gnu-taler/taler-util"; -import { ErrorType, HttpError, useMerchantApiContext, useTranslationContext } from "@gnu-taler/web-util/browser"; +import { TalerError } from "@gnu-taler/taler-util"; +import { useMerchantApiContext, useTranslationContext } from "@gnu-taler/web-util/browser"; import { Fragment, VNode, h } from "preact"; import { useState } from "preact/hooks"; +import { ErrorLoadingMerchant } from "../../../components/ErrorLoadingMerchant.js"; import { Loading } from "../../../components/exception/loading.js"; import { NotificationCard } from "../../../components/menu/index.js"; import { useSessionContext } from "../../../context/session.js"; import { useInstanceDetails } from "../../../hooks/instance.js"; import { Notification } from "../../../utils/types.js"; import { DetailPage } from "./DetailPage.js"; -import { ErrorLoadingMerchant } from "../../../components/ErrorLoadingMerchant.js"; interface Props { - onUnauthorized: () => VNode; - onLoadError: (error: HttpError<TalerErrorDetail>) => VNode; onChange: () => void; - onNotFound: () => VNode; onCancel: () => void; } export default function Token({ - onLoadError, onChange, - onUnauthorized, - onNotFound, onCancel, }: Props): VNode { const { i18n } = useTranslationContext(); const { lib } = useMerchantApiContext(); const { logIn } = useSessionContext(); const [notif, setNotif] = useState<Notification | undefined>(undefined); - // const { clearAccessToken } = useInstanceAPI(); const result = useInstanceDetails() if (!result) return <Loading /> @@ -52,21 +45,6 @@ export default function Token({ return <ErrorLoadingMerchant error={result} /> } - // 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); - // } - const hasToken = result.body.auth.method === "token" return ( diff --git a/packages/merchant-backoffice-ui/src/paths/instance/transfers/create/index.tsx b/packages/merchant-backoffice-ui/src/paths/instance/transfers/create/index.tsx index ac1d692a4..35389f5f5 100644 --- a/packages/merchant-backoffice-ui/src/paths/instance/transfers/create/index.tsx +++ b/packages/merchant-backoffice-ui/src/paths/instance/transfers/create/index.tsx @@ -19,8 +19,11 @@ * @author Sebastian Javier Marchano (sebasjm) */ -import { TalerMerchantApi } from "@gnu-taler/taler-util"; -import { useMerchantApiContext, useTranslationContext } from "@gnu-taler/web-util/browser"; +import { TalerError, TalerMerchantApi } from "@gnu-taler/taler-util"; +import { + useMerchantApiContext, + useTranslationContext, +} from "@gnu-taler/web-util/browser"; import { Fragment, h, VNode } from "preact"; import { useState } from "preact/hooks"; import { NotificationCard } from "../../../../components/menu/index.js"; @@ -41,9 +44,10 @@ export default function CreateTransfer({ onConfirm, onBack }: Props): VNode { const [notif, setNotif] = useState<Notification | undefined>(undefined); const { i18n } = useTranslationContext(); const instance = useInstanceBankAccounts(); - const accounts = !instance.ok - ? [] - : instance.data.accounts.map((a) => a.payto_uri); + const accounts = + !instance || instance instanceof TalerError || instance.type === "fail" + ? [] + : instance.body.map((a) => a.payto_uri); return ( <> @@ -52,7 +56,8 @@ export default function CreateTransfer({ onConfirm, onBack }: Props): VNode { onBack={onBack} accounts={accounts} onCreate={(request: TalerMerchantApi.TransferInformation) => { - return lib.management.informWireTransfer(state.token, request) + return lib.management + .informWireTransfer(state.token, request) .then(() => onConfirm()) .catch((error) => { setNotif({ diff --git a/packages/merchant-backoffice-ui/src/paths/instance/transfers/list/index.tsx b/packages/merchant-backoffice-ui/src/paths/instance/transfers/list/index.tsx index 15706b4c5..5edea377f 100644 --- a/packages/merchant-backoffice-ui/src/paths/instance/transfers/list/index.tsx +++ b/packages/merchant-backoffice-ui/src/paths/instance/transfers/list/index.tsx @@ -19,40 +19,34 @@ * @author Sebastian Javier Marchano (sebasjm) */ -import { HttpStatusCode, TalerErrorDetail } from "@gnu-taler/taler-util"; -import { ErrorType, HttpError } from "@gnu-taler/web-util/browser"; +import { TalerError } from "@gnu-taler/taler-util"; import { VNode, h } from "preact"; import { useEffect, useState } from "preact/hooks"; +import { ErrorLoadingMerchant } from "../../../../components/ErrorLoadingMerchant.js"; import { Loading } from "../../../../components/exception/loading.js"; import { useInstanceBankAccounts } from "../../../../hooks/bank.js"; import { useInstanceTransfers } from "../../../../hooks/transfer.js"; import { ListPage } from "./ListPage.js"; interface Props { - onUnauthorized: () => VNode; - onLoadError: (error: HttpError<TalerErrorDetail>) => VNode; - onNotFound: () => VNode; onCreate: () => void; } interface Form { - verified?: "yes" | "no"; + verified?: boolean; payto_uri?: string; } export default function ListTransfer({ - onUnauthorized, - onLoadError, onCreate, - onNotFound, }: Props): VNode { - const setFilter = (s?: "yes" | "no") => setForm({ ...form, verified: s }); + const setFilter = (s?: boolean) => setForm({ ...form, verified: s }); const [position, setPosition] = useState<string | undefined>(undefined); const instance = useInstanceBankAccounts(); - const accounts = !instance.ok + const accounts = !instance || (instance instanceof TalerError) || instance.type === "fail" ? [] - : instance.data.accounts.map((a) => a.payto_uri); + : instance.body.map((a) => a.payto_uri); const [form, setForm] = useState<Form>({ payto_uri: "" }); const shoulUseDefaultAccount = accounts.length === 1 @@ -62,8 +56,8 @@ export default function ListTransfer({ } }, [shoulUseDefaultAccount]) - const isVerifiedTransfers = form.verified === "yes"; - const isNonVerifiedTransfers = form.verified === "no"; + const isVerifiedTransfers = form.verified === true; + const isNonVerifiedTransfers = form.verified === false; const isAllTransfers = form.verified === undefined; const result = useInstanceTransfers( @@ -75,37 +69,35 @@ export default function ListTransfer({ (id) => setPosition(id), ); - 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); + if (!result) return <Loading />; + if (result instanceof TalerError) { + return <ErrorLoadingMerchant error={result} />; } + // if (result.type === "fail") { + // switch (result.case) { + // case HttpStatusCode.NotFound: { + // return <NotFoundPageOrAdminCreate />; + // } + // default: { + // assertUnreachable(result.case); + // } + // } + // } + return ( <ListPage accounts={accounts} - transfers={result.data.transfers} - onLoadMoreBefore={ - result.isReachingStart ? result.loadMorePrev : undefined - } - onLoadMoreAfter={result.isReachingEnd ? result.loadMore : undefined} + transfers={result.body} + onLoadMoreBefore={result.isFirstPage ? undefined: result.loadFirst } + onLoadMoreAfter={result.isLastPage ? undefined : result.loadNext} onCreate={onCreate} onDelete={() => { null; }} - // position={position} setPosition={setPosition} onShowAll={() => setFilter(undefined)} - onShowUnverified={() => setFilter("no")} - onShowVerified={() => setFilter("yes")} + onShowUnverified={() => setFilter(false)} + onShowVerified={() => setFilter(true)} isAllTransfers={isAllTransfers} isVerifiedTransfers={isVerifiedTransfers} isNonVerifiedTransfers={isNonVerifiedTransfers} diff --git a/packages/merchant-backoffice-ui/src/paths/instance/update/index.tsx b/packages/merchant-backoffice-ui/src/paths/instance/update/index.tsx index 290bfa214..6dc5b9b02 100644 --- a/packages/merchant-backoffice-ui/src/paths/instance/update/index.tsx +++ b/packages/merchant-backoffice-ui/src/paths/instance/update/index.tsx @@ -13,35 +13,32 @@ 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 { HttpStatusCode, OperationOk, TalerError, TalerErrorDetail, TalerMerchantApi, TalerMerchantInstanceHttpClient } from "@gnu-taler/taler-util"; +import { OperationOk, TalerError, TalerMerchantApi, TalerMerchantInstanceHttpClient } from "@gnu-taler/taler-util"; import { - ErrorType, - HttpError, - HttpResponse, useMerchantApiContext, - useTranslationContext, + useTranslationContext } from "@gnu-taler/web-util/browser"; import { Fragment, VNode, h } from "preact"; import { useState } from "preact/hooks"; +import { ErrorLoadingMerchant } from "../../../components/ErrorLoadingMerchant.js"; import { Loading } from "../../../components/exception/loading.js"; import { NotificationCard } from "../../../components/menu/index.js"; +import { useSessionContext } from "../../../context/session.js"; import { useInstanceDetails, useManagedInstanceDetails, } from "../../../hooks/instance.js"; import { Notification } from "../../../utils/types.js"; import { UpdatePage } from "./UpdatePage.js"; -import { useSessionContext } from "../../../context/session.js"; -import { ErrorLoadingMerchant } from "../../../components/ErrorLoadingMerchant.js"; export interface Props { onBack: () => void; onConfirm: () => void; - onUnauthorized: () => VNode; - onNotFound: () => VNode; - onLoadError: (e: HttpError<TalerErrorDetail>) => VNode; - onUpdateError: (e: HttpError<TalerErrorDetail>) => void; + // onUnauthorized: () => VNode; + // onNotFound: () => VNode; + // onLoadError: (e: HttpError<TalerErrorDetail>) => VNode; + // onUpdateError: (e: HttpError<TalerErrorDetail>) => void; } export default function Update(props: Props): VNode { @@ -64,9 +61,6 @@ function CommonUpdate( { onBack, onConfirm, - onLoadError, - onNotFound, - onUnauthorized, }: Props, result: OperationOk<TalerMerchantApi.QueryInstancesResponse> | TalerError | undefined, updateInstance: typeof TalerMerchantInstanceHttpClient.prototype.updateCurrentInstance, diff --git a/packages/merchant-backoffice-ui/src/paths/instance/webhooks/list/index.tsx b/packages/merchant-backoffice-ui/src/paths/instance/webhooks/list/index.tsx index 2923a8096..7c24a7228 100644 --- a/packages/merchant-backoffice-ui/src/paths/instance/webhooks/list/index.tsx +++ b/packages/merchant-backoffice-ui/src/paths/instance/webhooks/list/index.tsx @@ -20,58 +20,51 @@ */ import { - ErrorType, - HttpError, + HttpStatusCode, + TalerError, + TalerMerchantApi, + assertUnreachable, +} from "@gnu-taler/taler-util"; +import { useMerchantApiContext, useTranslationContext, } from "@gnu-taler/web-util/browser"; -import { Fragment, h, VNode } from "preact"; +import { Fragment, VNode, h } from "preact"; import { useState } from "preact/hooks"; +import { ErrorLoadingMerchant } from "../../../../components/ErrorLoadingMerchant.js"; import { Loading } from "../../../../components/exception/loading.js"; import { NotificationCard } from "../../../../components/menu/index.js"; -import { - useInstanceWebhooks, -} from "../../../../hooks/webhooks.js"; +import { useSessionContext } from "../../../../context/session.js"; +import { useInstanceWebhooks } from "../../../../hooks/webhooks.js"; import { Notification } from "../../../../utils/types.js"; +import { NotFoundPageOrAdminCreate } from "../../../notfound/index.js"; import { ListPage } from "./ListPage.js"; -import { HttpStatusCode, TalerErrorDetail, TalerMerchantApi } from "@gnu-taler/taler-util"; -import { useSessionContext } from "../../../../context/session.js"; interface Props { - onUnauthorized: () => VNode; - onLoadError: (error: HttpError<TalerErrorDetail>) => VNode; - onNotFound: () => VNode; onCreate: () => void; onSelect: (id: string) => void; } -export default function ListWebhooks({ - onUnauthorized, - onLoadError, - onCreate, - onSelect, - onNotFound, -}: Props): VNode { - const [position, setPosition] = useState<string | undefined>(undefined); +export default function ListWebhooks({ onCreate, onSelect }: Props): VNode { const { i18n } = useTranslationContext(); const [notif, setNotif] = useState<Notification | undefined>(undefined); const { lib } = useMerchantApiContext(); const { state } = useSessionContext(); - const result = useInstanceWebhooks({ position }, (id) => setPosition(id)); + const result = useInstanceWebhooks(); - 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); + if (!result) return <Loading />; + if (result instanceof TalerError) { + return <ErrorLoadingMerchant error={result} />; + } + if (result.type === "fail") { + switch (result.case) { + case HttpStatusCode.NotFound: { + return <NotFoundPageOrAdminCreate />; + } + default: { + assertUnreachable(result.case); + } + } } return ( @@ -79,17 +72,16 @@ export default function ListWebhooks({ <NotificationCard notification={notif} /> <ListPage - webhooks={result.data.webhooks} - onLoadMoreBefore={ - result.isReachingStart ? result.loadMorePrev : undefined - } - onLoadMoreAfter={result.isReachingEnd ? result.loadMore : undefined} + webhooks={result.body} + onLoadMoreBefore={result.isFirstPage ? undefined : result.loadFirst} + onLoadMoreAfter={result.isLastPage ? undefined : result.loadNext} onCreate={onCreate} onSelect={(e) => { onSelect(e.webhook_id); }} onDelete={(e: TalerMerchantApi.WebhookEntry) => { - return lib.management.deleteWebhook(state.token, e.webhook_id) + return lib.management + .deleteWebhook(state.token, e.webhook_id) .then(() => setNotif({ message: i18n.str`webhook delete successfully`, @@ -102,7 +94,7 @@ export default function ListWebhooks({ type: "ERROR", description: error.message, }), - ) + ); }} /> </Fragment> diff --git a/packages/merchant-backoffice-ui/src/paths/instance/webhooks/update/index.tsx b/packages/merchant-backoffice-ui/src/paths/instance/webhooks/update/index.tsx index aecb4b947..1c3172ffd 100644 --- a/packages/merchant-backoffice-ui/src/paths/instance/webhooks/update/index.tsx +++ b/packages/merchant-backoffice-ui/src/paths/instance/webhooks/update/index.tsx @@ -19,41 +19,35 @@ * @author Sebastian Javier Marchano (sebasjm) */ +import { HttpStatusCode, TalerError, TalerMerchantApi, assertUnreachable } from "@gnu-taler/taler-util"; import { - ErrorType, - HttpError, useMerchantApiContext, - useTranslationContext, + useTranslationContext } from "@gnu-taler/web-util/browser"; -import { Fragment, h, VNode } from "preact"; +import { Fragment, VNode, h } from "preact"; import { useState } from "preact/hooks"; +import { ErrorLoadingMerchant } from "../../../../components/ErrorLoadingMerchant.js"; import { Loading } from "../../../../components/exception/loading.js"; import { NotificationCard } from "../../../../components/menu/index.js"; +import { useSessionContext } from "../../../../context/session.js"; import { useWebhookDetails, } from "../../../../hooks/webhooks.js"; import { Notification } from "../../../../utils/types.js"; +import { NotFoundPageOrAdminCreate } from "../../../notfound/index.js"; import { UpdatePage } from "./UpdatePage.js"; -import { HttpStatusCode, TalerErrorDetail, TalerMerchantApi } from "@gnu-taler/taler-util"; -import { useSessionContext } from "../../../../context/session.js"; export type Entity = TalerMerchantApi.WebhookPatchDetails & WithId; interface Props { onBack?: () => void; onConfirm: () => void; - onUnauthorized: () => VNode; - onNotFound: () => VNode; - onLoadError: (e: HttpError<TalerErrorDetail>) => VNode; tid: string; } export default function UpdateWebhook({ tid, onConfirm, onBack, - onUnauthorized, - onNotFound, - onLoadError, }: Props): VNode { const { lib } = useMerchantApiContext(); const { state } = useSessionContext(); @@ -62,26 +56,26 @@ export default function UpdateWebhook({ 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); + if (!result) return <Loading />; + if (result instanceof TalerError) { + return <ErrorLoadingMerchant error={result} />; + } + if (result.type === "fail") { + switch (result.case) { + case HttpStatusCode.NotFound: { + return <NotFoundPageOrAdminCreate />; + } + default: { + assertUnreachable(result.case); + } + } } return ( <Fragment> <NotificationCard notification={notif} /> <UpdatePage - webhook={{ ...result.data, id: tid }} + webhook={{ ...result.body, id: tid }} onBack={onBack} onUpdate={(data) => { return lib.management.updateWebhook(state.token, tid, data) |