create-gufran-expo-app 2.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 ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Gufran Gaury
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,413 @@
1
+ # šŸš€ @gufran/expo-boilerplate
2
+
3
+ ![npm version](https://img.shields.io/npm/v/@gufran/expo-boilerplate.svg)
4
+ ![downloads](https://img.shields.io/npm/dt/@gufran/expo-boilerplate.svg)
5
+ ![license](https://img.shields.io/npm/l/@gufran/expo-boilerplate.svg)
6
+
7
+ **Ultimate Expo React Native Boilerplate** - A professionally configured Expo environment designed for production-ready applications. Skip the tedious setup and dive straight into building amazing features!
8
+
9
+ ---
10
+
11
+ ## ✨ Why Choose This Boilerplate?
12
+
13
+ This boilerplate provides a complete, production-ready setup with enterprise-grade features:
14
+
15
+ - šŸ”„ **Firebase Integration** - Authentication, Push Notifications, Analytics
16
+ - šŸŽØ **Professional UI** - Pre-built components and screens
17
+ - šŸ—‚ļø **Clean Architecture** - Organized folder structure that scales
18
+ - ā˜ļø **Cloud Storage** - Azure Blob Storage for file uploads
19
+ - šŸ” **Authentication Flow** - Complete auth screens and navigation
20
+ - šŸ“± **Native Features** - Camera, Image Picker, Permissions
21
+ - šŸ”” **Push Notifications** - Notifee and Firebase Messaging
22
+ - 🌐 **API Management** - TanStack Query configured
23
+ - šŸ“Š **State Management** - Zustand for efficient state handling
24
+ - šŸŽÆ **TypeScript** - Full type safety
25
+
26
+ ---
27
+
28
+ ## šŸš€ Quick Start
29
+
30
+ Create a new project with a single command:
31
+
32
+ ```bash
33
+ npx @gufran/expo-boilerplate my-awesome-app
34
+ ```
35
+
36
+ Or use npm directly:
37
+
38
+ ```bash
39
+ npm create @gufran/expo-boilerplate my-awesome-app
40
+ ```
41
+
42
+ With yarn:
43
+
44
+ ```bash
45
+ yarn create @gufran/expo-boilerplate my-awesome-app
46
+ ```
47
+
48
+ ### Interactive Mode
49
+
50
+ Simply run without a project name to enter interactive mode (will prompt for project name and bundle ID):
51
+
52
+ ```bash
53
+ npx @gufran/expo-boilerplate
54
+ ```
55
+
56
+ ---
57
+
58
+ ## šŸ“‹ Command Options
59
+
60
+ ```bash
61
+ npx @gufran/expo-boilerplate [project-name] [options]
62
+ ```
63
+
64
+ ### Options:
65
+
66
+ | Option | Description |
67
+ |--------|-------------|
68
+ | `-b, --bundle-id <bundleId>` | Bundle identifier (e.g., com.myapp) |
69
+ | `--skip-install` | Skip automatic dependency installation |
70
+ | `--skip-git` | Skip git initialization |
71
+ | `--npm` | Use npm instead of yarn |
72
+ | `-h, --help` | Display help information |
73
+ | `-V, --version` | Display version number |
74
+
75
+ ### Examples:
76
+
77
+ ```bash
78
+ # Create project with custom bundle ID
79
+ npx @gufran/expo-boilerplate my-app -b com.myapp
80
+
81
+ # Create project with npm
82
+ npx @gufran/expo-boilerplate my-app --npm
83
+
84
+ # Skip installation and git init
85
+ npx @gufran/expo-boilerplate my-app --skip-install --skip-git
86
+
87
+ # Full command with all options
88
+ npx @gufran/expo-boilerplate my-app -b com.myapp --npm
89
+
90
+ # Interactive mode (prompts for name and bundle ID)
91
+ npx @gufran/expo-boilerplate
92
+ ```
93
+
94
+ ---
95
+
96
+ ## šŸ“¦ What's Included?
97
+
98
+ ### šŸŽÆ Core Technologies
99
+
100
+ - **Expo SDK 54** - Latest Expo framework
101
+ - **React Native 0.81** - Latest stable RN version
102
+ - **TypeScript** - Full type safety
103
+ - **React Navigation 7** - Native stack navigation
104
+
105
+ ### šŸ”„ Firebase Services
106
+
107
+ - Firebase App & Messaging
108
+ - Push Notifications with Notifee
109
+ - Cloud Messaging
110
+ - Analytics ready
111
+
112
+ ### šŸ’¾ State & Data Management
113
+
114
+ - **Zustand** - Lightweight state management
115
+ - **TanStack Query** - Server state management
116
+ - **MMKV** - Fast local storage
117
+ - **React Native Gesture Handler** - Smooth gestures
118
+
119
+ ### šŸŽØ UI & Media
120
+
121
+ - Image Picker & Camera
122
+ - Image Zoom capabilities
123
+ - SVG support
124
+ - Reanimated animations
125
+ - Keyboard-aware scrolling
126
+
127
+
128
+ ### ā˜ļø Cloud Services
129
+
130
+ - Azure Blob Storage integration
131
+ - Background file upload
132
+ - Progress tracking
133
+
134
+ ### šŸ” Authentication
135
+
136
+ - Complete auth flow
137
+ - Context-based auth management
138
+ - Secure storage
139
+
140
+ ---
141
+
142
+ ## šŸ“ Project Structure
143
+
144
+ ```
145
+ my-app/
146
+ ā”œā”€ā”€ src/
147
+ │ ā”œā”€ā”€ assets/ # Images, fonts, icons
148
+ │ ā”œā”€ā”€ components/ # Reusable UI components
149
+ │ │ └── common/ # Common components
150
+ │ ā”œā”€ā”€ config/ # App configuration
151
+ │ ā”œā”€ā”€ constants/ # Constants, themes, strings
152
+ │ ā”œā”€ā”€ contexts/ # React contexts (Auth, etc.)
153
+ │ ā”œā”€ā”€ hooks/ # Custom React hooks
154
+ │ ā”œā”€ā”€ navigation/ # Navigation setup
155
+ │ │ ā”œā”€ā”€ AuthStack.tsx
156
+ │ │ ā”œā”€ā”€ MainStack.tsx
157
+ │ │ └── RootNavigator.tsx
158
+ │ ā”œā”€ā”€ screens/ # App screens
159
+ │ │ ā”œā”€ā”€ auth/ # Authentication screens
160
+ │ │ ā”œā”€ā”€ chat/ # Chat features
161
+ │ │ ā”œā”€ā”€ clubs/ # Club management
162
+ │ │ ā”œā”€ā”€ events/ # Events
163
+ │ │ └── ...
164
+ │ ā”œā”€ā”€ services/ # API services
165
+ │ ā”œā”€ā”€ stores/ # Zustand stores
166
+ │ ā”œā”€ā”€ types/ # TypeScript types
167
+ │ └── utils/ # Utility functions
168
+ ā”œā”€ā”€ android/ # Android native code
169
+ ā”œā”€ā”€ ios/ # iOS native code
170
+ ā”œā”€ā”€ FirebaseFiles/ # Firebase configuration files
171
+ └── assets/ # Root assets
172
+ ```
173
+
174
+ ---
175
+
176
+ ## šŸ› ļø Setup Steps
177
+
178
+ ### 1. Create Your Project
179
+
180
+ ```bash
181
+ # Interactive mode (recommended)
182
+ npx @gufran/expo-boilerplate
183
+
184
+ # Or specify project name and bundle ID
185
+ npx @gufran/expo-boilerplate my-app -b com.myapp
186
+
187
+ cd my-app
188
+ ```
189
+
190
+ The CLI will automatically:
191
+ - Create project directory
192
+ - Copy all template files (no git clone needed!)
193
+ - Update `package.json` with your project name
194
+ - Update `app.json` with your project name and bundle IDs
195
+ - Install dependencies (unless --skip-install)
196
+ - Initialize git repository (unless --skip-git)
197
+
198
+ ### 2. Configure Firebase
199
+
200
+ Add your Firebase configuration files:
201
+
202
+ **For Android:**
203
+ ```bash
204
+ # Add google-services.json to:
205
+ android/app/google-services.json
206
+ ```
207
+
208
+ **For iOS:**
209
+ ```bash
210
+ # Add GoogleService-Info.plist to:
211
+ ios/ClubYakka/GoogleService-Info.plist
212
+ ```
213
+
214
+ ### 3. Install iOS Dependencies
215
+
216
+ ```bash
217
+ cd ios && pod install && cd ..
218
+ ```
219
+
220
+ ### 4. Verify Configuration
221
+
222
+ The CLI automatically updates `app.json` with your bundle IDs, but you can verify:
223
+
224
+ ```json
225
+ {
226
+ "expo": {
227
+ "name": "my-app",
228
+ "slug": "my-app",
229
+ "version": "1.0.0",
230
+ "ios": {
231
+ "bundleIdentifier": "com.myapp"
232
+ },
233
+ "android": {
234
+ "package": "com.myapp"
235
+ }
236
+ }
237
+ }
238
+ ```
239
+
240
+ ### 5. Start Development
241
+
242
+ ```bash
243
+ # Start Metro bundler
244
+ npm start
245
+
246
+ # Run on Android
247
+ npm run android
248
+
249
+ # Run on iOS
250
+ npm run ios
251
+ ```
252
+
253
+ ---
254
+
255
+ ## šŸ”§ Available Scripts
256
+
257
+ | Script | Description |
258
+ |--------|-------------|
259
+ | `npm start` | Start Metro bundler |
260
+ | `npm run android` | Run on Android device/emulator |
261
+ | `npm run ios` | Run on iOS device/simulator |
262
+ | `npm run web` | Run on web browser |
263
+ | `npm run pod` | Install iOS pods |
264
+ | `npm run clear` | Clear Metro cache |
265
+ | `npm run clean` | Clean Android build |
266
+
267
+ ---
268
+
269
+ ## šŸŽØ Key Features Explained
270
+
271
+ ### Authentication Flow
272
+
273
+ Complete authentication system with:
274
+ - Login/Register screens
275
+ - OTP verification
276
+ - Password reset
277
+ - Protected routes
278
+ - Auth context management
279
+
280
+ ### Navigation Structure
281
+
282
+ Three-level navigation:
283
+ 1. **RootNavigator** - Entry point
284
+ 2. **AuthStack** - Unauthenticated screens
285
+ 3. **MainStack** - Authenticated screens
286
+
287
+ ### API Integration
288
+
289
+ Pre-configured with:
290
+ - Axios for HTTP requests
291
+ - TanStack Query for caching
292
+ - Error handling
293
+ - Request/response interceptors
294
+
295
+ ### File Upload
296
+
297
+ Background upload with:
298
+ - Azure Blob Storage integration
299
+ - Progress tracking
300
+ - Multiple file support
301
+ - Error handling
302
+
303
+ ### Push Notifications
304
+
305
+ Complete notification system:
306
+ - Firebase Cloud Messaging
307
+ - Notifee for local notifications
308
+ - Permission handling
309
+ - Deep linking support
310
+
311
+ ---
312
+
313
+ ## šŸ” Environment Setup
314
+
315
+ Create `.env` file in root:
316
+
317
+ ```env
318
+ API_BASE_URL=https://api.yourapp.com
319
+ AZURE_STORAGE_URL=your-azure-url
320
+ SQUARE_APPLICATION_ID=your-square-id
321
+ ```
322
+
323
+ ---
324
+
325
+ ## šŸ“± Platform-Specific Notes
326
+
327
+ ### iOS
328
+
329
+ - Requires Xcode 14+
330
+ - Run `pod install` after installing dependencies
331
+ - Configure signing in Xcode
332
+ - Update `Info.plist` with required permissions
333
+
334
+ ### Android
335
+
336
+ - Requires Android Studio
337
+ - Update `google-services.json`
338
+ - Configure signing in `android/app/build.gradle`
339
+ - Set up keystore for release builds
340
+
341
+ ---
342
+
343
+ ## 🧪 Testing
344
+
345
+ ```bash
346
+ # Run tests (when configured)
347
+ npm test
348
+
349
+ # Type checking
350
+ npx tsc --noEmit
351
+ ```
352
+
353
+ ---
354
+
355
+ ## šŸ“š Documentation
356
+
357
+ For detailed documentation on specific features:
358
+
359
+ - [Firebase Setup](./docs/firebase.md)
360
+ - [Azure Storage](./docs/azure-storage.md)
361
+ - [Navigation Guide](./docs/navigation.md)
362
+ - [API Services](./docs/api-services.md)
363
+
364
+ ---
365
+
366
+ ## šŸ¤ Contributing
367
+
368
+ Contributions are welcome! Please feel free to submit a Pull Request.
369
+
370
+ 1. Fork the repository
371
+ 2. Create your feature branch (`git checkout -b feature/amazing-feature`)
372
+ 3. Commit your changes (`git commit -m 'Add some amazing feature'`)
373
+ 4. Push to the branch (`git push origin feature/amazing-feature`)
374
+ 5. Open a Pull Request
375
+
376
+ ---
377
+
378
+ ## šŸ› Issues
379
+
380
+ Found a bug? Please [open an issue](https://github.com/GufranGaury1887/Boiler_Plat_Expo_-Gufran/issues) with a detailed description.
381
+
382
+ ---
383
+
384
+ ## šŸ“„ License
385
+
386
+ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
387
+
388
+ ---
389
+
390
+ ## šŸ‘¤ Author
391
+
392
+ **Gufran Gaury**
393
+
394
+ - GitHub: [@GufranGaury1887](https://github.com/GufranGaury1887)
395
+ - Repository: [Boiler_Plat_Expo_-Gufran](https://github.com/GufranGaury1887/Boiler_Plat_Expo_-Gufran)
396
+
397
+ ---
398
+
399
+ ## 🌟 Show Your Support
400
+
401
+ Give a ā­ļø if this project helped you!
402
+
403
+ ---
404
+
405
+ ## šŸ“® Support
406
+
407
+ For support, email your-email@example.com or open an issue on GitHub.
408
+
409
+ ---
410
+
411
+ **Built with ā¤ļø by Gufran Gaury**
412
+
413
+ *Happy Coding! šŸš€*
package/bin/cli.js ADDED
@@ -0,0 +1,36 @@
1
+ #!/usr/bin/env node
2
+
3
+ const { program } = require('commander');
4
+ const chalk = require('chalk');
5
+ const { createExpoApp } = require('../lib/createApp');
6
+ const packageJson = require('../package.json');
7
+
8
+ console.log(chalk.cyan.bold(`
9
+ ╔═══════════════════════════════════════════════════════════╗
10
+ ā•‘ ā•‘
11
+ ā•‘ šŸš€ Gufran's Expo Boilerplate Generator šŸš€ ā•‘
12
+ ā•‘ ā•‘
13
+ ā•‘ Create production-ready Expo apps in seconds! ā•‘
14
+ ā•‘ ā•‘
15
+ ā•šā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•
16
+ `));
17
+
18
+ program
19
+ .version(packageJson.version)
20
+ .description('Create a new Expo app using Gufran\'s professional boilerplate')
21
+ .argument('[project-name]', 'Name of your new project')
22
+ .option('-b, --bundle-id <bundleId>', 'Bundle identifier (e.g., com.company.appname)')
23
+ .option('-t, --template <template>', 'Template variant to use', 'default')
24
+ .option('--skip-install', 'Skip dependency installation')
25
+ .option('--skip-git', 'Skip git initialization')
26
+ .option('--npm', 'Use npm instead of yarn')
27
+ .action(async (projectName, options) => {
28
+ try {
29
+ await createExpoApp(projectName, options);
30
+ } catch (error) {
31
+ console.error(chalk.red('\nāŒ Error creating project:'), error.message);
32
+ process.exit(1);
33
+ }
34
+ });
35
+
36
+ program.parse(process.argv);
package/index.js ADDED
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env node
2
+
3
+ // This is the main entry point that will be executed when installed globally
4
+ require('./bin/cli.js');
@@ -0,0 +1,324 @@
1
+ const { execSync } = require('child_process');
2
+ const fs = require('fs');
3
+ const path = require('path');
4
+ const chalk = require('chalk');
5
+ const ora = require('ora');
6
+ const prompts = require('prompts');
7
+ const validateProjectName = require('validate-npm-package-name');
8
+
9
+ /**
10
+ * Execute command with proper error handling
11
+ */
12
+ function executeCommand(command, options = {}) {
13
+ try {
14
+ execSync(command, {
15
+ stdio: options.silent ? 'pipe' : 'inherit',
16
+ ...options
17
+ });
18
+ return true;
19
+ } catch (error) {
20
+ if (!options.ignoreError) {
21
+ throw error;
22
+ }
23
+ return false;
24
+ }
25
+ }
26
+
27
+ /**
28
+ * Check if command exists
29
+ */
30
+ function commandExists(command) {
31
+ try {
32
+ execSync(`command -v ${command}`, { stdio: 'pipe' });
33
+ return true;
34
+ } catch {
35
+ return false;
36
+ }
37
+ }
38
+
39
+ /**
40
+ * Validate project name
41
+ */
42
+ function validateName(name) {
43
+ const validation = validateProjectName(name);
44
+ if (!validation.validForNewPackages) {
45
+ const errors = [
46
+ ...(validation.errors || []),
47
+ ...(validation.warnings || [])
48
+ ];
49
+ throw new Error(`Invalid project name: ${errors.join(', ')}`);
50
+ }
51
+ }
52
+
53
+ /**
54
+ * Generate bundle identifier
55
+ */
56
+ function generateBundleId(projectName, bundleIdPrefix) {
57
+ const cleanName = projectName.toLowerCase().replace(/[^a-z0-9]/g, '');
58
+ return `${bundleIdPrefix}.${cleanName}`;
59
+ }
60
+
61
+ /**
62
+ * Copy directory recursively
63
+ */
64
+ function copyDirectory(src, dest, excludeDirs = []) {
65
+ if (!fs.existsSync(dest)) {
66
+ fs.mkdirSync(dest, { recursive: true });
67
+ }
68
+
69
+ const entries = fs.readdirSync(src, { withFileTypes: true });
70
+
71
+ for (const entry of entries) {
72
+ const srcPath = path.join(src, entry.name);
73
+ const destPath = path.join(dest, entry.name);
74
+
75
+ // Skip excluded directories
76
+ if (excludeDirs.includes(entry.name)) {
77
+ continue;
78
+ }
79
+
80
+ if (entry.isDirectory()) {
81
+ copyDirectory(srcPath, destPath, excludeDirs);
82
+ } else {
83
+ fs.copyFileSync(srcPath, destPath);
84
+ }
85
+ }
86
+ }
87
+
88
+ /**
89
+ * Copy template files and update configurations
90
+ */
91
+ function copyTemplateFiles(templatePath, projectPath, appName, bundleId) {
92
+ // Directories to exclude from copying
93
+ const excludeDirs = [
94
+ 'node_modules',
95
+ '.git',
96
+ 'cli-package',
97
+ 'build',
98
+ 'ios/build',
99
+ 'android/build',
100
+ 'android/.gradle',
101
+ '.expo',
102
+ 'dist',
103
+ 'Pods',
104
+ 'ios/Pods',
105
+ '.idea',
106
+ 'ios/ClubYakka.xcworkspace/xcuserdata',
107
+ 'ios/ClubYakka.xcodeproj/xcuserdata'
108
+ ];
109
+
110
+ // Copy all files except excluded directories
111
+ copyDirectory(templatePath, projectPath, excludeDirs);
112
+ }
113
+
114
+ /**
115
+ * Main function to create the Expo app
116
+ */
117
+ async function createExpoApp(projectName, options) {
118
+ let appName = projectName;
119
+ let bundleId = options.bundleId;
120
+
121
+ // Prompt for project name and bundle ID if not provided
122
+ if (!appName || !bundleId) {
123
+ const responses = await prompts([
124
+ {
125
+ type: 'text',
126
+ name: 'projectName',
127
+ message: 'What is your project name?',
128
+ initial: appName || 'my-expo-app',
129
+ validate: (value) => {
130
+ if (!value) return 'Project name is required';
131
+ const validation = validateProjectName(value);
132
+ if (!validation.validForNewPackages) {
133
+ const errors = [
134
+ ...(validation.errors || []),
135
+ ...(validation.warnings || [])
136
+ ];
137
+ return errors.join(', ');
138
+ }
139
+ return true;
140
+ }
141
+ },
142
+ {
143
+ type: 'text',
144
+ name: 'bundleId',
145
+ message: 'What is your bundle identifier? (e.g., com.appname)',
146
+ initial: (prev) => bundleId || generateBundleId(prev, 'com'),
147
+ validate: (value) => {
148
+ if (!value) return 'Bundle ID is required';
149
+ if (!/^[a-z][a-z0-9]*(\.[a-z][a-z0-9]*)+$/i.test(value)) {
150
+ return 'Invalid bundle ID format. Use format: com.company.appname';
151
+ }
152
+ return true;
153
+ }
154
+ }
155
+ ]);
156
+
157
+ if (!responses.projectName || !responses.bundleId) {
158
+ console.log(chalk.red('\nāŒ Project creation cancelled'));
159
+ process.exit(1);
160
+ }
161
+
162
+ appName = responses.projectName;
163
+ bundleId = responses.bundleId;
164
+ }
165
+
166
+ // Validate project name
167
+ validateName(appName);
168
+
169
+ const projectPath = path.resolve(process.cwd(), appName);
170
+
171
+ // Check if directory already exists
172
+ if (fs.existsSync(projectPath)) {
173
+ console.log(chalk.red(`\nāŒ Directory "${appName}" already exists!`));
174
+ process.exit(1);
175
+ }
176
+
177
+ console.log(chalk.green(`\n✨ Creating a new Expo app: ${chalk.bold(appName)}`));
178
+ console.log(chalk.cyan(`šŸ“¦ Bundle ID: ${chalk.bold(bundleId)}\n`));
179
+
180
+ // Check for Node.js
181
+ let spinner = ora('Checking prerequisites...').start();
182
+ if (!commandExists('node')) {
183
+ spinner.fail('Node.js is not installed. Please install Node.js and try again.');
184
+ process.exit(1);
185
+ }
186
+ spinner.succeed('Prerequisites check passed');
187
+
188
+ // Create project directory
189
+ spinner = ora('Creating project directory...').start();
190
+ try {
191
+ fs.mkdirSync(projectPath, { recursive: true });
192
+ spinner.succeed('Project directory created');
193
+ } catch (error) {
194
+ spinner.fail('Failed to create project directory');
195
+ throw error;
196
+ }
197
+
198
+ // Copy template files from current directory (the boilerplate itself)
199
+ spinner = ora('Copying template files...').start();
200
+ try {
201
+ const templatePath = path.resolve(__dirname, '../../');
202
+ copyTemplateFiles(templatePath, projectPath, appName, bundleId);
203
+ spinner.succeed('Template files copied successfully');
204
+ } catch (error) {
205
+ spinner.fail('Failed to copy template files');
206
+ throw error;
207
+ }
208
+
209
+ // Update package.json
210
+ spinner = ora('Updating package.json...').start();
211
+ const packageJsonPath = path.join(projectPath, 'package.json');
212
+ if (fs.existsSync(packageJsonPath)) {
213
+ const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8'));
214
+ packageJson.name = appName;
215
+ packageJson.version = '1.0.0';
216
+ fs.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2));
217
+ spinner.succeed('package.json updated');
218
+ } else {
219
+ spinner.warn('package.json not found, skipping update');
220
+ }
221
+
222
+ // Update app.json
223
+ spinner = ora('Updating app.json...').start();
224
+ const appJsonPath = path.join(projectPath, 'app.json');
225
+ if (fs.existsSync(appJsonPath)) {
226
+ const appJson = JSON.parse(fs.readFileSync(appJsonPath, 'utf-8'));
227
+ if (appJson.expo) {
228
+ appJson.expo.name = appName;
229
+ appJson.expo.slug = appName.toLowerCase().replace(/[^a-z0-9-]/g, '-');
230
+
231
+ // Update bundle identifiers
232
+ if (appJson.expo.ios) {
233
+ appJson.expo.ios.bundleIdentifier = bundleId;
234
+ } else {
235
+ appJson.expo.ios = { bundleIdentifier: bundleId };
236
+ }
237
+
238
+ if (appJson.expo.android) {
239
+ appJson.expo.android.package = bundleId;
240
+ } else {
241
+ appJson.expo.android = { package: bundleId };
242
+ }
243
+ }
244
+ fs.writeFileSync(appJsonPath, JSON.stringify(appJson, null, 2));
245
+ spinner.succeed('app.json updated with bundle IDs');
246
+ } else {
247
+ spinner.warn('app.json not found, skipping update');
248
+ }
249
+
250
+ // Install dependencies
251
+ if (!options.skipInstall) {
252
+ const useYarn = !options.npm && commandExists('yarn');
253
+ const packageManager = useYarn ? 'yarn' : 'npm';
254
+
255
+ spinner = ora(`Installing dependencies with ${packageManager}...`).start();
256
+ spinner.text = `Installing dependencies... This might take a few minutes ā˜•`;
257
+
258
+ try {
259
+ executeCommand(`cd "${projectPath}" && ${packageManager} install`);
260
+ spinner.succeed('Dependencies installed successfully');
261
+ } catch (error) {
262
+ spinner.fail('Failed to install dependencies');
263
+ console.log(chalk.yellow('\nYou can install dependencies later by running:'));
264
+ console.log(chalk.cyan(` cd ${appName} && ${packageManager} install\n`));
265
+ }
266
+ }
267
+
268
+ // Initialize git
269
+ if (!options.skipGit) {
270
+ spinner = ora('Initializing git repository...').start();
271
+ try {
272
+ executeCommand(`cd "${projectPath}" && git init`, { silent: true });
273
+ executeCommand(`cd "${projectPath}" && git add -A`, { silent: true });
274
+ executeCommand(`cd "${projectPath}" && git commit -m "Initial commit from @gufran/expo-boilerplate"`, { silent: true });
275
+ spinner.succeed('Git repository initialized');
276
+ } catch (error) {
277
+ spinner.warn('Git initialization skipped');
278
+ }
279
+ }
280
+
281
+ // Success message
282
+ console.log(chalk.green.bold('\nšŸŽ‰ Success! Your Expo app is ready!\n'));
283
+ console.log(chalk.cyan('šŸ“ Project created at:'), chalk.bold(projectPath));
284
+ console.log(chalk.cyan('\nšŸ“š Next steps:\n'));
285
+ console.log(chalk.white(` ${chalk.bold('1.')} Navigate to your project:`));
286
+ console.log(chalk.gray(` cd ${appName}\n`));
287
+
288
+ if (options.skipInstall) {
289
+ console.log(chalk.white(` ${chalk.bold('2.')} Install dependencies:`));
290
+ console.log(chalk.gray(` npm install\n`));
291
+ }
292
+
293
+ console.log(chalk.white(` ${chalk.bold(options.skipInstall ? '3' : '2')}. Configure Firebase:`));
294
+ console.log(chalk.gray(` - Add your google-services.json to android/app/`));
295
+ console.log(chalk.gray(` - Add your GoogleService-Info.plist to ios/ClubYakka/\n`));
296
+
297
+ console.log(chalk.white(` ${chalk.bold(options.skipInstall ? '4' : '3')}. Install iOS dependencies:`));
298
+ console.log(chalk.gray(` cd ios && pod install && cd ..\n`));
299
+
300
+ console.log(chalk.white(` ${chalk.bold(options.skipInstall ? '5' : '4')}. Start the development server:`));
301
+ console.log(chalk.gray(` npm start\n`));
302
+
303
+ console.log(chalk.white(` ${chalk.bold(options.skipInstall ? '6' : '5')}. Run on device:`));
304
+ console.log(chalk.gray(` npm run android ${chalk.dim('# For Android')}`));
305
+ console.log(chalk.gray(` npm run ios ${chalk.dim('# For iOS')}\n`));
306
+
307
+ console.log(chalk.cyan('šŸ“– Features included:'));
308
+ console.log(chalk.gray(' āœ… React Navigation with Authentication Flow'));
309
+ console.log(chalk.gray(' āœ… Firebase Integration (Messaging, Analytics)'));
310
+ console.log(chalk.gray(' āœ… Azure Blob Storage Upload'));
311
+ console.log(chalk.gray(' āœ… TanStack Query for API Management'));
312
+ console.log(chalk.gray(' āœ… TypeScript Configuration'));
313
+ console.log(chalk.gray(' āœ… Zustand State Management'));
314
+ console.log(chalk.gray(' āœ… Image Picker & Camera Integration'));
315
+ console.log(chalk.gray(' āœ… Push Notifications with Notifee\n'));
316
+
317
+ console.log(chalk.yellow('āš ļø Important:'));
318
+ console.log(chalk.gray(' Remember to update your app.json with your own configuration'));
319
+ console.log(chalk.gray(' and add your Firebase configuration files!\n'));
320
+
321
+ console.log(chalk.magenta('šŸ’” Happy coding! šŸš€\n'));
322
+ }
323
+
324
+ module.exports = { createExpoApp };
package/package.json ADDED
@@ -0,0 +1,52 @@
1
+ {
2
+ "name": "create-gufran-expo-app",
3
+ "version": "2.0.0",
4
+ "description": "šŸš€ Ultimate Expo React Native Boilerplate - Create production-ready Expo apps instantly with Firebase, Navigation, TypeScript, and more. No git clone needed, works offline!",
5
+ "main": "index.js",
6
+ "bin": {
7
+ "create-gufran-expo-app": "./bin/cli.js"
8
+ },
9
+ "scripts": {
10
+ "test": "echo \"Error: no test specified\" && exit 1",
11
+ "prepare": "chmod +x bin/cli.js"
12
+ },
13
+ "keywords": [
14
+ "react-native",
15
+ "expo",
16
+ "boilerplate",
17
+ "template",
18
+ "firebase",
19
+ "typescript",
20
+ "react-navigation",
21
+ "azure-storage",
22
+ "starter-kit",
23
+ "gufran"
24
+ ],
25
+ "author": "Gufran Gaury <your-email@example.com>",
26
+ "license": "MIT",
27
+ "repository": {
28
+ "type": "git",
29
+ "url": "https://github.com/GufranGaury1887/Boiler_Plat_Expo_-Gufran.git"
30
+ },
31
+ "bugs": {
32
+ "url": "https://github.com/GufranGaury1887/Boiler_Plat_Expo_-Gufran/issues"
33
+ },
34
+ "homepage": "https://github.com/GufranGaury1887/Boiler_Plat_Expo_-Gufran#readme",
35
+ "engines": {
36
+ "node": ">=18.0.0"
37
+ },
38
+ "dependencies": {
39
+ "chalk": "^4.1.2",
40
+ "commander": "^11.1.0",
41
+ "ora": "^5.4.1",
42
+ "prompts": "^2.4.2",
43
+ "validate-npm-package-name": "^5.0.0"
44
+ },
45
+ "files": [
46
+ "bin",
47
+ "lib",
48
+ "template",
49
+ "README.md",
50
+ "LICENSE"
51
+ ]
52
+ }