@lasterp/shared 1.0.0-beta.1 → 1.0.0-beta.10
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.
|
@@ -1,10 +1,83 @@
|
|
|
1
1
|
"use client";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
4
|
+
var __defProp = Object.defineProperty;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __toESM = (mod, isNodeMode, target) => {
|
|
9
|
+
target = mod != null ? __create(__getProtoOf(mod)) : {};
|
|
10
|
+
const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
|
|
11
|
+
for (let key of __getOwnPropNames(mod))
|
|
12
|
+
if (!__hasOwnProp.call(to, key))
|
|
13
|
+
__defProp(to, key, {
|
|
14
|
+
get: () => mod[key],
|
|
15
|
+
enumerable: true
|
|
16
|
+
});
|
|
17
|
+
return to;
|
|
18
|
+
};
|
|
19
|
+
var __moduleCache = /* @__PURE__ */ new WeakMap;
|
|
20
|
+
var __toCommonJS = (from) => {
|
|
21
|
+
var entry = __moduleCache.get(from), desc;
|
|
22
|
+
if (entry)
|
|
23
|
+
return entry;
|
|
24
|
+
entry = __defProp({}, "__esModule", { value: true });
|
|
25
|
+
if (from && typeof from === "object" || typeof from === "function")
|
|
26
|
+
__getOwnPropNames(from).map((key) => !__hasOwnProp.call(entry, key) && __defProp(entry, key, {
|
|
27
|
+
get: () => from[key],
|
|
28
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
29
|
+
}));
|
|
30
|
+
__moduleCache.set(from, entry);
|
|
31
|
+
return entry;
|
|
32
|
+
};
|
|
33
|
+
var __export = (target, all) => {
|
|
34
|
+
for (var name in all)
|
|
35
|
+
__defProp(target, name, {
|
|
36
|
+
get: all[name],
|
|
37
|
+
enumerable: true,
|
|
38
|
+
configurable: true,
|
|
39
|
+
set: (newValue) => all[name] = () => newValue
|
|
40
|
+
});
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
// src/index.ts
|
|
44
|
+
var exports_src = {};
|
|
45
|
+
__export(exports_src, {
|
|
46
|
+
useVariantSelector: () => useVariantSelector,
|
|
47
|
+
useSearch: () => useSearch,
|
|
48
|
+
useLocale: () => useLocale,
|
|
49
|
+
useFrappeUpdateDoc: () => useFrappeUpdateDoc,
|
|
50
|
+
useFrappePutCall: () => useFrappePutCall,
|
|
51
|
+
useFrappePrefetchDoc: () => useFrappePrefetchDoc,
|
|
52
|
+
useFrappePostCall: () => useFrappePostCall,
|
|
53
|
+
useFrappeGetDocList: () => useFrappeGetDocList,
|
|
54
|
+
useFrappeGetDocCount: () => useFrappeGetDocCount,
|
|
55
|
+
useFrappeGetDoc: () => useFrappeGetDoc,
|
|
56
|
+
useFrappeGetCall: () => useFrappeGetCall,
|
|
57
|
+
useFrappeFileUpload: () => useFrappeFileUpload,
|
|
58
|
+
useFrappeEventListener: () => useFrappeEventListener,
|
|
59
|
+
useFrappeDocumentEventListener: () => useFrappeDocumentEventListener,
|
|
60
|
+
useFrappeDocTypeEventListener: () => useFrappeDocTypeEventListener,
|
|
61
|
+
useFrappeDeleteDoc: () => useFrappeDeleteDoc,
|
|
62
|
+
useFrappeDeleteCall: () => useFrappeDeleteCall,
|
|
63
|
+
useFrappeCreateDoc: () => useFrappeCreateDoc,
|
|
64
|
+
useFrappeAuth: () => useFrappeAuth,
|
|
65
|
+
equalsIgnoreCase: () => equalsIgnoreCase,
|
|
66
|
+
decamelizeKeys: () => import_humps.decamelizeKeys,
|
|
67
|
+
decamelize: () => import_humps.decamelize,
|
|
68
|
+
camelizeKeys: () => import_humps.camelizeKeys,
|
|
69
|
+
camelize: () => import_humps.camelize,
|
|
70
|
+
LocaleProvider: () => LocaleProvider,
|
|
71
|
+
FrappeProvider: () => FrappeProvider,
|
|
72
|
+
FrappeContext: () => FrappeContext
|
|
73
|
+
});
|
|
74
|
+
module.exports = __toCommonJS(exports_src);
|
|
2
75
|
// src/frappe/provider.tsx
|
|
3
|
-
|
|
4
|
-
|
|
76
|
+
var import_react = require("react");
|
|
77
|
+
var import_frappe_js_sdk = require("frappe-js-sdk");
|
|
5
78
|
|
|
6
79
|
// src/frappe/socket.ts
|
|
7
|
-
|
|
80
|
+
var import_socket = __toESM(require("socket.io-client"));
|
|
8
81
|
|
|
9
82
|
class SocketIO {
|
|
10
83
|
socket_port;
|
|
@@ -35,7 +108,7 @@ class SocketIO {
|
|
|
35
108
|
this.url = `${this.url}${site_name}`;
|
|
36
109
|
}
|
|
37
110
|
this.site_name = site_name;
|
|
38
|
-
this.socket =
|
|
111
|
+
this.socket = import_socket.default(`${this.url}`, {
|
|
39
112
|
withCredentials: true,
|
|
40
113
|
secure: this.protocol === "https",
|
|
41
114
|
extraHeaders: tokenParams && tokenParams.useToken === true ? {
|
|
@@ -46,9 +119,9 @@ class SocketIO {
|
|
|
46
119
|
}
|
|
47
120
|
|
|
48
121
|
// src/frappe/provider.tsx
|
|
49
|
-
|
|
122
|
+
var jsx_runtime = require("react/jsx-runtime");
|
|
50
123
|
|
|
51
|
-
var FrappeContext = createContext(null);
|
|
124
|
+
var FrappeContext = import_react.createContext(null);
|
|
52
125
|
var FrappeProvider = ({
|
|
53
126
|
url = "",
|
|
54
127
|
tokenParams,
|
|
@@ -58,8 +131,8 @@ var FrappeProvider = ({
|
|
|
58
131
|
children,
|
|
59
132
|
customHeaders
|
|
60
133
|
}) => {
|
|
61
|
-
const
|
|
62
|
-
const frappe = new FrappeApp(url, tokenParams, undefined, customHeaders);
|
|
134
|
+
const config = import_react.useMemo(() => {
|
|
135
|
+
const frappe = new import_frappe_js_sdk.FrappeApp(url, tokenParams, undefined, customHeaders);
|
|
63
136
|
return {
|
|
64
137
|
url,
|
|
65
138
|
tokenParams,
|
|
@@ -71,19 +144,19 @@ var FrappeProvider = ({
|
|
|
71
144
|
socket: enableSocket ? new SocketIO(url, siteName, socketPort, tokenParams).socket : undefined
|
|
72
145
|
};
|
|
73
146
|
}, [url, tokenParams, enableSocket, socketPort, siteName, customHeaders]);
|
|
74
|
-
return /* @__PURE__ */ jsx(FrappeContext.Provider, {
|
|
75
|
-
value:
|
|
147
|
+
return /* @__PURE__ */ jsx_runtime.jsx(FrappeContext.Provider, {
|
|
148
|
+
value: config,
|
|
76
149
|
children
|
|
77
150
|
});
|
|
78
151
|
};
|
|
79
152
|
// src/frappe/hooks/auth.ts
|
|
80
|
-
|
|
81
|
-
|
|
153
|
+
var import_react2 = require("react");
|
|
154
|
+
var import_react_query = require("@tanstack/react-query");
|
|
82
155
|
var useFrappeAuth = () => {
|
|
83
|
-
const queryClient = useQueryClient();
|
|
84
|
-
const { auth, tokenParams } = useContext(FrappeContext);
|
|
85
|
-
const [userID, setUserID] = useState();
|
|
86
|
-
const getUserCookie = useCallback(() => {
|
|
156
|
+
const queryClient = import_react_query.useQueryClient();
|
|
157
|
+
const { auth, tokenParams } = import_react2.useContext(FrappeContext);
|
|
158
|
+
const [userID, setUserID] = import_react2.useState();
|
|
159
|
+
const getUserCookie = import_react2.useCallback(() => {
|
|
87
160
|
const userCookie = document.cookie.split(";").find((c) => c.trim().startsWith("user_id="));
|
|
88
161
|
if (userCookie) {
|
|
89
162
|
const userName = userCookie.split("=")[1];
|
|
@@ -96,7 +169,7 @@ var useFrappeAuth = () => {
|
|
|
96
169
|
setUserID(null);
|
|
97
170
|
}
|
|
98
171
|
}, []);
|
|
99
|
-
useEffect(() => {
|
|
172
|
+
import_react2.useEffect(() => {
|
|
100
173
|
if (tokenParams && tokenParams.useToken) {
|
|
101
174
|
setUserID(null);
|
|
102
175
|
} else {
|
|
@@ -108,7 +181,7 @@ var useFrappeAuth = () => {
|
|
|
108
181
|
error,
|
|
109
182
|
isLoading,
|
|
110
183
|
isFetching: isValidating
|
|
111
|
-
} = useQuery({
|
|
184
|
+
} = import_react_query.useQuery({
|
|
112
185
|
queryKey: ["currentUser", { tokenParams, userID }],
|
|
113
186
|
queryFn: () => auth.getLoggedInUser(),
|
|
114
187
|
enabled: !!(tokenParams?.useToken || userID),
|
|
@@ -116,14 +189,14 @@ var useFrappeAuth = () => {
|
|
|
116
189
|
refetchOnWindowFocus: false,
|
|
117
190
|
staleTime: Infinity
|
|
118
191
|
});
|
|
119
|
-
const loginMutation = useMutation({
|
|
192
|
+
const loginMutation = import_react_query.useMutation({
|
|
120
193
|
mutationFn: (credentials) => auth.loginWithUsernamePassword(credentials),
|
|
121
194
|
onSuccess: () => {
|
|
122
195
|
getUserCookie();
|
|
123
196
|
queryClient.invalidateQueries({ queryKey: ["currentUser"] });
|
|
124
197
|
}
|
|
125
198
|
});
|
|
126
|
-
const logoutMutation = useMutation({
|
|
199
|
+
const logoutMutation = import_react_query.useMutation({
|
|
127
200
|
mutationFn: () => auth.logout(),
|
|
128
201
|
onSuccess: () => {
|
|
129
202
|
setUserID(null);
|
|
@@ -142,8 +215,8 @@ var useFrappeAuth = () => {
|
|
|
142
215
|
};
|
|
143
216
|
};
|
|
144
217
|
// src/frappe/hooks/call.ts
|
|
145
|
-
|
|
146
|
-
|
|
218
|
+
var import_react3 = require("react");
|
|
219
|
+
var import_react_query2 = require("@tanstack/react-query");
|
|
147
220
|
|
|
148
221
|
// src/frappe/utils.ts
|
|
149
222
|
function encodeQueryData(data) {
|
|
@@ -155,11 +228,11 @@ function encodeQueryData(data) {
|
|
|
155
228
|
|
|
156
229
|
// src/frappe/hooks/call.ts
|
|
157
230
|
var useFrappeGetCall = (method, params, options, type = "GET") => {
|
|
158
|
-
const { call } =
|
|
231
|
+
const { call } = import_react3.useContext(FrappeContext);
|
|
159
232
|
const urlParams = encodeQueryData(params ?? {});
|
|
160
233
|
const url = `${method}?${urlParams}`;
|
|
161
234
|
const queryKey = ["frappeCall", type, method, url];
|
|
162
|
-
const { data, error, isLoading, isFetching, refetch } =
|
|
235
|
+
const { data, error, isLoading, isFetching, refetch } = import_react_query2.useQuery({
|
|
163
236
|
queryKey,
|
|
164
237
|
queryFn: type === "GET" ? () => call.get(method, params) : () => call.post(method, params),
|
|
165
238
|
enabled: (options?.enabled ?? true) && !!method,
|
|
@@ -175,9 +248,9 @@ var useFrappeGetCall = (method, params, options, type = "GET") => {
|
|
|
175
248
|
};
|
|
176
249
|
};
|
|
177
250
|
var useFrappeMutation = (method, httpMethod) => {
|
|
178
|
-
const { call: frappeCall } =
|
|
251
|
+
const { call: frappeCall } = import_react3.useContext(FrappeContext);
|
|
179
252
|
const queryKey = ["frappeCall", httpMethod, method];
|
|
180
|
-
const { mutateAsync, data, isPending, error, isSuccess, reset } =
|
|
253
|
+
const { mutateAsync, data, isPending, error, isSuccess, reset } = import_react_query2.useMutation({
|
|
181
254
|
mutationKey: queryKey,
|
|
182
255
|
mutationFn: (params) => {
|
|
183
256
|
if (httpMethod === "POST")
|
|
@@ -200,12 +273,12 @@ var useFrappePostCall = (method) => useFrappeMutation(method, "POST");
|
|
|
200
273
|
var useFrappePutCall = (method) => useFrappeMutation(method, "PUT");
|
|
201
274
|
var useFrappeDeleteCall = (method) => useFrappeMutation(method, "DELETE");
|
|
202
275
|
// src/frappe/hooks/count.ts
|
|
203
|
-
|
|
204
|
-
|
|
276
|
+
var import_react4 = require("react");
|
|
277
|
+
var import_react_query3 = require("@tanstack/react-query");
|
|
205
278
|
var useFrappeGetDocCount = (doctype, filters, debug = false, options) => {
|
|
206
|
-
const { url, db } =
|
|
279
|
+
const { url, db } = import_react4.useContext(FrappeContext);
|
|
207
280
|
const queryKey = ["docCount", url, doctype, filters ?? [], debug];
|
|
208
|
-
const { data, error, isLoading, isFetching, refetch } =
|
|
281
|
+
const { data, error, isLoading, isFetching, refetch } = import_react_query3.useQuery({
|
|
209
282
|
queryKey,
|
|
210
283
|
queryFn: () => db.getCount(doctype, filters, debug),
|
|
211
284
|
enabled: !!doctype,
|
|
@@ -220,11 +293,11 @@ var useFrappeGetDocCount = (doctype, filters, debug = false, options) => {
|
|
|
220
293
|
};
|
|
221
294
|
};
|
|
222
295
|
// src/frappe/hooks/create.ts
|
|
223
|
-
|
|
224
|
-
|
|
296
|
+
var import_react5 = require("react");
|
|
297
|
+
var import_react_query4 = require("@tanstack/react-query");
|
|
225
298
|
var useFrappeCreateDoc = () => {
|
|
226
|
-
const { db } =
|
|
227
|
-
const { mutateAsync, isPending, error, isSuccess, reset } =
|
|
299
|
+
const { db } = import_react5.useContext(FrappeContext);
|
|
300
|
+
const { mutateAsync, isPending, error, isSuccess, reset } = import_react_query4.useMutation({
|
|
228
301
|
mutationFn: ({ doctype, doc }) => db.createDoc(doctype, doc)
|
|
229
302
|
});
|
|
230
303
|
const createDoc = (doctype, doc) => mutateAsync({ doctype, doc });
|
|
@@ -237,11 +310,11 @@ var useFrappeCreateDoc = () => {
|
|
|
237
310
|
};
|
|
238
311
|
};
|
|
239
312
|
// src/frappe/hooks/delete.ts
|
|
240
|
-
|
|
241
|
-
|
|
313
|
+
var import_react6 = require("react");
|
|
314
|
+
var import_react_query5 = require("@tanstack/react-query");
|
|
242
315
|
var useFrappeDeleteDoc = () => {
|
|
243
|
-
const { db } =
|
|
244
|
-
const { mutateAsync, isPending, error, isSuccess, reset } =
|
|
316
|
+
const { db } = import_react6.useContext(FrappeContext);
|
|
317
|
+
const { mutateAsync, isPending, error, isSuccess, reset } = import_react_query5.useMutation({
|
|
245
318
|
mutationFn: ({ doctype, docname }) => db.deleteDoc(doctype, docname)
|
|
246
319
|
});
|
|
247
320
|
const deleteDoc = (doctype, docname) => mutateAsync({ doctype, docname });
|
|
@@ -254,10 +327,10 @@ var useFrappeDeleteDoc = () => {
|
|
|
254
327
|
};
|
|
255
328
|
};
|
|
256
329
|
// src/frappe/hooks/event.ts
|
|
257
|
-
|
|
330
|
+
var import_react7 = require("react");
|
|
258
331
|
var useFrappeEventListener = (eventName, callback) => {
|
|
259
|
-
const { socket } =
|
|
260
|
-
|
|
332
|
+
const { socket } = import_react7.useContext(FrappeContext);
|
|
333
|
+
import_react7.useEffect(() => {
|
|
261
334
|
if (socket === undefined) {
|
|
262
335
|
console.warn("Socket is not enabled. Please enable socket in FrappeProvider.");
|
|
263
336
|
}
|
|
@@ -268,9 +341,9 @@ var useFrappeEventListener = (eventName, callback) => {
|
|
|
268
341
|
}, [eventName, callback, socket]);
|
|
269
342
|
};
|
|
270
343
|
var useFrappeDocumentEventListener = (doctype, docname, onUpdateCallback, emitOpenCloseEventsOnMount = true) => {
|
|
271
|
-
const { socket } =
|
|
272
|
-
const [viewers, setViewers] =
|
|
273
|
-
|
|
344
|
+
const { socket } = import_react7.useContext(FrappeContext);
|
|
345
|
+
const [viewers, setViewers] = import_react7.useState([]);
|
|
346
|
+
import_react7.useEffect(() => {
|
|
274
347
|
if (socket === undefined) {
|
|
275
348
|
console.warn("Socket is not enabled. Please enable socket in FrappeProvider.");
|
|
276
349
|
}
|
|
@@ -291,13 +364,13 @@ var useFrappeDocumentEventListener = (doctype, docname, onUpdateCallback, emitOp
|
|
|
291
364
|
};
|
|
292
365
|
}, [doctype, docname, emitOpenCloseEventsOnMount, socket]);
|
|
293
366
|
useFrappeEventListener("doc_update", onUpdateCallback);
|
|
294
|
-
const emitDocOpen =
|
|
367
|
+
const emitDocOpen = import_react7.useCallback(() => {
|
|
295
368
|
socket?.emit("doc_open", doctype, docname);
|
|
296
369
|
}, [doctype, docname, socket]);
|
|
297
|
-
const emitDocClose =
|
|
370
|
+
const emitDocClose = import_react7.useCallback(() => {
|
|
298
371
|
socket?.emit("doc_close", doctype, docname);
|
|
299
372
|
}, [doctype, docname, socket]);
|
|
300
|
-
const onViewerEvent =
|
|
373
|
+
const onViewerEvent = import_react7.useCallback((data) => {
|
|
301
374
|
if (data.doctype === doctype && data.docname === docname) {
|
|
302
375
|
setViewers(data.users);
|
|
303
376
|
}
|
|
@@ -310,8 +383,8 @@ var useFrappeDocumentEventListener = (doctype, docname, onUpdateCallback, emitOp
|
|
|
310
383
|
};
|
|
311
384
|
};
|
|
312
385
|
var useFrappeDocTypeEventListener = (doctype, onListUpdateCallback) => {
|
|
313
|
-
const { socket } =
|
|
314
|
-
|
|
386
|
+
const { socket } = import_react7.useContext(FrappeContext);
|
|
387
|
+
import_react7.useEffect(() => {
|
|
315
388
|
if (socket === undefined) {
|
|
316
389
|
console.warn("Socket is not enabled. Please enable socket in FrappeProvider.");
|
|
317
390
|
}
|
|
@@ -328,18 +401,18 @@ var useFrappeDocTypeEventListener = (doctype, onListUpdateCallback) => {
|
|
|
328
401
|
useFrappeEventListener("list_update", onListUpdateCallback);
|
|
329
402
|
};
|
|
330
403
|
// src/frappe/hooks/file.ts
|
|
331
|
-
|
|
332
|
-
|
|
404
|
+
var import_react8 = require("react");
|
|
405
|
+
var import_react_query6 = require("@tanstack/react-query");
|
|
333
406
|
var useFrappeFileUpload = () => {
|
|
334
|
-
const { file } =
|
|
335
|
-
const [progress, setProgress] =
|
|
407
|
+
const { file } = import_react8.useContext(FrappeContext);
|
|
408
|
+
const [progress, setProgress] = import_react8.useState(0);
|
|
336
409
|
const {
|
|
337
410
|
mutateAsync,
|
|
338
411
|
isPending,
|
|
339
412
|
error,
|
|
340
413
|
isSuccess,
|
|
341
414
|
reset: resetMutation
|
|
342
|
-
} =
|
|
415
|
+
} = import_react_query6.useMutation({
|
|
343
416
|
mutationFn: ({ f, args, apiPath }) => {
|
|
344
417
|
setProgress(0);
|
|
345
418
|
return file.uploadFile(f, args, (completed, total) => {
|
|
@@ -366,12 +439,12 @@ var useFrappeFileUpload = () => {
|
|
|
366
439
|
};
|
|
367
440
|
};
|
|
368
441
|
// src/frappe/hooks/get.ts
|
|
369
|
-
|
|
370
|
-
|
|
442
|
+
var import_react9 = require("react");
|
|
443
|
+
var import_react_query7 = require("@tanstack/react-query");
|
|
371
444
|
var useFrappeGetDoc = (doctype, name, options) => {
|
|
372
|
-
const { url, db } =
|
|
445
|
+
const { url, db } = import_react9.useContext(FrappeContext);
|
|
373
446
|
const queryKey = ["doc", url, doctype, name];
|
|
374
|
-
const { data, error, isLoading, isFetching, refetch } =
|
|
447
|
+
const { data, error, isLoading, isFetching, refetch } = import_react_query7.useQuery({
|
|
375
448
|
queryKey,
|
|
376
449
|
queryFn: () => db.getDoc(doctype, name),
|
|
377
450
|
enabled: !!name,
|
|
@@ -387,14 +460,12 @@ var useFrappeGetDoc = (doctype, name, options) => {
|
|
|
387
460
|
};
|
|
388
461
|
};
|
|
389
462
|
// src/frappe/hooks/list.ts
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
useQuery as useQuery5
|
|
393
|
-
} from "@tanstack/react-query";
|
|
463
|
+
var import_react10 = require("react");
|
|
464
|
+
var import_react_query8 = require("@tanstack/react-query");
|
|
394
465
|
var useFrappeGetDocList = (doctype, args, options) => {
|
|
395
|
-
const { url, db } =
|
|
466
|
+
const { url, db } = import_react10.useContext(FrappeContext);
|
|
396
467
|
const queryKey = ["docList", url, doctype, args ?? null];
|
|
397
|
-
const { data, error, isLoading, isFetching, refetch } =
|
|
468
|
+
const { data, error, isLoading, isFetching, refetch } = import_react_query8.useQuery({
|
|
398
469
|
queryKey,
|
|
399
470
|
queryFn: () => db.getDocList(doctype, args),
|
|
400
471
|
...options
|
|
@@ -408,12 +479,12 @@ var useFrappeGetDocList = (doctype, args, options) => {
|
|
|
408
479
|
};
|
|
409
480
|
};
|
|
410
481
|
// src/frappe/hooks/prefetch.ts
|
|
411
|
-
|
|
412
|
-
|
|
482
|
+
var import_react11 = require("react");
|
|
483
|
+
var import_react_query9 = require("@tanstack/react-query");
|
|
413
484
|
var useFrappePrefetchDoc = (doctype, name, options) => {
|
|
414
|
-
const queryClient =
|
|
415
|
-
const { url, db } =
|
|
416
|
-
const preloadDoc =
|
|
485
|
+
const queryClient = import_react_query9.useQueryClient();
|
|
486
|
+
const { url, db } = import_react11.useContext(FrappeContext);
|
|
487
|
+
const preloadDoc = import_react11.useCallback(() => {
|
|
417
488
|
if (!name)
|
|
418
489
|
return;
|
|
419
490
|
const queryKey = ["doc", url, doctype, name];
|
|
@@ -426,7 +497,7 @@ var useFrappePrefetchDoc = (doctype, name, options) => {
|
|
|
426
497
|
return preloadDoc;
|
|
427
498
|
};
|
|
428
499
|
// src/frappe/hooks/search.ts
|
|
429
|
-
|
|
500
|
+
var import_react12 = require("react");
|
|
430
501
|
var useSearch = (doctype, text, filters = [], limit = 20, debounce = 250) => {
|
|
431
502
|
const debouncedText = useDebounce(text, debounce);
|
|
432
503
|
return useFrappeGetCall("frappe.desk.search.search_link", {
|
|
@@ -437,8 +508,8 @@ var useSearch = (doctype, text, filters = [], limit = 20, debounce = 250) => {
|
|
|
437
508
|
});
|
|
438
509
|
};
|
|
439
510
|
var useDebounce = (value, delay) => {
|
|
440
|
-
const [debouncedValue, setDebouncedValue] =
|
|
441
|
-
|
|
511
|
+
const [debouncedValue, setDebouncedValue] = import_react12.useState(value);
|
|
512
|
+
import_react12.useEffect(() => {
|
|
442
513
|
const handler = setTimeout(() => {
|
|
443
514
|
setDebouncedValue(value);
|
|
444
515
|
}, delay);
|
|
@@ -449,11 +520,11 @@ var useDebounce = (value, delay) => {
|
|
|
449
520
|
return debouncedValue;
|
|
450
521
|
};
|
|
451
522
|
// src/frappe/hooks/update.ts
|
|
452
|
-
|
|
453
|
-
|
|
523
|
+
var import_react13 = require("react");
|
|
524
|
+
var import_react_query10 = require("@tanstack/react-query");
|
|
454
525
|
var useFrappeUpdateDoc = () => {
|
|
455
|
-
const { db } =
|
|
456
|
-
const { mutateAsync, isPending, error, isSuccess, reset } =
|
|
526
|
+
const { db } = import_react13.useContext(FrappeContext);
|
|
527
|
+
const { mutateAsync, isPending, error, isSuccess, reset } = import_react_query10.useMutation({
|
|
457
528
|
mutationFn: ({ doctype, docname, doc }) => db.updateDoc(doctype, docname, doc)
|
|
458
529
|
});
|
|
459
530
|
const updateDoc = (doctype, docname, doc) => mutateAsync({ doctype, docname, doc });
|
|
@@ -466,7 +537,7 @@ var useFrappeUpdateDoc = () => {
|
|
|
466
537
|
};
|
|
467
538
|
};
|
|
468
539
|
// src/hooks/use-variant-selector/hook.ts
|
|
469
|
-
|
|
540
|
+
var import_react14 = require("react");
|
|
470
541
|
|
|
471
542
|
// src/hooks/use-variant-selector/utils.ts
|
|
472
543
|
function findVariant(variants, specs, caseInsensitive) {
|
|
@@ -499,21 +570,21 @@ function findVariants(variants, specs, caseInsensitive) {
|
|
|
499
570
|
// src/hooks/use-variant-selector/hook.ts
|
|
500
571
|
var useVariantSelector = (props) => {
|
|
501
572
|
const { variants, attributes, defaultId } = props;
|
|
502
|
-
const [selectedSpecs, setSelectedSpecs] =
|
|
573
|
+
const [selectedSpecs, setSelectedSpecs] = import_react14.useState(() => {
|
|
503
574
|
if (defaultId) {
|
|
504
575
|
const variant = variants.find((v) => v.id === defaultId);
|
|
505
576
|
return variant?.specs || {};
|
|
506
577
|
}
|
|
507
578
|
return {};
|
|
508
579
|
});
|
|
509
|
-
const variantId =
|
|
580
|
+
const variantId = import_react14.useMemo(() => {
|
|
510
581
|
const complete = attributes.every((attr) => selectedSpecs[attr.key]);
|
|
511
582
|
if (!complete)
|
|
512
583
|
return;
|
|
513
584
|
const variant = findVariant(variants, selectedSpecs);
|
|
514
585
|
return variant?.id;
|
|
515
586
|
}, [variants, selectedSpecs, attributes]);
|
|
516
|
-
const options =
|
|
587
|
+
const options = import_react14.useMemo(() => {
|
|
517
588
|
const result = {};
|
|
518
589
|
attributes.forEach((attr, attrIndex) => {
|
|
519
590
|
const constraints = {};
|
|
@@ -536,7 +607,7 @@ var useVariantSelector = (props) => {
|
|
|
536
607
|
});
|
|
537
608
|
return result;
|
|
538
609
|
}, [variants, attributes, selectedSpecs]);
|
|
539
|
-
const onOptionSelect =
|
|
610
|
+
const onOptionSelect = import_react14.useCallback((key, value) => {
|
|
540
611
|
setSelectedSpecs((prev) => {
|
|
541
612
|
const newSpecs = { ...prev, [key]: value };
|
|
542
613
|
const attrIndex = attributes.findIndex((a) => a.key === key);
|
|
@@ -570,35 +641,54 @@ var useVariantSelector = (props) => {
|
|
|
570
641
|
getOptions: (key) => options[key] || []
|
|
571
642
|
};
|
|
572
643
|
};
|
|
644
|
+
// src/locale/provider.tsx
|
|
645
|
+
var import_react15 = require("react");
|
|
646
|
+
var jsx_runtime2 = require("react/jsx-runtime");
|
|
647
|
+
function translate(message, replace, messages = {}) {
|
|
648
|
+
let translated = messages[message] ?? message;
|
|
649
|
+
replace?.forEach((val, i) => {
|
|
650
|
+
translated = translated.replace(`{${i}}`, String(val));
|
|
651
|
+
});
|
|
652
|
+
return translated;
|
|
653
|
+
}
|
|
654
|
+
var LocaleContext = import_react15.createContext((message) => message);
|
|
655
|
+
function LocaleProvider({
|
|
656
|
+
method,
|
|
657
|
+
language,
|
|
658
|
+
storage,
|
|
659
|
+
children
|
|
660
|
+
}) {
|
|
661
|
+
const [messages, setMessages] = import_react15.useState({});
|
|
662
|
+
import_react15.useEffect(() => {
|
|
663
|
+
if (!storage)
|
|
664
|
+
return;
|
|
665
|
+
const key = `locale:${language}`;
|
|
666
|
+
Promise.resolve(storage.getItem(key)).then((cached) => {
|
|
667
|
+
if (cached)
|
|
668
|
+
setMessages(JSON.parse(cached));
|
|
669
|
+
}).catch(() => {});
|
|
670
|
+
}, [language, storage]);
|
|
671
|
+
const { data, isLoading } = useFrappeGetCall(method, { lang: language }, { staleTime: Infinity });
|
|
672
|
+
import_react15.useEffect(() => {
|
|
673
|
+
if (!data?.message)
|
|
674
|
+
return;
|
|
675
|
+
setMessages(data.message);
|
|
676
|
+
storage?.setItem(`locale:${language}`, JSON.stringify(data.message));
|
|
677
|
+
}, [data, language, storage]);
|
|
678
|
+
const __ = import_react15.useCallback((message, replace) => translate(message, replace, messages), [messages]);
|
|
679
|
+
if (isLoading && Object.keys(messages).length === 0)
|
|
680
|
+
return null;
|
|
681
|
+
return /* @__PURE__ */ jsx_runtime2.jsx(LocaleContext.Provider, {
|
|
682
|
+
value: __,
|
|
683
|
+
children
|
|
684
|
+
});
|
|
685
|
+
}
|
|
686
|
+
function useLocale() {
|
|
687
|
+
const __ = import_react15.useContext(LocaleContext);
|
|
688
|
+
return { __ };
|
|
689
|
+
}
|
|
573
690
|
// src/utils/char.ts
|
|
574
|
-
|
|
691
|
+
var import_humps = require("humps");
|
|
575
692
|
function equalsIgnoreCase(str1, str2) {
|
|
576
693
|
return str1.localeCompare(str2, undefined, { sensitivity: "accent" }) === 0;
|
|
577
694
|
}
|
|
578
|
-
export {
|
|
579
|
-
useVariantSelector,
|
|
580
|
-
useSearch,
|
|
581
|
-
useFrappeUpdateDoc,
|
|
582
|
-
useFrappePutCall,
|
|
583
|
-
useFrappePrefetchDoc,
|
|
584
|
-
useFrappePostCall,
|
|
585
|
-
useFrappeGetDocList,
|
|
586
|
-
useFrappeGetDocCount,
|
|
587
|
-
useFrappeGetDoc,
|
|
588
|
-
useFrappeGetCall,
|
|
589
|
-
useFrappeFileUpload,
|
|
590
|
-
useFrappeEventListener,
|
|
591
|
-
useFrappeDocumentEventListener,
|
|
592
|
-
useFrappeDocTypeEventListener,
|
|
593
|
-
useFrappeDeleteDoc,
|
|
594
|
-
useFrappeDeleteCall,
|
|
595
|
-
useFrappeCreateDoc,
|
|
596
|
-
useFrappeAuth,
|
|
597
|
-
equalsIgnoreCase,
|
|
598
|
-
decamelizeKeys,
|
|
599
|
-
decamelize,
|
|
600
|
-
camelizeKeys,
|
|
601
|
-
camelize,
|
|
602
|
-
FrappeProvider,
|
|
603
|
-
FrappeContext
|
|
604
|
-
};
|
|
@@ -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,4 +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
|
-
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, 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 };
|
|
@@ -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,4 +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
|
-
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, 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
|
|
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:
|
|
75
|
+
value: config,
|
|
76
76
|
children
|
|
77
77
|
});
|
|
78
78
|
};
|
|
@@ -570,6 +570,58 @@ var useVariantSelector = (props) => {
|
|
|
570
570
|
getOptions: (key) => options[key] || []
|
|
571
571
|
};
|
|
572
572
|
};
|
|
573
|
+
// src/locale/provider.tsx
|
|
574
|
+
import {
|
|
575
|
+
createContext as createContext2,
|
|
576
|
+
useCallback as useCallback5,
|
|
577
|
+
useContext as useContext12,
|
|
578
|
+
useEffect as useEffect4,
|
|
579
|
+
useState as useState6
|
|
580
|
+
} from "react";
|
|
581
|
+
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
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,
|
|
594
|
+
children
|
|
595
|
+
}) {
|
|
596
|
+
const [messages, setMessages] = useState6({});
|
|
597
|
+
useEffect4(() => {
|
|
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, { lang: 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: __,
|
|
618
|
+
children
|
|
619
|
+
});
|
|
620
|
+
}
|
|
621
|
+
function useLocale() {
|
|
622
|
+
const __ = useContext12(LocaleContext);
|
|
623
|
+
return { __ };
|
|
624
|
+
}
|
|
573
625
|
// src/utils/char.ts
|
|
574
626
|
import { camelize, decamelize, camelizeKeys, decamelizeKeys } from "humps";
|
|
575
627
|
function equalsIgnoreCase(str1, str2) {
|
|
@@ -578,6 +630,7 @@ function equalsIgnoreCase(str1, str2) {
|
|
|
578
630
|
export {
|
|
579
631
|
useVariantSelector,
|
|
580
632
|
useSearch,
|
|
633
|
+
useLocale,
|
|
581
634
|
useFrappeUpdateDoc,
|
|
582
635
|
useFrappePutCall,
|
|
583
636
|
useFrappePrefetchDoc,
|
|
@@ -599,6 +652,7 @@ export {
|
|
|
599
652
|
decamelize,
|
|
600
653
|
camelizeKeys,
|
|
601
654
|
camelize,
|
|
655
|
+
LocaleProvider,
|
|
602
656
|
FrappeProvider,
|
|
603
657
|
FrappeContext
|
|
604
658
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lasterp/shared",
|
|
3
|
-
"version": "1.0.0-beta.
|
|
3
|
+
"version": "1.0.0-beta.10",
|
|
4
4
|
"description": "Shared repo for webapp and native app",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"files": [
|
|
@@ -20,38 +20,32 @@
|
|
|
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",
|
|
42
34
|
"exports": {
|
|
43
35
|
".": {
|
|
44
|
-
"
|
|
45
|
-
"
|
|
46
|
-
"
|
|
36
|
+
"types": "./dist/index.d.ts",
|
|
37
|
+
"import": "./dist/index.js",
|
|
38
|
+
"require": "./dist/index.cjs"
|
|
47
39
|
},
|
|
48
40
|
"./package.json": "./package.json"
|
|
49
41
|
},
|
|
50
42
|
"module": "./dist/index.js",
|
|
43
|
+
"main": "./dist/index.cjs",
|
|
51
44
|
"types": "./dist/index.d.ts",
|
|
52
45
|
"dependencies": {
|
|
53
46
|
"frappe-js-sdk": "^1.12.0",
|
|
54
47
|
"humps": "^2.0.1",
|
|
55
|
-
"socket.io-client": "^4.8.3"
|
|
48
|
+
"socket.io-client": "^4.8.3",
|
|
49
|
+
"zustand": "^5.0.11"
|
|
56
50
|
}
|
|
57
51
|
}
|