@moamc/rn-cli 1.3.0 → 1.4.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.
package/README.md CHANGED
@@ -11,6 +11,7 @@ Enterprise-grade Code Generation CLI for React Native Applications
11
11
  - ✅ Support for multiple field types (text, number, email, date, dropdown, etc.)
12
12
  - ✅ Automatic validation generation
13
13
  - ✅ TypeScript-ready templates
14
+ - ✅ **Cross-project compatibility** - Automatically detects and adapts to different project structures
14
15
 
15
16
  ## 📦 Installation
16
17
 
@@ -88,6 +89,29 @@ project-root/
88
89
  └── navigations/
89
90
  ```
90
91
 
92
+ ### Component Structure Compatibility
93
+
94
+ The CLI automatically detects your project's component structure:
95
+
96
+ **Option 1: Nested Structure** (e.g., investor-app)
97
+ ```
98
+ components/
99
+ └── common/
100
+ ├── headers/
101
+ │ └── Header.js
102
+ └── Container.js
103
+ ```
104
+
105
+ **Option 2: Flat Structure** (e.g., distributor-app)
106
+ ```
107
+ components/
108
+ └── common/
109
+ ├── Header.js
110
+ └── Container.js
111
+ ```
112
+
113
+ The CLI will automatically generate the correct import paths for your project structure.
114
+
91
115
  ## 🎨 Form Field Types
92
116
 
93
117
  - **Text** - Standard text input
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@moamc/rn-cli",
3
- "version": "1.3.0",
3
+ "version": "1.4.0",
4
4
  "description": "Enterprise-grade Code Generation CLI for React Native Applications",
5
5
  "main": "index.js",
6
6
  "bin": {
@@ -45,7 +45,7 @@ const generateHookTemplate = (hookName, hasForm = false, formFields = [], eventN
45
45
  import { showToastNotification } from '../../../../helpers/common';${hasDate ? '\nimport moment from \'moment\';' : ''}
46
46
  import { validate${hookName} } from '../validation';
47
47
 
48
- export const use${hookName} = () => {
48
+ export const use${hookName} = ({ navigation }) => {
49
49
  \tconst [formData, setFormData] = useState({
50
50
  ${formFields.map(f => `\t\t${f.name}: '',`).join('\n')}
51
51
  \t});
@@ -121,9 +121,15 @@ export const use${hookName} = ({ navigation }) => {
121
121
  \t\t}
122
122
  \t}, [error]);
123
123
 
124
+ \tconst handleSubmit = () => {
125
+ \t\t// Add your submit logic here
126
+ \t\tshowToastNotification('Submit clicked');
127
+ \t};
128
+
124
129
  \treturn {
125
130
  \t\tloading: isLoading,
126
131
  \t\tdata,
132
+ \t\thandleSubmit,
127
133
  \t};
128
134
  };
129
135
  `;
@@ -1,4 +1,5 @@
1
1
  const { generateFormField, FIELD_TYPES } = require('./fieldGeneratorTemplate');
2
+ const { detectProjectStructure } = require('../utils/fileUtils');
2
3
 
