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.
- package/generators/components-advanced.js +221 -0
- package/generators/components-basic.js +243 -0
- package/generators/components-intermediate.js +290 -0
- package/generators/components-upload.js +181 -0
- package/generators/components.js +659 -0
- package/generators/constants.js +54 -0
- package/generators/features.js +51 -0
- package/generators/helpers.js +195 -0
- package/generators/hooks.js +239 -0
- package/generators/navigation.js +138 -0
- package/generators/readme.js +51 -0
- package/generators/shared.js +56 -0
- package/generators/storage.js +175 -0
- package/generators/store.js +181 -0
- package/generators/utils.js +202 -0
- package/package.json +3 -2
|
@@ -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
|
+
};
|