@imksh/create 1.0.31 → 1.0.32

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.
Files changed (152) hide show
  1. package/README.md +2 -0
  2. package/package.json +1 -1
  3. package/src/commands/create.js +2 -0
  4. package/src/index.js +1 -1
  5. package/templates/layers/next/javascript/package.json +8 -2
  6. package/templates/layers/next/typescript/.eslintrc.json +12 -0
  7. package/templates/layers/next/typescript/package.json +14 -3
  8. package/templates/layers/next/typescript/src/components/common/Loading.tsx +1 -1
  9. package/templates/layers/next/typescript/src/components/common/LottieIcon.tsx +2 -2
  10. package/templates/layers/next/typescript/src/components/common/Table.tsx +4 -4
  11. package/templates/layers/next/typescript/src/components/modals/ConfirmModal.tsx +2 -1
  12. package/templates/layers/next/typescript/src/components/ui/Header.tsx +2 -2
  13. package/templates/layers/next/typescript/src/hooks/usePwaInstall.ts +10 -4
  14. package/templates/layers/next/typescript/src/services/authService.ts +1 -1
  15. package/templates/layers/next/typescript/src/store/useAuthStore.ts +24 -9
  16. package/templates/layers/node/javascript/.env.example +3 -1
  17. package/templates/layers/node/javascript/package.json +12 -3
  18. package/templates/layers/node/javascript/src/app.js +2 -1
  19. package/templates/layers/node/javascript/src/controllers/auth.controller.js +106 -168
  20. package/templates/layers/node/javascript/src/controllers/push.controller.js +51 -58
  21. package/templates/layers/node/javascript/src/controllers/upload.controller.js +12 -19
  22. package/templates/layers/node/javascript/src/middleware/auth.middleware.js +5 -11
  23. package/templates/layers/node/javascript/src/middleware/errorHandler.js +6 -4
  24. package/templates/layers/node/javascript/src/routes/auth.route.js +2 -0
  25. package/templates/layers/node/javascript/src/services/auth.service.js +159 -164
  26. package/templates/layers/node/javascript/src/utils/ApiError.js +20 -0
  27. package/templates/layers/node/javascript/src/utils/SuccessResponse.js +15 -0
  28. package/templates/layers/node/javascript/src/utils/apiResponse.js +4 -0
  29. package/templates/layers/node/javascript/src/utils/asyncHandler.js +5 -0
  30. package/templates/layers/node/typescript/.env.example +3 -1
  31. package/templates/layers/node/typescript/.eslintrc.cjs +28 -0
  32. package/templates/layers/node/typescript/package.json +16 -2
  33. package/templates/layers/node/typescript/src/app.ts +3 -2
  34. package/templates/layers/node/typescript/src/config/db.ts +3 -2
  35. package/templates/layers/node/typescript/src/config/socket.ts +5 -4
  36. package/templates/layers/node/typescript/src/controllers/auth.controller.ts +104 -132
  37. package/templates/layers/node/typescript/src/controllers/push.controller.ts +52 -59
  38. package/templates/layers/node/typescript/src/controllers/upload.controller.ts +12 -19
  39. package/templates/layers/node/typescript/src/middleware/auth.middleware.ts +13 -7
  40. package/templates/layers/node/typescript/src/middleware/errorHandler.ts +18 -5
  41. package/templates/layers/node/typescript/src/middleware/rateLimiter.ts +2 -2
  42. package/templates/layers/node/typescript/src/routes/auth.route.ts +2 -0
  43. package/templates/layers/node/typescript/src/services/auth.service.ts +86 -43
  44. package/templates/layers/node/typescript/src/types/express.d.ts +5 -3
  45. package/templates/layers/node/typescript/src/utils/ApiError.ts +25 -0
  46. package/templates/layers/node/typescript/src/utils/SuccessResponse.ts +17 -0
  47. package/templates/layers/node/typescript/src/utils/apiResponse.ts +4 -0
  48. package/templates/layers/node/typescript/src/utils/asyncHandler.ts +13 -0
  49. package/templates/layers/node/typescript/src/utils/cloudinaryUpload.ts +18 -7
  50. package/templates/layers/node/typescript/src/utils/expoNotification.ts +1 -1
  51. package/templates/layers/node/typescript/src/utils/genOtpToken.ts +7 -1
  52. package/templates/layers/node/typescript/src/utils/jwt.ts +8 -2
  53. package/templates/layers/node/typescript/src/utils/logger.ts +2 -1
  54. package/templates/layers/node/typescript/src/utils/pushHelper.ts +13 -9
  55. package/templates/layers/node-prisma/javascript/.env.example +3 -1
  56. package/templates/layers/node-prisma/javascript/package.json +11 -2
  57. package/templates/layers/node-prisma/javascript/src/app.js +2 -1
  58. package/templates/layers/node-prisma/javascript/src/controllers/auth.controller.js +90 -135
  59. package/templates/layers/node-prisma/javascript/src/controllers/push.controller.js +64 -76
  60. package/templates/layers/node-prisma/javascript/src/controllers/upload.controller.js +12 -19
  61. package/templates/layers/node-prisma/javascript/src/middleware/auth.middleware.js +5 -4
  62. package/templates/layers/node-prisma/javascript/src/middleware/errorHandler.js +6 -4
  63. package/templates/layers/node-prisma/javascript/src/routes/auth.route.js +2 -0
  64. package/templates/layers/node-prisma/javascript/src/services/auth.service.js +145 -122
  65. package/templates/layers/node-prisma/javascript/src/utils/ApiError.js +20 -0
  66. package/templates/layers/node-prisma/javascript/src/utils/SuccessResponse.js +15 -0
  67. package/templates/layers/node-prisma/javascript/src/utils/apiResponse.js +4 -0
  68. package/templates/layers/node-prisma/javascript/src/utils/asyncHandler.js +5 -0
  69. package/templates/layers/node-prisma/typescript/.env.example +3 -1
  70. package/templates/layers/node-prisma/typescript/.eslintrc.cjs +28 -0
  71. package/templates/layers/node-prisma/typescript/package.json +19 -5
  72. package/templates/layers/node-prisma/typescript/src/app.ts +3 -2
  73. package/templates/layers/node-prisma/typescript/src/config/prisma.ts +3 -2
  74. package/templates/layers/node-prisma/typescript/src/config/socket.ts +5 -4
  75. package/templates/layers/node-prisma/typescript/src/controllers/auth.controller.ts +89 -105
  76. package/templates/layers/node-prisma/typescript/src/controllers/push.controller.ts +67 -83
  77. package/templates/layers/node-prisma/typescript/src/controllers/upload.controller.ts +12 -19
  78. package/templates/layers/node-prisma/typescript/src/middleware/auth.middleware.ts +9 -13
  79. package/templates/layers/node-prisma/typescript/src/middleware/errorHandler.ts +18 -5
  80. package/templates/layers/node-prisma/typescript/src/middleware/rateLimiter.ts +2 -2
  81. package/templates/layers/node-prisma/typescript/src/routes/auth.route.ts +2 -0
  82. package/templates/layers/node-prisma/typescript/src/services/auth.service.ts +83 -31
  83. package/templates/layers/node-prisma/typescript/src/types/express.d.ts +5 -3
  84. package/templates/layers/node-prisma/typescript/src/utils/ApiError.ts +25 -0
  85. package/templates/layers/node-prisma/typescript/src/utils/SuccessResponse.ts +17 -0
  86. package/templates/layers/node-prisma/typescript/src/utils/apiResponse.ts +4 -0
  87. package/templates/layers/node-prisma/typescript/src/utils/asyncHandler.ts +13 -0
  88. package/templates/layers/node-prisma/typescript/src/utils/cloudinaryUpload.ts +18 -7
  89. package/templates/layers/node-prisma/typescript/src/utils/genOtpToken.ts +7 -1
  90. package/templates/layers/node-prisma/typescript/src/utils/jwt.ts +8 -2
  91. package/templates/layers/node-prisma/typescript/src/utils/logger.ts +2 -1
  92. package/templates/layers/node-prisma/typescript/src/utils/pushHelper.ts +10 -6
  93. package/templates/layers/prisma/javascript/package.json +8 -0
  94. package/templates/layers/prisma/typescript/package.json +14 -1
  95. package/templates/layers/prisma/typescript/src/config/db.ts +3 -2
  96. package/templates/layers/react/javascript/package.json +6 -0
  97. package/templates/layers/react/typescript/.eslintrc.cjs +20 -0
  98. package/templates/layers/react/typescript/package.json +11 -2
  99. package/templates/layers/react/typescript/src/components/common/Table.tsx +4 -4
  100. package/templates/layers/react/typescript/src/components/ui/Sidebar.tsx +1 -1
  101. package/templates/layers/react/typescript/src/main.tsx +11 -11
  102. package/templates/layers/react/typescript/src/services/authService.ts +1 -1
  103. package/templates/layers/react/typescript/src/store/useAuthStore.ts +24 -9
  104. package/templates/layers/react-native/base/app.json +9 -22
  105. package/templates/layers/react-native/base/eslint.config.js +5 -1
  106. package/templates/layers/react-native/base/package.json +11 -1
  107. package/templates/layers/react-native/base/src/app/(auth)/edit-profile.tsx +7 -7
  108. package/templates/layers/react-native/base/src/app/(auth)/login.tsx +31 -7
  109. package/templates/layers/react-native/base/src/app/(tabs)/_layout.tsx +3 -3
  110. package/templates/layers/react-native/base/src/app/(tabs)/index.tsx +6 -5
  111. package/templates/layers/react-native/base/src/app/_layout.tsx +3 -3
  112. package/templates/layers/react-native/base/src/app/doc-viewer.tsx +3 -3
  113. package/templates/layers/react-native/base/src/components/common/ConfirmationToast.tsx +58 -40
  114. package/templates/layers/react-native/base/src/components/common/GoogleAuthButton.tsx +144 -0
  115. package/templates/layers/react-native/base/src/components/common/LocationLoader.tsx +64 -9
  116. package/templates/layers/react-native/base/src/components/common/Typography.tsx +54 -19
  117. package/templates/layers/react-native/base/src/components/ui/ClassicTabBar.tsx +15 -12
  118. package/templates/layers/react-native/base/src/components/ui/CustomTabBar.tsx +84 -90
  119. package/templates/layers/react-native/base/src/components/ui/Drawer.tsx +344 -0
  120. package/templates/layers/react-native/base/src/components/ui/Sidebar.tsx +4 -4
  121. package/templates/layers/react-native/base/src/components/ui/buttons/Button.tsx +29 -6
  122. package/templates/layers/react-native/base/src/components/ui/data-display/Accordion.tsx +2 -2
  123. package/templates/layers/react-native/base/src/components/ui/data-display/Badge.tsx +1 -2
  124. package/templates/layers/react-native/base/src/components/ui/data-display/Image.tsx +3 -3
  125. package/templates/layers/react-native/base/src/components/ui/data-display/SwipeableRow.tsx +28 -7
  126. package/templates/layers/react-native/base/src/components/ui/feedback/GestureWrapper.tsx +11 -4
  127. package/templates/layers/react-native/base/src/components/ui/inputs/DatePicker.tsx +3 -3
  128. package/templates/layers/react-native/base/src/components/ui/inputs/ImagePickerModal.tsx +45 -19
  129. package/templates/layers/react-native/base/src/components/ui/inputs/Input.tsx +28 -9
  130. package/templates/layers/react-native/base/src/components/ui/inputs/SearchablePicker.tsx +199 -0
  131. package/templates/layers/react-native/base/src/components/ui/inputs/Switch.tsx +7 -7
  132. package/templates/layers/react-native/base/src/components/ui/inputs/WebLocationPicker.tsx +146 -72
  133. package/templates/layers/react-native/base/src/config/api.ts +5 -5
  134. package/templates/layers/react-native/base/src/services/auth.service.ts +3 -1
  135. package/templates/layers/react-native/base/src/services/permission.service.ts +0 -2
  136. package/templates/layers/react-native/base/src/services/socket.service.ts +0 -7
  137. package/templates/layers/react-native/base/src/store/useAuthStore.ts +61 -16
  138. package/templates/layers/react-native/base/src/store/useNotificationStore.ts +36 -42
  139. package/templates/layers/react-native/base/src/types/images.d.ts +7 -5
  140. package/templates/layers/react-native/base/src/utils/fileDownload.ts +206 -0
  141. package/templates/layers/react-native/base/src/utils/storage.ts +1 -1
  142. package/templates/presets/production-fullstack/overrides/client/package.json +9 -0
  143. package/templates/presets/production-fullstack/overrides/mobile/app.json +2 -15
  144. package/templates/presets/production-fullstack/overrides/mobile/package.json +11 -1
  145. package/templates/presets/production-fullstack/overrides/mobile/src/app/_layout.tsx +3 -3
  146. package/templates/presets/production-fullstack/overrides/mobile/src/components/ui/Drawer.tsx +344 -0
  147. package/templates/presets/production-fullstack/overrides/mobile/src/components/ui/inputs/DatePicker.tsx +3 -3
  148. package/templates/presets/production-fullstack/overrides/mobile/src/components/ui/inputs/ImagePickerModal.tsx +3 -3
  149. package/templates/presets/production-fullstack/overrides/server/package.json +11 -2
  150. package/templates/layers/react-native/base/src/components/ui/BottomModal.tsx +0 -176
  151. package/templates/presets/production-fullstack/overrides/mobile/src/components/ui/BottomModal.tsx +0 -159
  152. /package/templates/layers/react-native/base/assets/images/logo/{logoWithBg.png → icon.png} +0 -0