3
4
  const groupFieldsByRows = (formFields) => {
4
5
  const rows = [];
@@ -49,13 +50,96 @@ const generateEnhancedTemplate = (screenName, featureName, hasForm = false, form
49
50
  const componentName = screenName;
50
51
  const hasDropdown = formFields.some(f => f.type === 'dropdown');
51
52
  const hasDate = formFields.some(f => f.type === 'date');
53
+ const { headerImportPath, hasHeadersFolder } = detectProjectStructure();
54
+ const isDistributorStyle = !hasHeadersFolder;
52
55
 
53
- return `import React, { useState } from 'react';
56
+ if (isDistributorStyle) {
57
+ // Distributor app style with proper imports and styling
58
+ return `import React, { useState } from 'react';
59
+ import { Text, ScrollView, View, StyleSheet } from 'react-native';
60
+ import { colorConstant, fonts, utilities } from '../../../assets/styles';
61
+ import Container from '../../../components/common/Container';
62
+ import Header from '../../../components/common/Header';
63
+ import Footer from '../../../components/common/Footer';
64
+ import Loader from '../../../components/common/Loader';
65
+ import { FloatingTextInput, FormButton } from '../../../components/form';${hasDropdown ? '\nimport { BottomSheet } from \'../../../components/common\';\nimport DropDownReview from \'../../../components/common/DropDownReview\';' : ''}${hasDate ? '\nimport { DatePickerCustom } from \'../../../components/form/DatePicker\';\nimport moment from \'moment\';' : ''}
66
+ import { use${componentName} } from './hooks/use${componentName}';
67
+
68
+ const ${componentName} = ({ navigation }) => {
69
+ \tconst {
70
+ \t\tformData,
71
+ \t\terrors,
72
+ \t\ttouched,
73
+ \t\tloading,
74
+ \t\thandleChange,
75
+ \t\thandleSubmit${hasDropdown ? ',\n\t\topenBottomSheet,\n\t\tbottomSheetType' : ''}${hasDate ? ',\n\t\topenCalendar,\n\t\tsetOpenCalendar' : ''}
76
+ \t} = use${componentName}({ navigation });
77
+ \t${hasDropdown ? '\n\tconst [openBottomNote, setOpenBottomNote] = useState(false);' : ''}
78
+
79
+ \tif (loading) {
80
+ \t\treturn <Loader loaderText="Hang On..." />;
81
+ \t}
82
+
83
+ \treturn (
84
+ \t\t<>
85
+ \t\t\t<Container>
86
+ \t\t\t\t<Header redirect={() => navigation.goBack()} />
87
+ \t\t\t\t<ScrollView
88
+ \t\t\t\t\tshowsVerticalScrollIndicator={false}
89
+ \t\t\t\t\tcontentContainerStyle={[utilities.rowPadding24]}
90
+ \t\t\t\t>
91
+ \t\t\t\t\t<Text style={styles.heading}>${screenName}</Text>
92
+ ${generateFormFields(formFields)}
93
+ \t\t\t\t</ScrollView>
94
+ \t\t\t</Container>
95
+ \t\t\t<Footer isBottom={true}>
96
+ \t\t\t\t<FormButton title="Submit" onPress={handleSubmit} />
97
+ \t\t\t</Footer>${hasDropdown ? \`
98
+ \t\t\t<BottomSheet
99
+ \t\t\t\tmodalVisible={!!openBottomNote}
100
+ \t\t\t\tsetIsModalVisible={() => setOpenBottomNote(null)}
101
+ \t\t\t>
102
+ \t\t\t\t<DropDownReview
103
+ \t\t\t\t\tFundBuyType={/* Add options */[]}
104
+ \t\t\t\t\tselectValue={formData[bottomSheetType]}
105
+ \t\t\t\t\tonSelectValue={e => {
106
+ \t\t\t\t\t\thandleChange(e, bottomSheetType);
107
+ \t\t\t\t\t\tsetOpenBottomNote(null);
108
+ \t\t\t\t\t}}
109
+ \t\t\t\t\tlabel={bottomSheetType}
110
+ \t\t\t\t/>
111
+ \t\t\t</BottomSheet>\` : ''}${hasDate ? \`
112
+ \t\t\t<DatePickerCustom
113
+ \t\t\t\tmodalTransparent={true}
114
+ \t\t\t\tonDateChange={data => {
115
+ \t\t\t\t\thandleChange(moment(data).format('DD MMM YYYY'), 'dateField');
116
+ \t\t\t\t}}
117
+ \t\t\t\tsetModalVisible={() => setOpenCalendar(!openCalendar)}
118
+ \t\t\t\tmodalVisible={openCalendar}
119
+ \t\t\t\tminimumDate={new Date(1920, 0, 1)}
120
+ \t\t\t/>\` : ''}
121
+ \t\t</>
122
+ \t);
123
+ };
124
+
125
+ const styles = StyleSheet.create({
126
+ \theading: {
127
+ \t\t...fonts.fontWSSB18,
128
+ \t\tcolor: colorConstant.moBlack,
129
+ \t\tmarginVertical: 20,
130
+ \t},
131
+ });
132
+
133
+ export default ${componentName};
134
+ `;
135
+ } else {
136
+ // Investor app style - original template
137
+ return `import React, { useState } from 'react';
54
138
  import { Text, ScrollView, View } from 'react-native';
55
139
  import { TouchableRipple } from 'react-native-paper';
56
140
  import { colorConstant, utilities } from '../../../assets/styles';
57
141
  import { Container } from '../../../components/common';
58
- import { Header } from '../../../components/common/headers';
142
+ import { Header } from '${headerImportPath}';
59
143
  import Footer from '../../../components/common/Footer';
60
144
  import FormButton from '../../../components/form/FormButton';
61
145
  import { FloatingTextInput } from '../../../components/form';${hasDropdown ? '\nimport { BottomSheet } from \'../../../components/common\';\nimport DropDownReview from \'../../../components/common/DropDownReview\';' : ''}${hasDate ? '\nimport { DatePickerCustom } from \'../../../components/form/DatePicker\';\nimport moment from \'moment\';' : ''}
@@ -89,7 +173,7 @@ ${generateFormFields(formFields)}
89
173
  \t\t\t</Container>
90
174
  \t\t\t<Footer style={styles.footerDesign}>
91
175
  \t\t\t\t<FormButton title="Submit" onPress={handleSubmit} />
92
- \t\t\t</Footer>${hasDropdown ? `
176
+ \t\t\t</Footer>${hasDropdown ? \`
93
177
  \t\t\t<BottomSheet
94
178
  \t\t\t\tmodalVisible={!!openBottomNote}
95
179
  \t\t\t\tsetIsModalVisible={() => setOpenBottomNote(null)}
@@ -103,7 +187,7 @@ ${generateFormFields(formFields)}
103
187
  \t\t\t\t\t}}
104
188
  \t\t\t\t\tlabel={bottomSheetType}
105
189
  \t\t\t\t/>
106
- \t\t\t</BottomSheet>` : ''}${hasDate ? `
190
+ \t\t\t</BottomSheet>\` : ''}${hasDate ? \`
107
191
  \t\t\t<DatePickerCustom
108
192
  \t\t\t\tmodalTransparent={true}
109
193
  \t\t\t\tonDateChange={data => {
@@ -112,13 +196,14 @@ ${generateFormFields(formFields)}
112
196
  \t\t\t\tsetModalVisible={() => setOpenCalendar(!openCalendar)}
113
197
  \t\t\t\tmodalVisible={openCalendar}
114
198
  \t\t\t\tminimumDate={new Date(1920, 0, 1)}
115
- \t\t\t/>` : ''}
199
+ \t\t\t/>\` : ''}
116
200
  \t\t</>
117
201
  \t);
118
202
  };
119
203
 
120
204
  export default ${componentName};
121
205
  `;
206
+ }
122
207
  };
123
208
 
124
209
  const generateScreenTemplate = (screenName, featureName, hasForm = false, formFields = []) => {
@@ -129,10 +214,67 @@ const generateScreenTemplate = (screenName, featureName, hasForm = false, formFi
129
214
 
130
215
  // Simple screen template
131
216
  const componentName = screenName;
132
- return `import React from 'react';
217
+ const { headerImportPath, hasHeadersFolder } = detectProjectStructure();
218
+ const isDistributorStyle = !hasHeadersFolder;
219
+
220
+ if (isDistributorStyle) {
221
+ // Distributor app style - with Header, Footer, and FormButton
222
+ return `import React from 'react';
223
+ import { View, Text, ScrollView, StyleSheet } from 'react-native';
224
+ import { colorConstant, fonts, utilities } from '../../../assets/styles';
225
+ import Container from '../../../components/common/Container';
226
+ import Header from '../../../components/common/Header';
227
+ import Footer from '../../../components/common/Footer';
228
+ import Loader from '../../../components/common/Loader';
229
+ import { FormButton } from '../../../components/form';
230
+ import { use${componentName} } from './hooks/use${componentName}';
231
+
232
+ const ${componentName} = ({ navigation }) => {
233
+ \tconst {
234
+ \t\tloading,
235
+ \t\tdata,
236
+ \t\thandleSubmit,
237
+ \t} = use${componentName}({ navigation });
238
+
239
+ \tif (loading) {
240
+ \t\treturn <Loader loaderText="Hang On..." />;
241
+ \t}
242
+
243
+ \treturn (
244
+ \t\t<>
245
+ \t\t\t<Container>
246
+ \t\t\t\t<Header redirect={() => navigation.goBack()} />
247
+ \t\t\t\t<ScrollView
248
+ \t\t\t\t\tshowsVerticalScrollIndicator={false}
249
+ \t\t\t\t\tcontentContainerStyle={[utilities.rowPadding24]}
250
+ \t\t\t\t>
251
+ \t\t\t\t\t<Text style={styles.heading}>${screenName}</Text>
252
+ \t\t\t\t\t{/* Add your content here */}
253
+ \t\t\t\t</ScrollView>
254
+ \t\t\t</Container>
255
+ \t\t\t<Footer isBottom={true}>
256
+ \t\t\t\t<FormButton title="Submit" onPress={handleSubmit} />
257
+ \t\t\t</Footer>
258
+ \t\t</>
259
+ \t);
260
+ };
261
+
262
+ const styles = StyleSheet.create({
263
+ \theading: {
264
+ \t\t...fonts.fontWSSB18,
265
+ \t\tcolor: colorConstant.moBlack,
266
+ \t\tmarginVertical: 20,
267
+ \t},
268
+ });
269
+
270
+ export default ${componentName};
271
+ `;
272
+ } else {
273
+ // Investor app style - original template
274
+ return `import React from 'react';
133
275
  import { View, Text, ScrollView } from 'react-native';
134
276
  import { Container, Loader } from '../../../components/common';
135
- import { Header } from '../../../components/common/headers';
277
+ import { Header } from '${headerImportPath}';
136
278
  import { colorConstant, utilities } from '../../../assets/styles';
137
279
  import { use${componentName} } from './hooks/use${componentName}';
138
280
  import { styles } from './components/styles';
@@ -160,6 +302,7 @@ const ${componentName} = ({ navigation }) => {
160
302
 
161
303
  export default ${componentName};
162
304
  `;
305
+ }
163
306
  };
164
307
 
165
308
  module.exports = { generateScreenTemplate };
@@ -1,3 +1,5 @@
1
+ const { detectProjectStructure } = require('../utils/fileUtils');
2
+
1
3
  const generateFormFields = (formFields = []) => {
2
4
  if (!formFields || formFields.length === 0) return '\t\t\t\t{/* Add your form fields here */}';
3
5
 
@@ -55,6 +57,7 @@ const generateFormFields = (formFields = []) => {
55
57
 
56
58
  const generateScreenTemplate = (screenName, featureName, hasForm = false, formFields = []) => {
57
59
  const componentName = screenName;
60
+ const { headerImportPath } = detectProjectStructure();
58
61
 
59
62
  if (hasForm) {
60
63
  const formFieldsCode = generateFormFields(formFields);
@@ -64,7 +67,7 @@ const generateScreenTemplate = (screenName, featureName, hasForm = false, formFi
64
67
  return `import React from 'react';
65
68
  import { View, Text, ScrollView, StyleSheet } from 'react-native';
66
69
  import { Container, Footer, Loader } from '../../../components/common';
67
- import { Header } from '../../../components/common/headers';
70
+ import { Header } from '${headerImportPath}';
68
71
  import { FloatingTextInput, FormButton } from '../../../components/form';${hasDropdown ? '\nimport RadioForm from \'../../../components/form/RadioForm\';' : ''}${hasCheckbox ? '\nimport CheckBox from \'../../../components/common/CheckBox\';' : ''}
69
72
  import { withUser } from '../../../components/HOC';
70
73
  import { colorConstant, fonts, utilities } from '../../../assets/styles';
@@ -110,7 +113,7 @@ export default withUser(${componentName});
110
113
  return `import React from 'react';
111
114
  import { View, Text, ScrollView, StyleSheet } from 'react-native';
112
115
  import { Container, Loader } from '../../../components/common';
113
- import { Header } from '../../../components/common/headers';
116
+ import { Header } from '${headerImportPath}';
114
117
  import { withUser } from '../../../components/HOC';
115
118
  import { colorConstant, fonts, utilities } from '../../../assets/styles';
116
119
  import { use${componentName} } from './use${componentName}';
@@ -19,6 +19,19 @@ const findProjectRoot = () => {
19
19
 
20
20
  const PROJECT_ROOT = findProjectRoot();
21
21
 
22
+ // Detect project structure for imports
23
+ const detectProjectStructure = () => {
24
+ const headersPath = path.join(PROJECT_ROOT, 'components', 'common', 'headers');
25
+ const hasHeadersFolder = fs.existsSync(headersPath);
26
+
27
+ return {
28
+ hasHeadersFolder,
29
+ headerImportPath: hasHeadersFolder
30
+ ? "../../../components/common/headers"
31
+ : "../../../components/common"
32
+ };
33
+ };
34
+
22
35
  const ensureDirectoryExists = (dirPath) => {
23
36
  if (!fs.existsSync(dirPath)) {
24
37
  fs.mkdirSync(dirPath, { recursive: true });
@@ -113,4 +126,5 @@ module.exports = {
113
126
  logWarning,
114
127
  logError,
115
128
  confirmOverwrite,
129
+ detectProjectStructure,
116
130
  };