@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 +2 -4
- package/dist/api/api.js +27 -21
- package/dist/auth/auth.js +3 -3
- package/dist/cavity/cavity.js +3 -0
- package/dist/conversion/conversion.js +3 -0
- package/dist/form/form.d.ts +6 -6
- package/dist/form/form.js +13 -22
- package/dist/resource/resource.js +12 -16
- package/dist/shortcut/shortcut.js +12 -0
- package/dist/table/table.d.ts +4 -4
- package/dist/table/table.js +2 -4
- package/package.json +2 -2
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
|
|
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
|
// ==============================>
|
package/dist/cavity/cavity.js
CHANGED
|
@@ -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")
|
package/dist/form/form.d.ts
CHANGED
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
import { ValidationRules } from "../validation";
|
|
2
2
|
import { ApiType } from "../api";
|
|
3
3
|
type DBSchema = any;
|
|
4
|
-
export
|
|
4
|
+
export type FormRegisterType = {
|
|
5
5
|
name: string;
|
|
6
6
|
status?: boolean;
|
|
7
7
|
validations?: ValidationRules;
|
|
8
|
-
}
|
|
9
|
-
export
|
|
8
|
+
};
|
|
9
|
+
export type FormValueType = {
|
|
10
10
|
name: string;
|
|
11
11
|
value?: any;
|
|
12
|
-
}
|
|
13
|
-
export
|
|
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
|
|
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
|
|
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;
|
package/dist/table/table.d.ts
CHANGED
|
@@ -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
|
};
|
package/dist/table/table.js
CHANGED
|
@@ -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.
|
|
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": "
|
|
19
|
+
"license": "MIT",
|
|
20
20
|
"dependencies": {
|
|
21
21
|
"axios": "^1.12.0",
|
|
22
22
|
"clsx": "^2.1.1",
|