@controleonline/ui-default 1.0.280 → 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 +1 -1
- package/src/react/components/cards/DefaultEntityCard.js +13 -0
- package/src/react/components/files/DefaultFile.js +11 -24
- package/src/react/components/inputs/DefaultInput.js +417 -414
- package/src/react/components/table/DefaultColumnMenu.js +1 -1
- package/src/react/components/table/DefaultSearchModal.js +14 -5
- package/src/react/components/table/DefaultTable.js +27 -21
- package/src/react/components/table/DefaultTable.layoutUtils.js +1 -0
- package/src/react/components/table/DefaultTableCards.js +5 -2
- package/src/react/components/table/DefaultTableControls.js +2 -2
- package/src/react/components/table/DefaultTableInput.js +1 -1
- package/src/react/components/table/DefaultTableRows.js +1 -1
- package/src/react/components/table/DefaultTableToolbar.js +1 -1
- package/src/react/components/table/useDefaultTablePagination.js +48 -6
- package/src/react/components/table/useDefaultTableStoreSync.js +18 -6
- package/src/store/default/actions.js +117 -116
- package/src/tests/react/components/table/defaultTableTestSetup.cjs +1 -0
package/package.json
CHANGED
|
@@ -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
|
|
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(() =>
|
|
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(() => {
|