@controleonline/ui-default 1.0.279 → 1.0.281

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@controleonline/ui-default",
3
- "version": "1.0.279",
3
+ "version": "1.0.281",
4
4
  "author": "ControleOnline",
5
5
  "description": "ControleOnline Default Quasar UI Component",
6
6
  "license": "MIT",
@@ -0,0 +1,13 @@
1
+ import React from 'react';
2
+ import {View} from 'react-native';
3
+
4
+ // Visual composition only. The consuming module owns labels, data and actions.
5
+ export default function DefaultEntityCard({media=null,children,footer=null,palette={},style,contentStyle,footerStyle,bodyStyle,embedded=false}) {
6
+ return <View style={[{width:'100%',padding:12,gap:12,borderRadius:12,borderWidth:1,borderColor:palette.cardBorder,backgroundColor:palette.cardBackground},embedded?{borderWidth:0,borderRadius:0,backgroundColor:'transparent'}:null,style]}>
7
+ <View testID="default-entity-card-content" style={[{flexDirection:'row',alignItems:'flex-start',gap:12},contentStyle]}>
8
+ {media}
9
+ <View style={[{flex:1,minWidth:0},bodyStyle]}>{children}</View>
10
+ </View>
11
+ {footer&&<View testID="default-entity-card-footer" style={[{width:'100%'},footerStyle]}>{footer}</View>}
12
+ </View>;
13
+ }
@@ -1,8 +1,11 @@
1
- import React, {memo, useEffect, useMemo, useRef, useState} from 'react';
1
+ import {readStoredSessionToken} from '@controleonline/ui-common/src/utils/storedSessionToken';
2
+ import React, {memo, createContext, useContext, useEffect, useMemo, useRef, useState} from 'react';
2
3
  import {Image, Platform} from 'react-native';
3
4
  import {useStore} from '@store';
4
5
  import {resolveDefaultFileSource} from '@controleonline/ui-common/src/react/utils/fileUrl';
5
6
 
7
+ export const DefaultFileCacheContext = createContext(null);
8
+
6
9
  const resolveCompanyFromStore = peopleGetters => {
7
10
  if (peopleGetters?.mainCompany?.id) {
8
11
  return peopleGetters.mainCompany;
@@ -15,27 +18,6 @@ const resolveCompanyFromStore = peopleGetters => {
15
18
  return null;
16
19
  };
17
20
 
18
- /** Sync session token (same source as api.getToken). */
19
- const readSessionApiToken = () => {
20
- try {
21
- if (typeof localStorage === 'undefined') {
22
- return '';
23
- }
24
- const sessionString = localStorage.getItem('session');
25
- if (!sessionString) {
26
- return '';
27
- }
28
- const cleanString =
29
- typeof sessionString === 'string' && sessionString.startsWith('__q_objt|')
30
- ? sessionString.substring('__q_objt|'.length)
31
- : sessionString;
32
- const session = JSON.parse(cleanString);
33
- return session?.token || session?.api_key || '';
34
- } catch (e) {
35
- return '';
36
- }
37
- };
38
-
39
21
  const headersKey = headers => {
40
22
  if (!headers || typeof headers !== 'object') {
41
23
  return '';
@@ -70,11 +52,12 @@ const DefaultFile = ({
70
52
  headers = {},
71
53
  ...imageProps
72
54
  }) => {
55
+ const imageCache = useContext(DefaultFileCacheContext);
73
56
  const peopleStore = useStore('people');
74
57
  const peopleGetters = peopleStore?.getters || {};
75
58
  const resolvedCompany = company || resolveCompanyFromStore(peopleGetters);
76
59
 
77
- const sessionToken = useMemo(() => readSessionApiToken(), []);
60
+ const sessionToken = useMemo(() => readStoredSessionToken(), []);
78
61
  const authHeaders = useMemo(
79
62
  () => ({
80
63
  ...(sessionToken ? {'API-TOKEN': sessionToken} : {}),
@@ -152,6 +135,7 @@ const DefaultFile = ({
152
135
 
153
136
  const load = async () => {
154
137
  try {
138
+ const loadBlob = async () => {
155
139
  const response = await fetch(remoteUri, {
156
140
  method: 'GET',
157
141
  headers: remoteHeaders,
@@ -170,6 +154,9 @@ const DefaultFile = ({
170
154
  if (!blob || blob.size === 0) {
171
155
  throw new Error('empty blob');
172
156
  }
157
+ return blob;
158
+ };
159
+ const blob = imageCache ? await imageCache.load(remoteUri, remoteHeaders, loadBlob) : await loadBlob();
173
160
  if (cancelled || requestId !== requestIdRef.current) {
174
161
  return;
175
162
  }
@@ -196,7 +183,7 @@ const DefaultFile = ({
196
183
  // transient dependency flicker (Strict Mode double-invoke is OK:
197
184
  // requestId invalidates the stale response).
198
185
  };
199
- }, [remoteUri, headersKey(remoteHeaders)]);
186
+ }, [remoteUri, headersKey(remoteHeaders), imageCache]);
200
187
 
201
188
  // Unmount: revoke blob
202
189
  useEffect(() => {