@lasterp/shared 1.0.0-beta.3 → 1.0.0-beta.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -611,6 +611,19 @@ declare const useVariantSelector: <T extends {
611
611
  id: string;
612
612
  specs: Record<string, string>;
613
613
  }>(props: VariantSelectorProps<T>) => VariantSelectorResult;
614
+ import { JSX, ReactNode } from "react";
615
+ import { StateStorage } from "zustand/middleware";
616
+ type TranslateFn = (message: string, replace?: (string | number)[]) => string;
617
+ interface LocaleProviderProps {
618
+ method: string;
619
+ language: string;
620
+ storage?: StateStorage;
621
+ children: ReactNode;
622
+ }
623
+ declare function LocaleProvider({ method, language, storage, children }: LocaleProviderProps): JSX.Element | null;
624
+ declare function useLocale(): {
625
+ __: TranslateFn;
626
+ };
614
627
  interface Category {
615
628
  name: string;
616
629
  }
@@ -644,12 +657,4 @@ interface ProductContext {
644
657
  }
645
658
  import { camelize, decamelize, camelizeKeys, decamelizeKeys } from "humps";
646
659
  declare function equalsIgnoreCase(str1: string, str2: string): boolean;
647
- import { JSX, ReactNode } from "react";
648
- interface ServerProviderProps {
649
- frappeUrl: string;
650
- siteName?: string;
651
- resource: string;
652
- children: ReactNode;
653
- }
654
- declare function ServerProvider({ frappeUrl, siteName, resource, children }: ServerProviderProps): JSX.Element;
655
- export { useVariantSelector, useSearch, useFrappeUpdateDoc, useFrappePutCall, useFrappePrefetchDoc, useFrappePostCall, useFrappeGetDocList, useFrappeGetDocCount, useFrappeGetDoc, useFrappeGetCall, useFrappeFileUpload, useFrappeEventListener, useFrappeDocumentEventListener, useFrappeDocTypeEventListener, useFrappeDeleteDoc, useFrappeDeleteCall, useFrappeCreateDoc, useFrappeAuth, equalsIgnoreCase, decamelizeKeys, decamelize, camelizeKeys, camelize, ViewerEventData, VariantSelectorResult, VariantSelectorProps, VariantSelectorOption, UseFrappeFileUploadReturnType, TopbarItem, Topbar, TokenParams, ShopContext, ServerProvider, SearchResult, ProductVariant, ProductContext, Product, Page, NavbarSubItemGroup, NavbarSubItem, NavbarItem, Model, ItemVariant, Item, Hero, Header, Globals, FrappeProviderProps, FrappeProvider, FrappeMutationResult, FrappeFileUploadResponse, FrappeError, FrappeContext, FrappeConfig, FooterItemGroup, FooterItem, Footer, DocumentUpdateEventData, DocTypeListUpdateEventData, Colour, Category, Brand, Block };
660
+ export { useVariantSelector, useSearch, useLocale, useFrappeUpdateDoc, useFrappePutCall, useFrappePrefetchDoc, useFrappePostCall, useFrappeGetDocList, useFrappeGetDocCount, useFrappeGetDoc, useFrappeGetCall, useFrappeFileUpload, useFrappeEventListener, useFrappeDocumentEventListener, useFrappeDocTypeEventListener, useFrappeDeleteDoc, useFrappeDeleteCall, useFrappeCreateDoc, useFrappeAuth, equalsIgnoreCase, decamelizeKeys, decamelize, camelizeKeys, camelize, ViewerEventData, VariantSelectorResult, VariantSelectorProps, VariantSelectorOption, UseFrappeFileUploadReturnType, TopbarItem, Topbar, TokenParams, ShopContext, SearchResult, ProductVariant, ProductContext, Product, Page, NavbarSubItemGroup, NavbarSubItem, NavbarItem, Model, LocaleProvider, ItemVariant, Item, Hero, Header, Globals, FrappeProviderProps, FrappeProvider, FrappeMutationResult, FrappeFileUploadResponse, FrappeError, FrappeContext, FrappeConfig, FooterItemGroup, FooterItem, Footer, DocumentUpdateEventData, DocTypeListUpdateEventData, Colour, Category, Brand, Block };
@@ -58,7 +58,7 @@ var FrappeProvider = ({
58
58
  children,
59
59
  customHeaders
60
60
  }) => {
61
- const frappeConfig = useMemo(() => {
61
+ const config = useMemo(() => {
62
62
  const frappe = new FrappeApp(url, tokenParams, undefined, customHeaders);
63
63
  return {
64
64
  url,
@@ -72,7 +72,7 @@ var FrappeProvider = ({
72
72
  };
73
73
  }, [url, tokenParams, enableSocket, socketPort, siteName, customHeaders]);
74
74
  return /* @__PURE__ */ jsx(FrappeContext.Provider, {
75
- value: frappeConfig,
75
+ value: config,
76
76
  children
77
77
  });
78
78
  };
@@ -570,62 +570,67 @@ var useVariantSelector = (props) => {
570
570
  getOptions: (key) => options[key] || []
571
571
  };
572
572
  };
573
- // src/utils/char.ts
574
- import { camelize, decamelize, camelizeKeys, decamelizeKeys } from "humps";
575
- function equalsIgnoreCase(str1, str2) {
576
- return str1.localeCompare(str2, undefined, { sensitivity: "accent" }) === 0;
577
- }
578
- // src/context/server-provider.node.tsx
573
+ // src/locale/provider.tsx
579
574
  import {
575
+ createContext as createContext2,
580
576
  useCallback as useCallback5,
577
+ useContext as useContext12,
581
578
  useEffect as useEffect4,
582
- useRef
579
+ useState as useState6
583
580
  } from "react";
584
- import { useLogto } from "@logto/react";
585
581
  import { jsx as jsx2 } from "react/jsx-runtime";
586
- var TOKEN_STALE_MS = 50 * 60 * 1000;
587
- function ServerProvider({
588
- frappeUrl,
589
- siteName,
590
- resource,
582
+ function translate(message, replace, messages = {}) {
583
+ let translated = messages[message] ?? message;
584
+ replace?.forEach((val, i) => {
585
+ translated = translated.replace(`{${i}}`, String(val));
586
+ });
587
+ return translated;
588
+ }
589
+ var LocaleContext = createContext2((message) => message);
590
+ function LocaleProvider({
591
+ method,
592
+ language,
593
+ storage,
591
594
  children
592
595
  }) {
593
- const { getAccessToken, isAuthenticated } = useLogto();
594
- const tokenRef = useRef("");
595
- const fetchedAtRef = useRef(0);
596
- const isRefreshingRef = useRef(false);
597
- const refresh = useCallback5(async () => {
598
- const token = await getAccessToken(resource);
599
- if (token) {
600
- tokenRef.current = token;
601
- fetchedAtRef.current = Date.now();
602
- }
603
- }, [getAccessToken, resource]);
596
+ const [messages, setMessages] = useState6({});
604
597
  useEffect4(() => {
605
- if (isAuthenticated)
606
- refresh();
607
- }, [isAuthenticated, refresh]);
608
- const getToken = useCallback5(() => {
609
- if (!isRefreshingRef.current && fetchedAtRef.current > 0 && Date.now() - fetchedAtRef.current > TOKEN_STALE_MS) {
610
- isRefreshingRef.current = true;
611
- refresh().finally(() => {
612
- isRefreshingRef.current = false;
613
- });
614
- }
615
- return tokenRef.current;
616
- }, [refresh]);
617
- return /* @__PURE__ */ jsx2(FrappeProvider, {
618
- url: frappeUrl,
619
- siteName,
620
- customHeaders: siteName ? { "X-Frappe-Site-Name": siteName } : undefined,
621
- enableSocket: false,
622
- tokenParams: { useToken: true, token: getToken, type: "Bearer" },
598
+ if (!storage)
599
+ return;
600
+ const key = `locale:${language}`;
601
+ Promise.resolve(storage.getItem(key)).then((cached) => {
602
+ if (cached)
603
+ setMessages(JSON.parse(cached));
604
+ }).catch(() => {});
605
+ }, [language, storage]);
606
+ const { data, isLoading } = useFrappeGetCall(method, { language }, { staleTime: Infinity });
607
+ useEffect4(() => {
608
+ if (!data?.message)
609
+ return;
610
+ setMessages(data.message);
611
+ storage?.setItem(`locale:${language}`, JSON.stringify(data.message));
612
+ }, [data, language, storage]);
613
+ const __ = useCallback5((message, replace) => translate(message, replace, messages), [messages]);
614
+ if (isLoading && Object.keys(messages).length === 0)
615
+ return null;
616
+ return /* @__PURE__ */ jsx2(LocaleContext.Provider, {
617
+ value: __,
623
618
  children
624
619
  });
625
620
  }
621
+ function useLocale() {
622
+ const __ = useContext12(LocaleContext);
623
+ return { __ };
624
+ }
625
+ // src/utils/char.ts
626
+ import { camelize, decamelize, camelizeKeys, decamelizeKeys } from "humps";
627
+ function equalsIgnoreCase(str1, str2) {
628
+ return str1.localeCompare(str2, undefined, { sensitivity: "accent" }) === 0;
629
+ }
626
630
  export {
627
631
  useVariantSelector,
628
632
  useSearch,
633
+ useLocale,
629
634
  useFrappeUpdateDoc,
630
635
  useFrappePutCall,
631
636
  useFrappePrefetchDoc,
@@ -647,7 +652,7 @@ export {
647
652
  decamelize,
648
653
  camelizeKeys,
649
654
  camelize,
650
- ServerProvider,
655
+ LocaleProvider,
651
656
  FrappeProvider,
652
657
  FrappeContext
653
658
  };
@@ -611,6 +611,19 @@ declare const useVariantSelector: <T extends {
611
611
  id: string;
612
612
  specs: Record<string, string>;
613
613
  }>(props: VariantSelectorProps<T>) => VariantSelectorResult;
614
+ import { JSX, ReactNode } from "react";
615
+ import { StateStorage } from "zustand/middleware";
616
+ type TranslateFn = (message: string, replace?: (string | number)[]) => string;
617
+ interface LocaleProviderProps {
618
+ method: string;
619
+ language: string;
620
+ storage?: StateStorage;
621
+ children: ReactNode;
622
+ }
623
+ declare function LocaleProvider({ method, language, storage, children }: LocaleProviderProps): JSX.Element | null;
624
+ declare function useLocale(): {
625
+ __: TranslateFn;
626
+ };
614
627
  interface Category {
615
628
  name: string;
616
629
  }
@@ -644,12 +657,4 @@ interface ProductContext {
644
657
  }
645
658
  import { camelize, decamelize, camelizeKeys, decamelizeKeys } from "humps";
646
659
  declare function equalsIgnoreCase(str1: string, str2: string): boolean;
647
- import { JSX, ReactNode } from "react";
648
- interface ServerProviderProps {
649
- frappeUrl: string;
650
- siteName?: string;
651
- resource: string;
652
- children: ReactNode;
653
- }
654
- declare function ServerProvider({ frappeUrl, siteName, resource, children }: ServerProviderProps): JSX.Element;
655
- export { useVariantSelector, useSearch, useFrappeUpdateDoc, useFrappePutCall, useFrappePrefetchDoc, useFrappePostCall, useFrappeGetDocList, useFrappeGetDocCount, useFrappeGetDoc, useFrappeGetCall, useFrappeFileUpload, useFrappeEventListener, useFrappeDocumentEventListener, useFrappeDocTypeEventListener, useFrappeDeleteDoc, useFrappeDeleteCall, useFrappeCreateDoc, useFrappeAuth, equalsIgnoreCase, decamelizeKeys, decamelize, camelizeKeys, camelize, ViewerEventData, VariantSelectorResult, VariantSelectorProps, VariantSelectorOption, UseFrappeFileUploadReturnType, TopbarItem, Topbar, TokenParams, ShopContext, ServerProvider, SearchResult, ProductVariant, ProductContext, Product, Page, NavbarSubItemGroup, NavbarSubItem, NavbarItem, Model, ItemVariant, Item, Hero, Header, Globals, FrappeProviderProps, FrappeProvider, FrappeMutationResult, FrappeFileUploadResponse, FrappeError, FrappeContext, FrappeConfig, FooterItemGroup, FooterItem, Footer, DocumentUpdateEventData, DocTypeListUpdateEventData, Colour, Category, Brand, Block };
660
+ export { useVariantSelector, useSearch, useLocale, useFrappeUpdateDoc, useFrappePutCall, useFrappePrefetchDoc, useFrappePostCall, useFrappeGetDocList, useFrappeGetDocCount, useFrappeGetDoc, useFrappeGetCall, useFrappeFileUpload, useFrappeEventListener, useFrappeDocumentEventListener, useFrappeDocTypeEventListener, useFrappeDeleteDoc, useFrappeDeleteCall, useFrappeCreateDoc, useFrappeAuth, equalsIgnoreCase, decamelizeKeys, decamelize, camelizeKeys, camelize, ViewerEventData, VariantSelectorResult, VariantSelectorProps, VariantSelectorOption, UseFrappeFileUploadReturnType, TopbarItem, Topbar, TokenParams, ShopContext, SearchResult, ProductVariant, ProductContext, Product, Page, NavbarSubItemGroup, NavbarSubItem, NavbarItem, Model, LocaleProvider, ItemVariant, Item, Hero, Header, Globals, FrappeProviderProps, FrappeProvider, FrappeMutationResult, FrappeFileUploadResponse, FrappeError, FrappeContext, FrappeConfig, FooterItemGroup, FooterItem, Footer, DocumentUpdateEventData, DocTypeListUpdateEventData, Colour, Category, Brand, Block };
@@ -58,7 +58,7 @@ var FrappeProvider = ({
58
58
  children,
59
59
  customHeaders
60
60
  }) => {
61
- const frappeConfig = useMemo(() => {
61
+ const config = useMemo(() => {
62
62
  const frappe = new FrappeApp(url, tokenParams, undefined, customHeaders);
63
63
  return {
64
64
  url,
@@ -72,7 +72,7 @@ var FrappeProvider = ({
72
72
  };
73
73
  }, [url, tokenParams, enableSocket, socketPort, siteName, customHeaders]);
74
74
  return /* @__PURE__ */ jsx(FrappeContext.Provider, {
75
- value: frappeConfig,
75
+ value: config,
76
76
  children
77
77
  });
78
78
  };
@@ -570,62 +570,67 @@ var useVariantSelector = (props) => {
570
570
  getOptions: (key) => options[key] || []
571
571
  };
572
572
  };
573
- // src/utils/char.ts
574
- import { camelize, decamelize, camelizeKeys, decamelizeKeys } from "humps";
575
- function equalsIgnoreCase(str1, str2) {
576
- return str1.localeCompare(str2, undefined, { sensitivity: "accent" }) === 0;
577
- }
578
- // src/context/server-provider.rn.tsx
573
+ // src/locale/provider.tsx
579
574
  import {
575
+ createContext as createContext2,
580
576
  useCallback as useCallback5,
577
+ useContext as useContext12,
581
578
  useEffect as useEffect4,
582
- useRef
579
+ useState as useState6
583
580
  } from "react";
584
- import { useLogto } from "@logto/rn";
585
581
  import { jsx as jsx2 } from "react/jsx-runtime";
586
- var TOKEN_STALE_MS = 50 * 60 * 1000;
587
- function ServerProvider({
588
- frappeUrl,
589
- siteName,
590
- resource,
582
+ function translate(message, replace, messages = {}) {
583
+ let translated = messages[message] ?? message;
584
+ replace?.forEach((val, i) => {
585
+ translated = translated.replace(`{${i}}`, String(val));
586
+ });
587
+ return translated;
588
+ }
589
+ var LocaleContext = createContext2((message) => message);
590
+ function LocaleProvider({
591
+ method,
592
+ language,
593
+ storage,
591
594
  children
592
595
  }) {
593
- const { getAccessToken, isAuthenticated } = useLogto();
594
- const tokenRef = useRef("");
595
- const fetchedAtRef = useRef(0);
596
- const isRefreshingRef = useRef(false);
597
- const refresh = useCallback5(async () => {
598
- const token = await getAccessToken(resource);
599
- if (token) {
600
- tokenRef.current = token;
601
- fetchedAtRef.current = Date.now();
602
- }
603
- }, [getAccessToken, resource]);
596
+ const [messages, setMessages] = useState6({});
604
597
  useEffect4(() => {
605
- if (isAuthenticated)
606
- refresh();
607
- }, [isAuthenticated, refresh]);
608
- const getToken = useCallback5(() => {
609
- if (!isRefreshingRef.current && fetchedAtRef.current > 0 && Date.now() - fetchedAtRef.current > TOKEN_STALE_MS) {
610
- isRefreshingRef.current = true;
611
- refresh().finally(() => {
612
- isRefreshingRef.current = false;
613
- });
614
- }
615
- return tokenRef.current;
616
- }, [refresh]);
617
- return /* @__PURE__ */ jsx2(FrappeProvider, {
618
- url: frappeUrl,
619
- siteName,
620
- customHeaders: siteName ? { "X-Frappe-Site-Name": siteName } : undefined,
621
- enableSocket: false,
622
- tokenParams: { useToken: true, token: getToken, type: "Bearer" },
598
+ if (!storage)
599
+ return;
600
+ const key = `locale:${language}`;
601
+ Promise.resolve(storage.getItem(key)).then((cached) => {
602
+ if (cached)
603
+ setMessages(JSON.parse(cached));
604
+ }).catch(() => {});
605
+ }, [language, storage]);
606
+ const { data, isLoading } = useFrappeGetCall(method, { language }, { staleTime: Infinity });
607
+ useEffect4(() => {
608
+ if (!data?.message)
609
+ return;
610
+ setMessages(data.message);
611
+ storage?.setItem(`locale:${language}`, JSON.stringify(data.message));
612
+ }, [data, language, storage]);
613
+ const __ = useCallback5((message, replace) => translate(message, replace, messages), [messages]);
614
+ if (isLoading && Object.keys(messages).length === 0)
615
+ return null;
616
+ return /* @__PURE__ */ jsx2(LocaleContext.Provider, {
617
+ value: __,
623
618
  children
624
619
  });
625
620
  }
621
+ function useLocale() {
622
+ const __ = useContext12(LocaleContext);
623
+ return { __ };
624
+ }
625
+ // src/utils/char.ts
626
+ import { camelize, decamelize, camelizeKeys, decamelizeKeys } from "humps";
627
+ function equalsIgnoreCase(str1, str2) {
628
+ return str1.localeCompare(str2, undefined, { sensitivity: "accent" }) === 0;
629
+ }
626
630
  export {
627
631
  useVariantSelector,
628
632
  useSearch,
633
+ useLocale,
629
634
  useFrappeUpdateDoc,
630
635
  useFrappePutCall,
631
636
  useFrappePrefetchDoc,
@@ -647,7 +652,7 @@ export {
647
652
  decamelize,
648
653
  camelizeKeys,
649
654
  camelize,
650
- ServerProvider,
655
+ LocaleProvider,
651
656
  FrappeProvider,
652
657
  FrappeContext
653
658
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lasterp/shared",
3
- "version": "1.0.0-beta.3",
3
+ "version": "1.0.0-beta.6",
4
4
  "description": "Shared repo for webapp and native app",
5
5
  "license": "MIT",
6
6
  "files": [
@@ -20,22 +20,14 @@
20
20
  "typescript": "^5.9.3"
21
21
  },
22
22
  "peerDependencies": {
23
+ "@tanstack/react-query": "^5.90.21",
23
24
  "react": ">=18.0.0",
24
25
  "react-dom": ">=18.0.0",
25
- "typescript": ">=4.5.0",
26
- "@tanstack/react-query": "^5.90.21",
27
- "@logto/react": "^4.0.13",
28
- "@logto/rn": "^1.1.0"
26
+ "typescript": ">=4.5.0"
29
27
  },
30
28
  "peerDependenciesMeta": {
31
29
  "typescript": {
32
30
  "optional": true
33
- },
34
- "@logto/react": {
35
- "optional": true
36
- },
37
- "@logto/rn": {
38
- "optional": true
39
31
  }
40
32
  },
41
33
  "type": "module",
@@ -52,6 +44,7 @@
52
44
  "dependencies": {
53
45
  "frappe-js-sdk": "^1.12.0",
54
46
  "humps": "^2.0.1",
55
- "socket.io-client": "^4.8.3"
47
+ "socket.io-client": "^4.8.3",
48
+ "zustand": "^5.0.11"
56
49
  }
57
50
  }