@fctc/widget-logic 1.1.3 → 1.1.5

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/dist/hooks.mjs CHANGED
@@ -1,5 +1,531 @@
1
- // src/hooks/use-click-outside.ts
2
- import { useEffect, useRef } from "react";
1
+ // src/hooks/core/use-call-action.ts
2
+ import { getEnv, useLoadAction, useRunAction } from "@fctc/interface-logic";
3
+ import { useState } from "react";
4
+ var useCallAction = () => {
5
+ const queryLoadAction = useLoadAction();
6
+ const queryRunAction = useRunAction();
7
+ const [data, setData] = useState(void 0);
8
+ const callAction = async ({
9
+ aid,
10
+ actionType = "ir.actions.act_window"
11
+ }) => {
12
+ const context = getEnv().context;
13
+ let res = void 0;
14
+ if (actionType === "ir.actions.act_window") {
15
+ res = await queryLoadAction.mutateAsync({
16
+ idAction: aid,
17
+ context
18
+ });
19
+ } else if (actionType === "ir.actions.server") {
20
+ res = await queryRunAction.mutateAsync({
21
+ idAction: aid,
22
+ context
23
+ });
24
+ }
25
+ setData(res);
26
+ return res;
27
+ };
28
+ return [data, callAction];
29
+ };
30
+
31
+ // src/hooks/core/use-config.ts
32
+ import {
33
+ getEnv as getEnv2,
34
+ setEnvFile,
35
+ useAppDispatch
36
+ } from "@fctc/interface-logic";
37
+ import { useEffect, useMemo } from "react";
38
+ var useConfig = ({ localStorageUtils, sessionStorageUtils }) => {
39
+ const dispatch = useAppDispatch();
40
+ const envConfig = useMemo(() => {
41
+ return {
42
+ mode: "development",
43
+ baseUrl: "https://api.vitrust.app/c2/api/v2",
44
+ config: {
45
+ grantType: "password",
46
+ clientId: "C52foVQSMpnNOcAP2CBIIkupOSfxUarF8nlOPfXM",
47
+ clientSecret: "rColINr4a9QBFQPqQB8YU1XfBjqzwerDMJGBxsFK"
48
+ }
49
+ };
50
+ }, []);
51
+ const config = useMemo(() => {
52
+ return {
53
+ VITE_SIDEBAR_TYPE: "grid/sidebar",
54
+ VITE_APP_DOMAIN: "https://api.vitrust.app/c2/",
55
+ VITE_IS_EDU: true,
56
+ VITE_LOGO_WHITE_LOGIN: "https://static.vitrust.app/vitrust/3a/3a1301f614dea6ee19ebf99b68f57e3fd46011d2.png",
57
+ VITE_LOGO_BLACK_LOGIN: "https://static.vitrust.app/vitrust/32/3223918780da7a439f916faac9abf0bfe98dfa07.png",
58
+ VITE_BACKGROUND_SIDEBAR: "linear-gradient(178deg, rgb(1, 106, 13) -0.89%, rgb(4, 179, 66) 99.46%",
59
+ VITE_BANNER: "https://static.vitrust.app/vitrust/5d/5d20cab0627182b4ed5cba4ee42c58b98b663e5b.svg",
60
+ VITE_BG_BUTTON: "#008F3C",
61
+ VITE_BACKGROUND_PAGE: "#F9FAFB"
62
+ };
63
+ }, []);
64
+ useEffect(() => {
65
+ try {
66
+ const env = getEnv2();
67
+ env.setupEnv({
68
+ baseUrl: envConfig.baseUrl,
69
+ port: 3e3,
70
+ config: {
71
+ grantType: envConfig.config.grantType,
72
+ clientId: envConfig.config.clientId,
73
+ clientSecret: envConfig.config.clientSecret
74
+ },
75
+ db: "preschool",
76
+ localStorageUtils: localStorageUtils(),
77
+ sessionStorageUtils: sessionStorageUtils()
78
+ });
79
+ dispatch(setEnvFile(config));
80
+ } catch (error) {
81
+ console.error("Error loading env or config:", error);
82
+ }
83
+ }, [dispatch, envConfig, config]);
84
+ return { envConfig, config };
85
+ };
86
+
87
+ // src/hooks/core/use-detail.ts
88
+ import { setProfile, useAppDispatch as useAppDispatch2, useGetDetail } from "@fctc/interface-logic";
89
+ import { useQuery } from "@tanstack/react-query";
90
+ import { useEffect as useEffect2 } from "react";
91
+ var useDetail = (accessToken, sub) => {
92
+ const dispatch = useAppDispatch2();
93
+ const fetchGetDetail = useGetDetail();
94
+ const userDetailQuery = useQuery({
95
+ queryKey: ["userDetailQuery", sub && accessToken],
96
+ queryFn: () => {
97
+ return fetchGetDetail.mutateAsync({
98
+ model: "res.users",
99
+ ids: [sub],
100
+ specification: { image_256: {} }
101
+ });
102
+ },
103
+ enabled: !!sub && !!accessToken
104
+ });
105
+ useEffect2(() => {
106
+ if (userDetailQuery.data) {
107
+ const userPicture = userDetailQuery.data;
108
+ dispatch(
109
+ setProfile({ ...userPicture, image: userPicture?.[0]?.image_256 })
110
+ );
111
+ }
112
+ }, [userDetailQuery.data, dispatch]);
113
+ return userDetailQuery;
114
+ };
115
+
116
+ // src/hooks/core/use-list-data.ts
117
+ import { useMemo as useMemo2, useState as useState3 } from "react";
118
+ import {
119
+ evalJSONDomain,
120
+ formatSortingString,
121
+ selectList,
122
+ selectSearch,
123
+ useAppSelector,
124
+ useGetListData,
125
+ useModel
126
+ } from "@fctc/interface-logic";
127
+
128
+ // src/utils/function.ts
129
+ import { useCallback, useEffect as useEffect3, useReducer, useRef, useState as useState2 } from "react";
130
+ var getDateRange = (currentDate, unit) => {
131
+ const date = new Date(currentDate);
132
+ let dateStart, dateEnd;
133
+ function formatDate(d) {
134
+ return d.getFullYear() + "-" + String(d.getMonth() + 1).padStart(2, "0") + "-" + String(d.getDate()).padStart(2, "0") + " " + String(d.getHours()).padStart(2, "0") + ":" + String(d.getMinutes()).padStart(2, "0") + ":" + String(d.getSeconds()).padStart(2, "0");
135
+ }
136
+ switch (unit) {
137
+ case "month":
138
+ dateStart = new Date(
139
+ date.getFullYear(),
140
+ date.getMonth() + 1,
141
+ date.getDate(),
142
+ 23,
143
+ 59,
144
+ 59
145
+ );
146
+ dateStart.setHours(dateStart.getHours() - 7);
147
+ dateEnd = new Date(date.getFullYear(), date.getMonth(), 0, 0, 0, 0);
148
+ dateEnd.setHours(dateEnd.getHours() - 7);
149
+ break;
150
+ case "day":
151
+ dateStart = new Date(
152
+ date.getFullYear(),
153
+ date.getMonth(),
154
+ date.getDate(),
155
+ 23,
156
+ 59,
157
+ 59
158
+ );
159
+ dateStart.setHours(dateStart.getHours() - 7);
160
+ dateEnd = new Date(
161
+ date.getFullYear(),
162
+ date.getMonth(),
163
+ date.getDate(),
164
+ 0,
165
+ 0,
166
+ 0
167
+ );
168
+ dateEnd.setHours(dateEnd.getHours() - 7);
169
+ break;
170
+ case "week":
171
+ const dayOfWeek = date.getDay();
172
+ const daysToMonday = dayOfWeek === 0 ? -6 : 1 - dayOfWeek;
173
+ const daysToSunday = dayOfWeek === 0 ? 0 : 7 - dayOfWeek;
174
+ dateStart = new Date(
175
+ date.getFullYear(),
176
+ date.getMonth(),
177
+ date.getDate() + daysToSunday,
178
+ 23,
179
+ 59,
180
+ 59
181
+ );
182
+ dateStart.setHours(dateStart.getHours() - 7);
183
+ dateEnd = new Date(
184
+ date.getFullYear(),
185
+ date.getMonth(),
186
+ date.getDate() + daysToMonday,
187
+ 0,
188
+ 0,
189
+ 0
190
+ );
191
+ dateEnd.setHours(dateEnd.getHours() - 7);
192
+ break;
193
+ case "year":
194
+ dateStart = new Date(date.getFullYear(), 11, 31, 23, 59, 59);
195
+ dateStart.setHours(dateStart.getHours() - 7);
196
+ dateEnd = new Date(date.getFullYear() - 1, 11, 31, 0, 0, 0);
197
+ dateEnd.setHours(dateEnd.getHours() - 7);
198
+ break;
199
+ default:
200
+ throw new Error(
201
+ "\u0110\u01A1n v\u1ECB kh\xF4ng h\u1EE3p l\u1EC7. Ch\u1EC9 ch\u1EA5p nh\u1EADn: week, day, month, year"
202
+ );
203
+ }
204
+ return [
205
+ ["date_start", "<=", formatDate(dateStart)],
206
+ ["date_end", ">=", formatDate(dateEnd)]
207
+ ];
208
+ };
209
+ var convertFieldsToArray = (fields) => {
210
+ const defaultFields = ["display_name", "date_start", "date_end"];
211
+ if (!fields || !Array.isArray(fields)) {
212
+ return defaultFields;
213
+ }
214
+ const inputFields = fields.filter((field) => field && field.type_co === "field").map((field) => field.name);
215
+ return [...defaultFields, ...inputFields];
216
+ };
217
+ function useAsyncState(initialValue = [true, null]) {
218
+ return useReducer(
219
+ (_state, action = null) => [false, action],
220
+ initialValue
221
+ );
222
+ }
223
+ async function setStorageItemAsync(key, value) {
224
+ try {
225
+ if (value === null) {
226
+ localStorage.removeItem(key);
227
+ } else {
228
+ localStorage.setItem(key, value);
229
+ }
230
+ } catch (e) {
231
+ console.error("Local storage is unavailable:", e);
232
+ }
233
+ }
234
+ function useStorageState(key) {
235
+ const [state, setState] = useAsyncState();
236
+ useEffect3(() => {
237
+ try {
238
+ const storedValue = localStorage.getItem(key);
239
+ setState(storedValue);
240
+ } catch (e) {
241
+ console.error("Local storage is unavailable:", e);
242
+ }
243
+ }, [key]);
244
+ const setValue = useCallback(
245
+ (value) => {
246
+ setState(value);
247
+ setStorageItemAsync(key, value);
248
+ },
249
+ [key]
250
+ );
251
+ return [state, setValue];
252
+ }
253
+
254
+ // src/hooks/core/use-list-data.ts
255
+ var useListData = ({
256
+ action,
257
+ context,
258
+ viewResponse
259
+ }) => {
260
+ const { groupByDomain } = useAppSelector(selectSearch);
261
+ const initModel = useModel();
262
+ const [type, setType] = useState3("list");
263
+ const [mode, setMode] = useState3("month");
264
+ const [currentDate, setCurrentDate] = useState3(/* @__PURE__ */ new Date());
265
+ const { pageLimit, page, order } = useAppSelector(selectList);
266
+ const listDataProps = useMemo2(() => {
267
+ const actData = action?.result;
268
+ if (!viewResponse || !actData || !context) {
269
+ return null;
270
+ }
271
+ const specification = initModel.initModel({
272
+ name: String(actData.res_model),
273
+ view: viewResponse || {},
274
+ actContext: context,
275
+ fields: type === "kanban" ? viewResponse?.views?.kanban?.fields : type === "calendar" ? viewResponse?.views?.calendar?.fields : viewResponse?.views?.list?.fields
276
+ }).getSpecification();
277
+ const domain = type === "calendar" ? getDateRange(currentDate, mode) : actData?.domain ? Array.isArray(actData?.domain) ? [...actData?.domain] : evalJSONDomain(actData?.domain, context) : [];
278
+ const limit = type === "calendar" ? 2500 : pageLimit;
279
+ const offset = page * pageLimit;
280
+ const fields = type === "calendar" ? convertFieldsToArray(viewResponse?.views?.calendar?.fields) || [] : typeof groupByDomain === "object" ? groupByDomain?.fields : void 0;
281
+ const groupby = typeof groupByDomain === "object" ? [groupByDomain?.contexts?.[0]?.group_by] : [];
282
+ const sort = order ? order : viewResponse?.views?.list?.default_order ? formatSortingString(viewResponse?.views?.list?.default_order) : "";
283
+ return {
284
+ model: actData.res_model,
285
+ specification,
286
+ domain,
287
+ limit,
288
+ offset,
289
+ fields,
290
+ groupby,
291
+ context,
292
+ sort,
293
+ type
294
+ };
295
+ }, [
296
+ action?.result,
297
+ context,
298
+ currentDate,
299
+ groupByDomain,
300
+ initModel,
301
+ mode,
302
+ order,
303
+ page,
304
+ pageLimit,
305
+ type,
306
+ viewResponse
307
+ ]);
308
+ const list = useGetListData(
309
+ listDataProps,
310
+ [listDataProps],
311
+ !!listDataProps
312
+ );
313
+ return {
314
+ ...list,
315
+ state: {
316
+ type,
317
+ setType,
318
+ mode,
319
+ setMode,
320
+ currentDate,
321
+ setCurrentDate
322
+ }
323
+ };
324
+ };
325
+
326
+ // src/hooks/core/use-menu.ts
327
+ import { useEffect as useEffect4, useMemo as useMemo3, useState as useState4 } from "react";
328
+ import { useGetMenu } from "@fctc/interface-logic";
329
+
330
+ // src/utils/constants.ts
331
+ var languages = [
332
+ { id: "vi_VN", name: "VIE" },
333
+ { id: "en_US", name: "ENG" }
334
+ ];
335
+ var API_APP_URL = {
336
+ baseUrl: "https://api.vitrust.app",
337
+ c2: "https://api.vitrust.app/c2",
338
+ apiV2: "https://api.vitrust.app/c2/api/v2"
339
+ };
340
+
341
+ // src/hooks/core/use-menu.ts
342
+ var useMenu = ({ context }) => {
343
+ const menuData = useGetMenu(context, !!context);
344
+ const [menuid, setMenuId] = useState4(void 0);
345
+ const [action, setAction] = useCallAction();
346
+ const configedIconData = useMemo3(() => {
347
+ const data = menuData.data;
348
+ return data?.map((item) => {
349
+ return {
350
+ ...item,
351
+ child_id: item?.child_id?.map((child) => {
352
+ return {
353
+ ...child,
354
+ url_icon: API_APP_URL.c2 + "/" + child.url_icon
355
+ };
356
+ }) ?? [],
357
+ url_icon: API_APP_URL.c2 + "/" + item.url_icon
358
+ };
359
+ });
360
+ }, [menuData.data]);
361
+ const handleChangeMenu = async ({
362
+ menu,
363
+ subMenu
364
+ }) => {
365
+ const aid = subMenu?.action?.id?.id;
366
+ const actionType = subMenu?.action?.type;
367
+ await setAction({
368
+ aid: Number(aid),
369
+ actionType
370
+ });
371
+ if (menu) {
372
+ setMenuId(menu.id?.toString() ?? "");
373
+ }
374
+ };
375
+ useEffect4(() => {
376
+ const firstRecord = configedIconData?.[0];
377
+ const firstChild = firstRecord?.child_id?.[0];
378
+ if (firstChild && firstRecord) {
379
+ handleChangeMenu({ menu: firstRecord, subMenu: firstChild });
380
+ }
381
+ }, [configedIconData]);
382
+ return {
383
+ ...menuData,
384
+ data: configedIconData,
385
+ action: { handleChangeMenu },
386
+ state: { menuid, action },
387
+ context
388
+ };
389
+ };
390
+
391
+ // src/hooks/core/use-profile.ts
392
+ import { useQuery as useQuery2 } from "@tanstack/react-query";
393
+ import { useEffect as useEffect5, useMemo as useMemo4 } from "react";
394
+ import { useTranslation } from "react-i18next";
395
+ import {
396
+ getEnv as getEnv3,
397
+ setDataUser,
398
+ useAppDispatch as useAppDispatch3,
399
+ useGetProfile
400
+ } from "@fctc/interface-logic";
401
+ var useProfile = (accessToken) => {
402
+ const getProfile = useGetProfile();
403
+ const dispatch = useAppDispatch3();
404
+ const { i18n } = useTranslation();
405
+ const fetchUserProfile = async () => {
406
+ return await getProfile.mutateAsync();
407
+ };
408
+ const userInfoQuery = useQuery2({
409
+ queryKey: ["userInfo", accessToken],
410
+ queryFn: fetchUserProfile,
411
+ enabled: !!accessToken
412
+ });
413
+ useEffect5(() => {
414
+ if (userInfoQuery.data) {
415
+ const userInfo = userInfoQuery.data;
416
+ const env = getEnv3();
417
+ env.setUid(userInfo?.sub);
418
+ dispatch(setDataUser(userInfo));
419
+ const userLocale = languages.find((lang) => lang?.id === userInfo?.locale);
420
+ env.setLang(userLocale?.id);
421
+ i18n.changeLanguage(userLocale?.id.split("_")[0]);
422
+ }
423
+ }, [dispatch, userInfoQuery.data]);
424
+ const context = useMemo4(() => {
425
+ if (userInfoQuery.data?.sub && userInfoQuery.data?.locale) {
426
+ return {
427
+ uid: Number(userInfoQuery.data.sub),
428
+ allowed_company_ids: [],
429
+ lang: String(userInfoQuery.data.locale),
430
+ tz: "Asia/Saigon"
431
+ };
432
+ }
433
+ return void 0;
434
+ }, [userInfoQuery.data]);
435
+ return { ...userInfoQuery, context };
436
+ };
437
+
438
+ // src/hooks/core/use-user.ts
439
+ var useUser = (accessToken) => {
440
+ const userProfile = useProfile(accessToken);
441
+ const userDetail = useDetail(accessToken, userProfile.data?.sub);
442
+ return { userProfile, userDetail, context: userProfile.context };
443
+ };
444
+
445
+ // src/hooks/core/use-view-v2.ts
446
+ import { useMemo as useMemo5 } from "react";
447
+ import { useGetView } from "@fctc/interface-logic";
448
+ var useViewV2 = ({
449
+ action,
450
+ context
451
+ }) => {
452
+ const viewParams = useMemo5(() => {
453
+ if (!action?.result) {
454
+ return void 0;
455
+ }
456
+ const actionResult = action?.result;
457
+ return {
458
+ model: String(actionResult?.res_model),
459
+ views: [
460
+ ...Array.isArray(actionResult?.views) ? actionResult?.views.map(
461
+ (view2) => view2[1] === "list" ? [view2[0], "list"] : view2
462
+ ) : [],
463
+ [
464
+ Array.isArray(actionResult?.search_view_id) ? actionResult?.search_view_id[0] : actionResult?.search_view_id,
465
+ "search"
466
+ ]
467
+ ],
468
+ context
469
+ };
470
+ }, [action, context]);
471
+ const view = useGetView(
472
+ viewParams || {},
473
+ !!viewParams
474
+ );
475
+ return {
476
+ ...view,
477
+ context
478
+ };
479
+ };
480
+
481
+ // src/hooks/core/use-auth.ts
482
+ import {
483
+ setDataUser as setDataUser2,
484
+ setMenuList,
485
+ setProfile as setProfile2,
486
+ useAppDispatch as useAppDispatch4,
487
+ useLoginCredential
488
+ } from "@fctc/interface-logic";
489
+ var useAuth = () => {
490
+ const [[isLoading, accessToken], setAccessToken] = useStorageState("TOKEN");
491
+ const loginMutate = useLoginCredential();
492
+ const dispatch = useAppDispatch4();
493
+ const signIn = async (email, password) => {
494
+ try {
495
+ loginMutate.mutate(
496
+ {
497
+ email,
498
+ password,
499
+ path: "/authentication/oauth2/token"
500
+ },
501
+ {
502
+ onSuccess: (res) => {
503
+ setAccessToken(res.access_token);
504
+ },
505
+ onError: (err) => {
506
+ }
507
+ }
508
+ );
509
+ } catch (error) {
510
+ throw new Error("Login failed");
511
+ }
512
+ };
513
+ const signOut = async () => {
514
+ dispatch(setMenuList([]));
515
+ dispatch(setDataUser2({}));
516
+ dispatch(setProfile2({}));
517
+ setAccessToken(null);
518
+ };
519
+ return {
520
+ signIn,
521
+ signOut,
522
+ accessToken,
523
+ isLoading
524
+ };
525
+ };
526
+
527
+ // src/hooks/utils/use-click-outside.ts
528
+ import { useEffect as useEffect6, useRef as useRef2 } from "react";
3
529
  var DEFAULT_EVENTS = ["mousedown", "touchstart"];
