@feardread/feature-factory 2.0.5 → 3.0.1

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.
@@ -0,0 +1,28 @@
1
+ // src/services/myApi.js
2
+ import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react';
3
+ const USERS_URL = "auth"
4
+
5
+ const ApiFactory = ( sliceName ) => {
6
+ const _this = {};
7
+ _this.API_BASE_URL = _this.base_url || "http://localhost:4000/fear/api/";
8
+ _this.baseQuery = { baseUrl: _this.API_BASE_URL };
9
+
10
+ _this.baseApi = createApi({
11
+ reducerPath: sliceName,
12
+ tagTypes: ["Product", "Order", "User", "Category"],
13
+ baseQuery: fetchBaseQuery(_this.baseQuery),
14
+ endpoints: () => ({})
15
+ });
16
+
17
+ _this.create = (routes) => {
18
+ const endpoints = (routes) ? routes : () => ({});
19
+ console.log('routes = ', routes);
20
+ const api = _this.baseApi.injectEndpoints((builder) => (routes));
21
+
22
+ return api;
23
+ }
24
+
25
+ return _this;
26
+ }
27
+
28
+ export default ApiFactory;
@@ -0,0 +1,28 @@
1
+ // src/services/myApi.js
2
+ import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react';
3
+ const USERS_URL = "auth"
4
+
5
+ const ApiFactory = ( sliceName ) => {
6
+ const _this = {};
7
+ _this.API_BASE_URL = _this.base_url || "http://localhost:4000/fear/api/";
8
+ _this.baseQuery = { baseUrl: _this.API_BASE_URL };
9
+
10
+ _this.baseApi = createApi({
11
+ reducerPath: sliceName,
12
+ tagTypes: ["Product", "Order", "User", "Category"],
13
+ baseQuery: fetchBaseQuery(_this.baseQuery),
14
+ endpoints: () => ({})
15
+ });
16
+
17
+ _this.create = (routes) => {
18
+ const endpoints = (routes) ? routes : () => ({});
19
+ console.log('routes = ', routes);
20
+ const api = _this.baseApi.injectEndpoints((builder) => (routes));
21
+
22
+ return api;
23
+ }
24
+
25
+ return _this;
26
+ }
27
+
28
+ export default ApiFactory;
@@ -0,0 +1,10 @@
1
+
2
+ export const StateFactory = (namespace) => ({
3
+ [namespace]: {},
4
+ data: [],
5
+ loading: false,
6
+ success: false,
7
+ error: null
8
+ });
9
+
10
+ export default StateFactory;
@@ -0,0 +1,10 @@
1
+
2
+ export const StateFactory = (namespace) => ({
3
+ [namespace]: {},
4
+ data: [],
5
+ loading: false,
6
+ success: false,
7
+ error: null
8
+ });
9
+
10
+ export default StateFactory;
@@ -0,0 +1,53 @@
1
+ import { createAsyncThunk } from "@reduxjs/toolkit"
2
+ import API from "./api"
3
+
4
+ // Async Thunk Factory Function
5
+ // This factory creates a specific createAsyncThunk for a given 'itemType'
6
+ export const ThunkFactory = {
7
+
8
+ create: (entity, prefix) => {
9
+
10
+ return (
11
+ createAsyncThunk(
12
+
13
+ `${entity}/${prefix}`,
14
+
15
+ async ( params, thunkApi ) => {
16
+ let url = `${entity}/${prefix}`;
17
+ console.log('params = ', params);
18
+ if ( prefix == 'one' ) url = `${entity}/${params.id}`
19
+
20
+ return API.get(url, (prefix == 'search') ? {params} : {})
21
+
22
+ .then((response) => response.data.result )
23
+
24
+ .catch((error) => thunkApi.rejectWithValue(error.message) )
25
+ }
26
+ )
27
+ )
28
+ },
29
+
30
+ post: (entity, prefix) => {
31
+ return (
32
+ createAsyncThunk(
33
+
34
+ `${entity}/${prefix}`,
35
+
36
+ async ( data, thunkApi ) => {
37
+
38
+ return API.post(`${entity}/${prefix}`, data)
39
+
40
+ .then((response) => {
41
+
42
+ return response.data.result;
43
+
44
+ })
45
+
46
+ .catch((error) => thunkApi.rejectWithValue(error.message) )
47
+ }
48
+ )
49
+ )
50
+ }
51
+ }
52
+
53
+ export default ThunkFactory;
@@ -0,0 +1,53 @@
1
+ import { createAsyncThunk } from "@reduxjs/toolkit"
2
+ import API from "./api"
3
+
4
+ // Async Thunk Factory Function
5
+ // This factory creates a specific createAsyncThunk for a given 'itemType'
6
+ export const ThunkFactory = {
7
+
8
+ create: (entity, prefix) => {
9
+
10
+ return (
11
+ createAsyncThunk(
12
+
13
+ `${entity}/${prefix}`,
14
+
15
+ async ( params, thunkApi ) => {
16
+ let url = `${entity}/${prefix}`;
17
+ console.log('params = ', params);
18
+ if ( prefix == 'one' ) url = `${entity}/${params.id}`
19
+
20
+ return API.get(url, (prefix == 'search') ? {params} : {})
21
+
22
+ .then((response) => response.data.result )
23
+
24
+ .catch((error) => thunkApi.rejectWithValue(error.message) )
25
+ }
26
+ )
27
+ )
28
+ },
29
+
30
+ post: (entity, prefix) => {
31
+ return (
32
+ createAsyncThunk(
33
+
34
+ `${entity}/${prefix}`,
35
+
36
+ async ( data, thunkApi ) => {
37
+
38
+ return API.post(`${entity}/${prefix}`, data)
39
+
40
+ .then((response) => {
41
+
42
+ return response.data.result;
43
+
44
+ })
45
+
46
+ .catch((error) => thunkApi.rejectWithValue(error.message) )
47
+ }
48
+ )
49
+ )
50
+ }
51
+ }
52
+
53
+ export default ThunkFactory;
@@ -0,0 +1,72 @@
1
+ import axios from "axios";
2
+ import qs from "qs";
3
+ import cache from "./cache";
4
+
5
+
6
+ const API_BASE_URL = (process.env.NODE_ENV === "production")
7
+ ? "http://fear.master.com:4000/fear/api/"
8
+ : "http://localhost:4000/fear/api/";
9
+
10
+ const ACCESS_TOKEN_NAME = (process.env.JWT_TOKEN)
11
+ ? process.env.JWT_TOKEN
12
+ : "x-token";
13
+
14
+ const instance = axios.create({
15
+ baseURL: `${API_BASE_URL}`,
16
+ headers: {
17
+ Accept: "application/json",
18
+ "Content-Type": "application/json",
19
+ },
20
+ paramsSerializer: (params) => {
21
+ return qs.stringify(params, { indexes: false });
22
+ },
23
+ credentials: true
24
+ //httpsAgent: new https.Agent({ rejectUnauthorized: false })
25
+ });
26
+
27
+ instance.interceptors.request.use(
28
+ (config) => {
29
+ const isAuth = cache.local.get("auth") ? cache.local.get("auth") : null;
30
+ let token = isAuth !== null ? isAuth.token : "";
31
+
32
+ config.headers = {
33
+ Authorization: `Bearer ${token}`,
34
+ [ACCESS_TOKEN_NAME]: token
35
+ };
36
+
37
+ return config;
38
+ },
39
+ (error) => { Promise.reject(error) }
40
+ );
41
+
42
+ instance.interceptors.response.use(
43
+ (response) => {
44
+ console.log("API RES :: ", response);
45
+ const messages = response.data.message;
46
+
47
+ if (response.status === 200 || 203) {
48
+ return response;
49
+ }
50
+ if (messages) return Promise.reject({ messages: [messages] });
51
+
52
+ return Promise.reject({ messages: ["got errors"] });
53
+ },
54
+ (error) => {
55
+ console.log("API ERROR :: ", error);
56
+ if (error.response) {
57
+ if (error.response.status === 401) {
58
+ cache.local.remove("auth");
59
+ return Promise.reject(error.response);
60
+ }
61
+ if (error.response.status === 500) {
62
+ return Promise.reject(error.response);
63
+ }
64
+ }
65
+ return Promise.reject(error);
66
+ }
67
+ );
68
+
69
+
70
+ export const API = instance;
71
+
72
+ export default API;
@@ -0,0 +1,71 @@
1
+
2
+
3
+ // cache
4
+ export const cache = (options = {}) => {
5
+ var engine = options.type == 'local' ? 'localStorage' : 'sessionStorage';
6
+
7
+ return {
8
+ check: () => {
9
+ if (!window[engine]) {
10
+ return false;
11
+ }
12
+ return true;
13
+ },
14
+ set: (key, value) => {
15
+ if (!key) throw Error('Error:> Invalid key');
16
+
17
+ try {
18
+ window[engine].setItem(key, JSON.stringify(value));
19
+
20
+ } catch (error) {
21
+ console.error(`Error setting item ${key}:`, error);
22
+ return false;
23
+ }
24
+ return true;
25
+ },
26
+ get: (key) => {
27
+ try {
28
+ if (key !== "undefined") {
29
+ const data = window[engine].getItem(key);
30
+ return data != 'undefined' ? JSON.parse(data) : null;
31
+ }
32
+
33
+
34
+ } catch (error) {
35
+ console.error(`Error getting item ${key}:`, error);
36
+ return null;
37
+ }
38
+ },
39
+ remove: function (key) {
40
+ window[engine].removeItem(key);
41
+ },
42
+ clear: () => {
43
+ window[engine].clear();
44
+ },
45
+ keys: () => {
46
+ return Object.keys(window[engine]);
47
+ },
48
+ has: (key) => {
49
+ return window[engine].getItem(key) !== null;
50
+ },
51
+ /*
52
+ _extend: () => {
53
+ const destination = typeof arguments[0] === 'object' ? arguments[0] : {};
54
+
55
+ for (var i = 1; i < arguments.length; i++) {
56
+ if (arguments[i] && typeof arguments[i] === 'object') {
57
+ for (var property in arguments[i])
58
+ destination[property] = arguments[i][property];
59
+ }
60
+ }
61
+
62
+ return destination;
63
+ }
64
+ */
65
+ };
66
+ }
67
+
68
+ cache.local = cache({ type: 'local' });
69
+ cache.session = cache({ type: 'session' });
70
+
71
+ export default cache;
@@ -0,0 +1,115 @@
1
+ import { createSlice, createEntityAdapter, combineReducers } from '@reduxjs/toolkit';
2
+ import ThunkFactory from './thunk';
3
+ import StateFactory from "./state";
4
+ //import ApiFactory from './service';
5
+
6
+
7
+ export function FeatureFactory(entity, reducers = {}, endpoints = null) {
8
+
9
+ const _this = {
10
+ entity,
11
+ reducers,
12
+ //api: ApiFactory,
13
+ thunk: ThunkFactory,
14
+ state: StateFactory,
15
+ adapter: createEntityAdapter(),
16
+
17
+ manager: (initialReducers) => {
18
+ const reducers = { ...initialReducers };
19
+ let combinedReducer = combineReducers(reducers);
20
+
21
+ return {
22
+ reduce: (state, action) => combinedReducer(state, action),
23
+ add: (key, reducer) => {
24
+ if (!key || reducers[key]) return;
25
+ reducers[key] = reducer;
26
+ combinedReducer = combineReducers(reducers);
27
+ },
28
+ remove: (key) => {
29
+ if (!key || !reducers[key]) return;
30
+ delete reducers[key];
31
+ combinedReducer = combineReducers(reducers);
32
+ },
33
+ getReducerMap: () => reducers,
34
+ };
35
+ },
36
+ inject: (source, dest) => {
37
+ for (var prop in source) {
38
+ if (source.hasOwnProperty(prop)) {
39
+ dest[prop] = source[prop];
40
+ }
41
+ }
42
+ return dest;
43
+ },
44
+ create: (options = { service: null, initialState: null }) => {
45
+ const { service, initialState } = options;
46
+ const sliceName = _this.entity;
47
+ const standard = {
48
+ fetch: _this.thunk.create(sliceName, 'all'),
49
+ fetchOne: _this.thunk.create(sliceName, 'one'),
50
+ search: _this.thunk.create(sliceName, 'search')
51
+ }
52
+
53
+ const factorySlice = createSlice({
54
+ name: sliceName,
55
+ initialState: StateFactory(sliceName),
56
+ reducers: _this.reducers,
57
+ extraReducers: (builder) => {
58
+ Object.keys(standard).forEach(key => {
59
+ builder
60
+ .addCase(standard[key].pending, (state) => {
61
+ state.loading = true;
62
+ state.error = null;
63
+ })
64
+ .addCase(standard[key].fulfilled, (state, action) => {
65
+ state.loading = false;
66
+ state.success = true;
67
+ state.data = action.payload;
68
+ state[sliceName] = action.payload[0];
69
+ if (key == 'fetchOne') {
70
+ state[sliceName] = action.payload[0];
71
+ }
72
+ })
73
+ .addCase(standard[key].rejected, (state, action) => {
74
+ state.loading = false;
75
+ state.success = false;
76
+ state.error = action.error;
77
+ });
78
+ })
79
+ if (service) {
80
+ Object.keys(service).forEach(key => {
81
+ if (service[key] != standard[key]) {
82
+ builder
83
+ .addCase(service[key].pending, (state) => {
84
+ state.loading = true;
85
+ state.error = null;
86
+ })
87
+ .addCase(service[key].fulfilled, (state, action) => {
88
+ state.loading = false;
89
+ state.success = true;
90
+ state.data = action.payload;
91
+ state[sliceName] = action.payload[0]
92
+ })
93
+ .addCase(service[key].rejected, (state, action) => {
94
+ state.loading = false;
95
+ state.success = false;
96
+ state.error = action.payload;
97
+ });
98
+ }
99
+ })
100
+ }}
101
+ }
102
+ )
103
+
104
+ const asyncActions = _this.inject(standard, (service) ? service : {});
105
+
106
+ return {
107
+ slice: factorySlice,
108
+ asyncActions
109
+ };
110
+ }}
111
+
112
+ return _this;
113
+ }
114
+
115
+ export default FeatureFactory;
@@ -0,0 +1,28 @@
1
+ // src/services/myApi.js
2
+ import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react';
3
+ const USERS_URL = "auth"
4
+
5
+ const ApiFactory = ( sliceName ) => {
6
+ const _this = {};
7
+ _this.API_BASE_URL = _this.base_url || "http://localhost:4000/fear/api/";
8
+ _this.baseQuery = { baseUrl: _this.API_BASE_URL };
9
+
10
+ _this.baseApi = createApi({
11
+ reducerPath: sliceName,
12
+ tagTypes: ["Product", "Order", "User", "Category"],
13
+ baseQuery: fetchBaseQuery(_this.baseQuery),
14
+ endpoints: () => ({})
15
+ });
16
+
17
+ _this.create = (routes) => {
18
+ const endpoints = (routes) ? routes : () => ({});
19
+ console.log('routes = ', routes);
20
+ const api = _this.baseApi.injectEndpoints((builder) => (routes));
21
+
22
+ return api;
23
+ }
24
+
25
+ return _this;
26
+ }
27
+
28
+ export default ApiFactory;
@@ -0,0 +1,9 @@
1
+ export const StateFactory = (namespace) => ({
2
+ [namespace]: {},
3
+ data: [],
4
+ loading: false,
5
+ success: false,
6
+ error: null
7
+ });
8
+
9
+ export default StateFactory;
@@ -0,0 +1,53 @@
1
+ import { createAsyncThunk } from "@reduxjs/toolkit"
2
+ import API from "./api"
3
+
4
+ // Async Thunk Factory Function
5
+ // This factory creates a specific createAsyncThunk for a given 'itemType'
6
+ export const ThunkFactory = {
7
+
8
+ create: (entity, prefix) => {
9
+
10
+ return (
11
+ createAsyncThunk(
12
+
13
+ `${entity}/${prefix}`,
14
+
15
+ async ( params, thunkApi ) => {
16
+ let url = `${entity}/${prefix}`;
17
+ console.log('params = ', params);
18
+ if ( prefix == 'one' ) url = `${entity}/${params.id}`
19
+
20
+ return API.get(url, (prefix == 'search') ? {params} : {})
21
+
22
+ .then((response) => response.data.result )
23
+
24
+ .catch((error) => thunkApi.rejectWithValue(error.message) )
25
+ }
26
+ )
27
+ )
28
+ },
29
+
30
+ post: (entity, prefix) => {
31
+ return (
32
+ createAsyncThunk(
33
+
34
+ `${entity}/${prefix}`,
35
+
36
+ async ( data, thunkApi ) => {
37
+ console.log('params = ', data);
38
+ return API.post(`${entity}/${prefix}`, data)
39
+
40
+ .then((response) => {
41
+
42
+ return response.data.result;
43
+
44
+ })
45
+
46
+ .catch((error) => thunkApi.rejectWithValue(error.message) )
47
+ }
48
+ )
49
+ )
50
+ }
51
+ }
52
+
53
+ export default ThunkFactory;
package/src/index.js CHANGED
@@ -1,5 +1,7 @@
1
+ export { default as FeatureFactory } from "./factory/index.js";
1
2
 
