gnunet-svn
[Top][All Lists]
Advanced

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

[taler-wallet-core] branch master updated (2b6f37831 -> 56bd2c3cd)


From: gnunet
Subject: [taler-wallet-core] branch master updated (2b6f37831 -> 56bd2c3cd)
Date: Thu, 01 Aug 2024 20:50:41 +0200

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

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

    from 2b6f37831 fix broken build
     new 6069e2dea temporary disable desc in prod summary
     new 56bd2c3cd suggestion for categories

The 2 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .../src/components/form/InputArray.tsx             | 29 ++++++----
 .../src/components/product/ProductForm.tsx         | 64 ++++++++++++++++------
 packages/taler-util/src/http-client/merchant.ts    | 18 +++---
 packages/taler-util/src/types-taler-merchant.ts    |  8 +--
 4 files changed, 79 insertions(+), 40 deletions(-)

diff --git a/packages/merchant-backoffice-ui/src/components/form/InputArray.tsx 
b/packages/merchant-backoffice-ui/src/components/form/InputArray.tsx
index fd9dfbc8d..3d6b92295 100644
--- a/packages/merchant-backoffice-ui/src/components/form/InputArray.tsx
+++ b/packages/merchant-backoffice-ui/src/components/form/InputArray.tsx
@@ -19,17 +19,18 @@
  * @author Sebastian Javier Marchano (sebasjm)
  */
 import { useTranslationContext } from "@gnu-taler/web-util/browser";
-import { h, VNode } from "preact";
+import { Fragment, h, VNode } from "preact";
 import { useState } from "preact/hooks";
 import { InputProps, useField } from "./useField.js";
 import { DropdownList } from "./InputSearchOnList.js";
 
 export interface Props<T> extends InputProps<T> {
   isValid?: (e: any) => boolean;
-  getSuggestion?: (e: any) => { id: string; description: string }[];
+  getSuggestion?: (e: any) => Promise<{ id: string; description: string }[]>;
   addonBefore?: string;
   toStr?: (v?: any) => string;
   fromStr?: (s: string) => any;
+  unique?: boolean;
 }
 
 const defaultToString = (f?: any): string => (f ? String(f) : "");
