gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[taler-wallet-core] branch master updated: wip #8325 remove rewards


From: gnunet
Subject: [taler-wallet-core] branch master updated: wip #8325 remove rewards
Date: Fri, 09 Feb 2024 13:43:35 +0100

This is an automated email from the git hooks/post-receive script.

sebasjm pushed a commit to branch master
in repository wallet-core.

The following commit(s) were added to refs/heads/master by this push:
     new 6e370c350 wip #8325 remove rewards
6e370c350 is described below

commit 6e370c3502a8e6474d4665eb42ae1bfdec3034a1
Author: Sebastian <sebasjm@gmail.com>
AuthorDate: Fri Feb 9 09:43:29 2024 -0300

    wip #8325 remove rewards
---
 .../merchant-backoffice-ui/src/InstanceRoutes.tsx  |  39 ---
 .../src/components/menu/SideBar.tsx                |   8 -
 .../merchant-backoffice-ui/src/hooks/backend.ts    |  32 ---
 .../src/hooks/reserve.test.ts                      | 245 +---------------
 .../merchant-backoffice-ui/src/hooks/reserves.ts   |  89 +-----
 .../src/paths/instance/index.stories.ts            |   1 -
 .../instance/reserves/create/Create.stories.tsx    |  43 ---
 .../paths/instance/reserves/create/CreatePage.tsx  | 277 ------------------
 .../create/CreatedSuccessfully.stories.tsx         | 120 --------
 .../reserves/create/CreatedSuccessfully.tsx        | 190 ------------
 .../src/paths/instance/reserves/create/index.tsx   |  71 -----
 .../paths/instance/reserves/details/DetailPage.tsx | 266 -----------------
 .../instance/reserves/details/Details.stories.tsx  | 126 --------
 .../paths/instance/reserves/details/RewardInfo.tsx |  88 ------
 .../src/paths/instance/reserves/details/index.tsx  |  68 -----
 .../instance/reserves/list/AutorizeRewardModal.tsx | 124 --------
 .../instance/reserves/list/CreatedSuccessfully.tsx | 102 -------
 .../paths/instance/reserves/list/List.stories.tsx  |  96 -------
 .../src/paths/instance/reserves/list/Table.tsx     | 320 ---------------------
 .../src/paths/instance/reserves/list/index.tsx     | 171 -----------
 .../merchant-backoffice-ui/src/schemas/index.ts    |  21 --
 21 files changed, 3 insertions(+), 2494 deletions(-)

diff --git a/packages/merchant-backoffice-ui/src/InstanceRoutes.tsx 
b/packages/merchant-backoffice-ui/src/InstanceRoutes.tsx
index b5680eabb..a7fd3eb0f 100644
--- a/packages/merchant-backoffice-ui/src/InstanceRoutes.tsx
+++ b/packages/merchant-backoffice-ui/src/InstanceRoutes.tsx
@@ -52,9 +52,6 @@ import ProductUpdatePage from 
"./paths/instance/products/update/index.js";
 import BankAccountCreatePage from "./paths/instance/accounts/create/index.js";
 import BankAccountListPage from "./paths/instance/accounts/list/index.js";
 import BankAccountUpdatePage from "./paths/instance/accounts/update/index.js";
-import ReservesCreatePage from "./paths/instance/reserves/create/index.js";
-import ReservesDetailsPage from "./paths/instance/reserves/details/index.js";
-import ReservesListPage from "./paths/instance/reserves/list/index.js";
 import TemplateCreatePage from "./paths/instance/templates/create/index.js";
 import TemplateUsePage from "./paths/instance/templates/use/index.js";
 import TemplateQrPage from "./paths/instance/templates/qr/index.js";
@@ -643,42 +640,6 @@ export function InstanceRoutes({
           }}
         />
 
