@moamc/rn-cli 1.0.0

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,217 @@
1
+ const generateApiServiceTemplate = (apiConfig) => {
2
+ const { serviceName, methods } = apiConfig;
3
+
4
+ const methodsCode = methods.map(method => {
5
+ const { name, endpoint, type, hasAuth = true } = method;
6
+ const callType = type === 'GET' ? 'makeAuthenticatedGetCall' : 'makeAuthenticatedPostCall';
7
+
8
+ if (type === 'GET') {
9
+ return `function ${name}(data) {
10
+ \tconst response = coreAPI.${callType}('${endpoint}', ${hasAuth});
11
+ \treturn handleResponse(response);
12
+ }`;
13
+ } else {
14
+ return `function ${name}(data) {
15
+ \tconst response = coreAPI.${callType}('${endpoint}', data, ${hasAuth});
16
+ \treturn handleResponse(response);
17
+ }`;
18
+ }
19
+ }).join('\n\n');
20
+
21
+ const exports = methods.map(m => m.name).join(',\n\t');
22
+
23
+ return `import { coreAPI } from '../common/baseConfig';
24
+ import handleResponse from '../handler';
25
+
26
+ ${methodsCode}
27
+
28
+ export const ${serviceName}Service = {
29
+ \t${exports}
30
+ };
31
+ `;
32
+ };
33
+
34
+ const generateQueryOptionsTemplate = (apiConfig) => {
35
+ const { serviceName, methods } = apiConfig;
36
+
37
+ const queryMethods = methods.map(method => {
38
+ const { name, queryKey, hasParams = true } = method;
39
+
40
+ return `\t${name}: (data) => (queryOptions({
41
+ \t\tqueryKey: ['${queryKey}', data],
42
+ \t\tqueryFn: () => ${serviceName}Service.${name}(data),
43
+ \t\t...baseQueryOptions,
44
+ \t})),`;
45
+ }).join('\n\n');
46
+
47
+ return `import { queryOptions } from '@tanstack/react-query';
48
+ import { ${serviceName}Service } from '../services/${serviceName}/${serviceName}';
49
+
50
+ const baseQueryOptions = {
51
+ \trefetchOnWindowFocus: false,
52
+ \trefetchOnReconnect: false,
53
+ \trefetchInterval: false,
54
+ \tstaleTime: 5 * 60 * 1000,
55
+ \tgcTime: 10 * 60 * 1000,
56
+ };
57
+
58
+ export const ${serviceName}QueryOptions = {
59
+ ${queryMethods}
60
+ };
61
+ `;
62
+ };
63
+
64
+ const generateApiIntegratedHookTemplate = (screenName, apiConfig, formFields = []) => {
65
+ const { serviceName, methods, primaryMethod, hasPostMethod } = apiConfig;
66
+ const getMethod = methods.find(m => m.type === 'GET');
67
+ const postMethod = methods.find(m => m.type === 'POST');
68
+
69
+ const formFieldsInit = formFields.map(f => `\t\t${f.name}: '',`).join('\n');
70
+
71
+ if (hasPostMethod) {
72
+ return `import { useState, useEffect } from 'react';
73
+ import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
74
+ import { ${serviceName}QueryOptions } from '../../../../queries/${serviceName}Query';
75
+ import { ${serviceName}Service } from '../../../../services/${serviceName}/${serviceName}';
76
+ import { showToastNotification } from '../../../../helpers/common';
77
+ import { validate${screenName} } from '../validation';
78
+
79
+ export const use${screenName} = () => {
80
+ \tconst queryClient = useQueryClient();
81
+ \tconst [formData, setFormData] = useState({
82
+ ${formFieldsInit}
83
+ \t});
84
+ \tconst [errors, setErrors] = useState({});
85
+ \tconst [touched, setTouched] = useState({});
86
+
87
+ \t// Fetch data using React Query${getMethod ? `
88
+ \tconst { data, isLoading, error, refetch } = useQuery(
89
+ \t\t${serviceName}QueryOptions.${getMethod.name}(formData)
90
+ \t);` : ''}
91
+
92
+ \t// Submit mutation
93
+ \tconst submitMutation = useMutation({
94
+ \t\tmutationFn: (data) => ${serviceName}Service.${postMethod.name}(data),
95
+ \t\tonSuccess: (response) => {
96
+ \t\t\tshowToastNotification('Success!');
97
+ \t\t\t// Invalidate and refetch${getMethod ? `
98
+ \t\t\tqueryClient.invalidateQueries({ queryKey: ['${getMethod.queryKey}'] });` : ''}
99
+ \t\t},
100
+ \t\tonError: (error) => {
101
+ \t\t\tshowToastNotification(error?.message || 'Something went wrong');
102
+ \t\t},
103
+ \t});${getMethod ? `
104
+
105
+ \tuseEffect(() => {
106
+ \t\tif (error) {
107
+ \t\t\tshowToastNotification(error?.message || 'Something went wrong');
108
+ \t\t}
109
+ \t}, [error]);` : ''}
110
+
111
+ \tconst handleChange = (value, field) => {
112
+ \t\tconst updatedFormData = { ...formData, [field]: value };
113
+ \t\tsetFormData(updatedFormData);
114
+ \t\tsetTouched(prev => ({ ...prev, [field]: true }));
115
+ \t\t
116
+ \t\t// Re-validate on change
117
+ \t\tconst validationErrors = validate${screenName}(updatedFormData);
118
+ \t\tsetErrors(validationErrors);
119
+ \t};
120
+
121
+ \tconst handleSubmit = async () => {
122
+ \t\tconst validationErrors = validate${screenName}(formData);
123
+ \t\tif (Object.keys(validationErrors).length > 0) {
124
+ \t\t\tsetErrors(validationErrors);
125
+ \t\t\tsetTouched(Object.keys(formData).reduce((acc, key) => ({ ...acc, [key]: true }), {}));
126
+ \t\t\treturn;
127
+ \t\t}
128
+
129
+ \t\tsubmitMutation.mutate(formData);
130
+ \t};
131
+
132
+ \treturn {
133
+ \t\tformData,${getMethod ? `
134
+ \t\tdata,` : ''}
135
+ \t\terrors,
136
+ \t\ttouched,
137
+ \t\tloading: ${getMethod ? 'isLoading || ' : ''}submitMutation.isPending,
138
+ \t\thandleChange,
139
+ \t\thandleSubmit,${getMethod ? `
140
+ \t\trefetch,` : ''}
141
+ \t};
142
+ };
143
+ `;
144
+ }
145
+
146
+ const method = methods.find(m => m.name === primaryMethod) || methods[0];
147
+
148
+ return `import { useState, useEffect } from 'react';
149
+ import { useQuery, useQueryClient } from '@tanstack/react-query';
150
+ import { ${serviceName}QueryOptions } from '../../../../queries/${serviceName}Query';
151
+ import { showToastNotification } from '../../../../helpers/common';
152
+ import { validate${screenName} } from '../validation';
153
+
154
+ export const use${screenName} = () => {
155
+ \tconst queryClient = useQueryClient();
156
+ \tconst [formData, setFormData] = useState({
157
+ ${formFieldsInit}
158
+ \t});
159
+ \tconst [errors, setErrors] = useState({});
160
+ \tconst [touched, setTouched] = useState({});
161
+
162
+ \t// Fetch data using React Query
163
+ \tconst { data, isLoading, error, refetch } = useQuery(
164
+ \t\t${serviceName}QueryOptions.${method.name}(formData)
165
+ \t);
166
+
167
+ \tuseEffect(() => {
168
+ \t\tif (error) {
169
+ \t\t\tshowToastNotification(error?.message || 'Something went wrong');
170
+ \t\t}
171
+ \t}, [error]);
172
+
173
+ \tconst handleChange = (value, field) => {
174
+ \t\tconst updatedFormData = { ...formData, [field]: value };
175
+ \t\tsetFormData(updatedFormData);
176
+ \t\tsetTouched(prev => ({ ...prev, [field]: true }));
177
+ \t\t
178
+ \t\t// Re-validate on change
179
+ \t\tconst validationErrors = validate${screenName}(updatedFormData);
180
+ \t\tsetErrors(validationErrors);
181
+ \t};
182
+
183
+ \tconst handleSubmit = async () => {
184
+ \t\tconst validationErrors = validate${screenName}(formData);
185
+ \t\tif (Object.keys(validationErrors).length > 0) {
186
+ \t\t\tsetErrors(validationErrors);
187
+ \t\t\tsetTouched(Object.keys(formData).reduce((acc, key) => ({ ...acc, [key]: true }), {}));
188
+ \t\t\treturn;
189
+ \t\t}
190
+
191
+ \t\ttry {
192
+ \t\t\tawait refetch();
193
+ \t\t\tshowToastNotification('Success!');
194
+ \t\t} catch (error) {
195
+ \t\t\tshowToastNotification(error?.message || 'Something went wrong');
196
+ \t\t}
197
+ \t};
198
+
199
+ \treturn {
200
+ \t\tformData,
201
+ \t\tdata,
202
+ \t\terrors,
203
+ \t\ttouched,
204
+ \t\tloading: isLoading,
205
+ \t\thandleChange,
206
+ \t\thandleSubmit,
207
+ \t\trefetch,
208
+ \t};
209
+ };
210
+ `;
211
+ };
212
+
213
+ module.exports = {
214
+ generateApiServiceTemplate,
215
+ generateQueryOptionsTemplate,
216
+ generateApiIntegratedHookTemplate,
217
+ };
@@ -0,0 +1,33 @@
1
+ const generateConstantsTemplate = (formFields = []) => {
2
+ const dropdownFields = formFields.filter(f => f.type === 'dropdown' || f.type === 'radio');
3
+
4
+ if (dropdownFields.length === 0) {
5
+ return `// Add your constants here
6
+ export const DEFAULT_OPTION = [
7
+ \t{ label: 'Yes', value: 'yes' },
8
+ \t{ label: 'No', value: 'no' },
9
+ ];
10
+ `;
11
+ }
12
+
13
+ const constants = dropdownFields.map(field => {
14
+ const constantName = field.name.toUpperCase() + '_OPTIONS';
15
+ return `export const ${constantName} = [
16
+ \t{ label: 'Option 1', value: '1' },
17
+ \t{ label: 'Option 2', value: '2' },
18
+ \t// Add more options as needed
19
+ ];`;
20
+ }).join('\n\n');
21
+
22
+ return `// Dropdown and Radio button options
23
+ ${constants}
24
+
25
+ // Common options
26
+ export const DEFAULT_OPTION = [
27
+ \t{ label: 'Yes', value: 'yes' },
28
+ \t{ label: 'No', value: 'no' },
29
+ ];
30
+ `;
31
+ };
32
+
33
+ module.exports = { generateConstantsTemplate };
@@ -0,0 +1,18 @@
1
+ const generateConstantsTemplate = (formFields = []) => {
2
+ const dropdownFields = formFields?.filter(f => f.type === 'dropdown') || [];
3
+
4
+ if (dropdownFields.length === 0) {
5
+ return `// Add your constants here
6
+ export const EXAMPLE_CONSTANT = 'value';
7
+ `;
8
+ }
9
+
10
+ const constants = dropdownFields.map(field => {
11
+ const options = field.options?.map(opt => `\t{ label: '${opt}', value: '${opt.toUpperCase().replace(/\s+/g, '_')}' },`).join('\n') || '';
12
+ return `export const ${field.name.toUpperCase()}_OPTIONS = [\n${options}\n];`;
13
+ }).join('\n\n');
14
+
15
+ return `// Dropdown options\n${constants}\n`;
16
+ };
17
+
18
+ module.exports = { generateConstantsTemplate };
@@ -0,0 +1,165 @@
1
+ // Field type configurations
2
+ const FIELD_TYPES = {
3
+ TEXT: 'text',
4
+ EMAIL: 'email',
5
+ NUMBER: 'number',
6
+ DATE: 'date',
7
+ DROPDOWN: 'dropdown',
8
+ RADIO: 'radio',
9
+ CHECKBOX: 'checkbox',
10
+ FILE: 'file'
11
+ };
12
+
13
+ const FIELD_WIDTHS = {
14
+ FULL: 'full',
15
+ HALF: 'half'
16
+ };
17
+
18
+ const generateFormField = (field) => {
19
+ const { name, type, label, width = 'full' } = field;
20
+
21
+ const containerStyle = width === 'half' ? 'styles.headWidth' : '{ width: \'100%\' }';
22
+
23
+ switch (type) {
24
+ case FIELD_TYPES.DATE:
25
+ return generateDateField(name, label, containerStyle);
26
+
27
+ case FIELD_TYPES.DROPDOWN:
28
+ return generateDropdownField(name, label, containerStyle);
29
+
30
+ case FIELD_TYPES.RADIO:
31
+ return generateRadioField(name, label, containerStyle);
32
+
33
+ case FIELD_TYPES.CHECKBOX:
34
+ return generateCheckboxField(name, label);
35
+
36
+ case FIELD_TYPES.FILE:
37
+ return generateFileField(name, label, containerStyle);
38
+
39
+ case FIELD_TYPES.TEXT:
40
+ case FIELD_TYPES.EMAIL:
41
+ case FIELD_TYPES.NUMBER:
42
+ default:
43
+ return generateTextInputField(name, label, type, containerStyle);
44
+ }
45
+ };
46
+
47
+ const generateTextInputField = (name, label, type, containerStyle) => {
48
+ const keyboardType = type === 'number' ? 'numeric' : type === 'email' ? 'email-address' : 'default';
49
+ const autoCapitalize = type === 'email' ? 'none' : 'sentences';
50
+
51
+ return `\t\t\t\t\t<View style={${containerStyle}}>
52
+ \t\t\t\t\t\t<FloatingTextInput
53
+ \t\t\t\t\t\t\tlabel="${label}"
54
+ \t\t\t\t\t\t\tvalue={formData?.${name} || ''}
55
+ \t\t\t\t\t\t\tonChangeText={(e) => handleChange(e, '${name}')}
56
+ \t\t\t\t\t\t\ttextInputStyles={styles.floatContentStyle}
57
+ \t\t\t\t\t\t\tinputContainerStyle={styles.floatStyle}
58
+ \t\t\t\t\t\t\tlabelStyles={styles.floatLabelStyle}
59
+ \t\t\t\t\t\t\terror={touched?.${name} && errors?.${name}}
60
+ \t\t\t\t\t\t\tkeyboardType="${keyboardType}"${type === 'email' ? `\n\t\t\t\t\t\t\totherTextInputProps={{ autoCapitalize: '${autoCapitalize}' }}` : ''}
61
+ \t\t\t\t\t\t/>
62
+ \t\t\t\t\t</View>`;
63
+ };
64
+
65
+ const generateDateField = (name, label, containerStyle) => {
66
+ return `\t\t\t\t\t<TouchableRipple
67
+ \t\t\t\t\t\tpointerEvents="box-only"
68
+ \t\t\t\t\t\tstyle={${containerStyle}}
69
+ \t\t\t\t\t\tonPress={() => handleCalendar('${name}')}
70
+ \t\t\t\t\t>
71
+ \t\t\t\t\t\t<FloatingTextInput
72
+ \t\t\t\t\t\t\tlabel="${label}"
73
+ \t\t\t\t\t\t\tvalue={formikState?.values?.${name} || ''}
74
+ \t\t\t\t\t\t\ttextInputStyles={customStyle.floatContentStyle}
75
+ \t\t\t\t\t\t\tinputContainerStyle={customStyle.floatStyle}
76
+ \t\t\t\t\t\t\tlabelStyle={customStyle.floatLabelStyle}
77
+ \t\t\t\t\t\t\terror={(touched == '${name}' || touched == null) && formikState.errors.${name}}
78
+ \t\t\t\t\t\t\teditable={false}
79
+ \t\t\t\t\t\t\ttrailingIconName={!((touched == '${name}' || touched == null) && formikState.errors.${name}) && 'calendar'}
80
+ \t\t\t\t\t\t\ticonColor={colorConstant?.amcBlue}
81
+ \t\t\t\t\t\t\totherTextInputProps={{ selection: { start: 0 } }}
82
+ \t\t\t\t\t\t/>
83
+ \t\t\t\t\t</TouchableRipple>`;
84
+ };
85
+
86
+ const generateDropdownField = (name, label, containerStyle) => {
87
+ return `\t\t\t\t\t<TouchableRipple
88
+ \t\t\t\t\t\tpointerEvents="box-only"
89
+ \t\t\t\t\t\tstyle={${containerStyle}}
90
+ \t\t\t\t\t\tonPress={() => openBottomSheet('${name}')}
91
+ \t\t\t\t\t>
92
+ \t\t\t\t\t\t<FloatingTextInput
93
+ \t\t\t\t\t\t\tlabel="${label}"
94
+ \t\t\t\t\t\t\tvalue={formData?.${name}?.label || ''}
95
+ \t\t\t\t\t\t\ttextInputStyles={styles.floatContentStyle}
96
+ \t\t\t\t\t\t\tinputContainerStyle={styles.floatStyle}
97
+ \t\t\t\t\t\t\tlabelStyles={styles.floatLabelStyle}
98
+ \t\t\t\t\t\t\teditable={false}
99
+ \t\t\t\t\t\t\ttrailingIconName="menu-down"
100
+ \t\t\t\t\t\t\ticonColor={colorConstant?.amcBlack}
101
+ \t\t\t\t\t\t\totherTextInputProps={{ selection: { start: 0 } }}
102
+ \t\t\t\t\t\t/>
103
+ \t\t\t\t\t</TouchableRipple>`;
104
+ };
105
+
106
+ const generateRadioField = (name, label, containerStyle) => {
107
+ return `\t\t\t\t\t<View style={${containerStyle}}>
108
+ \t\t\t\t\t\t<Text style={customStyle?.optionText}>${label}</Text>
109
+ \t\t\t\t\t\t<RadioForm
110
+ \t\t\t\t\t\t\thelperTextStyle={{ height: 0 }}
111
+ \t\t\t\t\t\t\toption={${name.toUpperCase()}_OPTIONS}
112
+ \t\t\t\t\t\t\tvalue={formikState?.values?.${name}}
113
+ \t\t\t\t\t\t\ttextStyle={customStyle?.optionInnerText}
114
+ \t\t\t\t\t\t\tradioInputContainer={customStyle.optionContainer}
115
+ \t\t\t\t\t\t\tactiveRadioContainer={customStyle.activeOptionContainer}
116
+ \t\t\t\t\t\t\tactiveRadioText={customStyle.activeOptionText}
117
+ \t\t\t\t\t\t\tonChange={(e) => handleChange(e, '${name}')}
118
+ \t\t\t\t\t\t/>
119
+ \t\t\t\t\t</View>`;
120
+ };
121
+
122
+ const generateCheckboxField = (name, label) => {
123
+ return `\t\t\t\t\t<View style={customStyle.lastHeadContainer}>
124
+ \t\t\t\t\t\t<View style={customStyle.checkBoxContainer}>
125
+ \t\t\t\t\t\t\t<CheckBox
126
+ \t\t\t\t\t\t\t\tsetcheckBoxBtn={() => handleChange(!formikState?.values?.${name}, '${name}')}
127
+ \t\t\t\t\t\t\t\tlightBackground={false}
128
+ \t\t\t\t\t\t\t\tlabelStyle={customStyle.StartToday}
129
+ \t\t\t\t\t\t\t\tposition={'leading'}
130
+ \t\t\t\t\t\t\t\tlabel={''}
131
+ \t\t\t\t\t\t\t\tgreyColor={true}
132
+ \t\t\t\t\t\t\t\tcheckBoxBtn={formikState?.values?.${name}}
133
+ \t\t\t\t\t\t\t/>
134
+ \t\t\t\t\t\t</View>
135
+ \t\t\t\t\t\t<Text style={customStyle.bottomContainertTextLower}>${label}</Text>
136
+ \t\t\t\t\t</View>`;
137
+ };
138
+
139
+ const generateFileField = (name, label, containerStyle) => {
140
+ return `\t\t\t\t\t<TouchableRipple
141
+ \t\t\t\t\t\tpointerEvents="box-only"
142
+ \t\t\t\t\t\tstyle={${containerStyle}}
143
+ \t\t\t\t\t\tonPress={() => handleDocumentPicker('${name}')}
144
+ \t\t\t\t\t>
145
+ \t\t\t\t\t\t<FloatingTextInput
146
+ \t\t\t\t\t\t\tlabel="${label}"
147
+ \t\t\t\t\t\t\tvalue={formikState?.values?.${name}?.name || formikState?.values?.${name} && 'File selected' || 'Choose'}
148
+ \t\t\t\t\t\t\ttextInputStyles={customStyle.floatContentStyle}
149
+ \t\t\t\t\t\t\tlabelStyles={customStyle.labelStyles}
150
+ \t\t\t\t\t\t\teditable={false}
151
+ \t\t\t\t\t\t\tnumberOfLines={1}
152
+ \t\t\t\t\t\t\terror={(touched == '${name}' || touched == null) && formikState.errors.${name}}
153
+ \t\t\t\t\t\t\ttrailingIconName="attachment"
154
+ \t\t\t\t\t\t\ticonColor={colorConstant?.amcBlack}
155
+ \t\t\t\t\t\t\totherTextInputProps={{ selection: { start: 0 } }}
156
+ \t\t\t\t\t\t\tdisabled={true}
157
+ \t\t\t\t\t\t/>
158
+ \t\t\t\t\t</TouchableRipple>`;
159
+ };
160
+
161
+ module.exports = {
162
+ generateFormField,
163
+ FIELD_TYPES,
164
+ FIELD_WIDTHS
165
+ };
@@ -0,0 +1,10 @@
1
+ const generateHelpersTemplate = () => {
2
+ return `// Add your helper functions here
3
+
4
+ export const exampleHelper = (data) => {
5
+ \treturn data;
6
+ };
7
+ `;
8
+ };
9
+
10
+ module.exports = { generateHelpersTemplate };
@@ -0,0 +1,132 @@
1
+ const generateInitialValues = (formFields = []) => {
2
+ if (!formFields || formFields.length === 0) {
3
+ return '\t\tloader: false,';
4
+ }
5
+
6
+ const fields = formFields.map(field => {
7
+ let defaultValue;
8
+ switch (field.type) {
9
+ case 'checkbox':
10
+ defaultValue = 'false';
11
+ break;
12
+ case 'dropdown':
13
+ case 'radio':
14
+ defaultValue = 'null';
15
+ break;
16
+ case 'file':
17
+ defaultValue = 'null';
18
+ break;
19
+ default:
20
+ defaultValue = "''";
21
+ }
22
+ return `\t\t${field.name}: ${defaultValue},`;
23
+ }).join('\n');
24
+
25
+ const hasDropdown = formFields.some(f => f.type === 'dropdown');
26
+ const hasDate = formFields.some(f => f.type === 'date');
27
+
28
+ let additionalFields = '';
29
+ if (hasDropdown) {
30
+ additionalFields += '\n\t\topenBottomNote: false,\n\t\tdropDownType: \'\',';
31
+ }
32
+ if (hasDate) {
33
+ additionalFields += '\n\t\topenCalendar: false,\n\t\tcalendarField: \'\',';
34
+ }
35
+
36
+ return `\t\tloader: false,\n${fields}${additionalFields}`;
37
+ };
38
+
39
+ const generateHookTemplate = (hookName, hasForm = false, formFields = [], eventName = null) => {
40
+ if (hasForm) {
41
+ const hasDropdown = formFields.some(f => f.type === 'dropdown');
42
+ const hasDate = formFields.some(f => f.type === 'date');
43
+
44
+ return `import { useState } from 'react';
45
+ import { showToastNotification } from '../../../../helpers/common';${hasDate ? '\nimport moment from \'moment\';' : ''}
46
+ import { validate${hookName} } from '../validation';
47
+
48
+ export const use${hookName} = () => {
49
+ \tconst [formData, setFormData] = useState({
50
+ ${formFields.map(f => `\t\t${f.name}: '',`).join('\n')}
51
+ \t});
52
+ \tconst [errors, setErrors] = useState({});
53
+ \tconst [touched, setTouched] = useState({});
54
+ \tconst [loading, setLoading] = useState(false);${hasDropdown ? '\n\tconst [bottomSheetType, setBottomSheetType] = useState(null);' : ''}${hasDate ? '\n\tconst [openCalendar, setOpenCalendar] = useState(false);' : ''}
55
+
56
+ \tconst handleChange = (value, field) => {
57
+ \t\tconst updatedFormData = { ...formData, [field]: value };
58
+ \t\tsetFormData(updatedFormData);
59
+ \t\tsetTouched(prev => ({ ...prev, [field]: true }));
60
+ \t\t
61
+ \t\t// Re-validate on change
62
+ \t\tconst validationErrors = validate${hookName}(updatedFormData);
63
+ \t\tsetErrors(validationErrors);
64
+ \t};
65
+
66
+ \tconst handleSubmit = async () => {
67
+ \t\tconst validationErrors = validate${hookName}(formData);
68
+ \t\tif (Object.keys(validationErrors).length > 0) {
69
+ \t\t\tsetErrors(validationErrors);
70
+ \t\t\tsetTouched(Object.keys(formData).reduce((acc, key) => ({ ...acc, [key]: true }), {}));
71
+ \t\t\t// Validation errors are shown inline below each field
72
+ \t\t\treturn;
73
+ \t\t}
74
+
75
+ \t\tsetLoading(true);
76
+ \t\ttry {
77
+ \t\t\t// Add your API call here
78
+ \t\t\tshowToastNotification('Success!');
79
+ \t\t} catch (error) {
80
+ \t\t\tshowToastNotification(error?.message || 'Something went wrong');
81
+ \t\t} finally {
82
+ \t\t\tsetLoading(false);
83
+ \t\t}
84
+ \t};${hasDropdown ? `
85
+
86
+ \tconst openBottomSheet = (type) => {
87
+ \t\tsetBottomSheetType(type);
88
+ \t};` : ''}
89
+
90
+ \treturn {
91
+ \t\tformData,
92
+ \t\terrors,
93
+ \t\ttouched,
94
+ \t\tloading,
95
+ \t\thandleChange,
96
+ \t\thandleSubmit,${hasDropdown ? '\n\t\topenBottomSheet,\n\t\tbottomSheetType,' : ''}${hasDate ? '\n\t\topenCalendar,\n\t\tsetOpenCalendar,' : ''}
97
+ \t};
98
+ };
99
+ `;
100
+ }
101
+
102
+ return `import { useState, useEffect } from 'react';
103
+ import { useQuery } from '@tanstack/react-query';
104
+ import { showToastNotification } from '../../../../helpers/common';
105
+
106
+ export const use${hookName} = ({ navigation }) => {
107
+ \tconst [loading, setLoading] = useState(false);
108
+
109
+ \tconst { data, isLoading, error } = useQuery({
110
+ \t\tqueryKey: ['${hookName.toLowerCase()}'],
111
+ \t\tqueryFn: async () => {
112
+ \t\t\t// Add your API call here
113
+ \t\t\treturn null;
114
+ \t\t},
115
+ \t\tenabled: true,
116
+ \t});
117
+
118
+ \tuseEffect(() => {
119
+ \t\tif (error) {
120
+ \t\t\tshowToastNotification(error?.message || 'Something went wrong');
121
+ \t\t}
122
+ \t}, [error]);
123
+
124
+ \treturn {
125
+ \t\tloading: isLoading,
126
+ \t\tdata,
127
+ \t};
128
+ };
129
+ `;
130
+ };
131
+
132
+ module.exports = { generateHookTemplate };
@@ -0,0 +1,113 @@
1
+ const generateInitialValues = (formFields = []) => {
2
+ if (!formFields || formFields.length === 0) {
3
+ return '\t\tloader: false,';
4
+ }
5
+
6
+ const fields = formFields.map(field => {
7
+ const defaultValue = field.type === 'checkbox' ? 'false' : field.type === 'dropdown' ? 'null' : "''";
8
+ return `\t\t${field.name}: ${defaultValue},`;
9
+ }).join('\n');
10
+
11
+ return `\t\tloader: false,\n${fields}`;
12
+ };
13
+
14
+ const generateHookTemplate = (hookName, hasForm = false, formFields = []) => {
15
+ if (hasForm) {
16
+ const initialValues = generateInitialValues(formFields);
17
+
18
+ return `import { useState } from 'react';
19
+ import { useFormik } from 'formik';
20
+ import { useQueryClient } from '@tanstack/react-query';
21
+ import { showToastNotification } from '../../../helpers/common';
22
+ import { validationSchema } from './validation';
23
+
24
+ export const use${hookName} = ({ navigation, params, user }) => {
25
+ \tconst queryClient = useQueryClient();
26
+ \tconst [touched, setTouched] = useState([null]);
27
+
28
+ \tconst initialValues = {
29
+ ${initialValues}
30
+ \t};
31
+
32
+ \tconst onSubmit = async (values, formikAction) => {
33
+ \t\tformikState.setFieldValue('loader', true);
34
+
35
+ \t\ttry {
36
+ \t\t\t// Add your API call here
37
+ \t\t\t// const response = await queryClient.fetchQuery(...);
38
+ \t\t\t
39
+ \t\t\tshowToastNotification('Success!');
40
+ \t\t\tnavigation.goBack();
41
+ \t\t} catch (error) {
42
+ \t\t\tformikState.setFieldValue('loader', false);
43
+ \t\t\tconst errorMessage = error?.message || 'Something went wrong';
44
+ \t\t\tshowToastNotification(errorMessage);
45
+ \t\t}
46
+ \t};
47
+
48
+ \tconst formikState = useFormik({
49
+ \t\tinitialValues,
50
+ \t\tenableReinitialize: true,
51
+ \t\tvalidationSchema,
52
+ \t\tonSubmit,
53
+ \t});
54
+
55
+ \tconst handleChange = (data, type) => {
56
+ \t\tformikState.setFieldValue(type, data);
57
+ \t\tlet touchedType = touched;
58
+ \t\tif (touchedType.length === 1 && touchedType[0] === null) {
59
+ \t\t\ttouchedType = [];
60
+ \t\t}
61
+ \t\tif (!touchedType.includes(type)) {
62
+ \t\t\tsetTouched([...touchedType, type]);
63
+ \t\t}
64
+ \t};
65
+
66
+ \tconst handleSubmitValue = () => {
67
+ \t\tsetTouched([null]);
68
+ \t\tformikState.handleSubmit();
69
+ \t};
70
+
71
+ \treturn {
72
+ \t\tformikState,
73
+ \t\ttouched,
74
+ \t\thandleChange,
75
+ \t\thandleSubmitValue,
76
+ \t};
77
+ };
78
+ `;
79
+ }
80
+
81
+ return `import { useState, useEffect } from 'react';
82
+ import { useQuery, useQueryClient } from '@tanstack/react-query';
83
+ import { showToastNotification } from '../../../helpers/common';
84
+
85
+ export const use${hookName} = ({ navigation, params, user }) => {
86
+ \tconst queryClient = useQueryClient();
87
+ \tconst [loading, setLoading] = useState(false);
88
+
89
+ \tconst { data, isLoading, error } = useQuery({
90
+ \t\tqueryKey: ['${hookName.toLowerCase()}'],
91
+ \t\tqueryFn: async () => {
92
+ \t\t\t// Add your API call here
93
+ \t\t\t// return await queryClient.fetchQuery(...);
94
+ \t\t\treturn null;
95
+ \t\t},
96
+ \t\tenabled: true,
97
+ \t});
98
+
99
+ \tuseEffect(() => {
100
+ \t\tif (error) {
101
+ \t\t\tshowToastNotification(error?.message || 'Something went wrong');
102
+ \t\t}
103
+ \t}, [error]);
104
+
105
+ \treturn {
106
+ \t\tloading: isLoading,
107
+ \t\tdata,
108
+ \t};
109
+ };
110
+ `;
111
+ };
112
+
113
+ module.exports = { generateHookTemplate };