2
- export { default as FeatureFactory } from "./factory/factory.js";
3
+ export { default as ThunkFactory } from "./factory/thunk.js";
3
4
 
4
- export { default as InstanceFactory } from "./api/factory.js";
5
+ export { default as ApiFactory } from "./factory/service.js";
5
6
 
7
+ export { default as StateFactory } from "./factory/state.js";
package/src/index.ts ADDED
@@ -0,0 +1,7 @@
1
+ export { default as FeatureFactory } from "./factories/factory.js";
2
+
3
+ export { default as ThunkFactory } from "./factories/thunk.js";
4
+
5
+ export { default as ApiFactory } from "./factories/service.js";
6
+
7
+ export { default as StateFactory } from "./factories/state.js";
package/tsconfig.json ADDED
@@ -0,0 +1,11 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "es2019",
4
+ "module": "commonjs",
5
+ "declaration": true,
6
+ "outDir": "./dist",
7
+ "strict": true,
8
+ //"allowImportingTsExtensions": true,
9
+ },
10
+ "include": ["src/**/*"]
11
+ }
package/tsup.config.ts ADDED
@@ -0,0 +1,9 @@
1
+ // tsup.config.ts
2
+ import { defineConfig } from 'tsup';
3
+
4
+ export default defineConfig({
5
+ entry: ['src/index.ts'],
6
+ format: ['cjs', 'esm'],
7
+ dts: true, // Generate declaration files
8
+ clean: true, // Clean the dist folder before building
9
+ });
@@ -1,80 +0,0 @@
1
- import axios from "axios";
2
- import qs from "qs";
3
- import cache from "../cache/cache.js";
4
-
5
-
6
-
7
-
8
- function InstanceFactory ( options ) {
9
- console.log('Instance Opts = ', options)
10
- const API_BASE_URL = (options.API_BASE_URL)
11
- ? options.API_BASE_URL
12
- : "http://fear.master.com/fear/api/";
13
-
14
- const ACCESS_TOKEN_NAME = (options.JWT_TOKEN)
15
- ? options.JWT_TOKEN
16
- : "x-token";
17
-
18
- const instance = axios.create({
19
- baseURL: `${API_BASE_URL}`,
20
- headers: {
21
- Accept: "application/json",
22
- "Content-Type": "application/json",
23
- },
24
- paramsSerializer: (params) => {
25
- return qs.stringify(params, { indices: false });
26
- },
27
- credentials: true
28
- //httpsAgent: new https.Agent({ rejectUnauthorized: false })
29
- });
30
-
31
- instance.interceptors.request.use(
32
- (config) => {
33
- const isAuth = cache.local.get("auth") ? cache.local.get("auth") : null;
34
- let token = isAuth !== null ? isAuth.token : "";
35
-
36
- config.headers = {
37
- Authorization: `Bearer ${token}`,
38
- [ACCESS_TOKEN_NAME]: token
39
- };
40
-
41
- return config;
42
- },
43
- (error) => { Promise.reject(error) }
44
- );
45
-
46
- instance.interceptors.response.use(
47
- (response) => {
48
- console.log("API RES :: ", response);
49
- const messages = response.data.message;
50
-
51
- if (response.status === 200 || 203) {
52
- return response;
53
- }
54
- if (messages) return Promise.reject({ messages: [messages] });
55
-
56
- return Promise.reject({ messages: ["got errors"] });
57
- },
58
- (error) => {
59
- console.log("API ERROR :: ", error);
60
- if (error.response) {
61
- if (error.response.status === 401) {
62
- cache.local.remove("auth");
63
- return Promise.reject(error.response);
64
- }
65
- if (error.response.status === 500) {
66
- return Promise.reject(error.response);
67
- }
68
- }
69
- return Promise.reject(error);
70
- }
71
- );
72
-
73
- return instance;
74
- };
75
-
76
-
77
-
78
-
79
-
80
- export default InstanceFactory;