4
530
  var useClickOutside = ({
5
531
  handler,
@@ -7,8 +533,8 @@ var useClickOutside = ({
7
533
  nodes = [],
8
534
  refs
9
535
  }) => {
10
- const ref = useRef(null);
11
- useEffect(() => {
536
+ const ref = useRef2(null);
537
+ useEffect6(() => {
12
538
  const listener = (event) => {
13
539
  const { target } = event;
14
540
  if (refs && refs?.length > 0 && refs?.some((r) => r.current?.contains(target))) {
@@ -29,11 +555,11 @@ var useClickOutside = ({
29
555
  return ref;
30
556
  };
31
557
 
32
- // src/hooks/use-debounce.ts
33
- import { useEffect as useEffect2, useState } from "react";
558
+ // src/hooks/utils/use-debounce.ts
559
+ import { useEffect as useEffect7, useState as useState5 } from "react";
34
560
  function useDebounce(value, delay) {
35
- const [debouncedValue, setDebouncedValue] = useState(value);
36
- useEffect2(() => {
561
+ const [debouncedValue, setDebouncedValue] = useState5(value);
562
+ useEffect7(() => {
37
563
  const handler = setTimeout(() => {
38
564
  setDebouncedValue(value);
39
565
  }, delay);
@@ -44,6 +570,15 @@ function useDebounce(value, delay) {
44
570
  return [debouncedValue];
45
571
  }
46
572
  export {
573
+ useAuth,
574
+ useCallAction,
47
575
  useClickOutside,
48
- useDebounce
576
+ useConfig,
577
+ useDebounce,
578
+ useDetail,
579
+ useListData,
580
+ useMenu,
581
+ useProfile,
582
+ useUser,
583
+ useViewV2
49
584
  };