@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.
- package/LICENSE +21 -0
- package/README.md +154 -0
- package/generators/api.js +155 -0
- package/generators/feature.js +155 -0
- package/generators/hook.js +115 -0
- package/generators/screen.js +351 -0
- package/index.js +100 -0
- package/package.json +43 -0
- package/templates/apiTemplate.js +217 -0
- package/templates/constantsTemplate.js +33 -0
- package/templates/constantsTemplate.js.backup +18 -0
- package/templates/fieldGeneratorTemplate.js +165 -0
- package/templates/helpersTemplate.js +10 -0
- package/templates/hookTemplate.js +132 -0
- package/templates/hookTemplate.js.backup +113 -0
- package/templates/queryTemplate.js +23 -0
- package/templates/screenTemplate.js +165 -0
- package/templates/screenTemplate.js.backup +147 -0
- package/templates/stylesTemplate.js +52 -0
- package/templates/stylesTemplate.js.backup +88 -0
- package/templates/validationTemplate.js +122 -0
- package/templates/validationTemplate.js.backup +37 -0
- package/utils/fileUtils.js +116 -0
- package/utils/navigationUtils.js +74 -0
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
const generateQueryOptionsTemplate = (queryName, serviceName, methodName) => {
|
|
2
|
+
return `import { queryOptions } from '@tanstack/react-query';
|
|
3
|
+
import { ${serviceName}Service } from '../services/${serviceName.toLowerCase()}/${serviceName.toLowerCase()}';
|
|
4
|
+
|
|
5
|
+
const baseQueryOptions = {
|
|
6
|
+
\trefetchOnWindowFocus: false,
|
|
7
|
+
\trefetchOnReconnect: false,
|
|
8
|
+
\trefetchInterval: false,
|
|
9
|
+
\tstaleTime: 5 * 60 * 1000,
|
|
10
|
+
\tgcTime: 10 * 60 * 1000,
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export const ${queryName}QueryOptions = {
|
|
14
|
+
\t${methodName}: (data) => queryOptions({
|
|
15
|
+
\t\tqueryKey: ['${serviceName.toLowerCase()}', '${methodName}', data],
|
|
16
|
+
\t\tqueryFn: () => ${serviceName}Service.${methodName}(data),
|
|
17
|
+
\t\t...baseQueryOptions,
|
|
18
|
+
\t}),
|
|
19
|
+
};
|
|
20
|
+
`;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
module.exports = { generateQueryOptionsTemplate };
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
const { generateFormField, FIELD_TYPES } = require('./fieldGeneratorTemplate');
|
|
2
|
+
|
|
3
|
+
const groupFieldsByRows = (formFields) => {
|
|
4
|
+
const rows = [];
|
|
5
|
+
let currentRow = [];
|
|
6
|
+
|
|
7
|
+
formFields.forEach(field => {
|
|
8
|
+
if (field.width === 'half') {
|
|
9
|
+
currentRow.push(field);
|
|
10
|
+
if (currentRow.length === 2) {
|
|
11
|
+
rows.push(currentRow);
|
|
12
|
+
currentRow = [];
|
|
13
|
+
}
|
|
14
|
+
} else {
|
|
15
|
+
if (currentRow.length > 0) {
|
|
16
|
+
rows.push(currentRow);
|
|
17
|
+
currentRow = [];
|
|
18
|
+
}
|
|
19
|
+
rows.push([field]);
|
|
20
|
+
}
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
if (currentRow.length > 0) {
|
|
24
|
+
rows.push(currentRow);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return rows;
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
const generateFormFields = (formFields = []) => {
|
|
31
|
+
if (!formFields || formFields.length === 0) return '\t\t\t\t{/* Add your form fields here */}';
|
|
32
|
+
|
|
33
|
+
const rows = groupFieldsByRows(formFields);
|
|
34
|
+
|
|
35
|
+
return rows.map(row => {
|
|
36
|
+
if (row.length === 1) {
|
|
37
|
+
return `\t\t\t\t<View style={styles.headContainer}>
|
|
38
|
+
${generateFormField(row[0])}
|
|
39
|
+
\t\t\t\t</View>`;
|
|
40
|
+
} else {
|
|
41
|
+
return `\t\t\t\t<View style={styles.headContainer}>
|
|
42
|
+
${row.map(field => generateFormField(field)).join('\n')}
|
|
43
|
+
\t\t\t\t</View>`;
|
|
44
|
+
}
|
|
45
|
+
}).join('\n');
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
const generateEnhancedTemplate = (screenName, featureName, hasForm = false, formFields = []) => {
|
|
49
|
+
const componentName = screenName;
|
|
50
|
+
const hasDropdown = formFields.some(f => f.type === 'dropdown');
|
|
51
|
+
const hasDate = formFields.some(f => f.type === 'date');
|
|
52
|
+
|
|
53
|
+
return `import React, { useState } from 'react';
|
|
54
|
+
import { Text, ScrollView, View } from 'react-native';
|
|
55
|
+
import { TouchableRipple } from 'react-native-paper';
|
|
56
|
+
import { colorConstant, utilities } from '../../../assets/styles';
|
|
57
|
+
import { Container } from '../../../components/common';
|
|
58
|
+
import { Header } from '../../../components/common/headers';
|
|
59
|
+
import Footer from '../../../components/common/Footer';
|
|
60
|
+
import FormButton from '../../../components/form/FormButton';
|
|
61
|
+
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\';' : ''}
|
|
62
|
+
import Loader from '../../../components/common/Loader';
|
|
63
|
+
import { use${componentName} } from './hooks/use${componentName}';
|
|
64
|
+
import { styles } from './components/styles';
|
|
65
|
+
|
|
66
|
+
const ${componentName} = ({ navigation }) => {
|
|
67
|
+
\tconst {
|
|
68
|
+
\t\tformData,
|
|
69
|
+
\t\terrors,
|
|
70
|
+
\t\ttouched,
|
|
71
|
+
\t\tloading,
|
|
72
|
+
\t\thandleChange,
|
|
73
|
+
\t\thandleSubmit${hasDropdown ? ',\n\t\topenBottomSheet,\n\t\tbottomSheetType' : ''}${hasDate ? ',\n\t\topenCalendar,\n\t\tsetOpenCalendar' : ''}
|
|
74
|
+
\t} = use${componentName}();
|
|
75
|
+
\t${hasDropdown ? '\n\tconst [openBottomNote, setOpenBottomNote] = useState(false);' : ''}
|
|
76
|
+
|
|
77
|
+
\tif (loading) {
|
|
78
|
+
\t\treturn <Loader loaderText={'Hang On...'} />;
|
|
79
|
+
\t}
|
|
80
|
+
|
|
81
|
+
\treturn (
|
|
82
|
+
\t\t<>
|
|
83
|
+
\t\t\t<Container style={styles.containerStyle}>
|
|
84
|
+
\t\t\t\t<Header style={styles.topHeader} innerViewStyle={utilities.marginLeft15}/>
|
|
85
|
+
\t\t\t\t<Text style={styles.manageText}>${screenName}</Text>
|
|
86
|
+
\t\t\t\t<ScrollView showsVerticalScrollIndicator={false}>
|
|
87
|
+
${generateFormFields(formFields)}
|
|
88
|
+
\t\t\t\t</ScrollView>
|
|
89
|
+
\t\t\t</Container>
|
|
90
|
+
\t\t\t<Footer style={styles.footerDesign}>
|
|
91
|
+
\t\t\t\t<FormButton title="Submit" onPress={handleSubmit} />
|
|
92
|
+
\t\t\t</Footer>${hasDropdown ? `
|
|
93
|
+
\t\t\t<BottomSheet
|
|
94
|
+
\t\t\t\tmodalVisible={!!openBottomNote}
|
|
95
|
+
\t\t\t\tsetIsModalVisible={() => setOpenBottomNote(null)}
|
|
96
|
+
\t\t\t>
|
|
97
|
+
\t\t\t\t<DropDownReview
|
|
98
|
+
\t\t\t\t\tFundBuyType={/* Add options */[]}
|
|
99
|
+
\t\t\t\t\tselectValue={formData[bottomSheetType]}
|
|
100
|
+
\t\t\t\t\tonSelectValue={e => {
|
|
101
|
+
\t\t\t\t\t\thandleChange(e, bottomSheetType);
|
|
102
|
+
\t\t\t\t\t\tsetOpenBottomNote(null);
|
|
103
|
+
\t\t\t\t\t}}
|
|
104
|
+
\t\t\t\t\tlabel={bottomSheetType}
|
|
105
|
+
\t\t\t\t/>
|
|
106
|
+
\t\t\t</BottomSheet>` : ''}${hasDate ? `
|
|
107
|
+
\t\t\t<DatePickerCustom
|
|
108
|
+
\t\t\t\tmodalTransparent={true}
|
|
109
|
+
\t\t\t\tonDateChange={data => {
|
|
110
|
+
\t\t\t\t\thandleChange(moment(data).format('DD MMM YYYY'), 'dateField');
|
|
111
|
+
\t\t\t\t}}
|
|
112
|
+
\t\t\t\tsetModalVisible={() => setOpenCalendar(!openCalendar)}
|
|
113
|
+
\t\t\t\tmodalVisible={openCalendar}
|
|
114
|
+
\t\t\t\tminimumDate={new Date(1920, 0, 1)}
|
|
115
|
+
\t\t\t/>` : ''}
|
|
116
|
+
\t\t</>
|
|
117
|
+
\t);
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
export default ${componentName};
|
|
121
|
+
`;
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
const generateScreenTemplate = (screenName, featureName, hasForm = false, formFields = []) => {
|
|
125
|
+
// Use enhanced template for form screens
|
|
126
|
+
if (hasForm) {
|
|
127
|
+
return generateEnhancedTemplate(screenName, featureName, hasForm, formFields);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// Simple screen template
|
|
131
|
+
const componentName = screenName;
|
|
132
|
+
return `import React from 'react';
|
|
133
|
+
import { View, Text, ScrollView } from 'react-native';
|
|
134
|
+
import { Container, Loader } from '../../../components/common';
|
|
135
|
+
import { Header } from '../../../components/common/headers';
|
|
136
|
+
import { colorConstant, utilities } from '../../../assets/styles';
|
|
137
|
+
import { use${componentName} } from './hooks/use${componentName}';
|
|
138
|
+
import { styles } from './components/styles';
|
|
139
|
+
|
|
140
|
+
const ${componentName} = ({ navigation }) => {
|
|
141
|
+
\tconst {
|
|
142
|
+
\t\tloading,
|
|
143
|
+
\t\tdata,
|
|
144
|
+
\t} = use${componentName}({ navigation });
|
|
145
|
+
|
|
146
|
+
\tif (loading) {
|
|
147
|
+
\t\treturn <Loader loaderText={'Hang On...'} />;
|
|
148
|
+
\t}
|
|
149
|
+
|
|
150
|
+
\treturn (
|
|
151
|
+
\t\t<Container style={styles.containerStyle}>
|
|
152
|
+
\t\t\t<Header style={styles.topHeader} innerViewStyle={utilities.marginLeft15}/>
|
|
153
|
+
\t\t\t<Text style={styles.manageText}>${screenName}</Text>
|
|
154
|
+
\t\t\t<ScrollView showsVerticalScrollIndicator={false}>
|
|
155
|
+
\t\t\t\t{/* Add your content here */}
|
|
156
|
+
\t\t\t</ScrollView>
|
|
157
|
+
\t\t</Container>
|
|
158
|
+
\t);
|
|
159
|
+
};
|
|
160
|
+
|
|
161
|
+
export default ${componentName};
|
|
162
|
+
`;
|
|
163
|
+
};
|
|
164
|
+
|
|
165
|
+
module.exports = { generateScreenTemplate };
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
const generateFormFields = (formFields = []) => {
|
|
2
|
+
if (!formFields || formFields.length === 0) return '\t\t\t\t{/* Add your form fields here */}';
|
|
3
|
+
|
|
4
|
+
return formFields.map(field => {
|
|
5
|
+
const { name, type, label, required } = field;
|
|
6
|
+
|
|
7
|
+
if (type === 'dropdown') {
|
|
8
|
+
return `\t\t\t\t<View style={styles.headContainer}>
|
|
9
|
+
\t\t\t\t\t<View style={styles.headWidth}>
|
|
10
|
+
\t\t\t\t\t\t<Text style={styles.optionText}>${label}</Text>
|
|
11
|
+
\t\t\t\t\t\t<RadioForm
|
|
12
|
+
\t\t\t\t\t\t\thelperTextStyle={{ height: 0 }}
|
|
13
|
+
\t\t\t\t\t\t\toption={${name.toUpperCase()}_OPTIONS}
|
|
14
|
+
\t\t\t\t\t\t\tvalue={formikState.values.${name}}
|
|
15
|
+
\t\t\t\t\t\t\ttextStyle={styles.optionInnerText}
|
|
16
|
+
\t\t\t\t\t\t\tradioInputContainer={styles.optionContainer}
|
|
17
|
+
\t\t\t\t\t\t\tactiveRadioContainer={styles.activeOptionContainer}
|
|
18
|
+
\t\t\t\t\t\t\tactiveRadioText={styles.activeOptionText}
|
|
19
|
+
\t\t\t\t\t\t\tonChange={(e) => handleChange(e, '${name}')}
|
|
20
|
+
\t\t\t\t\t\t/>
|
|
21
|
+
\t\t\t\t\t</View>
|
|
22
|
+
\t\t\t\t</View>`;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
if (type === 'checkbox') {
|
|
26
|
+
return `\t\t\t\t<View style={styles.checkStyle}>
|
|
27
|
+
\t\t\t\t\t<CheckBox
|
|
28
|
+
\t\t\t\t\t\tcheckBoxBtn={formikState?.values?.${name}}
|
|
29
|
+
\t\t\t\t\t\tsetcheckBoxBtn={() => handleChange(!formikState?.values?.${name}, '${name}')}
|
|
30
|
+
\t\t\t\t\t/>
|
|
31
|
+
\t\t\t\t\t<Text style={styles.checkText}>${label}</Text>
|
|
32
|
+
\t\t\t\t</View>`;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const keyboardType = type === 'number' ? 'numeric' : type === 'email' ? 'email-address' : 'default';
|
|
36
|
+
const autoCapitalize = type === 'email' ? 'none' : 'sentences';
|
|
37
|
+
|
|
38
|
+
return `\t\t\t\t<View style={styles.headContainer}>
|
|
39
|
+
\t\t\t\t\t<View style={{ width: '100%' }}>
|
|
40
|
+
\t\t\t\t\t\t<FloatingTextInput
|
|
41
|
+
\t\t\t\t\t\t\tlabel="${label}"
|
|
42
|
+
\t\t\t\t\t\t\tvalue={formikState?.values?.${name}}
|
|
43
|
+
\t\t\t\t\t\t\tonChangeText={(e) => handleChange(e, '${name}')}
|
|
44
|
+
\t\t\t\t\t\t\ttextInputStyles={styles.floatContentStyle}
|
|
45
|
+
\t\t\t\t\t\t\tinputContainerStyle={styles.floatStyle}
|
|
46
|
+
\t\t\t\t\t\t\tlabelStyles={styles.floatLabelStyle}
|
|
47
|
+
\t\t\t\t\t\t\terror={(touched.includes(null) || touched.includes('${name}')) && formikState?.errors?.${name}}
|
|
48
|
+
\t\t\t\t\t\t\tkeyboardType="${keyboardType}"${type !== 'email' ? '' : `
|
|
49
|
+
\t\t\t\t\t\t\totherTextInputProps={{ autoCapitalize: '${autoCapitalize}' }}`}
|
|
50
|
+
\t\t\t\t\t\t/>
|
|
51
|
+
\t\t\t\t\t</View>
|
|
52
|
+
\t\t\t\t</View>`;
|
|
53
|
+
}).join('\n');
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
const generateScreenTemplate = (screenName, featureName, hasForm = false, formFields = []) => {
|
|
57
|
+
const componentName = screenName;
|
|
58
|
+
|
|
59
|
+
if (hasForm) {
|
|
60
|
+
const formFieldsCode = generateFormFields(formFields);
|
|
61
|
+
const hasDropdown = formFields.some(f => f.type === 'dropdown');
|
|
62
|
+
const hasCheckbox = formFields.some(f => f.type === 'checkbox');
|
|
63
|
+
|
|
64
|
+
return `import React from 'react';
|
|
65
|
+
import { View, Text, ScrollView, StyleSheet } from 'react-native';
|
|
66
|
+
import { Container, Footer, Loader } from '../../../components/common';
|
|
67
|
+
import { Header } from '../../../components/common/headers';
|
|
68
|
+
import { FloatingTextInput, FormButton } from '../../../components/form';${hasDropdown ? '\nimport RadioForm from \'../../../components/form/RadioForm\';' : ''}${hasCheckbox ? '\nimport CheckBox from \'../../../components/common/CheckBox\';' : ''}
|
|
69
|
+
import { withUser } from '../../../components/HOC';
|
|
70
|
+
import { colorConstant, fonts, utilities } from '../../../assets/styles';
|
|
71
|
+
import { use${componentName} } from './use${componentName}';
|
|
72
|
+
import { styles } from './styles';${hasDropdown ? '\nimport { ' + formFields.filter(f => f.type === 'dropdown').map(f => f.name.toUpperCase() + '_OPTIONS').join(', ') + ' } from \'./constants\';' : ''}
|
|
73
|
+
|
|
74
|
+
const ${componentName} = ({ navigation, route: { params }, user }) => {
|
|
75
|
+
\tconst {
|
|
76
|
+
\t\tformikState,
|
|
77
|
+
\t\ttouched,
|
|
78
|
+
\t\thandleChange,
|
|
79
|
+
\t\thandleSubmitValue,
|
|
80
|
+
\t} = use${componentName}({ navigation, params, user });
|
|
81
|
+
|
|
82
|
+
\tif (formikState.values.loader) {
|
|
83
|
+
\t\treturn <Loader loaderText={'Hang On...'} />;
|
|
84
|
+
\t}
|
|
85
|
+
|
|
86
|
+
\treturn (
|
|
87
|
+
\t\t<>
|
|
88
|
+
\t\t\t<Container style={styles.containerStyle}>
|
|
89
|
+
\t\t\t\t<Header style={styles.topHeader} innerViewStyle={utilities.marginLeft15} />
|
|
90
|
+
\t\t\t\t<Text style={styles.headerText}>${screenName}</Text>
|
|
91
|
+
\t\t\t\t<ScrollView
|
|
92
|
+
\t\t\t\t\tshowsVerticalScrollIndicator={false}
|
|
93
|
+
\t\t\t\t\tcontentContainerStyle={styles.scrollViewContent}
|
|
94
|
+
\t\t\t\t>
|
|
95
|
+
${formFieldsCode}
|
|
96
|
+
\t\t\t\t</ScrollView>
|
|
97
|
+
\t\t\t</Container>
|
|
98
|
+
|
|
99
|
+
\t\t\t<Footer isBottom={true}>
|
|
100
|
+
\t\t\t\t<FormButton title="Submit" onPress={handleSubmitValue} />
|
|
101
|
+
\t\t\t</Footer>
|
|
102
|
+
\t\t</>
|
|
103
|
+
\t);
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
export default withUser(${componentName});
|
|
107
|
+
`;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
return `import React from 'react';
|
|
111
|
+
import { View, Text, ScrollView, StyleSheet } from 'react-native';
|
|
112
|
+
import { Container, Loader } from '../../../components/common';
|
|
113
|
+
import { Header } from '../../../components/common/headers';
|
|
114
|
+
import { withUser } from '../../../components/HOC';
|
|
115
|
+
import { colorConstant, fonts, utilities } from '../../../assets/styles';
|
|
116
|
+
import { use${componentName} } from './use${componentName}';
|
|
117
|
+
import { styles } from './styles';
|
|
118
|
+
|
|
119
|
+
const ${componentName} = ({ navigation, route: { params }, user }) => {
|
|
120
|
+
\tconst {
|
|
121
|
+
\t\tloading,
|
|
122
|
+
\t\tdata,
|
|
123
|
+
\t} = use${componentName}({ navigation, params, user });
|
|
124
|
+
|
|
125
|
+
\tif (loading) {
|
|
126
|
+
\t\treturn <Loader loaderText={'Hang On...'} />;
|
|
127
|
+
\t}
|
|
128
|
+
|
|
129
|
+
\treturn (
|
|
130
|
+
\t\t<Container style={styles.containerStyle}>
|
|
131
|
+
\t\t\t<Header style={styles.topHeader} innerViewStyle={utilities.marginLeft15} />
|
|
132
|
+
\t\t\t<Text style={styles.headerText}>${screenName}</Text>
|
|
133
|
+
\t\t\t<ScrollView
|
|
134
|
+
\t\t\t\tshowsVerticalScrollIndicator={false}
|
|
135
|
+
\t\t\t\tcontentContainerStyle={styles.scrollViewContent}
|
|
136
|
+
\t\t\t>
|
|
137
|
+
\t\t\t\t<Text>Welcome to ${screenName}</Text>
|
|
138
|
+
\t\t\t</ScrollView>
|
|
139
|
+
\t\t</Container>
|
|
140
|
+
\t);
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
export default withUser(${componentName});
|
|
144
|
+
`;
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
module.exports = { generateScreenTemplate };
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
const generateStylesTemplate = () => {
|
|
2
|
+
return `import { StyleSheet } from 'react-native';
|
|
3
|
+
import { colorConstant, fonts } from '../../../../assets/styles';
|
|
4
|
+
import { isIOS } from '../../../../helpers/common';
|
|
5
|
+
|
|
6
|
+
export const styles = StyleSheet.create({
|
|
7
|
+
\tcontainerStyle: {
|
|
8
|
+
\t\tpaddingLeft: 24,
|
|
9
|
+
\t\tpaddingRight: 24,
|
|
10
|
+
\t\tposition: 'relative',
|
|
11
|
+
\t\tmarginBottom: isIOS ? 92 : 60,
|
|
12
|
+
\t},
|
|
13
|
+
\tfloatContentStyle: {
|
|
14
|
+
\t\t...fonts.fontWSR16,
|
|
15
|
+
\t\tcolor: colorConstant.amcBlack,
|
|
16
|
+
\t},
|
|
17
|
+
\ttopHeader: {
|
|
18
|
+
\t\theight: 44,
|
|
19
|
+
\t\tposition: 'relative',
|
|
20
|
+
\t},
|
|
21
|
+
\tfloatStyle: {},
|
|
22
|
+
\tfloatLabelStyle: {
|
|
23
|
+
\t\tcolor: colorConstant?.amcMediumGrey,
|
|
24
|
+
\t\tbackgroundColor: colorConstant?.amcWhite,
|
|
25
|
+
\t\t...fonts.fontWSM12,
|
|
26
|
+
\t\tlineHeight: 16,
|
|
27
|
+
\t},
|
|
28
|
+
\tmanageText: {
|
|
29
|
+
\t\theight: 48,
|
|
30
|
+
\t\t...fonts.fontWSSB24,
|
|
31
|
+
\t\tborderBottomWidth: 1,
|
|
32
|
+
\t\tborderBottomColor: colorConstant.amcLightGray,
|
|
33
|
+
\t\tmarginBottom: 24,
|
|
34
|
+
\t\tcolor: colorConstant.moslBlack,
|
|
35
|
+
\t},
|
|
36
|
+
\theadContainer: {
|
|
37
|
+
\t\tflexDirection: 'row',
|
|
38
|
+
\t\tjustifyContent: 'space-between',
|
|
39
|
+
\t\tmarginTop: 16,
|
|
40
|
+
\t},
|
|
41
|
+
\theadWidth: {
|
|
42
|
+
\t\twidth: '48%',
|
|
43
|
+
\t},
|
|
44
|
+
\tfooterDesign: {
|
|
45
|
+
\t\tborderTopWidth: 1,
|
|
46
|
+
\t\tborderTopColor: colorConstant.disabledGreyColor,
|
|
47
|
+
\t},
|
|
48
|
+
});
|
|
49
|
+
`;
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
module.exports = { generateStylesTemplate };
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
const generateStylesTemplate = () => {
|
|
2
|
+
return `import { StyleSheet } from 'react-native';
|
|
3
|
+
import { colorConstant, fonts } from '../../../assets/styles';
|
|
4
|
+
|
|
5
|
+
export const styles = StyleSheet.create({
|
|
6
|
+
\tcontainerStyle: {
|
|
7
|
+
\t\tpaddingLeft: 24,
|
|
8
|
+
\t\tpaddingRight: 24,
|
|
9
|
+
\t\tposition: 'relative',
|
|
10
|
+
\t},
|
|
11
|
+
\ttopHeader: {
|
|
12
|
+
\t\theight: 44,
|
|
13
|
+
\t\tposition: 'relative',
|
|
14
|
+
\t},
|
|
15
|
+
\theaderText: {
|
|
16
|
+
\t\theight: 48,
|
|
17
|
+
\t\t...fonts.fontWSSB24,
|
|
18
|
+
\t\tborderBottomWidth: 1,
|
|
19
|
+
\t\tborderBottomColor: colorConstant.amcLightGray,
|
|
20
|
+
\t\tmarginBottom: 24,
|
|
21
|
+
\t\tcolor: colorConstant.moslBlack,
|
|
22
|
+
\t},
|
|
23
|
+
\tscrollViewContent: {
|
|
24
|
+
\t\tflexGrow: 1,
|
|
25
|
+
\t\tpaddingBottom: 100,
|
|
26
|
+
\t},
|
|
27
|
+
\theadContainer: {
|
|
28
|
+
\t\tflexDirection: 'row',
|
|
29
|
+
\t\tjustifyContent: 'space-between',
|
|
30
|
+
\t\tmarginTop: 24,
|
|
31
|
+
\t},
|
|
32
|
+
\theadWidth: {
|
|
33
|
+
\t\twidth: '48%',
|
|
34
|
+
\t},
|
|
35
|
+
\toptionText: {
|
|
36
|
+
\t\tfontSize: 12,
|
|
37
|
+
\t\tlineHeight: 16,
|
|
38
|
+
\t\tfontWeight: '400',
|
|
39
|
+
\t\tcolor: colorConstant?.amcMediumGrey,
|
|
40
|
+
\t\tmarginBottom: 5,
|
|
41
|
+
\t},
|
|
42
|
+
\toptionContainer: {
|
|
43
|
+
\t\tborderRadius: 28,
|
|
44
|
+
\t\tborderColor: colorConstant?.amcBlue,
|
|
45
|
+
\t},
|
|
46
|
+
\toptionInnerText: {
|
|
47
|
+
\t\tfontSize: 14,
|
|
48
|
+
\t\tlineHeight: 16,
|
|
49
|
+
\t\tcolor: colorConstant?.amcBlue,
|
|
50
|
+
\t\tpaddingTop: 1,
|
|
51
|
+
\t\tpaddingBottom: 1,
|
|
52
|
+
\t\tpaddingLeft: 3,
|
|
53
|
+
\t\tpaddingRight: 3,
|
|
54
|
+
\t},
|
|
55
|
+
\tactiveOptionContainer: {
|
|
56
|
+
\t\tbackgroundColor: colorConstant?.amcBlue,
|
|
57
|
+
\t},
|
|
58
|
+
\tactiveOptionText: {
|
|
59
|
+
\t\tcolor: colorConstant?.amcWhite,
|
|
60
|
+
\t},
|
|
61
|
+
\tfloatContentStyle: {
|
|
62
|
+
\t\t...fonts.fontWSR16,
|
|
63
|
+
\t\tcolor: colorConstant.amcBlack,
|
|
64
|
+
\t},
|
|
65
|
+
\tfloatStyle: {
|
|
66
|
+
\t\tmarginTop: 5,
|
|
67
|
+
\t},
|
|
68
|
+
\tfloatLabelStyle: {
|
|
69
|
+
\t\tcolor: colorConstant?.amcMediumGrey,
|
|
70
|
+
\t\tbackgroundColor: colorConstant?.amcWhite,
|
|
71
|
+
\t\t...fonts.fontWSM12,
|
|
72
|
+
\t\tlineHeight: 16,
|
|
73
|
+
\t},
|
|
74
|
+
\tcheckStyle: {
|
|
75
|
+
\t\tflexDirection: 'row',
|
|
76
|
+
\t\talignItems: 'center',
|
|
77
|
+
\t\tmarginTop: 20,
|
|
78
|
+
\t},
|
|
79
|
+
\tcheckText: {
|
|
80
|
+
\t\t...fonts.fontWSR12LH18,
|
|
81
|
+
\t\tcolor: colorConstant.lightGreyBlack,
|
|
82
|
+
\t\tpaddingRight: 30,
|
|
83
|
+
\t},
|
|
84
|
+
});
|
|
85
|
+
`;
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
module.exports = { generateStylesTemplate };
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
const generateValidationRules = (formFields = []) => {
|
|
2
|
+
if (!formFields || formFields.length === 0) {
|
|
3
|
+
return '\t// Add your validation rules here';
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
return formFields.map(field => {
|
|
7
|
+
const { name, type, label, required } = field;
|
|
8
|
+
let validation = '';
|
|
9
|
+
|
|
10
|
+
switch (type) {
|
|
11
|
+
case 'email':
|
|
12
|
+
validation = `\t${name}: yup.string()${required ? `.required('Please enter ${label}')` : ''}.email('Please enter a valid email address'),`;
|
|
13
|
+
break;
|
|
14
|
+
|
|
15
|
+
case 'number':
|
|
16
|
+
validation = `\t${name}: yup.string()${required ? `.required('Please enter ${label}')` : ''}.matches(/^\\d+$/, 'Please enter a valid number'),`;
|
|
17
|
+
break;
|
|
18
|
+
|
|
19
|
+
case 'checkbox':
|
|
20
|
+
validation = `\t${name}: yup.boolean()${required ? `.oneOf([true], '${label} is required')` : ''},`;
|
|
21
|
+
break;
|
|
22
|
+
|
|
23
|
+
case 'dropdown':
|
|
24
|
+
case 'radio':
|
|
25
|
+
validation = `\t${name}: yup.object()${required ? `.test('select${name}', 'Please select ${label}', function (value) {
|
|
26
|
+
\t\tif (!value?.value) {
|
|
27
|
+
\t\t\treturn false;
|
|
28
|
+
\t\t}
|
|
29
|
+
\t\treturn true;
|
|
30
|
+
\t})` : '.nullable()'},`;
|
|
31
|
+
break;
|
|
32
|
+
|
|
33
|
+
case 'date':
|
|
34
|
+
validation = `\t${name}: yup.string()${required ? `.required('Please select ${label}')` : ''},`;
|
|
35
|
+
break;
|
|
36
|
+
|
|
37
|
+
case 'file':
|
|
38
|
+
validation = `\t${name}: yup.mixed()${required ? `.required('Please upload ${label}')
|
|
39
|
+
\t\t.test('fileType', 'Only JPG or JPEG files are allowed', value => {
|
|
40
|
+
\t\t\tif (!value) return false;
|
|
41
|
+
\t\t\tconst validFormats = ['image/jpeg', 'image/jpg'];
|
|
42
|
+
\t\t\tif (value instanceof File) return validFormats.includes(value.type);
|
|
43
|
+
\t\t\tif (typeof value === 'object' && value?.type) return validFormats.includes(value.type);
|
|
44
|
+
\t\t\treturn false;
|
|
45
|
+
\t\t})
|
|
46
|
+
\t\t.test('fileSize', 'File size must be less than 1MB', value => {
|
|
47
|
+
\t\t\tif (!value) return false;
|
|
48
|
+
\t\t\tconst maxSizeInBytes = 1 * 1024 * 1024;
|
|
49
|
+
\t\t\tif (value instanceof File) return value.size <= maxSizeInBytes;
|
|
50
|
+
\t\t\tif (typeof value === 'object' && value?.size) return value.size <= maxSizeInBytes;
|
|
51
|
+
\t\t\treturn false;
|
|
52
|
+
\t\t})` : ''},`;
|
|
53
|
+
break;
|
|
54
|
+
|
|
55
|
+
default:
|
|
56
|
+
validation = `\t${name}: yup.string()${required ? `.required('Please enter ${label}')` : ''},`;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return validation;
|
|
60
|
+
}).join('\n');
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
const generateValidationTemplate = (formFields = [], screenName) => {
|
|
64
|
+
if (!formFields || formFields.length === 0) {
|
|
65
|
+
return `export const validate${screenName} = (values) => {
|
|
66
|
+
\tconst errors = {};
|
|
67
|
+
\t// Add your validation rules here
|
|
68
|
+
\treturn errors;
|
|
69
|
+
};
|
|
70
|
+
`;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const validations = formFields.map(field => {
|
|
74
|
+
const { name, type, label, required } = field;
|
|
75
|
+
|
|
76
|
+
if (!required) return '';
|
|
77
|
+
|
|
78
|
+
let validation = '';
|
|
79
|
+
switch (type) {
|
|
80
|
+
case 'email':
|
|
81
|
+
validation = `\tif (!values.${name}) {
|
|
82
|
+
\t\terrors.${name} = 'Please enter ${label}';
|
|
83
|
+
\t} else if (!/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\\.[A-Z]{2,}$/i.test(values.${name})) {
|
|
84
|
+
\t\terrors.${name} = 'Please enter a valid email address';
|
|
85
|
+
\t}`;
|
|
86
|
+
break;
|
|
87
|
+
|
|
88
|
+
case 'number':
|
|
89
|
+
validation = `\tif (!values.${name}) {
|
|
90
|
+
\t\terrors.${name} = 'Please enter ${label}';
|
|
91
|
+
\t} else if (!/^\\d+$/.test(values.${name})) {
|
|
92
|
+
\t\terrors.${name} = 'Please enter a valid number';
|
|
93
|
+
\t}`;
|
|
94
|
+
break;
|
|
95
|
+
|
|
96
|
+
case 'dropdown':
|
|
97
|
+
case 'radio':
|
|
98
|
+
validation = `\tif (!values.${name}?.value) {
|
|
99
|
+
\t\terrors.${name} = 'Please select ${label}';
|
|
100
|
+
\t}`;
|
|
101
|
+
break;
|
|
102
|
+
|
|
103
|
+
default:
|
|
104
|
+
validation = `\tif (!values.${name} || !values.${name}.trim()) {
|
|
105
|
+
\t\terrors.${name} = 'Please enter ${label}';
|
|
106
|
+
\t}`;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
return validation;
|
|
110
|
+
}).filter(Boolean).join('\n\n');
|
|
111
|
+
|
|
112
|
+
return `export const validate${screenName} = (values) => {
|
|
113
|
+
\tconst errors = {};
|
|
114
|
+
|
|
115
|
+
${validations}
|
|
116
|
+
|
|
117
|
+
\treturn errors;
|
|
118
|
+
};
|
|
119
|
+
`;
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
module.exports = { generateValidationTemplate };
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
const generateValidationRules = (formFields = []) => {
|
|
2
|
+
if (!formFields || formFields.length === 0) {
|
|
3
|
+
return '\t// Add your validation rules here';
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
return formFields.map(field => {
|
|
7
|
+
const { name, type, label, required } = field;
|
|
8
|
+
let validation = '';
|
|
9
|
+
|
|
10
|
+
if (type === 'email') {
|
|
11
|
+
validation = `\t${name}: yup.string()${required ? ".required('Please enter " + label + "')" : ''}.email('Please enter a valid email address'),`;
|
|
12
|
+
} else if (type === 'number') {
|
|
13
|
+
validation = `\t${name}: yup.string()${required ? ".required('Please enter " + label + "')" : ''}.matches(/^\\d+$/, 'Please enter a valid number'),`;
|
|
14
|
+
} else if (type === 'checkbox') {
|
|
15
|
+
validation = `\t${name}: yup.boolean()${required ? ".oneOf([true], '" + label + " is required')" : ''},`;
|
|
16
|
+
} else if (type === 'dropdown') {
|
|
17
|
+
validation = `\t${name}: yup.object()${required ? ".required('Please select " + label + "')" : ''}.nullable(),`;
|
|
18
|
+
} else {
|
|
19
|
+
validation = `\t${name}: yup.string()${required ? ".required('Please enter " + label + "')" : ''},`;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
return validation;
|
|
23
|
+
}).join('\n');
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
const generateValidationTemplate = (formFields = []) => {
|
|
27
|
+
const validationRules = generateValidationRules(formFields);
|
|
28
|
+
|
|
29
|
+
return `import * as yup from 'yup';
|
|
30
|
+
|
|
31
|
+
export const validationSchema = yup.object().shape({
|
|
32
|
+
${validationRules}
|
|
33
|
+
});
|
|
34
|
+
`;
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
module.exports = { generateValidationTemplate };
|