@feardread/feature-factory 3.0.2 → 4.0.2

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,149 +0,0 @@
1
- import { createSlice, createEntityAdapter, combineReducers } from '@reduxjs/toolkit';
2
- import ThunkFactory from './thunk';
3
- //import ApiFactory from './service';
4
-
5
- export const StateFactory = (namespace) => ({
6
- [namespace]: {},
7
- data: [],
8
- loading: false,
9
- success: false,
10
- error: null
11
- });
12
-
13
- export function FeatureFactory(entity, reducers = {}, endpoints = null) {
14
-
15
- const factory = {
16
- entity,
17
- reducers,
18
- //api: ApiFactory,
19
- thunk: ThunkFactory,
20
- state: StateFactory,
21
- adapter: createEntityAdapter()
22
- };
23
-
24
- factory.manager = (initialReducers) => {
25
- const reducers = { ...initialReducers };
26
- let combinedReducer = combineReducers(reducers);
27
-
28
- return {
29
- reduce: (state, action) => combinedReducer(state, action),
30
- add: (key, reducer) => {
31
- if (!key || reducers[key]) return;
32
- reducers[key] = reducer;
33
- combinedReducer = combineReducers(reducers);
34
- },
35
- remove: (key) => {
36
- if (!key || !reducers[key]) return;
37
- delete reducers[key];
38
- combinedReducer = combineReducers(reducers);
39
- },
40
- getReducerMap: () => reducers,
41
- };
42
- }
43
-
44
- factory.inject = (source, dest) => {
45
- for (var prop in source) {
46
- if (source.hasOwnProperty(prop)) {
47
- dest[prop] = source[prop];
48
- }
49
- }
50
- return dest;
51
- }
52
-
53
- factory.create = (options = { service: null, initialState: null }) => {
54
- const { service, initialState } = options;
55
- const sliceName = factory.entity;
56
- const standard = {
57
- fetch: factory.thunk.create(sliceName, 'all'),
58
- fetchOne: factory.thunk.create(sliceName, 'one'),
59
- search: factory.thunk.create(sliceName, 'search')
60
- }
61
-
62
- const factorySlice = createSlice({
63
- name: sliceName,
64
- initialState: StateFactory(sliceName),
65
- reducers: factory.reducers,
66
- extraReducers: (builder) => {
67
- Object.key(standard).forEach( key => {
68
- builder
69
- .addCase(standard[key].pending, (state) => {
70
- state.loading = true;
71
- state.error = null;
72
- })
73
- .addCase(standard[key].fulfilled, (state, action) => {
74
- state.loading = false;
75
- state.success = true;
76
- state.data = action.payload;
77
- state[sliceName] = action.payload[0];
78
- if (act == 'fetchOne') {
79
- state[sliceName] = action.payload[0];
80
- }
81
- })
82
- .addCase(standard[key].rejected, (state, action) => {
83
- state.loading = false;
84
- state.success = false;
85
- state.error = action.error;
86
- });
87
- })
88
- /*
89
- for (var act in standard) {
90
- if (standard.hasOwnProperty(act)) {
91
- builder
92
- .addCase(standard[act].pending, (state) => {
93
- state.loading = true;
94
- state.error = null;
95
- })
96
- .addCase(standard[act].fulfilled, (state, action) => {
97
- state.loading = false;
98
- state.success = true;
99
- state.data = action.payload;
100
- state[sliceName] = action.payload[0];
101
- if (act == 'fetchOne') {
102
- state[sliceName] = action.payload[0];
103
- }
104
- })
105
- .addCase(standard[act].rejected, (state, action) => {
106
- state.loading = false;
107
- state.success = false;
108
- state.error = action.error;
109
- });
110
- }
111
- }
112
- */
113
- if (service) {
114
- for (var key in service) {
115
- if (service.hasOwnProperty(key) && !standard.hasOwnProperty(key)) {
116
- builder
117
- .addCase(service[key].pending, (state) => {
118
- state.loading = true;
119
- state.error = null;
120
- })
121
- .addCase(service[key].fulfilled, (state, action) => {
122
- state.loading = false;
123
- state.success = true;
124
- state.data = action.payload;
125
- console.log('action fulfilled :', state.data);
126
- })
127
- .addCase(service[key].rejected, (state, action) => {
128
- state.loading = false;
129
- state.success = false;
130
- state.error = action.payload;
131
- });
132
- }
133
- }
134
-
135
- }
136
- }
137
- });
138
-
139
- const asyncActions = factory.inject(standard, (service) ? service : {});
140
- console.log('async = ', asyncActions);
141
- return {
142
- slice: factorySlice,
143
- asyncActions
144
- };
145
- }
146
- return factory;
147
- }
148
-
149
- export default FeatureFactory;
@@ -1,158 +0,0 @@
1
- import {
2
- createSlice,
3
- createEntityAdapter,
4
- combineReducers,
5
- EntityAdapter,
6
- AsyncThunk,
7
- Reducer,
8
- AnyAction,
9
- SliceCaseReducers,
10
- PayloadAction,
11
- } from '@reduxjs/toolkit';
12
- import ThunkFactory from './thunk';
13
-
14
- // Define the shape of your feature state
15
- export interface FeatureState<T> {
16
- loading: boolean;
17
- success: boolean;
18
- error: unknown | null;
19
- data: T[];
20
- [key: string]: any;
21
- }
22
-
23
- // A helper type for mapping service thunks
24
- export type ServiceMap = Record<string, AsyncThunk<any, any, any>>;
25
-
26
- // Manager API for dynamic reducer injection
27
- export interface ReducerManager {
28
- reduce: (state: any, action: AnyAction) => any;
29
- add: (key: string, reducer: Reducer<any, AnyAction>) => void;
30
- remove: (key: string) => void;
31
- getReducerMap: () => Record<string, Reducer<any, AnyAction>>;
32
- }
33
-
34
- // Assume you have a StateFactory function somewhere:
35
- function StateFactory<T>(name: string): FeatureState<T> {
36
- return {
37
- loading: false,
38
- success: false,
39
- error: null,
40
- data: [],
41
- [name]: null,
42
- };
43
- }
44
-
45
- // The main factory, now generic in T
46
- export function FeatureFactory<T>(
47
- entity: string,
48
- reducers: SliceCaseReducers<FeatureState<T>> = {}, // → typed slices
49
- endpoints: ServiceMap | null = null // → typed services
50
- ) {
51
- const factory = {
52
- entity,
53
- reducers,
54
- manager: ReducerManager ,
55
- thunk: ThunkFactory,
56
- state: StateFactory as (name: string) => FeatureState<T>,
57
- adapter: createEntityAdapter<T>() as EntityAdapter<T>, // → typed adapter
58
- };
59
-
60
- factory.manager = (initialReducers: Record<string, Reducer<any, AnyAction>> = {}) => {
61
- const reducersMap = { ...initialReducers };
62
- let combined = combineReducers(reducersMap);
63
-
64
- const manager: ReducerManager = {
65
- reduce: (state, action) => combined(state, action),
66
- add: (key, reducer) => {
67
- if (!key || reducersMap[key]) return;
68
- reducersMap[key] = reducer;
69
- combined = combineReducers(reducersMap);
70
- },
71
- remove: (key) => {
72
- if (!key || !reducersMap[key]) return;
73
- delete reducersMap[key];
74
- combined = combineReducers(reducersMap);
75
- },
76
- getReducerMap: () => reducersMap,
77
- };
78
-
79
- return manager;
80
- };
81
-
82
- factory.inject = <S extends object, D extends object>(source: S, dest: D): D & S => {
83
- Object.keys(source).forEach((k) => {
84
- // @ts-ignore
85
- dest[k] = source[k];
86
- });
87
- return dest as D & S;
88
- };
89
-
90
- factory.create = (options: { service?: ServiceMap; initialState?: FeatureState<T> } = {}) => {
91
- const { service, initialState } = options;
92
- const sliceName = factory.entity;
93
-
94
- const standard: ServiceMap = {
95
- fetch: factory.thunk.create(sliceName, 'all'),
96
- fetchOne: factory.thunk.create(sliceName, 'one'),
97
- search: factory.thunk.create(sliceName, 'search'),
98
- };
99
-
100
- const slice = createSlice({
101
- name: sliceName,
102
- initialState: initialState ?? StateFactory<T>(sliceName),
103
- reducers: factory.reducers,
104
- extraReducers: (builder) => {
105
- // handle standard thunks
106
- Object.entries(standard).forEach(([act, thunk]) => {
107
- builder
108
- .addCase(thunk.pending, (state) => {
109
- state.loading = true;
110
- state.error = null;
111
- })
112
- .addCase(thunk.fulfilled, (state, action: PayloadAction<T[]>) => {
113
- state.loading = false;
114
- state.success = true;
115
- state.data = action.payload;
116
- state[sliceName] = action.payload[0];
117
- })
118
- .addCase(thunk.rejected, (state, action) => {
119
- state.loading = false;
120
- state.success = false;
121
- state.error = action.error;
122
- });
123
- });
124
-
125
- // handle extra service thunks
126
- if (service) {
127
- Object.entries(service).forEach(([key, thunk]) => {
128
- if (!standard[key]) {
129
- builder
130
- .addCase(thunk.pending, (state) => {
131
- state.loading = true;
132
- state.error = null;
133
- })
134
- .addCase(thunk.fulfilled, (state, action: PayloadAction<any>) => {
135
- state.loading = false;
136
- state.success = true;
137
- state.data = action.payload;
138
- console.log('action fulfilled :', state.data);
139
- })
140
- .addCase(thunk.rejected, (state, action) => {
141
- state.loading = false;
142
- state.success = false;
143
- state.error = action.payload;
144
- });
145
- }
146
- });
147
- }
148
- },
149
- });
150
-
151
- const asyncActions = factory.inject(standard, service ?? {});
152
- return { slice, asyncActions };
153
- };
154
-
155
- return factory;
156
- }
157
-
158
- export default FeatureFactory;
@@ -1,28 +0,0 @@
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;
@@ -1,28 +0,0 @@
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;
@@ -1,10 +0,0 @@
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;
@@ -1,10 +0,0 @@
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;
@@ -1,53 +0,0 @@
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;
@@ -1,53 +0,0 @@
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;
package/src/index.ts DELETED
@@ -1,7 +0,0 @@
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 DELETED
@@ -1,11 +0,0 @@
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
- }