@@ -1,24 +1,26 @@
1
+ import type { ImageSourcePropType } from "react-native";
2
+
1
3
  declare module "*.png" {
2
- const value: any;
4
+ const value: ImageSourcePropType;
3
5
  export default value;
4
6
  }
5
7
 
6
8
  declare module "*.jpg" {
7
- const value: any;
9
+ const value: ImageSourcePropType;
8
10
  export default value;
9
11
  }
10
12
 
11
13
  declare module "*.jpeg" {
12
- const value: any;
14
+ const value: ImageSourcePropType;
13
15
  export default value;
14
16
  }
15
17
 
16
18
  declare module "*.gif" {
17
- const value: any;
19
+ const value: ImageSourcePropType;
18
20
  export default value;
19
21
  }
20
22
 
21
23
  declare module "*.svg" {
22
- const value: any;
24
+ const value: ImageSourcePropType;
23
25
  export default value;
24
26
  }
@@ -0,0 +1,206 @@
1
+ import { Platform } from "react-native";
2
+ import { toast } from "./toast";
3
+ import * as FileSystem from "expo-file-system/legacy";
4
+ import * as Sharing from "expo-sharing";
5
+
6
+ /**
7
+ * Downloads a string or base64 data to a file.
8
+ * - On Web: triggers browser download via an anchor element and Blob.
9
+ * - On Android: saves to user-selected folder via StorageAccessFramework.
10
+ * - On iOS: writes to app document directory and opens native iOS Share/Save sheet.
11
+ */
12
+ export const downloadFileString = async (
13
+ content: string,
14
+ filename: string,
15
+ mimeType: string,
16
+ isBase64: boolean = false
17
+ ): Promise<boolean> => {
18
+ if (Platform.OS === "web") {
19
+ try {
20
+ let blob: Blob;
21
+ if (isBase64) {
22
+ const byteCharacters = atob(content);
23
+ const byteArrays: Uint8Array[] = [];
24
+ for (let offset = 0; offset < byteCharacters.length; offset += 512) {
25
+ const slice = byteCharacters.slice(offset, offset + 512);
26
+ const byteNumbers = new Array(slice.length);
27
+ for (let i = 0; i < slice.length; i++) {
28
+ byteNumbers[i] = slice.charCodeAt(i);
29
+ }
30
+ const byteArray = new Uint8Array(byteNumbers);
31
+ byteArrays.push(byteArray);
32
+ }
33
+ blob = new Blob(byteArrays, { type: mimeType });
34
+ } else {
35
+ blob = new Blob([content], { type: mimeType });
36
+ }
37
+ const link = document.createElement("a");
38
+ const url = URL.createObjectURL(blob);
39
+ link.setAttribute("href", url);
40
+ link.setAttribute("download", filename);
41
+ link.style.visibility = "hidden";
42
+ document.body.appendChild(link);
43
+ link.click();
44
+ document.body.removeChild(link);
45
+ URL.revokeObjectURL(url);
46
+ return true;
47
+ } catch (error: unknown) {
48
+ const err = error as Error;
49
+ toast.error("Error", err.message || `Failed to download ${filename}`);
50
+ return false;
51
+ }
52
+ }
53
+
54
+ try {
55
+ const encoding = isBase64
56
+ ? FileSystem.EncodingType.Base64
57
+ : FileSystem.EncodingType.UTF8;
58
+
59
+ if (Platform.OS === "android") {
60
+ const permissions =
61
+ await FileSystem.StorageAccessFramework.requestDirectoryPermissionsAsync();
62
+ if (!permissions.granted) {
63
+ toast.info("Cancelled", "Directory permission was not granted.");
64
+ return false;
65
+ }
66
+
67
+ const createdFileUri =
68
+ await FileSystem.StorageAccessFramework.createFileAsync(
69
+ permissions.directoryUri,
70
+ filename,
71
+ mimeType
72
+ );
73
+ await FileSystem.writeAsStringAsync(createdFileUri, content, {
74
+ encoding,
75
+ });
76
+ toast.success("Success", `${filename} saved successfully!`);
77
+ return true;
78
+ }
79
+
80
+ // iOS and other native platforms
81
+ const baseDir =
82
+ FileSystem.documentDirectory ?? FileSystem.cacheDirectory ?? "";
83
+ const fileUri = `${baseDir}${filename}`;
84
+ await FileSystem.writeAsStringAsync(fileUri, content, { encoding });
85
+
86
+ const isSharingAvailable = await Sharing.isAvailableAsync();
87
+ if (isSharingAvailable) {
88
+ await Sharing.shareAsync(fileUri, {
89
+ mimeType,
90
+ dialogTitle: `Save ${filename}`,
91
+ UTI: mimeType,
92
+ });
93
+ toast.success("Success", "File ready to save or share.");
94
+ return true;
95
+ } else {
96
+ toast.error("Error", "Sharing is not available on this device.");
97
+ return false;
98
+ }
99
+ } catch (error: unknown) {
100
+ const err = error as Error;
101
+ toast.error("Error", err.message || `Failed to download ${filename}`);
102
+ return false;
103
+ }
104
+ };
105
+
106
+ /**
107
+ * Downloads a CSV string as a .csv file.
108
+ */
109
+ export const downloadCsvString = async (
110
+ csvString: string,
111
+ filename: string = "export.csv"
112
+ ): Promise<boolean> => {
113
+ return downloadFileString(csvString, filename, "text/csv;charset=utf-8;");
114
+ };
115
+
116
+ /**
117
+ * Downloads JSON data as a formatted .json file.
118
+ */
119
+ export const downloadJson = async (
120
+ data: unknown,
121
+ filename: string = "export.json"
122
+ ): Promise<boolean> => {
123
+ const jsonString = JSON.stringify(data, null, 2);
124
+ return downloadFileString(jsonString, filename, "application/json");
125
+ };
126
+
127
+ /**
128
+ * Downloads a file from a remote URL.
129
+ * - On Web: triggers browser download.
130
+ * - On Mobile: downloads to local filesystem, then prompts to save on Android
131
+ * via StorageAccessFramework or opens iOS Share sheet.
132
+ */
133
+ export const downloadFileFromUrl = async (
134
+ url: string,
135
+ filename: string,
136
+ mimeType: string = "application/octet-stream"
137
+ ): Promise<boolean> => {
138
+ if (Platform.OS === "web") {
139
+ try {
140
+ const link = document.createElement("a");
141
+ link.href = url;
142
+ link.download = filename;
143
+ link.target = "_blank";
144
+ link.style.visibility = "hidden";
145
+ document.body.appendChild(link);
146
+ link.click();
147
+ document.body.removeChild(link);
148
+ return true;
149
+ } catch (error: unknown) {
150
+ const err = error as Error;
151
+ toast.error("Error", err.message || `Failed to download ${filename}`);
152
+ return false;
153
+ }
154
+ }
155
+
156
+ try {
157
+ const baseDir =
158
+ FileSystem.cacheDirectory ?? FileSystem.documentDirectory ?? "";
159
+ const localUri = `${baseDir}${filename}`;
160
+ const result = await FileSystem.downloadAsync(url, localUri);
161
+
162
+ if (Platform.OS === "android") {
163
+ const permissions =
164
+ await FileSystem.StorageAccessFramework.requestDirectoryPermissionsAsync();
165
+ if (!permissions.granted) {
166
+ toast.info("Cancelled", "Directory permission was not granted.");
167
+ return false;
168
+ }
169
+
170
+ const fileBase64 = await FileSystem.readAsStringAsync(result.uri, {
171
+ encoding: FileSystem.EncodingType.Base64,
172
+ });
173
+
174
+ const createdFileUri =
175
+ await FileSystem.StorageAccessFramework.createFileAsync(
176
+ permissions.directoryUri,
177
+ filename,
178
+ mimeType
179
+ );
180
+
181
+ await FileSystem.writeAsStringAsync(createdFileUri, fileBase64, {
182
+ encoding: FileSystem.EncodingType.Base64,
183
+ });
184
+
185
+ toast.success("Success", `${filename} saved successfully!`);
186
+ return true;
187
+ }
188
+
189
+ const isSharingAvailable = await Sharing.isAvailableAsync();
190
+ if (isSharingAvailable) {
191
+ await Sharing.shareAsync(result.uri, {
192
+ mimeType,
193
+ dialogTitle: `Save ${filename}`,
194
+ });
195
+ toast.success("Success", "File ready to save or share.");
196
+ return true;
197
+ } else {
198
+ toast.error("Error", "Sharing is not available on this device.");
199
+ return false;
200
+ }
201
+ } catch (error: unknown) {
202
+ const err = error as Error;
203
+ toast.error("Error", err.message || `Failed to download ${filename}`);
204
+ return false;
205
+ }
206
+ };
@@ -1,7 +1,7 @@
1
1
  import AsyncStorage from '@react-native-async-storage/async-storage';
