@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 +24 -0
- package/package.json +1 -1
- package/templates/hookTemplate.js +7 -1
- package/templates/screenTemplate.js +150 -7
- package/templates/screenTemplate.js.backup +5 -2
- package/utils/fileUtils.js +14 -0
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
|
@@ -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
|
-
|
|
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 '
|
|
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
|
|
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
|
-
|
|
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 '
|
|
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 '
|
|
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 '
|
|
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}';
|
package/utils/fileUtils.js
CHANGED
|
@@ -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
|
};
|