create-rn-folder-structure 1.0.2 → 1.0.3

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,51 @@
1
+ const fs = require("fs");
2
+ const path = require("path");
3
+
4
+ function write(root, filePath, content) {
5
+ const fullPath = path.join(root, filePath);
6
+ fs.mkdirSync(path.dirname(fullPath), { recursive: true });
7
+ fs.writeFileSync(fullPath, content);
8
+ }
9
+
10
+ module.exports = function generateFeatures(projectRoot) {
11
+ console.log("📦 Creating feature folders...");
12
+
13
+ // Example features
14
+ const features = ["auth", "profile", "dashboard", "settings"];
15
+
16
+ features.forEach((feature) => {
17
+ write(
18
+ projectRoot,
19
+ `src/features/${feature}/screens/${capitalize(feature)}Screen.tsx`,
20
+ `
21
+ import { View, Text } from "react-native";
22
+
23
+ export default function ${capitalize(feature)}Screen() {
24
+ return (
25
+ <View>
26
+ <Text>${capitalize(feature)} Screen</Text>
27
+ </View>
28
+ );
29
+ }
30
+ `
31
+ );
32
+
33
+ write(
34
+ projectRoot,
35
+ `src/features/${feature}/store/index.ts`,
36
+ `export default {};`
37
+ );
38
+
39
+ write(
40
+ projectRoot,
41
+ `src/features/${feature}/api/index.ts`,
42
+ `// API calls for ${feature}`
43
+ );
44
+ });
45
+
46
+ console.log("✅ Features created successfully!");
47
+ };
48
+
49
+ function capitalize(str) {
50
+ return str.charAt(0).toUpperCase() + str.slice(1);
51
+ }
@@ -0,0 +1,195 @@
1
+ const fs = require("fs");
2
+ const path = require("path");
3
+
4
+ function write(root, filePath, content) {
5
+ const out = path.join(root, filePath);
6
+ fs.mkdirSync(path.dirname(out), { recursive: true });
7
+ fs.writeFileSync(out, content);
8
+ }
9
+
10
+ module.exports = function generateHelpers(projectRoot) {
11
+ console.log("🛠 Creating Helper Modules...");
12
+
13
+ const base = "src/shared/helpers";
14
+
15
+ // --------------------------------------------------------------
16
+ // DATE HELPERS
17
+ // --------------------------------------------------------------
18
+ write(
19
+ projectRoot,
20
+ `${base}/date.ts`,
21
+ `
22
+ export const formatDate = (date: Date, format = "DD/MM/YYYY") => {
23
+ const d = date.getDate().toString().padStart(2, "0");
24
+ const m = (date.getMonth() + 1).toString().padStart(2, "0");
25
+ const y = date.getFullYear();
26
+
27
+ return format
28
+ .replace("DD", d)
29
+ .replace("MM", m)
30
+ .replace("YYYY", y.toString());
31
+ };
32
+
33
+ export const timeAgo = (date: string | number | Date) => {
34
+ const diff = Date.now() - new Date(date).getTime();
35
+ const sec = Math.floor(diff / 1000);
36
+ if (sec < 60) return \`\${sec}s ago\`;
37
+ const min = Math.floor(sec / 60);
38
+ if (min < 60) return \`\${min}m ago\`;
39
+ const hr = Math.floor(min / 60);
40
+ if (hr < 24) return \`\${hr}h ago\`;
41
+ const days = Math.floor(hr / 24);
42
+ return \`\${days}d ago\`;
43
+ };
44
+
45
+ export const getToday = () => new Date();
46
+
47
+ export const isSameDay = (d1: Date, d2: Date) =>
48
+ d1.getFullYear() === d2.getFullYear() &&
49
+ d1.getMonth() === d2.getMonth() &&
50
+ d1.getDate() === d2.getDate();
51
+ `
52
+ );
53
+
54
+ // --------------------------------------------------------------
55
+ // NUMBER HELPERS
56
+ // --------------------------------------------------------------
57
+ write(
58
+ projectRoot,
59
+ `${base}/number.ts`,
60
+ `
61
+ export const formatNumber = (num: number) =>
62
+ new Intl.NumberFormat().format(num);
63
+
64
+ export const toCurrency = (num: number, currency = "USD") =>
65
+ new Intl.NumberFormat("en-US", {
66
+ style: "currency",
67
+ currency,
68
+ }).format(num);
69
+
70
+ export const randomNumber = (min: number, max: number) =>
71
+ Math.floor(Math.random() * (max - min + 1)) + min;
72
+ `
73
+ );
74
+
75
+ // --------------------------------------------------------------
76
+ // VALIDATION HELPERS
77
+ // --------------------------------------------------------------
78
+ write(
79
+ projectRoot,
80
+ `${base}/validation.ts`,
81
+ `
82
+ export const isEmail = (str: string) =>
83
+ /^[\\w-.]+@([\\w-]+\\.)+[\\w-]{2,4}$/.test(str);
84
+
85
+ export const isPhone = (str: string) =>
86
+ /^[0-9]{10}$/.test(str);
87
+
88
+ export const isEmpty = (value: any) =>
89
+ value === null || value === undefined || value === "";
90
+
91
+ export const isStrongPassword = (str: string) =>
92
+ /^(?=.*[A-Z])(?=.*[a-z])(?=.*\\d).{8,}$/.test(str);
93
+ `
94
+ );
95
+
96
+ // --------------------------------------------------------------
97
+ // FUNCTION HELPERS (DEBOUNCE, THROTTLE)
98
+ // --------------------------------------------------------------
99
+ write(
100
+ projectRoot,
101
+ `${base}/functions.ts`,
102
+ `
103
+ export const debounce = (fn: Function, delay = 300) => {
104
+ let timer: any;
105
+ return (...args: any[]) => {
106
+ clearTimeout(timer);
107
+ timer = setTimeout(() => fn(...args), delay);
108
+ };
109
+ };
110
+
111
+ export const throttle = (fn: Function, limit = 300) => {
112
+ let lastCall = 0;
113
+ return (...args: any[]) => {
114
+ const now = Date.now();
115
+ if (now - lastCall >= limit) {
116
+ lastCall = now;
117
+ fn(...args);
118
+ }
119
+ };
120
+ };
121
+ `
122
+ );
123
+
124
+ // --------------------------------------------------------------
125
+ // ASYNC HELPERS
126
+ // --------------------------------------------------------------
127
+ write(
128
+ projectRoot,
129
+ `${base}/async.ts`,
130
+ `
131
+ export const wait = (ms: number) =>
132
+ new Promise((res) => setTimeout(res, ms));
133
+
134
+ export const retry = async (fn: Function, attempts = 3) => {
135
+ for (let i = 0; i < attempts; i++) {
136
+ try {
137
+ return await fn();
138
+ } catch (err) {
139
+ if (i === attempts - 1) throw err;
140
+ }
141
+ }
142
+ };
143
+
144
+ export const timeoutPromise = (promise: Promise<any>, ms: number) =>
145
+ Promise.race([
146
+ promise,
147
+ new Promise((_, reject) =>
148
+ setTimeout(() => reject(new Error("Timeout exceeded")), ms)
149
+ ),
150
+ ]);
151
+ `
152
+ );
153
+
154
+ // --------------------------------------------------------------
155
+ // LOGGER HELPERS
156
+ // --------------------------------------------------------------
157
+ write(
158
+ projectRoot,
159
+ `${base}/logger.ts`,
160
+ `
161
+ export const debugLog = (...args: any[]) => {
162
+ if (__DEV__) console.log("🐛 DEBUG:", ...args);
163
+ };
164
+
165
+ export const warnLog = (...args: any[]) => {
166
+ if (__DEV__) console.warn("⚠️ WARNING:", ...args);
167
+ };
168
+
169
+ export const errorLog = (...args: any[]) => {
170
+ console.error("❌ ERROR:", ...args);
171
+ };
172
+ `
173
+ );
174
+
175
+ // --------------------------------------------------------------
176
+ // DEVICE HELPERS
177
+ // --------------------------------------------------------------
178
+ write(
179
+ projectRoot,
180
+ `${base}/device.ts`,
181
+ `
182
+ import { Platform, Dimensions } from "react-native";
183
+
184
+ const { width, height } = Dimensions.get("window");
185
+
186
+ export const isAndroid = Platform.OS === "android";
187
+ export const isIOS = Platform.OS === "ios";
188
+ export const screenWidth = width;
189
+ export const screenHeight = height;
190
+ export const isSmallDevice = width < 360;
191
+ `
192
+ );
193
+
194
+ console.log("✅ Helper Modules Created (renamed from utils)!");
195
+ };
@@ -0,0 +1,239 @@
1
+ const fs = require("fs");
2
+ const path = require("path");
3
+
4
+ function write(root, filePath, content) {
5
+ const fullPath = path.join(root, filePath);
6
+ fs.mkdirSync(path.dirname(fullPath), { recursive: true });
7
+ fs.writeFileSync(fullPath, content);
8
+ }
9
+
10
+ module.exports = function generateHooks(projectRoot) {
11
+ console.log("🪝 Creating custom hooks...");
12
+
13
+ const base = "src/shared/hooks";
14
+
15
+ // ---------------------------------------------------------
16
+ // useApi Hook
17
+ // ---------------------------------------------------------
18
+ write(
19
+ projectRoot,
20
+ `${base}/useApi.ts`,
21
+ `
22
+ import { useState } from "react";
23
+ import axiosInstance from "../../services/api/axiosInstance";
24
+
25
+ export default function useApi() {
26
+ const [loading, setLoading] = useState(false);
27
+ const [error, setError] = useState<string | null>(null);
28
+
29
+ const request = async (method: string, url: string, data?: any, config?: any) => {
30
+ try {
31
+ setLoading(true);
32
+ setError(null);
33
+
34
+ const response = await axiosInstance({
35
+ method,
36
+ url,
37
+ data,
38
+ ...config,
39
+ });
40
+
41
+ return response.data;
42
+ } catch (err: any) {
43
+ setError(err?.response?.data?.message || "Something went wrong");
44
+ return null;
45
+ } finally {
46
+ setLoading(false);
47
+ }
48
+ };
49
+
50
+ return { request, loading, error };
51
+ }
52
+ `
53
+ );
54
+
55
+ // ---------------------------------------------------------
56
+ // useAuth Hook
57
+ // ---------------------------------------------------------
58
+ write(
59
+ projectRoot,
60
+ `${base}/useAuth.ts`,
61
+ `
62
+ import { useState, useEffect } from "react";
63
+ import AsyncStorage from "@react-native-async-storage/async-storage";
64
+
65
+ export default function useAuth() {
66
+ const [token, setToken] = useState<string | null>(null);
67
+
68
+ useEffect(() => {
69
+ loadToken();
70
+ }, []);
71
+
72
+ const loadToken = async () => {
73
+ const saved = await AsyncStorage.getItem("token");
74
+ if (saved) setToken(saved);
75
+ };
76
+
77
+ const login = async (newToken: string) => {
78
+ await AsyncStorage.setItem("token", newToken);
79
+ setToken(newToken);
80
+ };
81
+
82
+ const logout = async () => {
83
+ await AsyncStorage.removeItem("token");
84
+ setToken(null);
85
+ };
86
+
87
+ return { token, login, logout, isLoggedIn: !!token };
88
+ }
89
+ `
90
+ );
91
+
92
+ // ---------------------------------------------------------
93
+ // useLoader Hook
94
+ // ---------------------------------------------------------
95
+ write(
96
+ projectRoot,
97
+ `${base}/useLoader.ts`,
98
+ `
99
+ import { useState } from "react";
100
+
101
+ export default function useLoader() {
102
+ const [loading, setLoading] = useState(false);
103
+
104
+ const show = () => setLoading(true);
105
+ const hide = () => setLoading(false);
106
+
107
+ return { loading, show, hide };
108
+ }
109
+ `
110
+ );
111
+
112
+ // ---------------------------------------------------------
113
+ // useDebounce Hook
114
+ // ---------------------------------------------------------
115
+ write(
116
+ projectRoot,
117
+ `${base}/useDebounce.ts`,
118
+ `
119
+ import { useEffect, useState } from "react";
120
+
121
+ export default function useDebounce(value: any, delay: number = 500) {
122
+ const [debouncedValue, setDebouncedValue] = useState(value);
123
+
124
+ useEffect(() => {
125
+ const timer = setTimeout(() => setDebouncedValue(value), delay);
126
+ return () => clearTimeout(timer);
127
+ }, [value]);
128
+
129
+ return debouncedValue;
130
+ }
131
+ `
132
+ );
133
+
134
+ // ---------------------------------------------------------
135
+ // useOnlineStatus Hook
136
+ // ---------------------------------------------------------
137
+ write(
138
+ projectRoot,
139
+ `${base}/useOnlineStatus.ts`,
140
+ `
141
+ import { useEffect, useState } from "react";
142
+ import NetInfo from "@react-native-community/netinfo";
143
+
144
+ export default function useOnlineStatus() {
145
+ const [online, setOnline] = useState(true);
146
+
147
+ useEffect(() => {
148
+ const unsubscribe = NetInfo.addEventListener(state => {
149
+ setOnline(state.isConnected ?? true);
150
+ });
151
+
152
+ return () => unsubscribe();
153
+ }, []);
154
+
155
+ return online;
156
+ }
157
+ `
158
+ );
159
+
160
+ // ---------------------------------------------------------
161
+ // useModal Hook
162
+ // ---------------------------------------------------------
163
+ write(
164
+ projectRoot,
165
+ `${base}/useModal.ts`,
166
+ `
167
+ import { useState } from "react";
168
+
169
+ export default function useModal() {
170
+ const [visible, setVisible] = useState(false);
171
+
172
+ const open = () => setVisible(true);
173
+ const close = () => setVisible(false);
174
+
175
+ return { visible, open, close };
176
+ }
177
+ `
178
+ );
179
+
180
+ // ---------------------------------------------------------
181
+ // usePagination Hook
182
+ // ---------------------------------------------------------
183
+ write(
184
+ projectRoot,
185
+ `${base}/usePagination.ts`,
186
+ `
187
+ import { useState } from "react";
188
+
189
+ export default function usePagination(initialPage: number = 1) {
190
+ const [page, setPage] = useState(initialPage);
191
+
192
+ const next = () => setPage(p => p + 1);
193
+ const prev = () => setPage(p => (p > 1 ? p - 1 : 1));
194
+ const reset = () => setPage(1);
195
+
196
+ return { page, next, prev, reset };
197
+ }
198
+ `
199
+ );
200
+
201
+ // ---------------------------------------------------------
202
+ // useStorage Hook
203
+ // ---------------------------------------------------------
204
+ write(
205
+ projectRoot,
206
+ `${base}/useStorage.ts`,
207
+ `
208
+ import { useEffect, useState } from "react";
209
+ import AsyncStorage from "@react-native-async-storage/async-storage";
210
+
211
+ export default function useStorage(key: string, initialValue: any = null) {
212
+ const [value, setValue] = useState(initialValue);
213
+
214
+ useEffect(() => {
215
+ load();
216
+ }, []);
217
+
218
+ const load = async () => {
219
+ const saved = await AsyncStorage.getItem(key);
220
+ if (saved) setValue(JSON.parse(saved));
221
+ };
222
+
223
+ const save = async (val: any) => {
224
+ setValue(val);
225
+ await AsyncStorage.setItem(key, JSON.stringify(val));
226
+ };
227
+
228
+ const remove = async () => {
229
+ setValue(null);
230
+ await AsyncStorage.removeItem(key);
231
+ };
232
+
233
+ return { value, save, remove };
234
+ }
235
+ `
236
+ );
237
+
238
+ console.log("✅ Hooks created successfully!");
239
+ };
@@ -0,0 +1,138 @@
1
+ const fs = require("fs");
2
+ const path = require("path");
3
+
4
+ function createFile(root, filePath, content = "") {
5
+ const fullPath = path.join(root, filePath);
6
+ fs.mkdirSync(path.dirname(fullPath), { recursive: true });
7
+ fs.writeFileSync(fullPath, content);
8
+ }
9
+
10
+ module.exports = function generateNavigation(projectRoot) {
11
+ console.log("📌 Creating Navigation Structure...");
12
+
13
+ const navBase = "src/app/navigation";
14
+
15
+ // ---------------------------------------------------------
16
+ // RootNavigator.tsx
17
+ // ---------------------------------------------------------
18
+ createFile(
19
+ projectRoot,
20
+ `${navBase}/RootNavigator.tsx`,
21
+ `
22
+ import React, { useEffect, useState } from "react";
23
+ import { NavigationContainer } from "@react-navigation/native";
24
+ import AuthStack from "./stacks/AuthStack";
25
+ import AppStack from "./stacks/AppStack";
26
+ import { getToken } from "../../services/storage/token";
27
+
28
+ export default function RootNavigator() {
29
+ const [loading, setLoading] = useState(true);
30
+ const [isLoggedIn, setLoggedIn] = useState(false);
31
+
32
+ useEffect(() => {
33
+ const init = async () => {
34
+ const token = await getToken();
35
+ setLoggedIn(!!token);
36
+ setLoading(false);
37
+ };
38
+ init();
39
+ }, []);
40
+
41
+ if (loading) return null;
42
+
43
+ return (
44
+ <NavigationContainer>
45
+ {isLoggedIn ? <AppStack /> : <AuthStack />}
46
+ </NavigationContainer>
47
+ );
48
+ }
49
+ `
50
+ );
51
+
52
+ // ---------------------------------------------------------
53
+ // Auth Stack
54
+ // ---------------------------------------------------------
55
+ createFile(
56
+ projectRoot,
57
+ `${navBase}/stacks/AuthStack.tsx`,
58
+ `
59
+ import React from "react";
60
+ import { createNativeStackNavigator } from "@react-navigation/native-stack";
61
+
62
+ import LoginScreen from "../../features/auth/screens/LoginScreen";
63
+ import RegisterScreen from "../../features/auth/screens/RegisterScreen";
64
+ import ForgotPasswordScreen from "../../features/auth/screens/ForgotPasswordScreen";
65
+
66
+ const Stack = createNativeStackNavigator();
67
+
68
+ export default function AuthStack() {
69
+ return (
70
+ <Stack.Navigator screenOptions={{ headerShown: false }}>
71
+ <Stack.Screen name="Login" component={LoginScreen} />
72
+ <Stack.Screen name="Register" component={RegisterScreen} />
73
+ <Stack.Screen name="ForgotPassword" component={ForgotPasswordScreen} />
74
+ </Stack.Navigator>
75
+ );
76
+ }
77
+ `
78
+ );
79
+
80
+ // ---------------------------------------------------------
81
+ // App Stack (Dashboard + other features)
82
+ // ---------------------------------------------------------
83
+ createFile(
84
+ projectRoot,
85
+ `${navBase}/stacks/AppStack.tsx`,
86
+ `
87
+ import React from "react";
88
+ import { createNativeStackNavigator } from "@react-navigation/native-stack";
89
+
90
+ import DashboardScreen from "../../features/dashboard/screens/DashboardScreen";
91
+ import HomeScreen from "../../features/home/screens/HomeScreen";
92
+ import ProfileScreen from "../../features/profile/screens/ProfileScreen";
93
+ import SettingsScreen from "../../features/settings/screens/SettingsScreen";
94
+ import NotificationsScreen from "../../features/notifications/screens/NotificationsScreen";
95
+
96
+ const Stack = createNativeStackNavigator();
97
+
98
+ export default function AppStack() {
99
+ return (
100
+ <Stack.Navigator screenOptions={{ headerShown: false }}>
101
+ <Stack.Screen name="Dashboard" component={DashboardScreen} />
102
+ <Stack.Screen name="Home" component={HomeScreen} />
103
+ <Stack.Screen name="Profile" component={ProfileScreen} />
104
+ <Stack.Screen name="Settings" component={SettingsScreen} />
105
+ <Stack.Screen name="Notifications" component={NotificationsScreen} />
106
+ </Stack.Navigator>
107
+ );
108
+ }
109
+ `
110
+ );
111
+
112
+ // ---------------------------------------------------------
113
+ // Example Dashboard Screen
114
+ // ---------------------------------------------------------
115
+ createFile(
116
+ projectRoot,
117
+ `src/features/dashboard/screens/DashboardScreen.tsx`,
118
+ `
119
+ import React from "react";
120
+ import { View, Text, StyleSheet } from "react-native";
121
+
122
+ export default function DashboardScreen() {
123
+ return (
124
+ <View style={styles.container}>
125
+ <Text style={styles.title}>Dashboard</Text>
126
+ </View>
127
+ );
128
+ }
129
+
130
+ const styles = StyleSheet.create({
131
+ container: { flex: 1, justifyContent: "center", alignItems: "center" },
132
+ title: { fontSize: 26, fontWeight: "bold" }
133
+ });
134
+ `
135
+ );
136
+
137
+ console.log("✅ Navigation setup completed.");
138
+ };
@@ -0,0 +1,51 @@
1
+ const fs = require("fs");
2
+ const path = require("path");
3
+
4
+ module.exports = function generateReadme(projectRoot) {
5
+ console.log("📘 Creating README...");
6
+
7
+ const content = `
8
+ # React Native Project Structure Generator
9
+
10
+ This project was automatically generated using **create-rn-folder-structure**.
11
+
12
+ ## 📁 Folder Structure
13
+
14
+ \`\`\`
15
+ src/
16
+ ├── app/
17
+ │ ├── navigation/
18
+ │ └── store/
19
+ ├── features/
20
+ │ ├── auth/
21
+ │ ├── profile/
22
+ │ ├── dashboard/
23
+ │ └── settings/
24
+ ├── shared/
25
+ │ ├── components/
26
+ │ ├── constants/
27
+ │ ├── custom-hooks/
28
+ │ └── utils/
29
+ ├── services/
30
+ │ ├── api/
31
+ │ └── storage/
32
+ \`\`\`
33
+
34
+ ## 🚀 Generated Modules
35
+
36
+ - Feature screens + API + Store
37
+ - Shared UI Components
38
+ - Custom Hooks
39
+ - Constants
40
+ - Centralized API setup
41
+ - Async storage helpers
42
+
43
+ ---
44
+
45
+ Generated with ❤️ using **create-rn-folder-structure**
46
+ `;
47
+
48
+ fs.writeFileSync(path.join(projectRoot, "README.md"), content);
49
+
50
+ console.log("✅ README created successfully!");
51
+ };