2
2
 
3
3
  // Save data
4
- export const save = async (key: string, value: any) => {
4
+ export const save = async (key: string, value: unknown) => {
5
5
  if (!key || !value) return;
6
6
  try {
7
7
  const jsonValue = JSON.stringify(value);
@@ -7,6 +7,12 @@
7
7
  "dev": "vite",
8
8
  "build": "tsc && vite build",
9
9
  "lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
10
+ "lint:fix": "eslint . --ext ts,tsx --fix",
11
+ "format": "prettier --write \"src/**/*.{ts,tsx,css,json}\"",
12
+ "format:check": "prettier --check \"src/**/*.{ts,tsx,css,json}\"",
13
+ "circular-check": "dpdm --circular --no-warning --no-tree --exit-code circular:1 \"src/**/*.{ts,tsx}\"",
14
+ "ts-prune": "ts-prune",
15
+ "ts-purns": "ts-prune",
10
16
  "preview": "vite preview"
11
17
  },
12
18
  "dependencies": {
@@ -37,10 +43,13 @@
37
43
  "@typescript-eslint/eslint-plugin": "^6.10.0",
38
44
  "@typescript-eslint/parser": "^6.10.0",
39
45
  "@vitejs/plugin-react": "^4.2.0",
46
+ "dpdm": "^3.14.0",
40
47
  "eslint": "^8.53.0",
41
48
  "eslint-plugin-react": "^7.33.2",
42
49
  "eslint-plugin-react-hooks": "^4.6.0",
43
50
  "eslint-plugin-react-refresh": "^0.4.4",
51
+ "prettier": "^3.4.2",
52
+ "ts-prune": "^0.10.3",
44
53
  "typescript": "^5.2.2",
45
54
  "vite": "^5.0.0"
46
55
  }
@@ -22,16 +22,8 @@
22
22
  "package": "com.anonymous.mobile",
23
23
  "permissions": [
24
24
  "android.permission.CAMERA",
25
- "android.permission.RECORD_AUDIO",
26
25
  "android.permission.ACCESS_FINE_LOCATION",
27
- "android.permission.ACCESS_COARSE_LOCATION",
28
- "android.permission.READ_CONTACTS",
29
- "android.permission.READ_CALENDAR",
30
- "android.permission.READ_EXTERNAL_STORAGE",
31
- "android.permission.WRITE_EXTERNAL_STORAGE",
32
- "android.permission.BLUETOOTH_CONNECT",
33
- "android.permission.BLUETOOTH_SCAN",
34
- "android.permission.CALL_PHONE"
26
+ "android.permission.ACCESS_COARSE_LOCATION"
35
27
  ]
36
28
  },
37
29
  "web": {
@@ -58,14 +50,9 @@
58
50
  {
59
51
  "iosPermissions": [
60
52
  "Camera",
61
- "Microphone",
62
- "LocationAlways",
63
53
  "LocationWhenInUse",
64
54
  "Notifications",
65
- "PhotoLibrary",
66
- "Contacts",
67
- "Calendars",
68
- "BluetoothPeripheral"
55
+ "PhotoLibrary"
69
56
  ]
70
57
  }
71
58
  ]
@@ -18,6 +18,8 @@
18
18
  "expo-blur": "~57.0.2",
19
19
  "expo-constants": "~57.0.6",
20
20
  "expo-device": "~57.0.1",
21
+ "expo-file-system": "~18.0.7",
22
+ "expo-sharing": "~13.0.1",
21
23
  "expo-font": "~57.0.1",
22
24
  "expo-glass-effect": "~57.0.1",
23
25
  "expo-image": "~57.0.1",
@@ -61,9 +63,12 @@
61
63
  "devDependencies": {
62
64
  "@types/react": "~19.2.2",
63
65
  "babel-plugin-inline-import": "^3.0.0",
66
+ "dpdm": "^3.14.0",
64
67
  "drizzle-kit": "^0.31.10",
65
68
  "eslint": "^9.0.0",
66
69
  "eslint-config-expo": "~57.0.0",
70
+ "prettier": "^3.4.2",
71
+ "ts-prune": "^0.10.3",
67
72
  "typescript": "~6.0.3"
68
73
  },
69
74
  "scripts": {
@@ -74,7 +79,12 @@
74
79
  "ios": "expo run:ios",
75
80
  "web": "expo start --web",
76
81
  "lint": "expo lint",
77
- "format": "expo lint --fix",
82
+ "lint:fix": "expo lint --fix",
83
+ "format": "prettier --write \"src/**/*.{ts,tsx,json}\"",
84
+ "format:check": "prettier --check \"src/**/*.{ts,tsx,json}\"",
85
+ "circular-check": "dpdm --circular --no-warning --no-tree --exit-code circular:1 \"src/**/*.{ts,tsx}\"",
86
+ "ts-prune": "ts-prune",
87
+ "ts-purns": "ts-prune",
78
88
  "ts:check": "tsc --noEmit",
79
89
  "build": "eas build",
80
90
  "build:android": "eas build -p android",
@@ -63,8 +63,8 @@ export default function RootLayout() {
63
63
  if (!user && !inAuthGroup) {
64
64
  // Redirect to the auth group
65
65
  router.replace("/(auth)/login");
66
- } else if (user && inAuthGroup) {
67
- // Redirect away from auth
66
+ } else if (user && (inAuthGroup || !segments[0])) {
67
+ // Redirect away from auth or root to main app tabs
68
68
  router.replace("/(tabs)");
69
69
  }
70
70
  }, [user, isCheckingAuth, segments]);
@@ -94,8 +94,8 @@ export default function RootLayout() {
94
94
  options={{ headerShown: false, animation: "fade" }}
95
95
  />
96
96
  </Stack>
97
- <Toast />
98
97
  </PaperProvider>
98
+ <Toast />
99
99
  </GestureHandlerRootView>
100
100
  </QueryClientProvider>
101
101
  );