@skalfa/skalfa-app-core 1.0.7 → 1.0.9

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/api/api.d.ts CHANGED
@@ -1,9 +1,6 @@
1
1
  import { AxiosResponse } from "axios";
2
- export declare const authBearer: (bearer?: string) => string | null;
3
2
  export type ApiFilterType = {
4
- /** Use filter logic with: "and" / "or". */
5
3
  logic?: "and" | "or";
6
- /** Use filter type with: "eq" = Equal, "ne" = Not Equal, "in" = In, "ni" = Not In, "bw" = Between. */
7
4
  type?: "eq" | "ne" | "in" | "ni" | "bw" | "";
8
5
  column?: string;
9
6
  value?: string | number | number[] | string[] | null;
@@ -36,7 +33,7 @@ export declare const ApiFilterValue: {
36
33
  ni: string;
37
34
  bw: string;
38
35
  };
39
- export declare const api: ({ path, url, method, params, payload, includeParams, headers, bearer, }: ApiType) => Promise<AxiosResponse<any, any, {}>>;
36
+ export declare const api: ({ path, url, method, params, payload, includeParams, headers, bearer }: ApiType) => Promise<AxiosResponse<any, any, {}>>;
40
37
  export declare const useGetApi: (props: ApiType & {
41
38
  method?: "GET";
42
39
  cacheName?: string;
@@ -47,3 +44,4 @@ export declare const useGetApi: (props: ApiType & {
47
44
  data: any;
48
45
  reset: () => Promise<"" | undefined>;
49
46
  };
47
+ export declare const authBearer: (bearer?: string) => string | null;
package/dist/api/api.js CHANGED
@@ -4,26 +4,6 @@ import axios from "axios";
4
4
  import { redirect } from "next/navigation";
5
5
  import { auth } from "../auth";
6
6
  import { cavity } from "../cavity";
7
- // =========================>
8
- // ## Build auth bearer
9
- // =========================>
10
- export const authBearer = (bearer) => {
11
- const token = bearer || auth.getAccessToken() || null;
12
- return token ? `Bearer ${token}` : null;
13
- };
14
- // =========================>
15
- // ## Api error handler
16
- // =========================>
17
- const handleErrors = (fetch) => {
18
- if (fetch?.status === 401)
19
- redirect(auth.PATH_LOGIN);
20
- if (fetch?.status === 403)
21
- redirect(auth.PATH_BASE);
22
- return fetch;
23
- };
24
- // =========================>
25
- // ## Api filter value
26
- // =========================>
27
7
  export const ApiFilterValue = {
28
8
  eq: "eq",
29
9
  ne: "ne",
@@ -34,10 +14,16 @@ export const ApiFilterValue = {
34
14
  // =========================>
35
15
  // ## Api fetching handler
36
16
  // =========================>
37
- export const api = async ({ path, url, method, params, payload, includeParams, headers, bearer, }) => {
17
+ export const api = async ({ path, url, method, params, payload, includeParams, headers, bearer }) => {
38
18
  const fetchUrl = url || `${process.env.NEXT_PUBLIC_API_HOST}/${path || ""}`;
19
+ // =========================>
20
+ // ## Build headers
21
+ // =========================>
39
22
  const buildHeaders = { Authorization: authBearer(bearer) || "", ...headers };
40
23
  buildHeaders["Content-Type"] = buildHeaders["Content-Type"] || "multipart/form-data";
24
+ // =========================>
25
+ // ## Build params
26
+ // =========================>
41
27
  const filter = {};
42
28
  const jsonParams = {};
43
29
  if (params?.filter) {
@@ -54,6 +40,9 @@ export const api = async ({ path, url, method, params, payload, includeParams, h
54
40
  }
55
41
  });
56
42
  }
43
+ // =========================>
44
+ // ## Axios handler
45
+ // =========================>
57
46
  return await axios(fetchUrl, {
58
47
  method: method || "GET",
59
48
  headers: buildHeaders,
@@ -123,3 +112,20 @@ export const useGetApi = (props, sleep) => {
123
112
  const reset = () => fetch(true);
124
113
  return { loading, code, data, reset };
125
114
  };
115
+ // =========================>
116
+ // ## Build auth bearer
117
+ // =========================>
118
+ export const authBearer = (bearer) => {
119
+ const token = bearer || auth.getAccessToken() || null;
120
+ return token ? `Bearer ${token}` : null;
121
+ };
122
+ // =========================>
123
+ // ## Api error handler
124
+ // =========================>
125
+ const handleErrors = (fetch) => {
126
+ if (fetch?.status === 401)
127
+ redirect(auth.PATH_LOGIN);
128
+ if (fetch?.status === 403)
129
+ redirect(auth.PATH_BASE);
130
+ return fetch;
131
+ };
package/dist/auth/auth.js CHANGED
@@ -5,15 +5,15 @@ export const auth = {
5
5
  // ==============================>
6
6
  // ## Path of login page
7
7
  // ==============================>
8
- PATH_LOGIN: '/auth/login',
8
+ PATH_LOGIN: process.env.NEXT_PUBLIC_LOGIN_PATH || '/auth/login',
9
9
  // ==============================>
10
10
  // ## Path of home page
11
11
  // ==============================>
12
- PATH_BASE: '/',
12
+ PATH_BASE: process.env.NEXT_PUBLIC_BASE_PATH || '/',
13
13
  // ==============================>
14
14
  // ## Access token expired (days)
15
15
  // ==============================>
16
- ACCESS_TOKEN_EXPIRED: 7,
16
+ ACCESS_TOKEN_EXPIRED: Number(process.env.NEXT_PUBLIC_ACCESS_TOKEN_EXPIRED) || 7,
17
17
  // ==============================>
18
18
  // ## Name of cookie access token
19
19
  // ==============================>
@@ -79,6 +79,9 @@ export const cavity = {
79
79
  store.delete(key);
80
80
  return tx.commit;
81
81
  },
82
+ // ==============================>
83
+ // ## Cavity socket handler
84
+ // ==============================>
82
85
  socket: {
83
86
  register: () => {
84
87
  const socket = getSocket();
@@ -42,6 +42,9 @@ export const conversion = {
42
42
  // ==============================>
43
43
  date: (date, format = "DD MMM YYYY") => moment(date).format(format),
44
44
  };
45
+ // ==============================>
46
+ // ## normalize string to words
47
+ // ==============================>
45
48
  function toWords(value) {
46
49
  return value
47
50
  .replace(/([a-z0-9])([A-Z])/g, "$1 $2")
@@ -1,19 +1,19 @@
1
1
  import { ValidationRules } from "../validation";
2
2
  import { ApiType } from "../api";
3
3
  type DBSchema = any;
4
- export interface FormRegisterType {
4
+ export type FormRegisterType = {
5
5
  name: string;
6
6
  status?: boolean;
7
7
  validations?: ValidationRules;
8
- }
9
- export interface FormValueType {
8
+ };
9
+ export type FormValueType = {
10
10
  name: string;
11
11
  value?: any;
12
- }
13
- export interface FormErrorType {
12
+ };
13
+ export type FormErrorType = {
14
14
  name: string;
15
15
  error?: string | null;
16
- }
16
+ };
17
17
  export interface FormStateType {
18
18
  formRegisters: FormRegisterType[];
19
19
  formValues: FormValueType[];
package/dist/form/form.js CHANGED
@@ -1,7 +1,7 @@
1
1
  "use client";
2
2
  import { useReducer, useEffect, useState } from "react";
3
- import { registry } from "../registry";
4
3
  import { validation } from "../validation";
4
+ import { registry } from "../registry";
5
5
  import { api } from "../api";
6
6
  const initialState = {
7
7
  formRegisters: [],
@@ -111,6 +111,9 @@ export const useForm = (submitControl) => {
111
111
  value: state.formValues.find((val) => val.name === name)?.value || undefined,
112
112
  invalid: state.formErrors.find((err) => err.name === name)?.error || undefined,
113
113
  });
114
+ // ==============================>
115
+ // ## Object values handler
116
+ // ==============================>
114
117
  const getObjectValues = () => {
115
118
  const registeredNames = new Set(state.formRegisters.map(r => r.name));
116
119
  return state.formValues.reduce((acc, val) => {
@@ -119,6 +122,9 @@ export const useForm = (submitControl) => {
119
122
  return acc;
120
123
  }, {});
121
124
  };
125
+ // ==============================>
126
+ // ## Submit idb handler
127
+ // ==============================>
122
128
  const submitIdb = async () => {
123
129
  const values = payload ? await payload(getObjectValues()) : getObjectValues();
124
130
  const idb = registry.get("idb");
@@ -129,6 +135,9 @@ export const useForm = (submitControl) => {
129
135
  await client.put(submitControl?.idb?.store || "", values);
130
136
  return { status: 200, data: values };
131
137
  };
138
+ // ==============================>
139
+ // ## Submit api handler
140
+ // ==============================>
132
141
  const submitApi = async () => {
133
142
  const formData = new FormData();
134
143
  const values = payload ? await payload(getObjectValues()) : getObjectValues();
@@ -144,9 +153,6 @@ export const useForm = (submitControl) => {
144
153
  payload: formData,
145
154
  });
146
155
  };
147
- // ==============================>
148
- // ## Fetch to api
149
- // ==============================>
150
156
  const fetch = async () => {
151
157
  dispatch({ type: "SET_LOADING", payload: true });
152
158
  let execute;
@@ -160,17 +166,11 @@ export const useForm = (submitControl) => {
160
166
  throw new Error("Invalid submitControl");
161
167
  }
162
168
  if (execute?.status === 200 || execute?.status === 201) {
163
- // ==============================>
164
- // ## When success
165
- // ==============================>
166
169
  dispatch({ type: "SET_LOADING", payload: false });
167
170
  onSuccess?.(execute.data);
168
171
  dispatch({ type: "RESET" });
169
172
  }
170
173
  else if (isApiSubmit && execute?.status === 422) {
171
- // ==============================>
172
- // ## When error invalid
173
- // ==============================>
174
174
  const errors = Object.keys(execute.data.errors).map((key) => ({
175
175
  name: key,
176
176
  error: execute.data.errors[key][0],
@@ -181,9 +181,6 @@ export const useForm = (submitControl) => {
181
181
  dispatch({ type: "SET_CONFIRM", payload: false });
182
182
  }
183
183
  else {
184
- // ==============================>
185
- // ## When error server
186
- // ==============================>
187
184
  onFailed?.(execute?.status || 500);
188
185
  dispatch({ type: "SET_CONFIRM", payload: false });
189
186
  dispatch({ type: "SET_LOADING", payload: false });
@@ -196,9 +193,6 @@ export const useForm = (submitControl) => {
196
193
  e?.preventDefault();
197
194
  dispatch({ type: "SET_ERRORS", payload: [] });
198
195
  const newErrors = [];
199
- // ==============================>
200
- // ## Check register validation
201
- // ==============================>
202
196
  state.formRegisters.forEach((form) => {
203
197
  const { valid, message } = validation.check({
204
198
  value: state.formValues.find((val) => val.name === form.name)?.value,
@@ -212,9 +206,6 @@ export const useForm = (submitControl) => {
212
206
  dispatch({ type: "SET_ERRORS", payload: newErrors });
213
207
  return;
214
208
  }
215
- // ==============================>
216
- // ## Execute handler
217
- // ==============================>
218
209
  if (confirmation) {
219
210
  dispatch({ type: "SET_CONFIRM", payload: true });
220
211
  }
@@ -227,7 +218,7 @@ export const useForm = (submitControl) => {
227
218
  // ==============================>
228
219
  const onConfirm = () => fetch();
229
220
  // ==============================>
230
- // ## Set default value
221
+ // ## Set default value handler
231
222
  // ==============================>
232
223
  const setDefaultValues = (values) => {
233
224
  const newValues = values ? Object.keys(values).map((keyName) => ({
@@ -259,7 +250,7 @@ export const useForm = (submitControl) => {
259
250
  };
260
251
  };
261
252
  // ==============================>
262
- // ## Generate random id
253
+ // ## Generate input random id hook
263
254
  // ==============================>
264
255
  export const useInputRandomId = () => {
265
256
  const [randomId, setRandomId] = useState("");
@@ -269,7 +260,7 @@ export const useInputRandomId = () => {
269
260
  return randomId;
270
261
  };
271
262
  // ==============================>
272
- // ## Input handle
263
+ // ## Input handler
273
264
  // ==============================>
274
265
  export const useInputHandler = (name, value, validations, register, unregister, isFile) => {
275
266
  const [inputValue, setInputValue] = useState("");
@@ -3,11 +3,14 @@ import { useEffect, useState } from "react";
3
3
  import { useGetApi } from "../api";
4
4
  import { registry } from "../registry";
5
5
  export function useResource(props) {
6
+ // ========================>
7
+ // ## API resource handler
8
+ // ========================>
6
9
  const isApi = "path" in props || "url" in props;
7
10
  const apiResult = useGetApi(isApi ? props : {}, !isApi);
8
- // =====================
9
- // IDB MODE
10
- // =====================
11
+ // ========================>
12
+ // ## IDB resource handler
13
+ // ========================>
11
14
  const [loading, setLoading] = useState(false);
12
15
  const [data, setData] = useState(null);
13
16
  const idbParams = props.params || {};
@@ -17,12 +20,9 @@ export function useResource(props) {
17
20
  setLoading(true);
18
21
  try {
19
22
  const idb = registry.get("idb");
20
- if (!idb) {
23
+ if (!idb)
21
24
  throw new Error("IndexedDB (IDB) extension is not installed or registered.");
22
- }
23
- const idbClient = props.idb.schema
24
- ? idb.useSchema(props.idb.schema)
25
- : idb;
25
+ const idbClient = props.idb.schema ? idb.useSchema(props.idb.schema) : idb;
26
26
  let q = await idbClient.query(props.idb.store);
27
27
  if (idbParams.search) {
28
28
  const keyword = idbParams.search.toLowerCase();
@@ -41,11 +41,7 @@ export function useResource(props) {
41
41
  if (idbParams.paginate) {
42
42
  q = q.paginate(idbParams.page || 0, idbParams.paginate);
43
43
  }
44
- const [rows, total] = await Promise.all([
45
- q.get(),
46
- q.count(),
47
- ]);
48
- // const rows = await q.get()
44
+ const [rows, total] = await Promise.all([q.get(), q.count()]);
49
45
  setData({ data: rows, total_row: total });
50
46
  }
51
47
  finally {
@@ -63,9 +59,9 @@ export function useResource(props) {
63
59
  idbParams.paginate,
64
60
  idbParams.page,
65
61
  ]);
66
- // =====================
67
- // Unified return
68
- // =====================
62
+ // =======================>
63
+ // ## Unified return
64
+ // =======================>
69
65
  if (isApi) {
70
66
  return {
71
67
  loading: apiResult.loading,
@@ -1,10 +1,22 @@
1
1
  const handlers = new Map();
2
2
  export const shortcut = {
3
+ // ==============================>
4
+ // ## Shortcut register handler
5
+ // ==============================>
3
6
  register: (key, handler, description) => {
4
7
  handlers.set(key, { key, handler, description });
5
8
  },
9
+ // ==============================>
10
+ // ## Shortcut unregister handler
11
+ // ==============================>
6
12
  unregister: (key) => handlers.delete(key),
13
+ // ==============================>
14
+ // ## Shortcut list handler
15
+ // ==============================>
7
16
  list: () => Array.from(handlers.values()),
17
+ // ==============================>
18
+ // ## Shortcut init handler
19
+ // ==============================>
8
20
  init: () => {
9
21
  window.addEventListener("keydown", (e) => {
10
22
  const target = e.target;
@@ -28,10 +28,6 @@ export declare const useTable: (fetchControl: UseResourceProps & {
28
28
  setParam: <K extends keyof ApiParamsType>(key: K, value: ApiParamsType[K]) => void;
29
29
  focus: number | null | undefined;
30
30
  setFocus: (focus: number | null) => void;
31
- selected: Record<string, any> | null | undefined;
32
- setSelected: (selected: Record<string, any> | null) => void;
33
- checks: (string | number)[] | null | undefined;
34
- setChecks: (checks: (string | number)[] | null) => void;
35
31
  tableControl: {
36
32
  loading: boolean;
37
33
  sortBy: string[] | undefined;
@@ -48,4 +44,8 @@ export declare const useTable: (fetchControl: UseResourceProps & {
48
44
  onChange: (_: number, paginate: number, page: number) => void;
49
45
  };
50
46
  };
47
+ selected: Record<string, any> | null | undefined;
48
+ setSelected: (selected: Record<string, any> | null) => void;
49
+ checks: (string | number)[] | null | undefined;
50
+ setChecks: (checks: (string | number)[] | null) => void;
51
51
  };
@@ -68,9 +68,7 @@ export const useTable = (fetchControl, id = "", title = "", urlParam) => {
68
68
  });
69
69
  }
70
70
  const newSearch = url.searchParams.toString();
71
- const currentSearch = typeof window !== "undefined"
72
- ? (window.location.search.startsWith("?") ? window.location.search.slice(1) : window.location.search)
73
- : "";
71
+ const currentSearch = typeof window !== "undefined" ? (window.location.search.startsWith("?") ? window.location.search.slice(1) : window.location.search) : "";
74
72
  if (newSearch !== currentSearch) {
75
73
  router.replace(url.pathname + "?" + newSearch, { scroll: false });
76
74
  }
@@ -137,10 +135,10 @@ export const useTable = (fetchControl, id = "", title = "", urlParam) => {
137
135
  setParam,
138
136
  focus: state.focus,
139
137
  setFocus,
138
+ tableControl,
140
139
  selected: state.selected,
141
140
  setSelected: setSelected,
142
141
  checks: state.checks,
143
142
  setChecks: setChecks,
144
- tableControl,
145
143
  };
146
144
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@skalfa/skalfa-app-core",
3
- "version": "1.0.7",
3
+ "version": "1.0.9",
4
4
  "description": "Core framework engine and foundational utility hook library for the Skalfa Next.js frontend.",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -16,7 +16,7 @@
16
16
  "core"
17
17
  ],
18
18
  "author": "",
19
- "license": "UNLICENSED",
19
+ "license": "MIT",
20
20
  "dependencies": {
21
21
  "axios": "^1.12.0",
22
22
  "clsx": "^2.1.1",