-        {/**
-         * reserves pages
-         */}
-        <Route
-          path={InstancePaths.reserves_list}
-          component={ReservesListPage}
-          onUnauthorized={LoginPageAccessDenied}
-          onNotFound={IfAdminCreateDefaultOr(NotFoundPage)}
-          onLoadError={ServerErrorRedirectTo(InstancePaths.settings)}
-          onSelect={(id: string) => {
-            route(InstancePaths.reserves_details.replace(":rid", id));
-          }}
-          onCreate={() => {
-            route(InstancePaths.reserves_new);
-          }}
-        />
-        <Route
-          path={InstancePaths.reserves_details}
-          component={ReservesDetailsPage}
-          onUnauthorized={LoginPageAccessDenied}
-          onLoadError={ServerErrorRedirectTo(InstancePaths.reserves_list)}
-          onNotFound={IfAdminCreateDefaultOr(NotFoundPage)}
-          onBack={() => {
-            route(InstancePaths.reserves_list);
-          }}
-        />
-        <Route
-          path={InstancePaths.reserves_new}
-          component={ReservesCreatePage}
-          onConfirm={() => {
-            route(InstancePaths.reserves_list);
-          }}
-          onBack={() => {
-            route(InstancePaths.reserves_list);
-          }}
-        />
         <Route path={InstancePaths.kyc} component={ListKYCPage} />
         <Route path={InstancePaths.interface} component={Settings} />
         {/**
diff --git a/packages/merchant-backoffice-ui/src/components/menu/SideBar.tsx 
b/packages/merchant-backoffice-ui/src/components/menu/SideBar.tsx
index cfc00148e..3146cf5e9 100644
--- a/packages/merchant-backoffice-ui/src/components/menu/SideBar.tsx
+++ b/packages/merchant-backoffice-ui/src/components/menu/SideBar.tsx
@@ -158,14 +158,6 @@ export function Sidebar({
                   </span>
                 </a>
               </li>
-              <li>
-                <a href={"/reserves"} class="has-icon">
-                  <span class="icon">
-                    <i class="mdi mdi-cash" />
-                  </span>
-                  <span class="menu-item-label">Reserves</span>
-                </a>
-              </li>
               <li>
                 <a href={"/webhooks"} class="has-icon">
                   <span class="icon">
diff --git a/packages/merchant-backoffice-ui/src/hooks/backend.ts 
b/packages/merchant-backoffice-ui/src/hooks/backend.ts
index 8d99546a8..3a31fcf9b 100644
--- a/packages/merchant-backoffice-ui/src/hooks/backend.ts
+++ b/packages/merchant-backoffice-ui/src/hooks/backend.ts
@@ -132,8 +132,6 @@ interface useBackendInstanceRequestType {
     options?: RequestOptions,
   ) => Promise<HttpResponseOk<T>>;
   fetcher: <T>(endpoint: string) => Promise<HttpResponseOk<T>>;
-  reserveDetailFetcher: <T>(endpoint: string) => Promise<HttpResponseOk<T>>;
-  rewardsDetailFetcher: <T>(endpoint: string) => Promise<HttpResponseOk<T>>;
   multiFetcher: <T>(params: [url: string[]]) => Promise<HttpResponseOk<T>[]>;
   orderFetcher: <T>(
     params: [endpoint: string,
@@ -353,34 +351,6 @@ export function useBackendInstanceRequest(): 
useBackendInstanceRequestType {
     [baseUrl, token],
   );
 
-  const reserveDetailFetcher = useCallback(
-    function reserveDetailFetcherImpl<T>(
-      endpoint: string,
-    ): Promise<HttpResponseOk<T>> {
-      return requestHandler<T>(baseUrl, endpoint, {
-        params: {
-          rewards: "yes",
-        },
-        token,
-      });
-    },
-    [baseUrl, token],
-  );
-
-  const rewardsDetailFetcher = useCallback(
-    function rewardsDetailFetcherImpl<T>(
-      endpoint: string,
-    ): Promise<HttpResponseOk<T>> {
-      return requestHandler<T>(baseUrl, endpoint, {
-        params: {
-          pickups: "yes",
-        },
-        token,
-      });
-    },
-    [baseUrl, token],
-  );
-
   const transferFetcher = useCallback(
     function transferFetcherImpl<T>(
       args: [endpoint: string,
@@ -468,8 +438,6 @@ export function useBackendInstanceRequest(): 
useBackendInstanceRequestType {
     fetcher,
     multiFetcher,
     orderFetcher,
-    reserveDetailFetcher,
-    rewardsDetailFetcher,
     transferFetcher,
     templateFetcher,
     webhookFetcher,
diff --git a/packages/merchant-backoffice-ui/src/hooks/reserve.test.ts 
b/packages/merchant-backoffice-ui/src/hooks/reserve.test.ts
index b3eecd754..186af1f61 100644
--- a/packages/merchant-backoffice-ui/src/hooks/reserve.test.ts
+++ b/packages/merchant-backoffice-ui/src/hooks/reserve.test.ts
@@ -19,25 +19,19 @@
  * @author Sebastian Javier Marchano (sebasjm)
  */
 
+import * as tests from "@gnu-taler/web-util/testing";
 import { expect } from "chai";
 import { MerchantBackend } from "../declaration.js";
 import {
   useInstanceReserves,
-  useReserveDetails,
   useReservesAPI,
-  useRewardDetails,
 } from "./reserves.js";
 import { ApiMockEnvironment } from "./testing.js";
 import {
-  API_AUTHORIZE_REWARD,
-  API_AUTHORIZE_REWARD_FOR_RESERVE,
   API_CREATE_RESERVE,
   API_DELETE_RESERVE,
-  API_GET_RESERVE_BY_ID,
-  API_GET_REWARD_BY_ID,
-  API_LIST_RESERVES,
+  API_LIST_RESERVES
 } from "./urls.js";
-import * as tests from "@gnu-taler/web-util/testing";
 
 describe("reserve api interaction with listing", () => {
   it("should evict cache when creating a reserve", async () => {
@@ -211,238 +205,3 @@ describe("reserve api interaction with listing", () => {
     expect(env.assertJustExpectedRequestWereMade()).deep.eq({ result: "ok" });
   });
 });
-
-describe("reserve api interaction with details", () => {
-  it("should evict cache when adding a reward for a specific reserve", async 
() => {
-    const env = new ApiMockEnvironment();
-
-    env.addRequestExpectation(API_GET_RESERVE_BY_ID("11"), {
-      response: {
-        accounts: [{ payto_uri: "payto://here" }],
-        rewards: [{ reason: "why?", reward_id: "id1", total_amount: "USD:10" 
}],
-      } as MerchantBackend.Rewards.ReserveDetail,
-      qparam: {
-        rewards: "yes",
-      },
-    });
-
-    const hookBehavior = await tests.hookBehaveLikeThis(
-      () => {
-        const api = useReservesAPI();
-        const query = useReserveDetails("11");
-        return { query, api };
-      },
-      {},
-      [
-        ({ query, api }) => {
-          expect(query.loading).true;
-        },
-        ({ query, api }) => {
-          expect(env.assertJustExpectedRequestWereMade()).deep.eq({
-            result: "ok",
-          });
-          expect(query.loading).false;
-          expect(query.ok).true;
-          if (!query.ok) return;
-          expect(query.data).deep.equals({
-            accounts: [{ payto_uri: "payto://here" }],
-            rewards: [{ reason: "why?", reward_id: "id1", total_amount: 
"USD:10" }],
-          });
-
-          env.addRequestExpectation(API_AUTHORIZE_REWARD_FOR_RESERVE("11"), {
-            request: {
-              amount: "USD:12",
-              justification: "not",
-              next_url: "http://taler.net";,
-            },
-            response: {
-              reward_id: "id2",
-              taler_reward_uri: "uri",
-              reward_expiration: { t_s: 1 },
-              reward_status_url: "url",
-            },
-          });
-
-          env.addRequestExpectation(API_GET_RESERVE_BY_ID("11"), {
-            response: {
-              accounts: [{ payto_uri: "payto://here" }],
-              rewards: [
-                { reason: "why?", reward_id: "id1", total_amount: "USD:10" },
-                { reason: "not", reward_id: "id2", total_amount: "USD:12" },
-              ],
-            } as MerchantBackend.Rewards.ReserveDetail,
-            qparam: {
-              rewards: "yes",
-            },
-          });
-
-          api.authorizeRewardReserve("11", {
-            amount: "USD:12",
-            justification: "not",
-            next_url: "http://taler.net";,
-          });
-        },
-        ({ query, api }) => {
-          expect(env.assertJustExpectedRequestWereMade()).deep.eq({
-            result: "ok",
-          });
-          expect(query.loading).false;
-
-          expect(query.loading).false;
-          expect(query.ok).true;
-          if (!query.ok) return;
-
-          expect(query.data).deep.equals({
-            accounts: [{ payto_uri: "payto://here" }],
-            rewards: [
-              { reason: "why?", reward_id: "id1", total_amount: "USD:10" },
-              { reason: "not", reward_id: "id2", total_amount: "USD:12" },
-            ],
-          });
-        },
-      ],
-      env.buildTestingContext(),
-    );
-
-    expect(hookBehavior).deep.eq({ result: "ok" });
-    expect(env.assertJustExpectedRequestWereMade()).deep.eq({ result: "ok" });
-  });
-
-  it("should evict cache when adding a reward for a random reserve", async () 
=> {
-    const env = new ApiMockEnvironment();
-
-    env.addRequestExpectation(API_GET_RESERVE_BY_ID("11"), {
-      response: {
-        accounts: [{ payto_uri: "payto://here" }],
-        rewards: [{ reason: "why?", reward_id: "id1", total_amount: "USD:10" 
}],
-      } as MerchantBackend.Rewards.ReserveDetail,
-      qparam: {
-        rewards: "yes",
-      },
-    });
-
-    const hookBehavior = await tests.hookBehaveLikeThis(
-      () => {
-        const api = useReservesAPI();
-        const query = useReserveDetails("11");
-        return { query, api };
-      },
-      {},
-      [
-        ({ query, api }) => {
-          expect(query.loading).true;
-        },
-        ({ query, api }) => {
-          expect(env.assertJustExpectedRequestWereMade()).deep.eq({
-            result: "ok",
-          });
-          expect(query.loading).false;
-          expect(query.ok).true;
-          if (!query.ok) return;
-          expect(query.data).deep.equals({
-            accounts: [{ payto_uri: "payto://here" }],
-            rewards: [{ reason: "why?", reward_id: "id1", total_amount: 
"USD:10" }],
-          });
-
-          env.addRequestExpectation(API_AUTHORIZE_REWARD, {
-            request: {
-              amount: "USD:12",
-              justification: "not",
-              next_url: "http://taler.net";,
-            },
-            response: {
-              reward_id: "id2",
-              taler_reward_uri: "uri",
-              reward_expiration: { t_s: 1 },
-              reward_status_url: "url",
-            },
-          });
-
-          env.addRequestExpectation(API_GET_RESERVE_BY_ID("11"), {
-            response: {
-              accounts: [{ payto_uri: "payto://here" }],
-              rewards: [
-                { reason: "why?", reward_id: "id1", total_amount: "USD:10" },
-                { reason: "not", reward_id: "id2", total_amount: "USD:12" },
-              ],
-            } as MerchantBackend.Rewards.ReserveDetail,
-            qparam: {
-              rewards: "yes",
-            },
-          });
-
-          api.authorizeReward({
-            amount: "USD:12",
-            justification: "not",
-            next_url: "http://taler.net";,
-          });
-        },
-        ({ query, api }) => {
-          expect(env.assertJustExpectedRequestWereMade()).deep.eq({
-            result: "ok",
-          });
-          expect(query.loading).false;
-          expect(query.ok).true;
-          if (!query.ok) return;
-
-          expect(query.data).deep.equals({
-            accounts: [{ payto_uri: "payto://here" }],
-            rewards: [
-              { reason: "why?", reward_id: "id1", total_amount: "USD:10" },
-              { reason: "not", reward_id: "id2", total_amount: "USD:12" },
-            ],
-          });
-        },
-      ],
-      env.buildTestingContext(),
-    );
-
-    expect(hookBehavior).deep.eq({ result: "ok" });
-    expect(env.assertJustExpectedRequestWereMade()).deep.eq({ result: "ok" });
-  });
-});
-
-describe("reserve api interaction with reward details", () => {
-  it("should list rewards", async () => {
-    const env = new ApiMockEnvironment();
-
-    env.addRequestExpectation(API_GET_REWARD_BY_ID("11"), {
-      response: {
-        total_picked_up: "USD:12",
-        reason: "not",
-      } as MerchantBackend.Rewards.RewardDetails,
-      qparam: {
-        pickups: "yes",
-      },
-    });
-
-    const hookBehavior = await tests.hookBehaveLikeThis(
-      () => {
-        const query = useRewardDetails("11");
-        return { query };
-      },
-      {},
-      [
-        ({ query }) => {
-          expect(env.assertJustExpectedRequestWereMade()).deep.eq({
-            result: "ok",
-          });
-          expect(query.loading).true;
-        },
-        ({ query }) => {
-          expect(query.loading).false;
-          expect(query.ok).true;
-          if (!query.ok) return;
-          expect(query.data).deep.equals({
-            total_picked_up: "USD:12",
-            reason: "not",
-          });
-        },
-      ],
-      env.buildTestingContext(),
-    );
-
-    expect(hookBehavior).deep.eq({ result: "ok" });
-    expect(env.assertJustExpectedRequestWereMade()).deep.eq({ result: "ok" });
-  });
-});
diff --git a/packages/merchant-backoffice-ui/src/hooks/reserves.ts 
b/packages/merchant-backoffice-ui/src/hooks/reserves.ts
index b719bfbe6..62dc48412 100644
--- a/packages/merchant-backoffice-ui/src/hooks/reserves.ts
+++ b/packages/merchant-backoffice-ui/src/hooks/reserves.ts
@@ -49,40 +49,6 @@ export function useReservesAPI(): ReserveMutateAPI {
     return res;
   };
 
-  const authorizeRewardReserve = async (
-    pub: string,
-    data: MerchantBackend.Rewards.RewardCreateRequest,
-  ): Promise<HttpResponseOk<MerchantBackend.Rewards.RewardCreateConfirmation>> 
=> {
-    const res = await 
request<MerchantBackend.Rewards.RewardCreateConfirmation>(
-      `/private/reserves/${pub}/authorize-reward`,
-      {
-        method: "POST",
-        data,
-      },
-    );
-
-    //evict reserve details query
-    await mutate([`/private/reserves/${pub}`]);
-
-    return res;
-  };
-
-  const authorizeReward = async (
-    data: MerchantBackend.Rewards.RewardCreateRequest,
-  ): Promise<HttpResponseOk<MerchantBackend.Rewards.RewardCreateConfirmation>> 
=> {
-    const res = await 
request<MerchantBackend.Rewards.RewardCreateConfirmation>(
-      `/private/rewards`,
-      {
-        method: "POST",
-        data,
-      },
-    );
-
-    //evict all details query
-    await mutateAll(/.*private\/reserves\/.*/);
-
-    return res;
-  };
 
   const deleteReserve = async (
     pub: string,
@@ -97,20 +63,13 @@ export function useReservesAPI(): ReserveMutateAPI {
     return res;
   };
 
-  return { createReserve, authorizeReward, authorizeRewardReserve, 
deleteReserve };
+  return { createReserve, deleteReserve };
 }
 
 export interface ReserveMutateAPI {
   createReserve: (
     data: MerchantBackend.Rewards.ReserveCreateRequest,
   ) => 
Promise<HttpResponseOk<MerchantBackend.Rewards.ReserveCreateConfirmation>>;
-  authorizeRewardReserve: (
-    id: string,
-    data: MerchantBackend.Rewards.RewardCreateRequest,
-  ) => 
Promise<HttpResponseOk<MerchantBackend.Rewards.RewardCreateConfirmation>>;
-  authorizeReward: (
-    data: MerchantBackend.Rewards.RewardCreateRequest,
-  ) => 
Promise<HttpResponseOk<MerchantBackend.Rewards.RewardCreateConfirmation>>;
   deleteReserve: (
     id: string,
   ) => Promise<HttpResponse<void, MerchantBackend.ErrorDetail>>;
@@ -133,49 +92,3 @@ export function useInstanceReserves(): HttpResponse<
   return { loading: true };
 }
 
-export function useReserveDetails(
-  reserveId: string,
-): HttpResponse<
-  MerchantBackend.Rewards.ReserveDetail,
-  MerchantBackend.ErrorDetail
-> {
-  const { reserveDetailFetcher } = useBackendInstanceRequest();
-
-  const { data, error, isValidating } = useSWR<
-    HttpResponseOk<MerchantBackend.Rewards.ReserveDetail>,
-    RequestError<MerchantBackend.ErrorDetail>
-  >([`/private/reserves/${reserveId}`], reserveDetailFetcher, {
-    refreshInterval: 0,
-    refreshWhenHidden: false,
-    revalidateOnFocus: false,
-    revalidateOnReconnect: false,
-    refreshWhenOffline: false,
-  });
-
-  if (isValidating) return { loading: true, data: data?.data };
-  if (data) return data;
-  if (error) return error.cause;
-  return { loading: true };
-}
-
-export function useRewardDetails(
-  rewardId: string,
-): HttpResponse<MerchantBackend.Rewards.RewardDetails, 
MerchantBackend.ErrorDetail> {
-  const { rewardsDetailFetcher } = useBackendInstanceRequest();
-
-  const { data, error, isValidating } = useSWR<
-    HttpResponseOk<MerchantBackend.Rewards.RewardDetails>,
-    RequestError<MerchantBackend.ErrorDetail>
-  >([`/private/rewards/${rewardId}`], rewardsDetailFetcher, {
-    refreshInterval: 0,
-    refreshWhenHidden: false,
-    revalidateOnFocus: false,
-    revalidateOnReconnect: false,
-    refreshWhenOffline: false,
-  });
-
-  if (isValidating) return { loading: true, data: data?.data };
-  if (data) return data;
-  if (error) return error.cause;
-  return { loading: true };
-}
diff --git 
a/packages/merchant-backoffice-ui/src/paths/instance/index.stories.ts 
b/packages/merchant-backoffice-ui/src/paths/instance/index.stories.ts
index 1d8c76ff9..50918e131 100644
--- a/packages/merchant-backoffice-ui/src/paths/instance/index.stories.ts
+++ b/packages/merchant-backoffice-ui/src/paths/instance/index.stories.ts
@@ -16,4 +16,3 @@
 
 export * as details from "./details/stories.js";
 export * as kycList from "./kyc/list/ListPage.stories.js";
-export * as reserve from "./reserves/create/CreatedSuccessfully.stories.js";
diff --git 
a/packages/merchant-backoffice-ui/src/paths/instance/reserves/create/Create.stories.tsx
 
b/packages/merchant-backoffice-ui/src/paths/instance/reserves/create/Create.stories.tsx
deleted file mode 100644
index 5542c028a..000000000
--- 
a/packages/merchant-backoffice-ui/src/paths/instance/reserves/create/Create.stories.tsx
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2021-2023 Taler Systems S.A.
-
- GNU Taler is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- GNU Taler; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
- */
-
-/**
- *
- * @author Sebastian Javier Marchano (sebasjm)
- */
-
-import { h, VNode, FunctionalComponent } from "preact";
-import { CreatePage as TestedComponent } from "./CreatePage.js";
-
-export default {
-  title: "Pages/Reserve/Create",
-  component: TestedComponent,
-  argTypes: {
-    onCreate: { action: "onCreate" },
-    onBack: { action: "onBack" },
-  },
-};
-
-function createExample<Props>(
-  Component: FunctionalComponent<Props>,
-  props: Partial<Props>,
-) {
-  const r = (args: any) => <Component {...args} />;
-  r.args = props;
-  return r;
-}
-
-export const Example = createExample(TestedComponent, {});
diff --git 
a/packages/merchant-backoffice-ui/src/paths/instance/reserves/create/CreatePage.tsx
 
b/packages/merchant-backoffice-ui/src/paths/instance/reserves/create/CreatePage.tsx
deleted file mode 100644
index e46941b6d..000000000
--- 
a/packages/merchant-backoffice-ui/src/paths/instance/reserves/create/CreatePage.tsx
+++ /dev/null
@@ -1,277 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2021-2023 Taler Systems S.A.
-
- GNU Taler is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- GNU Taler; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
- */
-
-/**
- *
- * @author Sebastian Javier Marchano (sebasjm)
- */
-
-import { HttpError, RequestError, useApiContext, useTranslationContext } from 
"@gnu-taler/web-util/browser";
-import { Fragment, h, VNode } from "preact";
-import { StateUpdater, useEffect, useState } from "preact/hooks";
-import { AsyncButton } from "../../../../components/exception/AsyncButton.js";
-import {
-  FormErrors,
-  FormProvider,
-} from "../../../../components/form/FormProvider.js";
-import { Input } from "../../../../components/form/Input.js";
-import { InputCurrency } from "../../../../components/form/InputCurrency.js";
-import { InputSelector } from "../../../../components/form/InputSelector.js";
-import { MerchantBackend } from "../../../../declaration.js";
-import {
-  PAYTO_WIRE_METHOD_LOOKUP,
-  URL_REGEX,
-} from "../../../../utils/constants.js";
-import { useBackendBaseRequest } from "../../../../hooks/backend.js";
-import { parsePaytoUri } from "@gnu-taler/taler-util";
-
-type Entity = MerchantBackend.Rewards.ReserveCreateRequest;
-
-interface Props {
-  onCreate: (d: Entity) => Promise<void>;
-  onBack?: () => void;
-}
-
-enum Steps {
-  EXCHANGE,
-  WIRE_METHOD,
-}
-
-interface ViewProps {
-  step: Steps;
-  setCurrentStep: (s: Steps) => void;
-  reserve: Partial<Entity>;
-  onBack?: () => void;
-  submitForm: () => Promise<void>;
-  setReserve: StateUpdater<Partial<Entity>>;
-}
-function ViewStep({
-  step,
-  setCurrentStep,
-  reserve,
-  onBack,
-  submitForm,
-  setReserve,
-}: ViewProps): VNode {
-  const { i18n } = useTranslationContext();
-  const {request} = useApiContext()
-  const [wireMethods, setWireMethods] = useState<Array<string>>([]);
-  const [exchangeQueryError, setExchangeQueryError] = useState<
-    string | undefined
-  >(undefined);
-
-  useEffect(() => {
-    setExchangeQueryError(undefined);
-  }, [reserve.exchange_url]);
-
-  switch (step) {
-    case Steps.EXCHANGE: {
-      const errors: FormErrors<Entity> = {
-        initial_balance: !reserve.initial_balance
-          ? "cannot be empty"
-          : !(parseInt(reserve.initial_balance.split(":")[1], 10) > 0)
-            ? i18n.str`it should be greater than 0`
-            : undefined,
-        exchange_url: !reserve.exchange_url
-          ? i18n.str`cannot be empty`
-          : !URL_REGEX.test(reserve.exchange_url)
-            ? i18n.str`must be a valid URL`
-            : !exchangeQueryError
-              ? undefined
-              : exchangeQueryError,
-      };
-
-      const hasErrors = Object.keys(errors).some(
-        (k) => (errors as any)[k] !== undefined,
-      );
-
-      return (
-        <Fragment>
-          <FormProvider<Entity>
-            object={reserve}
-            errors={errors}
-            valueHandler={setReserve}
-          >
-            <InputCurrency<Entity>
-              name="initial_balance"
-              label={i18n.str`Initial balance`}
-              tooltip={i18n.str`balance prior to deposit`}
-            />
-            <Input<Entity>
-              name="exchange_url"
-              label={i18n.str`Exchange URL`}
-              tooltip={i18n.str`URL of exchange`}
-            />
-          </FormProvider>
-
-          <div class="buttons is-right mt-5">
-            {onBack && (
-              <button class="button" onClick={onBack}>
-                <i18n.Translate>Cancel</i18n.Translate>
-              </button>
-            )}
-            <AsyncButton
-              class="has-tooltip-left"
-              onClick={() => {
-                if (!reserve.exchange_url) {
-                  return Promise.resolve();
-                }
-                
-                return request<any>(reserve.exchange_url, "keys")
-                  .then((r) => {
-                    console.log(r)
-                    if (r.loading) return;
-                    if (r.ok) {
-                      const wireMethods = r.data.accounts.map((a: any) => {
-                        const p = parsePaytoUri(a.payto_uri);
-                        const r = p?.targetType
-                        return r
-                      }).filter((x:any) => !!x);
-                      setWireMethods(Array.from(new Set(wireMethods)));
-                    }
-                    setCurrentStep(Steps.WIRE_METHOD);
-                    return;
-                  })
-                  .catch((r: RequestError<{}>) => {
-                    console.log(r.cause)
-                    setExchangeQueryError(r.cause.message);
-                  });
-              }}
-              data-tooltip={
-                hasErrors
-                  ? i18n.str`Need to complete marked fields`
-                  : "confirm operation"
-              }
-              disabled={hasErrors}
-            >
-              <i18n.Translate>Next</i18n.Translate>
-            </AsyncButton>
-          </div>
-        </Fragment>
-      );
-    }
-
-    case Steps.WIRE_METHOD: {
-      const errors: FormErrors<Entity> = {
-        wire_method: !reserve.wire_method
-          ? i18n.str`cannot be empty`
-          : undefined,
-      };
-
-      const hasErrors = Object.keys(errors).some(
-        (k) => (errors as any)[k] !== undefined,
-      );
-      return (
-        <Fragment>
-          <FormProvider<Entity>
-            object={reserve}
-            errors={errors}
-            valueHandler={setReserve}
-          >
-            <InputCurrency<Entity>
-              name="initial_balance"
-              label={i18n.str`Initial balance`}
-              tooltip={i18n.str`balance prior to deposit`}
-              readonly
-            />
-            <Input<Entity>
-              name="exchange_url"
-              label={i18n.str`Exchange URL`}
-              tooltip={i18n.str`URL of exchange`}
-              readonly
-            />
-            <InputSelector<Entity>
-              name="wire_method"
-              label={i18n.str`Wire method`}
-              tooltip={i18n.str`method to use for wire transfer`}
-              values={wireMethods}
-              placeholder={i18n.str`Select one wire method`}
-            />
-          </FormProvider>
-          <div class="buttons is-right mt-5">
-            {onBack && (
-              <button
-                class="button"
-                onClick={() => setCurrentStep(Steps.EXCHANGE)}
-              >
-                <i18n.Translate>Back</i18n.Translate>
-              </button>
-            )}
-            <AsyncButton
-              onClick={submitForm}
-              data-tooltip={
-                hasErrors
-                  ? i18n.str`Need to complete marked fields`
-                  : "confirm operation"
-              }
-              disabled={hasErrors}
-            >
-              <i18n.Translate>Confirm</i18n.Translate>
-            </AsyncButton>
-          </div>
-        </Fragment>
-      );
-    }
-  }
-}
-
-export function CreatePage({ onCreate, onBack }: Props): VNode {
-  const [reserve, setReserve] = useState<Partial<Entity>>({});
-
-  const submitForm = () => {
-    return onCreate(reserve as Entity);
-  };
-
-  const [currentStep, setCurrentStep] = useState(Steps.EXCHANGE);
-
-  return (
-    <div>
-      <section class="section is-main-section">
-        <div class="columns">
-          <div class="column" />
-          <div class="column is-four-fifths">
-            <div class="tabs is-toggle is-fullwidth is-small">
-              <ul>
-                <li class={currentStep === Steps.EXCHANGE ? "is-active" : ""}>
-                  <a style={{ cursor: "initial" }}>
-                    <span>Step 1: Specify exchange</span>
-                  </a>
-                </li>
-                <li
-                  class={currentStep === Steps.WIRE_METHOD ? "is-active" : ""}
-                >
-                  <a style={{ cursor: "initial" }}>
-                    <span>Step 2: Select wire method</span>
-                  </a>
-                </li>
-              </ul>
-            </div>
-
-            <ViewStep
-              step={currentStep}
-              reserve={reserve}
-              setCurrentStep={setCurrentStep}
-              setReserve={setReserve}
-              submitForm={submitForm}
-              onBack={onBack}
-            />
-          </div>
-          <div class="column" />
-        </div>
-      </section>
-    </div>
-  );
-}
diff --git 
a/packages/merchant-backoffice-ui/src/paths/instance/reserves/create/CreatedSuccessfully.stories.tsx
 
b/packages/merchant-backoffice-ui/src/paths/instance/reserves/create/CreatedSuccessfully.stories.tsx
deleted file mode 100644
index 445ca3ef0..000000000
--- 
a/packages/merchant-backoffice-ui/src/paths/instance/reserves/create/CreatedSuccessfully.stories.tsx
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2021-2023 Taler Systems S.A.
-
- GNU Taler is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- GNU Taler; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
- */
-
-/**
- *
- * @author Sebastian Javier Marchano (sebasjm)
- */
-
-import { h, VNode, FunctionalComponent } from "preact";
-import { CreatedSuccessfully as TestedComponent } from 
"./CreatedSuccessfully.js";
-import * as tests from "@gnu-taler/web-util/testing";
-
-export default {
-  title: "Pages/Reserve/CreatedSuccessfully",
-  component: TestedComponent,
-  argTypes: {
-    onCreate: { action: "onCreate" },
-    onBack: { action: "onBack" },
-  },
-};
-
-export const OneBankAccount = tests.createExample(TestedComponent, {
-  entity: {
-    request: {
-      exchange_url: "http://exchange.taler/";,
-      initial_balance: "TESTKUDOS:1",
-      wire_method: "x-taler-bank",
-    },
-    response: {
-      accounts: [
-        {
-          payto_uri: "payto://x-taler-bank/bank.taler:8080/exchange_account",
-          credit_restrictions: [],
-          debit_restrictions: [],
-          master_sig: "asd",
-          conversion_url: "",
-        },
-      ],
-      reserve_pub: "WEQWDASDQWEASDADASDQWEQWEASDAS",
-    },
-  },
-});
-
-export const ThreeBankAccount = tests.createExample(TestedComponent, {
-  entity: {
-    request: {
-      exchange_url: "http://exchange.taler/";,
-      initial_balance: "TESTKUDOS:1",
-      wire_method: "x-taler-bank",
-    },
-    response: {
-      accounts: [
-        {
-          payto_uri: "payto://x-taler-bank/bank.taler:8080/exchange_account",
-          credit_restrictions: [],
-          debit_restrictions: [],
-          master_sig: "asd",
-          conversion_url: "",
-        },
-        {
-          payto_uri: "payto://x-taler-bank/bank1.taler:8080/asd",
-          credit_restrictions: [],
-          debit_restrictions: [],
-          master_sig: "asd",
-          conversion_url: "",
-        },
-        {
-          payto_uri: "payto://x-taler-bank/bank2.taler:8080/qwe",
-          credit_restrictions: [],
-          debit_restrictions: [],
-          master_sig: "asd",
-          conversion_url: "",
-        },
-      ],
-      reserve_pub: "WEQWDASDQWEASDADASDQWEQWEASDAS",
-    },
-  },
-});
-
-export const NoBankAccount = tests.createExample(TestedComponent, {
-  entity: {
-    request: {
-      exchange_url: "http://exchange.taler/";,
-      initial_balance: "TESTKUDOS:1",
-      wire_method: "x-taler-bank",
-    },
-    response: {
-      accounts: [
-        {
-          payto_uri: "payo://x-talr-bank/bank.taler:8080/exchange_account",
-          credit_restrictions: [],
-          debit_restrictions: [],
-          master_sig: "asd",
-          conversion_url: "",
-        },
-        {
-          payto_uri: "payto://x-taler-bank",
-          credit_restrictions: [],
-          debit_restrictions: [],
-          master_sig: "asd",
-          conversion_url: "",
-        },
-      ],
-      reserve_pub: "WEQWDASDQWEASDADASDQWEQWEASDAS",
-    },
-  },
-});
diff --git 
a/packages/merchant-backoffice-ui/src/paths/instance/reserves/create/CreatedSuccessfully.tsx
 
b/packages/merchant-backoffice-ui/src/paths/instance/reserves/create/CreatedSuccessfully.tsx
deleted file mode 100644
index 1d512c843..000000000
--- 
a/packages/merchant-backoffice-ui/src/paths/instance/reserves/create/CreatedSuccessfully.tsx
+++ /dev/null
@@ -1,190 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2021-2023 Taler Systems S.A.
-
- GNU Taler is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- GNU Taler; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
- */
-
-import { parsePaytoUri, stringifyPaytoUri } from "@gnu-taler/taler-util";
-import { useTranslationContext } from "@gnu-taler/web-util/browser";
-import { Fragment, VNode, h } from "preact";
-import { QR } from "../../../../components/exception/QR.js";
-import { CreatedSuccessfully as Template } from 
"../../../../components/notifications/CreatedSuccessfully.js";
-import { MerchantBackend, WireAccount } from "../../../../declaration.js";
-
-type Entity = {
-  request: MerchantBackend.Rewards.ReserveCreateRequest;
-  response: MerchantBackend.Rewards.ReserveCreateConfirmation;
-};
-
-interface Props {
-  entity: Entity;
-  onConfirm: () => void;
-  onCreateAnother?: () => void;
-}
-
-function isNotUndefined<X>(x: X | undefined): x is X {
-  return !!x;
-}
-
-export function CreatedSuccessfully({
-  entity,
-  onConfirm,
-  onCreateAnother,
-}: Props): VNode {
-  const { i18n } = useTranslationContext();
-  return (
-    <Template onConfirm={onConfirm} onCreateAnother={onCreateAnother}>
-      <div class="field is-horizontal">
-        <div class="field-label is-normal">
-          <label class="label">Amount</label>
-        </div>
-        <div class="field-body is-flex-grow-3">
-          <div class="field">
-            <p class="control">
-              <input
-                readonly
-                class="input"
-                value={entity.request.initial_balance}
-              />
-            </p>
-          </div>
-        </div>
-      </div>
-      <div class="field is-horizontal">
-        <div class="field-label is-normal">
-          <label class="label">Wire transfer subject</label>
-        </div>
-        <div class="field-body is-flex-grow-3">
-          <div class="field">
-            <p class="control">
-              <input
-                class="input"
-                readonly
-                value={entity.response.reserve_pub}
-              />
-            </p>
-          </div>
-        </div>
-      </div>
-      <ShowAccountsOfReserveAsQRWithLink
-        accounts={entity.response.accounts ?? []}
-        message={entity.response.reserve_pub}
-        amount={entity.request.initial_balance}
-      />
-    </Template>
-  );
-}
-
-export function ShowAccountsOfReserveAsQRWithLink({
-  accounts,
-  message,
-  amount,
-}: {
-  accounts: WireAccount[];
-  message: string;
-  amount: string;
-}): VNode {
-  const { i18n } = useTranslationContext();
-  const accountsInfo = !accounts
-    ? []
-    : accounts
-      .map((acc) => {
-        const p = parsePaytoUri(acc.payto_uri);
-        if (p) {
-          p.params["message"] = message;
-          p.params["amount"] = amount;
-        }
-        return p;
-      })
-      .filter(isNotUndefined);
-
-  const links = accountsInfo.map((a) => stringifyPaytoUri(a));
-
-  if (links.length === 0) {
-    return (
-      <Fragment>
-        <p class="is-size-5">
-          The reserve have invalid accounts. List of invalid payto URIs below:
-        </p>
-        <ul>
-          {accounts.map((a, idx) => {
-            return <li key={idx}>{a.payto_uri}</li>;
-          })}
-        </ul>
-      </Fragment>
-    );
-  }
-
-  if (links.length === 1) {
-    return (
-      <Fragment>
-        <p class="is-size-5">
-          <i18n.Translate>
-            To complete the setup of the reserve, you must now initiate a wire
-            transfer using the given wire transfer subject and crediting the
-            specified amount to the indicated account of the exchange.
-          </i18n.Translate>
-        </p>
-        <p style={{ margin: 10 }}>
-          <b>Exchange bank account</b>
-        </p>
-        <QR text={links[0]} />
-        <p class="is-size-5">
-          <i18n.Translate>
-            If your system supports RFC 8905, you can do this by opening this
-            URI:
-          </i18n.Translate>
-        </p>
-        <pre>
-          <a target="_blank" rel="noreferrer" href={links[0]}>
-            {links[0]}
-          </a>
-        </pre>
-      </Fragment>
-    );
-  }
-
-  return (
-    <div>
-      <p class="is-size-5">
-        <i18n.Translate>
-          To complete the setup of the reserve, you must now initiate a wire
-          transfer using the given wire transfer subject and crediting the
-          specified amount to one of the indicated account of the exchange.
-        </i18n.Translate>
-      </p>
-
-      <p style={{ margin: 10 }}>
-        <b>Exchange bank accounts</b>
-      </p>
-      <p class="is-size-5">
-        <i18n.Translate>
-          If your system supports RFC 8905, you can do this by clicking on the
-          URI below the QR code:
-        </i18n.Translate>
-      </p>
-      {links.map((link) => {
-        return (
-          <Fragment>
-            <QR text={link} />
-            <pre>
-              <a target="_blank" rel="noreferrer" href={link}>
-                {link}
-              </a>
-            </pre>
-          </Fragment>
-        );
-      })}
-    </div>
-  );
-}
diff --git 
a/packages/merchant-backoffice-ui/src/paths/instance/reserves/create/index.tsx 
b/packages/merchant-backoffice-ui/src/paths/instance/reserves/create/index.tsx
deleted file mode 100644
index 4bbaf1459..000000000
--- 
a/packages/merchant-backoffice-ui/src/paths/instance/reserves/create/index.tsx
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2021-2023 Taler Systems S.A.
-
- GNU Taler is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- GNU Taler; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
- */
-
-/**
- *
- * @author Sebastian Javier Marchano (sebasjm)
- */
-
-import { useTranslationContext } from "@gnu-taler/web-util/browser";
-import { Fragment, h, VNode } from "preact";
-import { useState } from "preact/hooks";
-import { NotificationCard } from "../../../../components/menu/index.js";
-import { MerchantBackend } from "../../../../declaration.js";
-import { useReservesAPI } from "../../../../hooks/reserves.js";
-import { Notification } from "../../../../utils/types.js";
-import { CreatedSuccessfully } from "./CreatedSuccessfully.js";
-import { CreatePage } from "./CreatePage.js";
-interface Props {
-  onBack: () => void;
-  onConfirm: () => void;
-}
-export default function CreateReserve({ onBack, onConfirm }: Props): VNode {
-  const { createReserve } = useReservesAPI();
-  const [notif, setNotif] = useState<Notification | undefined>(undefined);
-  const { i18n } = useTranslationContext();
-
-  const [createdOk, setCreatedOk] = useState<
-    | {
-      request: MerchantBackend.Rewards.ReserveCreateRequest;
-      response: MerchantBackend.Rewards.ReserveCreateConfirmation;
-    }
-    | undefined
-  >(undefined);
-
-  if (createdOk) {
-    return <CreatedSuccessfully entity={createdOk} onConfirm={onConfirm} />;
-  }
-
-  return (
-    <Fragment>
-      <NotificationCard notification={notif} />
-      <CreatePage
-        onBack={onBack}
-        onCreate={(request: MerchantBackend.Rewards.ReserveCreateRequest) => {
-          return createReserve(request)
-            .then((r) => setCreatedOk({ request, response: r.data }))
-            .catch((error) => {
-              setNotif({
-                message: i18n.str`could not create reserve`,
-                type: "ERROR",
-                description: error.message,
-              });
-            });
-        }}
-      />
-    </Fragment>
-  );
-}
diff --git 
a/packages/merchant-backoffice-ui/src/paths/instance/reserves/details/DetailPage.tsx
 
b/packages/merchant-backoffice-ui/src/paths/instance/reserves/details/DetailPage.tsx
deleted file mode 100644
index d8840eeac..000000000
--- 
a/packages/merchant-backoffice-ui/src/paths/instance/reserves/details/DetailPage.tsx
+++ /dev/null
@@ -1,266 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2021-2023 Taler Systems S.A.
-
- GNU Taler is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- GNU Taler; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
- */
-
-/**
- *
- * @author Sebastian Javier Marchano (sebasjm)
- */
-
-import {
-  Amounts,
-  parsePaytoUri,
-  stringifyPaytoUri,
-} from "@gnu-taler/taler-util";
-import { useTranslationContext } from "@gnu-taler/web-util/browser";
-import { format } from "date-fns";
-import { Fragment, h, VNode } from "preact";
-import { useState } from "preact/hooks";
-import { QR } from "../../../../components/exception/QR.js";
-import { FormProvider } from "../../../../components/form/FormProvider.js";
-import { Input } from "../../../../components/form/Input.js";
-import { InputCurrency } from "../../../../components/form/InputCurrency.js";
-import { InputDate } from "../../../../components/form/InputDate.js";
-import { TextField } from "../../../../components/form/TextField.js";
-import { SimpleModal } from "../../../../components/modal/index.js";
-import { MerchantBackend } from "../../../../declaration.js";
-import { useRewardDetails } from "../../../../hooks/reserves.js";
-import { RewardInfo } from "./RewardInfo.js";
-import { ShowAccountsOfReserveAsQRWithLink } from 
"../create/CreatedSuccessfully.js";
-import { datetimeFormatForSettings, useSettings } from 
"../../../../hooks/useSettings.js";
-
-type Entity = MerchantBackend.Rewards.ReserveDetail;
-type CT = MerchantBackend.ContractTerms;
-
-interface Props {
-  onBack: () => void;
-  selected: Entity;
-  id: string;
-}
-
-export function DetailPage({ id, selected, onBack }: Props): VNode {
-  const { i18n } = useTranslationContext();
-  const didExchangeAckTransfer = Amounts.isNonZero(
-    Amounts.parseOrThrow(selected.exchange_initial_amount),
-  );
-
-  return (
-    <div class="columns">
-      <div class="column" />
-      <div class="column is-four-fifths">
-        <div class="section main-section">
-          <FormProvider object={{ ...selected, id }} valueHandler={null}>
-            <InputDate<Entity>
-              name="creation_time"
-              label={i18n.str`Created at`}
-              readonly
-            />
-            <InputDate<Entity>
-              name="expiration_time"
-              label={i18n.str`Valid until`}
-              readonly
-            />
-            <InputCurrency<Entity>
-              name="merchant_initial_amount"
-              label={i18n.str`Created balance`}
-              readonly
-            />
-            <TextField<Entity>
-              name="exchange_url"
-              label={i18n.str`Exchange URL`}
-              readonly
-            >
-              <a target="_blank" rel="noreferrer" href={selected.exchange_url}>
-                {selected.exchange_url}
-              </a>
-            </TextField>
-
-            {didExchangeAckTransfer && (
-              <Fragment>
-                <InputCurrency<Entity>
-                  name="exchange_initial_amount"
-                  label={i18n.str`Exchange balance`}
-                  readonly
-                />
-                <InputCurrency<Entity>
-                  name="pickup_amount"
-                  label={i18n.str`Picked up`}
-                  readonly
-                />
-                <InputCurrency<Entity>
-                  name="committed_amount"
-                  label={i18n.str`Committed`}
-                  readonly
-                />
-              </Fragment>
-            )}
-            <Input name="id" label={i18n.str`Subject`} readonly />
-          </FormProvider>
-
-          {didExchangeAckTransfer ? (
-            <Fragment>
-              <div class="card has-table">
-                <header class="card-header">
-                  <p class="card-header-title">
-                    <span class="icon">
-                      <i class="mdi mdi-cash-register" />
-                    </span>
-                    <i18n.Translate>Rewards</i18n.Translate>
-                  </p>
-                </header>
-                <div class="card-content">
-                  <div class="b-table has-pagination">
-                    <div class="table-wrapper has-mobile-cards">
-                      {selected.rewards && selected.rewards.length > 0 ? (
-                        <Table rewards={selected.rewards} />
-                      ) : (
-                        <EmptyTable />
-                      )}
-                    </div>
-                  </div>
-                </div>
-              </div>
-            </Fragment>
-          ) : selected.accounts ? (
-            <ShowAccountsOfReserveAsQRWithLink
-              accounts={selected.accounts}
-              amount={selected.merchant_initial_amount}
-              message={id}
-            />
-          ) : undefined}
-
-          <div class="buttons is-right mt-5">
-            <button class="button" onClick={onBack}>
-              <i18n.Translate>Back</i18n.Translate>
-            </button>
-          </div>
-        </div>
-      </div>
-      <div class="column" />
-    </div>
-  );
-}
-
-function EmptyTable(): VNode {
-  const { i18n } = useTranslationContext();
-  return (
-    <div class="content has-text-grey has-text-centered">
-      <p>
-        <span class="icon is-large">
-          <i class="mdi mdi-emoticon-sad mdi-48px" />
-        </span>
-      </p>
-      <p>
-        <i18n.Translate>
-          No reward has been authorized from this reserve
-        </i18n.Translate>
-      </p>
-    </div>
-  );
-}
-
-interface TableProps {
-  rewards: MerchantBackend.Rewards.RewardStatusEntry[];
-}
-
-function Table({ rewards }: TableProps): VNode {
-  const { i18n } = useTranslationContext();
-  return (
-    <div class="table-container">
-      <table class="table is-fullwidth is-striped is-hoverable is-fullwidth">
-        <thead>
-          <tr>
-            <th>
-              <i18n.Translate>Authorized</i18n.Translate>
-            </th>
-            <th>
-              <i18n.Translate>Picked up</i18n.Translate>
-            </th>
-            <th>
-              <i18n.Translate>Reason</i18n.Translate>
-            </th>
-            <th>
-              <i18n.Translate>Expiration</i18n.Translate>
-            </th>
-          </tr>
-        </thead>
-        <tbody>
-          {rewards.map((t, i) => {
-            return <RewardRow id={t.reward_id} key={i} entry={t} />;
-          })}
-        </tbody>
-      </table>
-    </div>
-  );
-}
-
-function RewardRow({
-  id,
-  entry,
-}: {
-  id: string;
-  entry: MerchantBackend.Rewards.RewardStatusEntry;
-}) {
-  const [selected, setSelected] = useState(false);
-  const result = useRewardDetails(id);
-  const [settings] = useSettings();
-  if (result.loading) {
-    return (
-      <tr>
-        <td>...</td>
-        <td>...</td>
-        <td>...</td>
-        <td>...</td>
-      </tr>
-    );
-  }
-  if (!result.ok) {
-    return (
-      <tr>
-        <td>...</td> {/* authorized */}
-        <td>{entry.total_amount}</td>
-        <td>{entry.reason}</td>
-        <td>...</td> {/* expired */}
-      </tr>
-    );
-  }
-  const info = result.data;
-  function onSelect() {
-    setSelected(true);
-  }
-  return (
-    <Fragment>
-      {selected && (
-        <SimpleModal
-          description="reward"
-          active
-          onCancel={() => setSelected(false)}
-        >
-          <RewardInfo id={id} amount={info.total_authorized} entity={info} />
-        </SimpleModal>
-      )}
-      <tr>
-        <td onClick={onSelect}>{info.total_authorized}</td>
-        <td onClick={onSelect}>{info.total_picked_up}</td>
-        <td onClick={onSelect}>{info.reason}</td>
-        <td onClick={onSelect}>
-          {info.expiration.t_s === "never"
-            ? "never"
-            : format(info.expiration.t_s * 1000, 
datetimeFormatForSettings(settings))}
-        </td>
-      </tr>
-    </Fragment>
-  );
-}
diff --git 
a/packages/merchant-backoffice-ui/src/paths/instance/reserves/details/Details.stories.tsx
 
b/packages/merchant-backoffice-ui/src/paths/instance/reserves/details/Details.stories.tsx
deleted file mode 100644
index 41c715f20..000000000
--- 
a/packages/merchant-backoffice-ui/src/paths/instance/reserves/details/Details.stories.tsx
+++ /dev/null
@@ -1,126 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2021-2023 Taler Systems S.A.
-
- GNU Taler is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- GNU Taler; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
- */
-
-/**
- *
- * @author Sebastian Javier Marchano (sebasjm)
- */
-
-import { h, VNode, FunctionalComponent } from "preact";
-import { DetailPage as TestedComponent } from "./DetailPage.js";
-
-export default {
-  title: "Pages/Reserve/Detail",
-  component: TestedComponent,
-  argTypes: {
-    onUpdate: { action: "onUpdate" },
-    onBack: { action: "onBack" },
-  },
-};
-
-function createExample<Props>(
-  Component: FunctionalComponent<Props>,
-  props: Partial<Props>,
-) {
-  const r = (args: any) => <Component {...args} />;
-  r.args = props;
-  return r;
-}
-
-export const Funded = createExample(TestedComponent, {
-  id: "THISISTHERESERVEID",
-  selected: {
-    active: true,
-    committed_amount: "TESTKUDOS:10",
-    creation_time: {
-      t_s: new Date().getTime() / 1000,
-    },
-    exchange_initial_amount: "TESTKUDOS:10",
-    expiration_time: {
-      t_s: new Date().getTime() / 1000,
-    },
-    merchant_initial_amount: "TESTKUDOS:10",
-    pickup_amount: "TESTKUDOS:10",
-    accounts: [
-      {
-        payto_uri: "payto://x-taler-bank/bank.taler:8080/account",
-        credit_restrictions: [],
-        debit_restrictions: [],
-        master_sig: "",
-      },
-    ],
-    exchange_url: "http://exchange.taler/";,
-  },
-});
-
-export const NotYetFunded = createExample(TestedComponent, {
-  id: "THISISTHERESERVEID",
-  selected: {
-    active: true,
-    committed_amount: "TESTKUDOS:10",
-    creation_time: {
-      t_s: new Date().getTime() / 1000,
-    },
-    exchange_initial_amount: "TESTKUDOS:0",
-    expiration_time: {
-      t_s: new Date().getTime() / 1000,
-    },
-    merchant_initial_amount: "TESTKUDOS:10",
-    pickup_amount: "TESTKUDOS:10",
-    accounts: [
-      {
-        payto_uri: "payto://x-taler-bank/bank.taler:8080/account",
-        credit_restrictions: [],
-        debit_restrictions: [],
-        master_sig: "",
-      },
-    ],
-    exchange_url: "http://exchange.taler/";,
-  },
-});
-
-export const FundedWithEmptyRewards = createExample(TestedComponent, {
-  id: "THISISTHERESERVEID",
-  selected: {
-    active: true,
-    committed_amount: "TESTKUDOS:10",
-    creation_time: {
-      t_s: new Date().getTime() / 1000,
-    },
-    exchange_initial_amount: "TESTKUDOS:10",
-    expiration_time: {
-      t_s: new Date().getTime() / 1000,
-    },
-    merchant_initial_amount: "TESTKUDOS:10",
-    pickup_amount: "TESTKUDOS:10",
-    accounts: [
-      {
-        payto_uri: "payto://x-taler-bank/bank.taler:8080/account",
-        credit_restrictions: [],
-        debit_restrictions: [],
-        master_sig: "",
-      },
-    ],
-    exchange_url: "http://exchange.taler/";,
-    rewards: [
-      {
-        reason: "asdasd",
-        reward_id: "123",
-        total_amount: "TESTKUDOS:1",
-      },
-    ],
-  },
-});
diff --git 
a/packages/merchant-backoffice-ui/src/paths/instance/reserves/details/RewardInfo.tsx
 
b/packages/merchant-backoffice-ui/src/paths/instance/reserves/details/RewardInfo.tsx
deleted file mode 100644
index 780068a91..000000000
--- 
a/packages/merchant-backoffice-ui/src/paths/instance/reserves/details/RewardInfo.tsx
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2021-2023 Taler Systems S.A.
-
- GNU Taler is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- GNU Taler; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
- */
-import { stringifyRewardUri } from "@gnu-taler/taler-util";
-import { format } from "date-fns";
-import { Fragment, h, VNode } from "preact";
-import { useBackendContext } from "../../../../context/backend.js";
-import { MerchantBackend } from "../../../../declaration.js";
-import { datetimeFormatForSettings, useSettings } from 
"../../../../hooks/useSettings.js";
-
-type Entity = MerchantBackend.Rewards.RewardDetails;
-
-interface Props {
-  id: string;
-  entity: Entity;
-  amount: string;
-}
-
-export function RewardInfo({ id: merchantRewardId, amount, entity }: Props): 
VNode {
-  const { url: backendURL } = useBackendContext()
-  const [settings] = useSettings();
-  const rewardURL = stringifyRewardUri({ merchantBaseUrl: backendURL, 
merchantRewardId })
-  return (
-    <Fragment>
-      <div class="field is-horizontal">
-        <div class="field-label is-normal">
-          <label class="label">Amount</label>
-        </div>
-        <div class="field-body is-flex-grow-3">
-          <div class="field">
-            <p class="control">
-              <input readonly class="input" value={amount} />
-            </p>
-          </div>
-        </div>
-      </div>
-      <div class="field is-horizontal">
-        <div class="field-label is-normal">
-          <label class="label">URL</label>
-        </div>
-        <div class="field-body is-flex-grow-3">
-          <div class="field" style={{ overflowWrap: "anywhere" }}>
-            <p class="control">
-              <a target="_blank" rel="noreferrer" href={rewardURL}>
-                {rewardURL}
-              </a>
-            </p>
-          </div>
-        </div>
-      </div>
-      <div class="field is-horizontal">
-        <div class="field-label is-normal">
-          <label class="label">Valid until</label>
-        </div>
-        <div class="field-body is-flex-grow-3">
-          <div class="field">
-            <p class="control">
-              <input
-                class="input"
-                readonly
-                value={
-                  !entity.expiration || entity.expiration.t_s === "never"
-                    ? "never"
-                    : format(
-                      entity.expiration.t_s * 1000,
-                      datetimeFormatForSettings(settings),
-                    )
-                }
-              />
-            </p>
-          </div>
-        </div>
-      </div>
-    </Fragment>
-  );
-}
diff --git 
a/packages/merchant-backoffice-ui/src/paths/instance/reserves/details/index.tsx 
b/packages/merchant-backoffice-ui/src/paths/instance/reserves/details/index.tsx
deleted file mode 100644
index 8e2a74529..000000000
--- 
a/packages/merchant-backoffice-ui/src/paths/instance/reserves/details/index.tsx
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2021-2023 Taler Systems S.A.
-
- GNU Taler is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- GNU Taler; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
- */
-
-/**
- *
- * @author Sebastian Javier Marchano (sebasjm)
- */
-
-import { ErrorType, HttpError } from "@gnu-taler/web-util/browser";
-import { Fragment, h, VNode } from "preact";
-import { Loading } from "../../../../components/exception/loading.js";
-import { MerchantBackend } from "../../../../declaration.js";
-import { useReserveDetails } from "../../../../hooks/reserves.js";
-import { DetailPage } from "./DetailPage.js";
-import { HttpStatusCode } from "@gnu-taler/taler-util";
-
-interface Props {
-  rid: string;
-
-  onUnauthorized: () => VNode;
-  onLoadError: (error: HttpError<MerchantBackend.ErrorDetail>) => VNode;
-  onNotFound: () => VNode;
-  onDelete: () => void;
-  onBack: () => void;
-}
-export default function DetailReserve({
-  rid,
-  onUnauthorized,
-  onLoadError,
-  onNotFound,
-  onBack,
-  onDelete,
-}: Props): VNode {
-  const result = useReserveDetails(rid);
-
-  if (result.loading) return <Loading />;
-  if (!result.ok) {
-    if (
-      result.type === ErrorType.CLIENT &&
-      result.status === HttpStatusCode.Unauthorized
-    )
-      return onUnauthorized();
-    if (
-      result.type === ErrorType.CLIENT &&
-      result.status === HttpStatusCode.NotFound
-    )
-      return onNotFound();
-    return onLoadError(result);
-  }
-  return (
-    <Fragment>
-      <DetailPage selected={result.data} onBack={onBack} id={rid} />
-    </Fragment>
-  );
-}
diff --git 
a/packages/merchant-backoffice-ui/src/paths/instance/reserves/list/AutorizeRewardModal.tsx
 
b/packages/merchant-backoffice-ui/src/paths/instance/reserves/list/AutorizeRewardModal.tsx
deleted file mode 100644
index e205ee621..000000000
--- 
a/packages/merchant-backoffice-ui/src/paths/instance/reserves/list/AutorizeRewardModal.tsx
+++ /dev/null
@@ -1,124 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2021-2023 Taler Systems S.A.
-
- GNU Taler is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- GNU Taler; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
- */
-
-/**
- *
- * @author Sebastian Javier Marchano (sebasjm)
- */
-
-import { useTranslationContext } from "@gnu-taler/web-util/browser";
-import { h, VNode } from "preact";
-import { useState } from "preact/hooks";
-import * as yup from "yup";
-import {
-  FormErrors,
-  FormProvider,
-} from "../../../../components/form/FormProvider.js";
-import { Input } from "../../../../components/form/Input.js";
-import { InputCurrency } from "../../../../components/form/InputCurrency.js";
-import {
-  ConfirmModal,
-  ContinueModal,
-} from "../../../../components/modal/index.js";
-import { MerchantBackend } from "../../../../declaration.js";
-import { AuthorizeRewardSchema } from "../../../../schemas/index.js";
-import { CreatedSuccessfully } from "./CreatedSuccessfully.js";
-
-interface AuthorizeRewardModalProps {
-  onCancel: () => void;
-  onConfirm: (value: MerchantBackend.Rewards.RewardCreateRequest) => void;
-  rewardAuthorized?: {
-    response: MerchantBackend.Rewards.RewardCreateConfirmation;
-    request: MerchantBackend.Rewards.RewardCreateRequest;
-  };
-}
-
-export function AuthorizeRewardModal({
-  onCancel,
-  onConfirm,
-  rewardAuthorized,
-}: AuthorizeRewardModalProps): VNode {
-  // const result = useOrderDetails(id)
-  type State = MerchantBackend.Rewards.RewardCreateRequest;
-  const [form, setValue] = useState<Partial<State>>({});
-  const { i18n } = useTranslationContext();
-
-  // const [errors, setErrors] = useState<FormErrors<State>>({})
-  let errors: FormErrors<State> = {};
-  try {
-    AuthorizeRewardSchema.validateSync(form, { abortEarly: false });
-  } catch (err) {
-    if (err instanceof yup.ValidationError) {
-      const yupErrors = err.inner as any[];
-      errors = yupErrors.reduce(
-        (prev, cur) =>
-          !cur.path ? prev : { ...prev, [cur.path]: cur.message },
-        {},
-      );
-    }
-  }
-  const hasErrors = Object.keys(errors).some(
-    (k) => (errors as any)[k] !== undefined,
-  );
-
-  const validateAndConfirm = () => {
-    onConfirm(form as State);
-  };
-  if (rewardAuthorized) {
-    return (
-      <ContinueModal description="reward" active onConfirm={onCancel}>
-        <CreatedSuccessfully
-          entity={rewardAuthorized.response}
-          request={rewardAuthorized.request}
-          onConfirm={onCancel}
-        />
-      </ContinueModal>
-    );
-  }
-
-  return (
-    <ConfirmModal
-      description="New reward"
-      active
-      onCancel={onCancel}
-      disabled={hasErrors}
-      onConfirm={validateAndConfirm}
-    >
-      <FormProvider<State>
-        errors={errors}
-        object={form}
-        valueHandler={setValue}
-      >
-        <InputCurrency<State>
-          name="amount"
-          label={i18n.str`Amount`}
-          tooltip={i18n.str`amount of reward`}
-        />
-        <Input<State>
-          name="justification"
-          label={i18n.str`Justification`}
-          inputType="multiline"
-          tooltip={i18n.str`reason for the reward`}
-        />
-        <Input<State>
-          name="next_url"
-          label={i18n.str`URL after reward`}
-          tooltip={i18n.str`URL to visit after reward payment`}
-        />
-      </FormProvider>
-    </ConfirmModal>
-  );
-}
diff --git 
a/packages/merchant-backoffice-ui/src/paths/instance/reserves/list/CreatedSuccessfully.tsx
 
b/packages/merchant-backoffice-ui/src/paths/instance/reserves/list/CreatedSuccessfully.tsx
deleted file mode 100644
index b78236bc7..000000000
--- 
a/packages/merchant-backoffice-ui/src/paths/instance/reserves/list/CreatedSuccessfully.tsx
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2021-2023 Taler Systems S.A.
-
- GNU Taler is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- GNU Taler; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
- */
-import { format } from "date-fns";
-import { Fragment, h, VNode } from "preact";
-import { CreatedSuccessfully as Template } from 
"../../../../components/notifications/CreatedSuccessfully.js";
-import { MerchantBackend } from "../../../../declaration.js";
-import { datetimeFormatForSettings, useSettings } from 
"../../../../hooks/useSettings.js";
-
-type Entity = MerchantBackend.Rewards.RewardCreateConfirmation;
-
-interface Props {
-  entity: Entity;
-  request: MerchantBackend.Rewards.RewardCreateRequest;
-  onConfirm: () => void;
-  onCreateAnother?: () => void;
-}
-
-export function CreatedSuccessfully({
-  request,
-  entity,
-  onConfirm,
-  onCreateAnother,
-}: Props): VNode {
-  const [settings] = useSettings();
-  return (
-    <Fragment>
-      <div class="field is-horizontal">
-        <div class="field-label is-normal">
-          <label class="label">Amount</label>
-        </div>
-        <div class="field-body is-flex-grow-3">
-          <div class="field">
-            <p class="control">
-              <input readonly class="input" value={request.amount} />
-            </p>
-          </div>
-        </div>
-      </div>
-      <div class="field is-horizontal">
-        <div class="field-label is-normal">
-          <label class="label">Justification</label>
-        </div>
-        <div class="field-body is-flex-grow-3">
-          <div class="field">
-            <p class="control">
-              <input readonly class="input" value={request.justification} />
-            </p>
-          </div>
-        </div>
-      </div>
-      <div class="field is-horizontal">
-        <div class="field-label is-normal">
-          <label class="label">URL</label>
-        </div>
-        <div class="field-body is-flex-grow-3">
-          <div class="field">
-            <p class="control">
-              <input readonly class="input" value={entity.reward_status_url} />
-            </p>
-          </div>
-        </div>
-      </div>
-      <div class="field is-horizontal">
-        <div class="field-label is-normal">
-          <label class="label">Valid until</label>
-        </div>
-        <div class="field-body is-flex-grow-3">
-          <div class="field">
-            <p class="control">
-              <input
-                class="input"
-                readonly
-                value={
-                  !entity.reward_expiration ||
-                    entity.reward_expiration.t_s === "never"
-                    ? "never"
-                    : format(
-                      entity.reward_expiration.t_s * 1000,
-                      datetimeFormatForSettings(settings),
-                    )
-                }
-              />
-            </p>
-          </div>
-        </div>
-      </div>
-    </Fragment>
-  );
-}
diff --git 
a/packages/merchant-backoffice-ui/src/paths/instance/reserves/list/List.stories.tsx
 
b/packages/merchant-backoffice-ui/src/paths/instance/reserves/list/List.stories.tsx
deleted file mode 100644
index b070bbde3..000000000
--- 
a/packages/merchant-backoffice-ui/src/paths/instance/reserves/list/List.stories.tsx
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2021-2023 Taler Systems S.A.
-
- GNU Taler is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- GNU Taler; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
- */
-
-/**
- *
- * @author Sebastian Javier Marchano (sebasjm)
- */
-
-import { h, VNode, FunctionalComponent } from "preact";
-import { CardTable as TestedComponent } from "./Table.js";
-
-export default {
-  title: "Pages/Reserve/List",
-  component: TestedComponent,
-};
-
-function createExample<Props>(
-  Component: FunctionalComponent<Props>,
-  props: Partial<Props>,
-) {
-  const r = (args: any) => <Component {...args} />;
-  r.args = props;
-  return r;
-}
-
-export const AllFunded = createExample(TestedComponent, {
-  instances: [
-    {
-      id: "reseverId",
-      active: true,
-      committed_amount: "TESTKUDOS:10",
-      creation_time: {
-        t_s: new Date().getTime() / 1000,
-      },
-      exchange_initial_amount: "TESTKUDOS:10",
-      expiration_time: {
-        t_s: new Date().getTime() / 1000,
-      },
-      merchant_initial_amount: "TESTKUDOS:10",
-      pickup_amount: "TESTKUDOS:10",
-      reserve_pub: "WEQWDASDQWEASDADASDQWEQWEASDAS",
-    },
-    {
-      id: "reseverId2",
-      active: true,
-      committed_amount: "TESTKUDOS:13",
-      creation_time: {
-        t_s: new Date().getTime() / 1000,
-      },
-      exchange_initial_amount: "TESTKUDOS:10",
-      expiration_time: {
-        t_s: new Date().getTime() / 1000,
-      },
-      merchant_initial_amount: "TESTKUDOS:10",
-      pickup_amount: "TESTKUDOS:10",
-      reserve_pub: "WEQWDASDQWEASDADASDQWEQWEASDAS",
-    },
-  ],
-});
-
-export const Empty = createExample(TestedComponent, {
-  instances: [],
-});
-
-export const OneNotYetFunded = createExample(TestedComponent, {
-  instances: [
-    {
-      id: "reseverId",
-      active: true,
-      committed_amount: "TESTKUDOS:0",
-      creation_time: {
-        t_s: new Date().getTime() / 1000,
-      },
-      exchange_initial_amount: "TESTKUDOS:0",
-      expiration_time: {
-        t_s: new Date().getTime() / 1000,
-      },
-      merchant_initial_amount: "TESTKUDOS:10",
-      pickup_amount: "TESTKUDOS:10",
-      reserve_pub: "WEQWDASDQWEASDADASDQWEQWEASDAS",
-    },
-  ],
-});
diff --git 
a/packages/merchant-backoffice-ui/src/paths/instance/reserves/list/Table.tsx 
b/packages/merchant-backoffice-ui/src/paths/instance/reserves/list/Table.tsx
deleted file mode 100644
index 795e7ec82..000000000
--- a/packages/merchant-backoffice-ui/src/paths/instance/reserves/list/Table.tsx
+++ /dev/null
@@ -1,320 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2021-2023 Taler Systems S.A.
-
- GNU Taler is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- GNU Taler; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
- */
-
-/**
- *
- * @author Sebastian Javier Marchano (sebasjm)
- */
-
-import { useTranslationContext } from "@gnu-taler/web-util/browser";
-import { format } from "date-fns";
-import { Fragment, h, VNode } from "preact";
-import { MerchantBackend, WithId } from "../../../../declaration.js";
-import { datetimeFormatForSettings, useSettings } from 
"../../../../hooks/useSettings.js";
-
-type Entity = MerchantBackend.Rewards.ReserveStatusEntry & WithId;
-
-interface Props {
-  instances: Entity[];
-  onNewReward: (id: Entity) => void;
-  onSelect: (id: Entity) => void;
-  onDelete: (id: Entity) => void;
-  onCreate: () => void;
-}
-
-export function CardTable({
-  instances,
-  onCreate,
-  onSelect,
-  onNewReward,
-  onDelete,
-}: Props): VNode {
-  const [withoutFunds, withFunds] = instances.reduce((prev, current) => {
-    const amount = current.exchange_initial_amount;
-    if (amount.endsWith(":0")) {
-      prev[0] = prev[0].concat(current);
-    } else {
-      prev[1] = prev[1].concat(current);
-    }
-    return prev;
-  }, new Array<Array<Entity>>([], []));
-
-  const { i18n } = useTranslationContext();
-
-  return (
-    <Fragment>
-      {withoutFunds.length > 0 && (
-        <div class="card has-table">
-          <header class="card-header">
-            <p class="card-header-title">
-              <span class="icon">
-                <i class="mdi mdi-cash" />
-              </span>
-              <i18n.Translate>Reserves not yet funded</i18n.Translate>
-            </p>
-          </header>
-          <div class="card-content">
-            <div class="b-table has-pagination">
-              <div class="table-wrapper has-mobile-cards">
-                <TableWithoutFund
-                  instances={withoutFunds}
-                  onNewReward={onNewReward}
-                  onSelect={onSelect}
-                  onDelete={onDelete}
-                />
-              </div>
-            </div>
-          </div>
-        </div>
-      )}
-
-      <div class="card has-table">
-        <header class="card-header">
-          <p class="card-header-title">
-            <span class="icon">
-              <i class="mdi mdi-cash" />
-            </span>
-            <i18n.Translate>Reserves ready</i18n.Translate>
-          </p>
-          <div class="card-header-icon" aria-label="more options" />
-          <div class="card-header-icon" aria-label="more options">
-            <span
-              class="has-tooltip-left"
-              data-tooltip={i18n.str`add new reserve`}
-            >
-              <button class="button is-info" type="button" onClick={onCreate}>
-                <span class="icon is-small">
-                  <i class="mdi mdi-plus mdi-36px" />
-                </span>
-              </button>
-            </span>
-          </div>
-        </header>
-        <div class="card-content">
-          <div class="b-table has-pagination">
-            <div class="table-wrapper has-mobile-cards">
-              {withFunds.length > 0 ? (
-                <Table
-                  instances={withFunds}
-                  onNewReward={onNewReward}
-                  onSelect={onSelect}
-                  onDelete={onDelete}
-                />
-              ) : (
-                <EmptyTable />
-              )}
-            </div>
-          </div>
-        </div>
-      </div>
-    </Fragment>
-  );
-}
-interface TableProps {
-  instances: Entity[];
-  onNewReward: (id: Entity) => void;
-  onDelete: (id: Entity) => void;
-  onSelect: (id: Entity) => void;
-}
-
-function Table({ instances, onNewReward, onSelect, onDelete }: TableProps): 
VNode {
-  const { i18n } = useTranslationContext();
-  const [settings] = useSettings();
-  return (
-    <div class="table-container">
-      <table class="table is-fullwidth is-striped is-hoverable is-fullwidth">
-        <thead>
-          <tr>
-            <th>
-              <i18n.Translate>Created at</i18n.Translate>
-            </th>
-            <th>
-              <i18n.Translate>Expires at</i18n.Translate>
-            </th>
-            <th>
-              <i18n.Translate>Initial</i18n.Translate>
-            </th>
-            <th>
-              <i18n.Translate>Picked up</i18n.Translate>
-            </th>
-            <th>
-              <i18n.Translate>Committed</i18n.Translate>
-            </th>
-            <th />
-          </tr>
-        </thead>
-        <tbody>
-          {instances.map((i) => {
-            return (
-              <tr key={i.id}>
-                <td
-                  onClick={(): void => onSelect(i)}
-                  style={{ cursor: "pointer" }}
-                >
-                  {i.creation_time.t_s === "never"
-                    ? "never"
-                    : format(i.creation_time.t_s * 1000, 
datetimeFormatForSettings(settings))}
-                </td>
-                <td
-                  onClick={(): void => onSelect(i)}
-                  style={{ cursor: "pointer" }}
-                >
-                  {i.expiration_time.t_s === "never"
-                    ? "never"
-                    : format(
-                      i.expiration_time.t_s * 1000,
-                      datetimeFormatForSettings(settings),
-                    )}
-                </td>
-                <td
-                  onClick={(): void => onSelect(i)}
-                  style={{ cursor: "pointer" }}
-                >
-                  {i.exchange_initial_amount}
-                </td>
-                <td
-                  onClick={(): void => onSelect(i)}
-                  style={{ cursor: "pointer" }}
-                >
-                  {i.pickup_amount}
-                </td>
-                <td
-                  onClick={(): void => onSelect(i)}
-                  style={{ cursor: "pointer" }}
-                >
-                  {i.committed_amount}
-                </td>
-                <td class="is-actions-cell right-sticky">
-                  <div class="buttons is-right">
-                    <button
-                      class="button is-small is-danger has-tooltip-left"
-                      data-tooltip={i18n.str`delete selected reserve from the 
database`}
-                      type="button"
-                      onClick={(): void => onDelete(i)}
-                    >
-                      Delete
-                    </button>
-                    <button
-                      class="button is-small is-info has-tooltip-left"
-                      data-tooltip={i18n.str`authorize new reward from 
selected reserve`}
-                      type="button"
-                      onClick={(): void => onNewReward(i)}
-                    >
-                      New Reward
-                    </button>
-                  </div>
-                </td>
-              </tr>
-            );
-          })}
-        </tbody>
-      </table>
-    </div>
-  );
-}
-
-function EmptyTable(): VNode {
-  const { i18n } = useTranslationContext();
-  return (
-    <div class="content has-text-grey has-text-centered">
-      <p>
-        <span class="icon is-large">
-          <i class="mdi mdi-emoticon-sad mdi-48px" />
-        </span>
-      </p>
-      <p>
-        <i18n.Translate>
-          There is no ready reserves yet, add more pressing the + sign or fund
-          them
-        </i18n.Translate>
-      </p>
-    </div>
-  );
-}
-
-function TableWithoutFund({
-  instances,
-  onSelect,
-  onDelete,
-}: TableProps): VNode {
-  const { i18n } = useTranslationContext();
-  const [settings] = useSettings();
-  return (
-    <div class="table-container">
-      <table class="table is-fullwidth is-striped is-hoverable is-fullwidth">
-        <thead>
-          <tr>
-            <th>
-              <i18n.Translate>Created at</i18n.Translate>
-            </th>
-            <th>
-              <i18n.Translate>Expires at</i18n.Translate>
-            </th>
-            <th>
-              <i18n.Translate>Expected Balance</i18n.Translate>
-            </th>
-            <th />
-          </tr>
-        </thead>
-        <tbody>
-          {instances.map((i) => {
-            return (
-              <tr key={i.id}>
-                <td
-                  onClick={(): void => onSelect(i)}
-                  style={{ cursor: "pointer" }}
-                >
-                  {i.creation_time.t_s === "never"
-                    ? "never"
-                    : format(i.creation_time.t_s * 1000, 
datetimeFormatForSettings(settings))}
-                </td>
-                <td
-                  onClick={(): void => onSelect(i)}
-                  style={{ cursor: "pointer" }}
-                >
-                  {i.expiration_time.t_s === "never"
-                    ? "never"
-                    : format(
-                      i.expiration_time.t_s * 1000,
-                      datetimeFormatForSettings(settings),
-                    )}
-                </td>
-                <td
-                  onClick={(): void => onSelect(i)}
-                  style={{ cursor: "pointer" }}
-                >
-                  {i.merchant_initial_amount}
-                </td>
-                <td class="is-actions-cell right-sticky">
-                  <div class="buttons is-right">
-                    <button
-                      class="button is-small is-danger jb-modal 
has-tooltip-left"
-                      type="button"
-                      data-tooltip={i18n.str`delete selected reserve from the 
database`}
-                      onClick={(): void => onDelete(i)}
-                    >
-                      Delete
-                    </button>
-                  </div>
-                </td>
-              </tr>
-            );
-          })}
-        </tbody>
-      </table>
-    </div>
-  );
-}
diff --git 
a/packages/merchant-backoffice-ui/src/paths/instance/reserves/list/index.tsx 
b/packages/merchant-backoffice-ui/src/paths/instance/reserves/list/index.tsx
deleted file mode 100644
index b26ff0000..000000000
--- a/packages/merchant-backoffice-ui/src/paths/instance/reserves/list/index.tsx
+++ /dev/null
@@ -1,171 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2021-2023 Taler Systems S.A.
-
- GNU Taler is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- GNU Taler; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
- */
-
-/**
- *
- * @author Sebastian Javier Marchano (sebasjm)
- */
-
-import {
-  ErrorType,
-  HttpError,
-  useTranslationContext,
-} from "@gnu-taler/web-util/browser";
-import { h, VNode } from "preact";
-import { useState } from "preact/hooks";
-import { Loading } from "../../../../components/exception/loading.js";
-import { NotificationCard } from "../../../../components/menu/index.js";
-import { MerchantBackend } from "../../../../declaration.js";
-import {
-  useInstanceReserves,
-  useReservesAPI,
-} from "../../../../hooks/reserves.js";
-import { Notification } from "../../../../utils/types.js";
-import { AuthorizeRewardModal } from "./AutorizeRewardModal.js";
-import { CardTable } from "./Table.js";
-import { HttpStatusCode } from "@gnu-taler/taler-util";
-import { ConfirmModal } from "../../../../components/modal/index.js";
-
-interface Props {
-  onUnauthorized: () => VNode;
-  onLoadError: (e: HttpError<MerchantBackend.ErrorDetail>) => VNode;
-  onSelect: (id: string) => void;
-  onNotFound: () => VNode;
-  onCreate: () => void;
-}
-
-interface RewardConfirmation {
-  response: MerchantBackend.Rewards.RewardCreateConfirmation;
-  request: MerchantBackend.Rewards.RewardCreateRequest;
-}
-
-export default function ListRewards({
-  onUnauthorized,
-  onLoadError,
-  onNotFound,
-  onSelect,
-  onCreate,
-}: Props): VNode {
-  const result = useInstanceReserves();
-  const { deleteReserve, authorizeRewardReserve } = useReservesAPI();
-  const [notif, setNotif] = useState<Notification | undefined>(undefined);
-  const { i18n } = useTranslationContext();
-  const [reserveForReward, setReserveForReward] = useState<string | undefined>(
-    undefined,
-  );
-  const [deleting, setDeleting] =
-    useState<MerchantBackend.Rewards.ReserveStatusEntry | null>(null);
-  const [rewardAuthorized, setRewardAuthorized] = useState<
-    RewardConfirmation | 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);
-  }
-
-  return (
-    <section class="section is-main-section">
-      <NotificationCard notification={notif} />
-
-      {reserveForReward && (
-        <AuthorizeRewardModal
-          onCancel={() => {
-            setReserveForReward(undefined);
-            setRewardAuthorized(undefined);
-          }}
-          rewardAuthorized={rewardAuthorized}
-          onConfirm={async (request) => {
-            try {
-              const response = await authorizeRewardReserve(
-                reserveForReward,
-                request,
-              );
-              setRewardAuthorized({
-                request,
-                response: response.data,
-              });
-            } catch (error) {
-              setNotif({
-                message: i18n.str`could not create the reward`,
-                type: "ERROR",
-                description: error instanceof Error ? error.message : 
undefined,
-              });
-              setReserveForReward(undefined);
-            }
-          }}
-        />
-      )}
-
-      <CardTable
-        instances={result.data.reserves
-          .filter((r) => r.active)
-          .map((o) => ({ ...o, id: o.reserve_pub }))}
-        onCreate={onCreate}
-        onDelete={(reserve) => {
-          setDeleting(reserve)
-        }}
-        onSelect={(reserve) => onSelect(reserve.id)}
-        onNewReward={(reserve) => setReserveForReward(reserve.id)}
-      />
-
-      {deleting && (
-        <ConfirmModal
-          label={`Delete reserve`}
-          description={`Delete the reserve`}
-          danger
-          active
-          onCancel={() => setDeleting(null)}
-          onConfirm={async (): Promise<void> => {
-            try {
-              await deleteReserve(deleting.reserve_pub);
-              setNotif({
-                message: i18n.str`Reserve for 
"${deleting.merchant_initial_amount}" (ID: ${deleting.reserve_pub}) has been 
deleted`,
-                type: "SUCCESS",
-              });
-            } catch (error) {
-              setNotif({
-                message: i18n.str`Failed to delete reserve`,
-                type: "ERROR",
-                description: error instanceof Error ? error.message : 
undefined,
-              });
-            }
-            setDeleting(null);
-          }}
-        >
-          <p>
-            If you delete the reserve for 
<b>&quot;{deleting.merchant_initial_amount}&quot;</b> you won't be able to 
create more rewards. <br />
-            Reserve ID: <b>{deleting.reserve_pub}</b>
-          </p>
-          <p class="warning">
-            Deleting an template <b>cannot be undone</b>.
-          </p>
-        </ConfirmModal>
-      )}
-
-    </section>
-  );
-}
diff --git a/packages/merchant-backoffice-ui/src/schemas/index.ts 
b/packages/merchant-backoffice-ui/src/schemas/index.ts
index c97d41204..5d168d6ac 100644
--- a/packages/merchant-backoffice-ui/src/schemas/index.ts
+++ b/packages/merchant-backoffice-ui/src/schemas/index.ts
@@ -124,27 +124,6 @@ export const InstanceSchema = yup.object().shape({
 export const InstanceUpdateSchema = InstanceSchema.clone().omit(["id"]);
 export const InstanceCreateSchema = InstanceSchema.clone();
 
-export const AuthorizeRewardSchema = yup.object().shape({
-  justification: yup.string().required(),
-  amount: yup
-    .string()
-    .required()
-    .test("amount", "the amount is not valid", currencyWithAmountIsValid)
-    .test("amount_positive", "the amount is not valid", currencyGreaterThan0),
-  next_url: yup.string().required(),
-});
-
-const stringIsValidJSON = (value?: string) => {
-  const p = value?.trim();
-  if (!p) return true;
-  try {
-    JSON.parse(p);
-    return true;
-  } catch {
-    return false;
-  }
-};
-
 export const OrderCreateSchema = yup.object().shape({
   pricing: yup
     .object()

-- 
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]