@@ -41,15 +42,14 @@ export function InputArray<T>({
   placeholder,
   tooltip,
   label,
+  unique,
   help,
   addonBefore,
   getSuggestion,
   fromStr = defaultFromString,
   toStr = defaultToString,
 }: Props<keyof T>): VNode {
-  const { error: formError, value, onChange, required } = useField<T>(name);
-
-  const error = formError;
+  const { error, value, onChange, required } = useField<T>(name);
 
   const array: T[keyof T][] = value ? value! : [];
   const [currentValue, setCurrentValue] = useState("");
@@ -87,10 +87,13 @@ export function InputArray<T>({
                 disabled={readonly}
                 name={String(name)}
                 value={currentValue}
-                onChange={(e): void => {
-                  setCurrentValue(e.currentTarget.value);
+                onChange={async (e): Promise<void> => {
+                  const v = e.currentTarget.value;
+                  setCurrentValue(v);
                   if (getSuggestion) {
-                    setSuggestions(getSuggestion(e.currentTarget.value));
+                    getSuggestion(v).then((ss) => {
+                      setSuggestions(ss);
+                    });
                   }
                 }}
               />
@@ -107,7 +110,9 @@ export function InputArray<T>({
                   disabled={!currentValue}
                   onClick={(): void => {
                     const v = fromStr(currentValue);
-                    onChange([v, ...array] as T[keyof T]);
+                    if (!unique || array.indexOf(v) === -1) {
+                      onChange([v, ...array] as T[keyof T]);
+                    }
                     setCurrentValue("");
                   }}
                   data-tooltip={i18n.str`Add element to the list`}
@@ -125,7 +130,7 @@ export function InputArray<T>({
                 class="tag is-medium is-info mb-0"
                 style={{ maxWidth: "90%" }}
               >
-                {toStr(v)}
+                {getSuggestion ? (v as any).description : toStr(v)}
               </span>
               <a
                 class="tag is-medium is-danger is-delete mb-0"
@@ -142,8 +147,10 @@ export function InputArray<T>({
                 name={currentValue}
                 list={suggestions}
                 onSelect={(p): void => {
+                  if (!unique || array.indexOf(p as any) === -1) {
+                    onChange([p, ...array] as T[keyof T]);
+                  }
                   setCurrentValue("");
-                  onChange([p, ...array] as T[keyof T]);
                   setSuggestions([]);
                 }}
                 withImage={false}
diff --git 
a/packages/merchant-backoffice-ui/src/components/product/ProductForm.tsx 
b/packages/merchant-backoffice-ui/src/components/product/ProductForm.tsx
index 821e30721..9bf97f8db 100644
--- a/packages/merchant-backoffice-ui/src/components/product/ProductForm.tsx
+++ b/packages/merchant-backoffice-ui/src/components/product/ProductForm.tsx
@@ -35,7 +35,9 @@ import { InputTaxes } from "../form/InputTaxes.js";
 import { InputWithAddon } from "../form/InputWithAddon.js";
 import { InputArray } from "../form/InputArray.js";
 
-type Entity = TalerMerchantApi.ProductDetail & { product_id: string };
+type Entity = TalerMerchantApi.ProductDetail & {
+  product_id: string;
+};
 
 interface Props {
   onSubscribe: (c?: () => Entity | undefined) => void;
@@ -45,9 +47,16 @@ interface Props {
 
 export function ProductForm({ onSubscribe, initial, alreadyExist }: Props) {
   const { i18n } = useTranslationContext();
-  const { state } = useSessionContext();
-
-  const [value, valueHandler] = useState<Partial<Entity & { stock: Stock }>>({
+  const { state, lib } = useSessionContext();
+
+  const [value, valueHandler] = useState<
+    Partial<
+      Entity & {
+        stock: Stock;
+        categories_map: { id: string; description: string }[];
+      }
+    >
+  >({
     address: {},
     description_i18n: {},
     taxes: [],
@@ -67,6 +76,28 @@ export function ProductForm({ onSubscribe, initial, 
alreadyExist }: Props) {
           },
   });
 
+  function notEmpty<TValue>(value: TValue | null | undefined): value is TValue 
{
+    return value !== null && value !== undefined;
+  }
+
+  useEffect(() => {
+    if (!initial || !initial?.categories) return;
+
+    const ps = initial.categories.map((catId) => {
+      return lib.instance
+        .getCategoryDetails(state.token, String(catId))
+        .then((res) => {
+          return res.type === "fail"
+            ? undefined
+            : { id: String(catId), description: res.body.name };
+        });
+    });
+    Promise.all(ps).then((all) => {
+      const categories_map = all.filter(notEmpty);
+      valueHandler({ ...value, categories_map });
+    });
+  }, []);
+
   const errors = undefinedIfEmpty({
     product_id: !value.product_id ? i18n.str`Required` : undefined,
     description: !value.description ? i18n.str`Required` : undefined,
@@ -106,6 +137,8 @@ export function ProductForm({ onSubscribe, initial, 
alreadyExist }: Props) {
       value.address = stock.address;
     }
     delete value.stock;
+    value.categories = value.categories_map?.map((d) => parseInt(d.id, 10))!;
+    delete value.categories_map;
 
     if (typeof value.minimum_age !== "undefined" && value.minimum_age < 1) {
       delete value.minimum_age;
@@ -175,23 +208,18 @@ export function ProductForm({ onSubscribe, initial, 
alreadyExist }: Props) {
           label={i18n.str`Taxes`}
           tooltip={i18n.str`Taxes included in the product price, exposed to 
customers.`}
         />
-        <InputArray<Entity>
-          name="categories"
+        <InputArray
+          name="categories_map"
           label={i18n.str`Categories`}
-          getSuggestion={() => {
-            return [
-              {
-                description: "brown beer",
-                id: "bb",
-              },
-              {
-                description: "yellow beer",
-                id: "yb",
-              },
-            ];
+          getSuggestion={async () => {
+            const resp = await lib.instance.listCategories(state.token);
+            if (resp.type === "fail") return [];
+            return resp.body.categories.map((cat) => {
+              return { description: cat.name, id: String(cat.category_id) };
+            });
           }}
-          toStr={(v) => v.description}
           tooltip={i18n.str`Categories where this product will be listed on.`}
+          unique
         />
       </FormProvider>
     </div>
diff --git a/packages/taler-util/src/http-client/merchant.ts 
b/packages/taler-util/src/http-client/merchant.ts
index 3260c1546..e765d286b 100644
--- a/packages/taler-util/src/http-client/merchant.ts
+++ b/packages/taler-util/src/http-client/merchant.ts
@@ -511,7 +511,7 @@ export class TalerMerchantInstanceHttpClient {
    * 
https://docs.taler.net/core/api-merchant.html#get-[-instances-$INSTANCE]-private
    *
    */
-  async getCurrentInstanceDetails(token: AccessToken) {
+  async getCurrentInstanceDetails(token: AccessToken | undefined) {
     const url = new URL(`private`, this.baseUrl);
 
     const headers: Record<string, string> = {};
@@ -706,7 +706,10 @@ export class TalerMerchantInstanceHttpClient {
   /**
    * 
https://docs.taler.net/core/api-merchant.html#get-[-instances-$INSTANCE]-private-accounts
    */
-  async listBankAccounts(token: AccessToken, params?: PaginationParams) {
+  async listBankAccounts(
+    token: AccessToken | undefined,
+    params?: PaginationParams,
+  ) {
     const url = new URL(`private/accounts`, this.baseUrl);
 
     // addMerchantPaginationParams(url, params);
@@ -800,7 +803,10 @@ export class TalerMerchantInstanceHttpClient {
   /**
    * 
https://docs.taler.net/core/api-merchant.html#get-[-instances-$INSTANCE]-private-categories
    */
-  async listCategories(token: AccessToken, params?: PaginationParams) {
+  async listCategories(
+    token: AccessToken | undefined,
+    params?: PaginationParams,
+  ) {
     const url = new URL(`private/categories`, this.baseUrl);
 
     // addMerchantPaginationParams(url, params);
@@ -817,9 +823,9 @@ export class TalerMerchantInstanceHttpClient {
     switch (resp.status) {
       case HttpStatusCode.Ok:
         return opSuccessFromHttp(resp, codecForCategoryListResponse());
-        case HttpStatusCode.NotFound: 
+      case HttpStatusCode.NotFound:
         return opKnownHttpFailure(resp.status, resp);
-        case HttpStatusCode.Unauthorized: // FIXME: missing in docs
+      case HttpStatusCode.Unauthorized: // FIXME: missing in docs
         return opKnownHttpFailure(resp.status, resp);
       default:
         return opUnknownFailure(resp, await readTalerErrorResponse(resp));
@@ -928,7 +934,6 @@ export class TalerMerchantInstanceHttpClient {
     }
   }
 
-
   /**
    * 
https://docs.taler.net/core/api-merchant.html#delete-[-instances-$INSTANCE]-private-categories-$CATEGORY_ID
    */
@@ -962,7 +967,6 @@ export class TalerMerchantInstanceHttpClient {
     }
   }
 
-
   /**
    * 
https://docs.taler.net/core/api-merchant.html#post-[-instances-$INSTANCE]-private-products
    */
diff --git a/packages/taler-util/src/types-taler-merchant.ts 
b/packages/taler-util/src/types-taler-merchant.ts
index 38d17b8c0..b3aa43454 100644
--- a/packages/taler-util/src/types-taler-merchant.ts
+++ b/packages/taler-util/src/types-taler-merchant.ts
@@ -1493,10 +1493,10 @@ export interface ProductSummary {
   product_id: string;
 
   // Human-readable product description.
-  description: string;
+  // description: string;
 
   // Map from IETF BCP 47 language tags to localized descriptions.
-  description_i18n?: { [lang_tag: string]: string };
+  // description_i18n?: { [lang_tag: string]: string };
 }
 
 export interface CategoryCreateRequest {
@@ -3037,8 +3037,8 @@ export const codecForCategoryProductList = (): 
Codec<CategoryProductList> =>
 export const codecForProductSummary = (): Codec<ProductSummary> =>
   buildCodecForObject<ProductSummary>()
     .property("product_id", codecForString())
-    .property("description", codecForString())
-    .property("description_i18n", codecForInternationalizedString())
+    // .property("description", codecForString())
+    // .property("description_i18n", codecForInternationalizedString())
     .build("TalerMerchantApi.ProductSummary");
 
 export const codecForInventorySummaryResponse =

-- 
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]