@oxyhq/services 5.4.2 → 5.4.4

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 (418) hide show
  1. package/README.md +14 -0
  2. package/lib/commonjs/assets/OxyLogo.svg +1 -0
  3. package/lib/commonjs/assets/assets/OxyLogo.svg +1 -0
  4. package/lib/commonjs/assets/assets/fonts/Phudu/Phudu-Black.ttf +0 -0
  5. package/lib/commonjs/assets/assets/fonts/Phudu/Phudu-Bold.ttf +0 -0
  6. package/lib/commonjs/assets/assets/fonts/Phudu/Phudu-ExtraBold.ttf +0 -0
  7. package/lib/commonjs/assets/assets/fonts/Phudu/Phudu-Light.ttf +0 -0
  8. package/lib/commonjs/assets/assets/fonts/Phudu/Phudu-Medium.ttf +0 -0
  9. package/lib/commonjs/assets/assets/fonts/Phudu/Phudu-Regular.ttf +0 -0
  10. package/lib/commonjs/assets/assets/fonts/Phudu/Phudu-SemiBold.ttf +0 -0
  11. package/lib/commonjs/assets/assets/icons/OxyServices.tsx +67 -0
  12. package/lib/commonjs/assets/assets/icons/logo_OxyServices.svg +1 -0
  13. package/lib/commonjs/assets/assets/illustrations/HighFive.tsx +41 -0
  14. package/lib/commonjs/assets/fonts/Phudu/Phudu-Black.ttf +0 -0
  15. package/lib/commonjs/assets/fonts/Phudu/Phudu-Bold.ttf +0 -0
  16. package/lib/commonjs/assets/fonts/Phudu/Phudu-ExtraBold.ttf +0 -0
  17. package/lib/commonjs/assets/fonts/Phudu/Phudu-Light.ttf +0 -0
  18. package/lib/commonjs/assets/fonts/Phudu/Phudu-Medium.ttf +0 -0
  19. package/lib/commonjs/assets/fonts/Phudu/Phudu-Regular.ttf +0 -0
  20. package/lib/commonjs/assets/fonts/Phudu/Phudu-SemiBold.ttf +0 -0
  21. package/lib/commonjs/assets/icons/OxyServices.js +53 -0
  22. package/lib/commonjs/assets/icons/OxyServices.js.map +1 -0
  23. package/lib/commonjs/assets/icons/logo_OxyServices.svg +1 -0
  24. package/lib/commonjs/assets/illustrations/HighFive.js +61 -0
  25. package/lib/commonjs/assets/illustrations/HighFive.js.map +1 -0
  26. package/lib/commonjs/constants/version.js +28 -0
  27. package/lib/commonjs/constants/version.js.map +1 -0
  28. package/lib/commonjs/core/index.js +1660 -0
  29. package/lib/commonjs/core/index.js.map +1 -0
  30. package/lib/commonjs/index.js +160 -0
  31. package/lib/commonjs/index.js.map +1 -0
  32. package/lib/commonjs/lib/sonner.js +21 -0
  33. package/lib/commonjs/lib/sonner.js.map +1 -0
  34. package/lib/commonjs/models/interfaces.js +2 -0
  35. package/lib/commonjs/models/interfaces.js.map +1 -0
  36. package/lib/commonjs/models/secureSession.js +2 -0
  37. package/lib/commonjs/models/secureSession.js.map +1 -0
  38. package/lib/commonjs/node/createAuth.js +95 -0
  39. package/lib/commonjs/node/createAuth.js.map +1 -0
  40. package/lib/commonjs/node/index.js +63 -0
  41. package/lib/commonjs/node/index.js.map +1 -0
  42. package/lib/commonjs/package.json +1 -0
  43. package/lib/commonjs/ui/components/Avatar.js +98 -0
  44. package/lib/commonjs/ui/components/Avatar.js.map +1 -0
  45. package/lib/commonjs/ui/components/FollowButton.js +246 -0
  46. package/lib/commonjs/ui/components/FollowButton.js.map +1 -0
  47. package/lib/commonjs/ui/components/FontLoader.js +181 -0
  48. package/lib/commonjs/ui/components/FontLoader.js.map +1 -0
  49. package/lib/commonjs/ui/components/GroupedItem.js +109 -0
  50. package/lib/commonjs/ui/components/GroupedItem.js.map +1 -0
  51. package/lib/commonjs/ui/components/GroupedSection.js +33 -0
  52. package/lib/commonjs/ui/components/GroupedSection.js.map +1 -0
  53. package/lib/commonjs/ui/components/OxyLogo.js +56 -0
  54. package/lib/commonjs/ui/components/OxyLogo.js.map +1 -0
  55. package/lib/commonjs/ui/components/OxyProvider.js +522 -0
  56. package/lib/commonjs/ui/components/OxyProvider.js.map +1 -0
  57. package/lib/commonjs/ui/components/OxySignInButton.js +178 -0
  58. package/lib/commonjs/ui/components/OxySignInButton.js.map +1 -0
  59. package/lib/commonjs/ui/components/ProfileCard.js +124 -0
  60. package/lib/commonjs/ui/components/ProfileCard.js.map +1 -0
  61. package/lib/commonjs/ui/components/QuickActions.js +87 -0
  62. package/lib/commonjs/ui/components/QuickActions.js.map +1 -0
  63. package/lib/commonjs/ui/components/Section.js +36 -0
  64. package/lib/commonjs/ui/components/Section.js.map +1 -0
  65. package/lib/commonjs/ui/components/SectionTitle.js +35 -0
  66. package/lib/commonjs/ui/components/SectionTitle.js.map +1 -0
  67. package/lib/commonjs/ui/components/bottomSheet/index.js +37 -0
  68. package/lib/commonjs/ui/components/bottomSheet/index.js.map +1 -0
  69. package/lib/commonjs/ui/components/icon/OxyIcon.js +27 -0
  70. package/lib/commonjs/ui/components/icon/OxyIcon.js.map +1 -0
  71. package/lib/commonjs/ui/components/icon/index.js +14 -0
  72. package/lib/commonjs/ui/components/icon/index.js.map +1 -0
  73. package/lib/commonjs/ui/components/index.js +97 -0
  74. package/lib/commonjs/ui/components/index.js.map +1 -0
  75. package/lib/commonjs/ui/components/internal/GroupedPillButtons.js +213 -0
  76. package/lib/commonjs/ui/components/internal/GroupedPillButtons.js.map +1 -0
  77. package/lib/commonjs/ui/components/internal/TextField.js +576 -0
  78. package/lib/commonjs/ui/components/internal/TextField.js.map +1 -0
  79. package/lib/commonjs/ui/context/OxyContext.js +584 -0
  80. package/lib/commonjs/ui/context/OxyContext.js.map +1 -0
  81. package/lib/commonjs/ui/index.js +136 -0
  82. package/lib/commonjs/ui/index.js.map +1 -0
  83. package/lib/commonjs/ui/navigation/OxyRouter.js +269 -0
  84. package/lib/commonjs/ui/navigation/OxyRouter.js.map +1 -0
  85. package/lib/commonjs/ui/navigation/types.js +6 -0
  86. package/lib/commonjs/ui/navigation/types.js.map +1 -0
  87. package/lib/commonjs/ui/screens/AccountCenterScreen.js +313 -0
  88. package/lib/commonjs/ui/screens/AccountCenterScreen.js.map +1 -0
  89. package/lib/commonjs/ui/screens/AccountManagementDemo.js +299 -0
  90. package/lib/commonjs/ui/screens/AccountManagementDemo.js.map +1 -0
  91. package/lib/commonjs/ui/screens/AccountOverviewScreen.js +855 -0
  92. package/lib/commonjs/ui/screens/AccountOverviewScreen.js.map +1 -0
  93. package/lib/commonjs/ui/screens/AccountSettingsScreen.js +843 -0
  94. package/lib/commonjs/ui/screens/AccountSettingsScreen.js.map +1 -0
  95. package/lib/commonjs/ui/screens/AccountSwitcherScreen.js +788 -0
  96. package/lib/commonjs/ui/screens/AccountSwitcherScreen.js.map +1 -0
  97. package/lib/commonjs/ui/screens/AppInfoScreen.js +664 -0
  98. package/lib/commonjs/ui/screens/AppInfoScreen.js.map +1 -0
  99. package/lib/commonjs/ui/screens/BillingManagementScreen.js +636 -0
  100. package/lib/commonjs/ui/screens/BillingManagementScreen.js.map +1 -0
  101. package/lib/commonjs/ui/screens/FeedbackScreen.js +1169 -0
  102. package/lib/commonjs/ui/screens/FeedbackScreen.js.map +1 -0
  103. package/lib/commonjs/ui/screens/FileManagementScreen.js +2515 -0
  104. package/lib/commonjs/ui/screens/FileManagementScreen.js.map +1 -0
  105. package/lib/commonjs/ui/screens/PremiumSubscriptionScreen.js +1620 -0
  106. package/lib/commonjs/ui/screens/PremiumSubscriptionScreen.js.map +1 -0
  107. package/lib/commonjs/ui/screens/ProfileScreen.js +450 -0
  108. package/lib/commonjs/ui/screens/ProfileScreen.js.map +1 -0
  109. package/lib/commonjs/ui/screens/SessionManagementScreen.js +449 -0
  110. package/lib/commonjs/ui/screens/SessionManagementScreen.js.map +1 -0
  111. package/lib/commonjs/ui/screens/SignInScreen.js +882 -0
  112. package/lib/commonjs/ui/screens/SignInScreen.js.map +1 -0
  113. package/lib/commonjs/ui/screens/SignUpScreen.js +1036 -0
  114. package/lib/commonjs/ui/screens/SignUpScreen.js.map +1 -0
  115. package/lib/commonjs/ui/screens/karma/KarmaAboutScreen.js +88 -0
  116. package/lib/commonjs/ui/screens/karma/KarmaAboutScreen.js.map +1 -0
  117. package/lib/commonjs/ui/screens/karma/KarmaCenterScreen.js +364 -0
  118. package/lib/commonjs/ui/screens/karma/KarmaCenterScreen.js.map +1 -0
  119. package/lib/commonjs/ui/screens/karma/KarmaFAQScreen.js +227 -0
  120. package/lib/commonjs/ui/screens/karma/KarmaFAQScreen.js.map +1 -0
  121. package/lib/commonjs/ui/screens/karma/KarmaLeaderboardScreen.js +148 -0
  122. package/lib/commonjs/ui/screens/karma/KarmaLeaderboardScreen.js.map +1 -0
  123. package/lib/commonjs/ui/screens/karma/KarmaRewardsScreen.js +127 -0
  124. package/lib/commonjs/ui/screens/karma/KarmaRewardsScreen.js.map +1 -0
  125. package/lib/commonjs/ui/screens/karma/KarmaRulesScreen.js +105 -0
  126. package/lib/commonjs/ui/screens/karma/KarmaRulesScreen.js.map +1 -0
  127. package/lib/commonjs/ui/store/index.js +52 -0
  128. package/lib/commonjs/ui/store/index.js.map +1 -0
  129. package/lib/commonjs/ui/styles/FONTS.md +126 -0
  130. package/lib/commonjs/ui/styles/fonts.js +84 -0
  131. package/lib/commonjs/ui/styles/fonts.js.map +1 -0
  132. package/lib/commonjs/ui/styles/index.js +28 -0
  133. package/lib/commonjs/ui/styles/index.js.map +1 -0
  134. package/lib/commonjs/ui/styles/theme.js +121 -0
  135. package/lib/commonjs/ui/styles/theme.js.map +1 -0
  136. package/lib/commonjs/utils/deviceManager.js +173 -0
  137. package/lib/commonjs/utils/deviceManager.js.map +1 -0
  138. package/lib/commonjs/utils/index.js +13 -0
  139. package/lib/commonjs/utils/index.js.map +1 -0
  140. package/lib/commonjs/utils/polyfills.js +42 -0
  141. package/lib/commonjs/utils/polyfills.js.map +1 -0
  142. package/lib/module/assets/OxyLogo.svg +1 -0
  143. package/lib/module/assets/assets/OxyLogo.svg +1 -0
  144. package/lib/module/assets/assets/fonts/Phudu/Phudu-Black.ttf +0 -0
  145. package/lib/module/assets/assets/fonts/Phudu/Phudu-Bold.ttf +0 -0
  146. package/lib/module/assets/assets/fonts/Phudu/Phudu-ExtraBold.ttf +0 -0
  147. package/lib/module/assets/assets/fonts/Phudu/Phudu-Light.ttf +0 -0
  148. package/lib/module/assets/assets/fonts/Phudu/Phudu-Medium.ttf +0 -0
  149. package/lib/module/assets/assets/fonts/Phudu/Phudu-Regular.ttf +0 -0
  150. package/lib/module/assets/assets/fonts/Phudu/Phudu-SemiBold.ttf +0 -0
  151. package/lib/module/assets/assets/icons/OxyServices.tsx +67 -0
  152. package/lib/module/assets/assets/icons/logo_OxyServices.svg +1 -0
  153. package/lib/module/assets/assets/illustrations/HighFive.tsx +41 -0
  154. package/lib/module/assets/fonts/Phudu/Phudu-Black.ttf +0 -0
  155. package/lib/module/assets/fonts/Phudu/Phudu-Bold.ttf +0 -0
  156. package/lib/module/assets/fonts/Phudu/Phudu-ExtraBold.ttf +0 -0
  157. package/lib/module/assets/fonts/Phudu/Phudu-Light.ttf +0 -0
  158. package/lib/module/assets/fonts/Phudu/Phudu-Medium.ttf +0 -0
  159. package/lib/module/assets/fonts/Phudu/Phudu-Regular.ttf +0 -0
  160. package/lib/module/assets/fonts/Phudu/Phudu-SemiBold.ttf +0 -0
  161. package/lib/module/assets/icons/OxyServices.js +46 -0
  162. package/lib/module/assets/icons/OxyServices.js.map +1 -0
  163. package/lib/module/assets/icons/logo_OxyServices.svg +1 -0
  164. package/lib/module/assets/illustrations/HighFive.js +55 -0
  165. package/lib/module/assets/illustrations/HighFive.js.map +1 -0
  166. package/lib/module/constants/version.js +21 -0
  167. package/lib/module/constants/version.js.map +1 -0
  168. package/lib/module/core/index.js +1634 -0
  169. package/lib/module/core/index.js.map +1 -0
  170. package/lib/module/index.js +48 -0
  171. package/lib/module/index.js.map +1 -0
  172. package/lib/module/lib/sonner.js +16 -0
  173. package/lib/module/lib/sonner.js.map +1 -0
  174. package/lib/module/models/interfaces.js +2 -0
  175. package/lib/module/models/interfaces.js.map +1 -0
  176. package/lib/module/models/secureSession.js +2 -0
  177. package/lib/module/models/secureSession.js.map +1 -0
  178. package/lib/module/node/createAuth.js +90 -0
  179. package/lib/module/node/createAuth.js.map +1 -0
  180. package/lib/module/node/index.js +27 -0
  181. package/lib/module/node/index.js.map +1 -0
  182. package/lib/module/package.json +1 -0
  183. package/lib/module/ui/components/Avatar.js +93 -0
  184. package/lib/module/ui/components/Avatar.js.map +1 -0
  185. package/lib/module/ui/components/FollowButton.js +241 -0
  186. package/lib/module/ui/components/FollowButton.js.map +1 -0
  187. package/lib/module/ui/components/FontLoader.js +176 -0
  188. package/lib/module/ui/components/FontLoader.js.map +1 -0
  189. package/lib/module/ui/components/GroupedItem.js +104 -0
  190. package/lib/module/ui/components/GroupedItem.js.map +1 -0
  191. package/lib/module/ui/components/GroupedSection.js +28 -0
  192. package/lib/module/ui/components/GroupedSection.js.map +1 -0
  193. package/lib/module/ui/components/OxyLogo.js +49 -0
  194. package/lib/module/ui/components/OxyLogo.js.map +1 -0
  195. package/lib/module/ui/components/OxyProvider.js +516 -0
  196. package/lib/module/ui/components/OxyProvider.js.map +1 -0
  197. package/lib/module/ui/components/OxySignInButton.js +172 -0
  198. package/lib/module/ui/components/OxySignInButton.js.map +1 -0
  199. package/lib/module/ui/components/ProfileCard.js +119 -0
  200. package/lib/module/ui/components/ProfileCard.js.map +1 -0
  201. package/lib/module/ui/components/QuickActions.js +82 -0
  202. package/lib/module/ui/components/QuickActions.js.map +1 -0
  203. package/lib/module/ui/components/Section.js +31 -0
  204. package/lib/module/ui/components/Section.js.map +1 -0
  205. package/lib/module/ui/components/SectionTitle.js +30 -0
  206. package/lib/module/ui/components/SectionTitle.js.map +1 -0
  207. package/lib/module/ui/components/bottomSheet/index.js +5 -0
  208. package/lib/module/ui/components/bottomSheet/index.js.map +1 -0
  209. package/lib/module/ui/components/icon/OxyIcon.js +22 -0
  210. package/lib/module/ui/components/icon/OxyIcon.js.map +1 -0
  211. package/lib/module/ui/components/icon/index.js +4 -0
  212. package/lib/module/ui/components/icon/index.js.map +1 -0
  213. package/lib/module/ui/components/index.js +18 -0
  214. package/lib/module/ui/components/index.js.map +1 -0
  215. package/lib/module/ui/components/internal/GroupedPillButtons.js +208 -0
  216. package/lib/module/ui/components/internal/GroupedPillButtons.js.map +1 -0
  217. package/lib/module/ui/components/internal/TextField.js +571 -0
  218. package/lib/module/ui/components/internal/TextField.js.map +1 -0
  219. package/lib/module/ui/context/OxyContext.js +579 -0
  220. package/lib/module/ui/context/OxyContext.js.map +1 -0
  221. package/lib/module/ui/index.js +26 -0
  222. package/lib/module/ui/index.js.map +1 -0
  223. package/lib/module/ui/navigation/OxyRouter.js +262 -0
  224. package/lib/module/ui/navigation/OxyRouter.js.map +1 -0
  225. package/lib/module/ui/navigation/types.js +4 -0
  226. package/lib/module/ui/navigation/types.js.map +1 -0
  227. package/lib/module/ui/screens/AccountCenterScreen.js +308 -0
  228. package/lib/module/ui/screens/AccountCenterScreen.js.map +1 -0
  229. package/lib/module/ui/screens/AccountManagementDemo.js +296 -0
  230. package/lib/module/ui/screens/AccountManagementDemo.js.map +1 -0
  231. package/lib/module/ui/screens/AccountOverviewScreen.js +849 -0
  232. package/lib/module/ui/screens/AccountOverviewScreen.js.map +1 -0
  233. package/lib/module/ui/screens/AccountSettingsScreen.js +837 -0
  234. package/lib/module/ui/screens/AccountSettingsScreen.js.map +1 -0
  235. package/lib/module/ui/screens/AccountSwitcherScreen.js +782 -0
  236. package/lib/module/ui/screens/AccountSwitcherScreen.js.map +1 -0
  237. package/lib/module/ui/screens/AppInfoScreen.js +658 -0
  238. package/lib/module/ui/screens/AppInfoScreen.js.map +1 -0
  239. package/lib/module/ui/screens/BillingManagementScreen.js +631 -0
  240. package/lib/module/ui/screens/BillingManagementScreen.js.map +1 -0
  241. package/lib/module/ui/screens/FeedbackScreen.js +1164 -0
  242. package/lib/module/ui/screens/FeedbackScreen.js.map +1 -0
  243. package/lib/module/ui/screens/FileManagementScreen.js +2510 -0
  244. package/lib/module/ui/screens/FileManagementScreen.js.map +1 -0
  245. package/lib/module/ui/screens/PremiumSubscriptionScreen.js +1615 -0
  246. package/lib/module/ui/screens/PremiumSubscriptionScreen.js.map +1 -0
  247. package/lib/module/ui/screens/ProfileScreen.js +444 -0
  248. package/lib/module/ui/screens/ProfileScreen.js.map +1 -0
  249. package/lib/module/ui/screens/SessionManagementScreen.js +444 -0
  250. package/lib/module/ui/screens/SessionManagementScreen.js.map +1 -0
  251. package/lib/module/ui/screens/SignInScreen.js +876 -0
  252. package/lib/module/ui/screens/SignInScreen.js.map +1 -0
  253. package/lib/module/ui/screens/SignUpScreen.js +1030 -0
  254. package/lib/module/ui/screens/SignUpScreen.js.map +1 -0
  255. package/lib/module/ui/screens/karma/KarmaAboutScreen.js +83 -0
  256. package/lib/module/ui/screens/karma/KarmaAboutScreen.js.map +1 -0
  257. package/lib/module/ui/screens/karma/KarmaCenterScreen.js +358 -0
  258. package/lib/module/ui/screens/karma/KarmaCenterScreen.js.map +1 -0
  259. package/lib/module/ui/screens/karma/KarmaFAQScreen.js +222 -0
  260. package/lib/module/ui/screens/karma/KarmaFAQScreen.js.map +1 -0
  261. package/lib/module/ui/screens/karma/KarmaLeaderboardScreen.js +142 -0
  262. package/lib/module/ui/screens/karma/KarmaLeaderboardScreen.js.map +1 -0
  263. package/lib/module/ui/screens/karma/KarmaRewardsScreen.js +122 -0
  264. package/lib/module/ui/screens/karma/KarmaRewardsScreen.js.map +1 -0
  265. package/lib/module/ui/screens/karma/KarmaRulesScreen.js +100 -0
  266. package/lib/module/ui/screens/karma/KarmaRulesScreen.js.map +1 -0
  267. package/lib/module/ui/store/index.js +44 -0
  268. package/lib/module/ui/store/index.js.map +1 -0
  269. package/lib/module/ui/styles/FONTS.md +126 -0
  270. package/lib/module/ui/styles/fonts.js +81 -0
  271. package/lib/module/ui/styles/fonts.js.map +1 -0
  272. package/lib/module/ui/styles/index.js +5 -0
  273. package/lib/module/ui/styles/index.js.map +1 -0
  274. package/lib/module/ui/styles/theme.js +114 -0
  275. package/lib/module/ui/styles/theme.js.map +1 -0
  276. package/lib/module/utils/deviceManager.js +167 -0
  277. package/lib/module/utils/deviceManager.js.map +1 -0
  278. package/lib/module/utils/index.js +4 -0
  279. package/lib/module/utils/index.js.map +1 -0
  280. package/lib/module/utils/polyfills.js +36 -0
  281. package/lib/module/utils/polyfills.js.map +1 -0
  282. package/lib/typescript/assets/icons/OxyServices.d.ts +29 -0
  283. package/lib/typescript/assets/icons/OxyServices.d.ts.map +1 -0
  284. package/lib/typescript/assets/illustrations/HighFive.d.ts +9 -0
  285. package/lib/typescript/assets/illustrations/HighFive.d.ts.map +1 -0
  286. package/lib/typescript/constants/version.d.ts +14 -0
  287. package/lib/typescript/constants/version.d.ts.map +1 -0
  288. package/lib/typescript/core/index.d.ts +603 -0
  289. package/lib/typescript/core/index.d.ts.map +1 -0
  290. package/lib/typescript/index.d.ts +20 -0
  291. package/lib/typescript/index.d.ts.map +1 -0
  292. package/lib/typescript/lib/sonner.d.ts +6 -0
  293. package/lib/typescript/lib/sonner.d.ts.map +1 -0
  294. package/lib/typescript/models/interfaces.d.ts +179 -0
  295. package/lib/typescript/models/interfaces.d.ts.map +1 -0
  296. package/lib/typescript/models/secureSession.d.ts +27 -0
  297. package/lib/typescript/models/secureSession.d.ts.map +1 -0
  298. package/lib/typescript/node/createAuth.d.ts +7 -0
  299. package/lib/typescript/node/createAuth.d.ts.map +1 -0
  300. package/lib/typescript/node/index.d.ts +13 -0
  301. package/lib/typescript/node/index.d.ts.map +1 -0
  302. package/lib/typescript/types/expo-vector-icons.d.ts +3 -0
  303. package/lib/typescript/types/express.d.ts +5 -0
  304. package/lib/typescript/types/react-redux.d.ts +5 -0
  305. package/lib/typescript/ui/components/Avatar.d.ts +62 -0
  306. package/lib/typescript/ui/components/Avatar.d.ts.map +1 -0
  307. package/lib/typescript/ui/components/FollowButton.d.ts +92 -0
  308. package/lib/typescript/ui/components/FollowButton.d.ts.map +1 -0
  309. package/lib/typescript/ui/components/FontLoader.d.ts +15 -0
  310. package/lib/typescript/ui/components/FontLoader.d.ts.map +1 -0
  311. package/lib/typescript/ui/components/GroupedItem.d.ts +17 -0
  312. package/lib/typescript/ui/components/GroupedItem.d.ts.map +1 -0
  313. package/lib/typescript/ui/components/GroupedSection.d.ts +19 -0
  314. package/lib/typescript/ui/components/GroupedSection.d.ts.map +1 -0
  315. package/lib/typescript/ui/components/OxyLogo.d.ts +29 -0
  316. package/lib/typescript/ui/components/OxyLogo.d.ts.map +1 -0
  317. package/lib/typescript/ui/components/OxyProvider.d.ts +12 -0
  318. package/lib/typescript/ui/components/OxyProvider.d.ts.map +1 -0
  319. package/lib/typescript/ui/components/OxySignInButton.d.ts +70 -0
  320. package/lib/typescript/ui/components/OxySignInButton.d.ts.map +1 -0
  321. package/lib/typescript/ui/components/ProfileCard.d.ts +20 -0
  322. package/lib/typescript/ui/components/ProfileCard.d.ts.map +1 -0
  323. package/lib/typescript/ui/components/QuickActions.d.ts +15 -0
  324. package/lib/typescript/ui/components/QuickActions.d.ts.map +1 -0
  325. package/lib/typescript/ui/components/Section.d.ts +11 -0
  326. package/lib/typescript/ui/components/Section.d.ts.map +1 -0
  327. package/lib/typescript/ui/components/SectionTitle.d.ts +9 -0
  328. package/lib/typescript/ui/components/SectionTitle.d.ts.map +1 -0
  329. package/lib/typescript/ui/components/bottomSheet/index.d.ts +4 -0
  330. package/lib/typescript/ui/components/bottomSheet/index.d.ts.map +1 -0
  331. package/lib/typescript/ui/components/icon/OxyIcon.d.ts +10 -0
  332. package/lib/typescript/ui/components/icon/OxyIcon.d.ts.map +1 -0
  333. package/lib/typescript/ui/components/icon/index.d.ts +3 -0
  334. package/lib/typescript/ui/components/icon/index.d.ts.map +1 -0
  335. package/lib/typescript/ui/components/index.d.ts +13 -0
  336. package/lib/typescript/ui/components/index.d.ts.map +1 -0
  337. package/lib/typescript/ui/components/internal/GroupedPillButtons.d.ts +18 -0
  338. package/lib/typescript/ui/components/internal/GroupedPillButtons.d.ts.map +1 -0
  339. package/lib/typescript/ui/components/internal/TextField.d.ts +25 -0
  340. package/lib/typescript/ui/components/internal/TextField.d.ts.map +1 -0
  341. package/lib/typescript/ui/context/OxyContext.d.ts +42 -0
  342. package/lib/typescript/ui/context/OxyContext.d.ts.map +1 -0
  343. package/lib/typescript/ui/index.d.ts +17 -0
  344. package/lib/typescript/ui/index.d.ts.map +1 -0
  345. package/lib/typescript/ui/navigation/OxyRouter.d.ts +5 -0
  346. package/lib/typescript/ui/navigation/OxyRouter.d.ts.map +1 -0
  347. package/lib/typescript/ui/navigation/types.d.ts +116 -0
  348. package/lib/typescript/ui/navigation/types.d.ts.map +1 -0
  349. package/lib/typescript/ui/screens/AccountCenterScreen.d.ts +5 -0
  350. package/lib/typescript/ui/screens/AccountCenterScreen.d.ts.map +1 -0
  351. package/lib/typescript/ui/screens/AccountManagementDemo.d.ts +8 -0
  352. package/lib/typescript/ui/screens/AccountManagementDemo.d.ts.map +1 -0
  353. package/lib/typescript/ui/screens/AccountOverviewScreen.d.ts +5 -0
  354. package/lib/typescript/ui/screens/AccountOverviewScreen.d.ts.map +1 -0
  355. package/lib/typescript/ui/screens/AccountSettingsScreen.d.ts +5 -0
  356. package/lib/typescript/ui/screens/AccountSettingsScreen.d.ts.map +1 -0
  357. package/lib/typescript/ui/screens/AccountSwitcherScreen.d.ts +5 -0
  358. package/lib/typescript/ui/screens/AccountSwitcherScreen.d.ts.map +1 -0
  359. package/lib/typescript/ui/screens/AppInfoScreen.d.ts +5 -0
  360. package/lib/typescript/ui/screens/AppInfoScreen.d.ts.map +1 -0
  361. package/lib/typescript/ui/screens/BillingManagementScreen.d.ts +5 -0
  362. package/lib/typescript/ui/screens/BillingManagementScreen.d.ts.map +1 -0
  363. package/lib/typescript/ui/screens/FeedbackScreen.d.ts +5 -0
  364. package/lib/typescript/ui/screens/FeedbackScreen.d.ts.map +1 -0
  365. package/lib/typescript/ui/screens/FileManagementScreen.d.ts +8 -0
  366. package/lib/typescript/ui/screens/FileManagementScreen.d.ts.map +1 -0
  367. package/lib/typescript/ui/screens/PremiumSubscriptionScreen.d.ts +5 -0
  368. package/lib/typescript/ui/screens/PremiumSubscriptionScreen.d.ts.map +1 -0
  369. package/lib/typescript/ui/screens/ProfileScreen.d.ts +9 -0
  370. package/lib/typescript/ui/screens/ProfileScreen.d.ts.map +1 -0
  371. package/lib/typescript/ui/screens/SessionManagementScreen.d.ts +5 -0
  372. package/lib/typescript/ui/screens/SessionManagementScreen.d.ts.map +1 -0
  373. package/lib/typescript/ui/screens/SignInScreen.d.ts +5 -0
  374. package/lib/typescript/ui/screens/SignInScreen.d.ts.map +1 -0
  375. package/lib/typescript/ui/screens/SignUpScreen.d.ts +5 -0
  376. package/lib/typescript/ui/screens/SignUpScreen.d.ts.map +1 -0
  377. package/lib/typescript/ui/screens/karma/KarmaAboutScreen.d.ts +5 -0
  378. package/lib/typescript/ui/screens/karma/KarmaAboutScreen.d.ts.map +1 -0
  379. package/lib/typescript/ui/screens/karma/KarmaCenterScreen.d.ts +5 -0
  380. package/lib/typescript/ui/screens/karma/KarmaCenterScreen.d.ts.map +1 -0
  381. package/lib/typescript/ui/screens/karma/KarmaFAQScreen.d.ts +5 -0
  382. package/lib/typescript/ui/screens/karma/KarmaFAQScreen.d.ts.map +1 -0
  383. package/lib/typescript/ui/screens/karma/KarmaLeaderboardScreen.d.ts +5 -0
  384. package/lib/typescript/ui/screens/karma/KarmaLeaderboardScreen.d.ts.map +1 -0
  385. package/lib/typescript/ui/screens/karma/KarmaRewardsScreen.d.ts +5 -0
  386. package/lib/typescript/ui/screens/karma/KarmaRewardsScreen.d.ts.map +1 -0
  387. package/lib/typescript/ui/screens/karma/KarmaRulesScreen.d.ts +5 -0
  388. package/lib/typescript/ui/screens/karma/KarmaRulesScreen.d.ts.map +1 -0
  389. package/lib/typescript/ui/store/index.d.ts +19 -0
  390. package/lib/typescript/ui/store/index.d.ts.map +1 -0
  391. package/lib/typescript/ui/styles/fonts.d.ts +21 -0
  392. package/lib/typescript/ui/styles/fonts.d.ts.map +1 -0
  393. package/lib/typescript/ui/styles/index.d.ts +3 -0
  394. package/lib/typescript/ui/styles/index.d.ts.map +1 -0
  395. package/lib/typescript/ui/styles/theme.d.ts +68 -0
  396. package/lib/typescript/ui/styles/theme.d.ts.map +1 -0
  397. package/lib/typescript/utils/deviceManager.d.ts +66 -0
  398. package/lib/typescript/utils/deviceManager.d.ts.map +1 -0
  399. package/lib/typescript/utils/index.d.ts +3 -0
  400. package/lib/typescript/utils/index.d.ts.map +1 -0
  401. package/lib/typescript/utils/polyfills.d.ts +6 -0
  402. package/lib/typescript/utils/polyfills.d.ts.map +1 -0
  403. package/package.json +7 -6
  404. package/src/assets/illustrations/HighFive.tsx +41 -0
  405. package/src/node/createAuth.ts +116 -0
  406. package/src/node/index.ts +4 -0
  407. package/src/types/expo-vector-icons.d.ts +3 -0
  408. package/src/types/express.d.ts +5 -0
  409. package/src/types/react-redux.d.ts +5 -0
  410. package/src/ui/components/OxyProvider.tsx +136 -135
  411. package/src/ui/components/internal/GroupedPillButtons.tsx +253 -0
  412. package/src/ui/components/internal/TextField.tsx +694 -0
  413. package/src/ui/index.ts +6 -2
  414. package/src/ui/navigation/OxyRouter.tsx +8 -3
  415. package/src/ui/screens/FeedbackScreen.tsx +1042 -0
  416. package/src/ui/screens/SignInScreen.tsx +179 -222
  417. package/src/ui/screens/SignUpScreen.tsx +772 -608
  418. package/src/ui/store/index.ts +51 -0
@@ -0,0 +1,2510 @@
1
+ "use strict";
2
+
3
+ import React, { useState, useEffect, useCallback, useMemo } from 'react';
4
+ import { View, Text, TouchableOpacity, StyleSheet, ScrollView, ActivityIndicator, Platform, RefreshControl, Modal, TextInput, Image } from 'react-native';
5
+ import { useOxy } from '../context/OxyContext';
6
+ import { fontFamilies } from '../styles/fonts';
7
+ import { toast } from '../../lib/sonner';
8
+ import { Ionicons } from '@expo/vector-icons';
9
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
10
+ const FileManagementScreen = ({
11
+ onClose,
12
+ theme,
13
+ goBack,
14
+ navigate,
15
+ userId,
16
+ containerWidth = 400 // Fallback for when not provided by the router
17
+ }) => {
18
+ const {
19
+ user,
20
+ oxyServices
21
+ } = useOxy();
22
+
23
+ // Debug: log the actual container width
24
+ useEffect(() => {
25
+ console.log('[FileManagementScreen] Container width (full):', containerWidth);
26
+ // Padding structure:
27
+ // - containerWidth = full bottom sheet container width (measured from OxyProvider)
28
+ // - photoScrollContainer adds padding: 16 (32px total horizontal padding)
29
+ // - Available content width = containerWidth - 32
30
+ const availableContentWidth = containerWidth - 32;
31
+ console.log('[FileManagementScreen] Available content width:', availableContentWidth);
32
+ console.log('[FileManagementScreen] Spacing fix applied: 4px uniform gap both horizontal and vertical');
33
+ }, [containerWidth]);
34
+ const [files, setFiles] = useState([]);
35
+ const [loading, setLoading] = useState(true);
36
+ const [refreshing, setRefreshing] = useState(false);
37
+ const [uploading, setUploading] = useState(false);
38
+ const [uploadProgress, setUploadProgress] = useState(null);
39
+ const [deleting, setDeleting] = useState(null);
40
+ const [selectedFile, setSelectedFile] = useState(null);
41
+ const [showFileDetails, setShowFileDetails] = useState(false);
42
+ const [openedFile, setOpenedFile] = useState(null);
43
+ const [fileContent, setFileContent] = useState(null);
44
+ const [loadingFileContent, setLoadingFileContent] = useState(false);
45
+ const [showFileDetailsInViewer, setShowFileDetailsInViewer] = useState(false);
46
+ const [viewMode, setViewMode] = useState('all');
47
+ const [searchQuery, setSearchQuery] = useState('');
48
+ const [filteredFiles, setFilteredFiles] = useState([]);
49
+ const [isDragging, setIsDragging] = useState(false);
50
+ const [photoDimensions, setPhotoDimensions] = useState({});
51
+ const [loadingDimensions, setLoadingDimensions] = useState(false);
52
+ const [hoveredPreview, setHoveredPreview] = useState(null);
53
+
54
+ // Memoize theme-related calculations to prevent unnecessary recalculations
55
+ const themeStyles = useMemo(() => {
56
+ const isDarkTheme = theme === 'dark';
57
+ return {
58
+ isDarkTheme,
59
+ textColor: isDarkTheme ? '#FFFFFF' : '#000000',
60
+ backgroundColor: isDarkTheme ? '#121212' : '#f2f2f2',
61
+ secondaryBackgroundColor: isDarkTheme ? '#222222' : '#FFFFFF',
62
+ borderColor: isDarkTheme ? '#444444' : '#E0E0E0',
63
+ primaryColor: '#007AFF',
64
+ dangerColor: '#FF3B30',
65
+ successColor: '#34C759'
66
+ };
67
+ }, [theme]);
68
+
69
+ // Extract commonly used theme variables
70
+ const backgroundColor = themeStyles.backgroundColor;
71
+ const borderColor = themeStyles.borderColor;
72
+ const targetUserId = userId || user?.id;
73
+ const loadFiles = useCallback(async (isRefresh = false) => {
74
+ if (!targetUserId) return;
75
+ try {
76
+ if (isRefresh) {
77
+ setRefreshing(true);
78
+ } else {
79
+ setLoading(true);
80
+ }
81
+ const response = await oxyServices.listUserFiles(targetUserId);
82
+ setFiles(response.files || []);
83
+ } catch (error) {
84
+ console.error('Failed to load files:', error);
85
+ toast.error(error.message || 'Failed to load files');
86
+ } finally {
87
+ setLoading(false);
88
+ setRefreshing(false);
89
+ }
90
+ }, [targetUserId, oxyServices]);
91
+
92
+ // Filter files based on search query and view mode
93
+ useEffect(() => {
94
+ let filteredByMode = files;
95
+
96
+ // Filter by view mode first
97
+ if (viewMode === 'photos') {
98
+ filteredByMode = files.filter(file => file.contentType.startsWith('image/'));
99
+ }
100
+
101
+ // Then filter by search query
102
+ if (!searchQuery.trim()) {
103
+ setFilteredFiles(filteredByMode);
104
+ } else {
105
+ const query = searchQuery.toLowerCase();
106
+ const filtered = filteredByMode.filter(file => file.filename.toLowerCase().includes(query) || file.contentType.toLowerCase().includes(query) || file.metadata?.description && file.metadata.description.toLowerCase().includes(query));
107
+ setFilteredFiles(filtered);
108
+ }
109
+ }, [files, searchQuery, viewMode]);
110
+
111
+ // Load photo dimensions for justified grid
112
+ const loadPhotoDimensions = useCallback(async photos => {
113
+ if (photos.length === 0) return;
114
+ setLoadingDimensions(true);
115
+ const newDimensions = {
116
+ ...photoDimensions
117
+ };
118
+ let hasNewDimensions = false;
119
+
120
+ // Only load dimensions for photos we don't have yet
121
+ const photosToLoad = photos.filter(photo => !newDimensions[photo.id]);
122
+ if (photosToLoad.length === 0) {
123
+ setLoadingDimensions(false);
124
+ return;
125
+ }
126
+ try {
127
+ await Promise.all(photosToLoad.map(async photo => {
128
+ try {
129
+ const downloadUrl = oxyServices.getFileDownloadUrl(photo.id);
130
+ if (Platform.OS === 'web') {
131
+ const img = new window.Image();
132
+ await new Promise((resolve, reject) => {
133
+ img.onload = () => {
134
+ newDimensions[photo.id] = {
135
+ width: img.naturalWidth,
136
+ height: img.naturalHeight
137
+ };
138
+ hasNewDimensions = true;
139
+ resolve();
140
+ };
141
+ img.onerror = () => {
142
+ // Fallback dimensions for failed loads
143
+ newDimensions[photo.id] = {
144
+ width: 1,
145
+ height: 1
146
+ };
147
+ hasNewDimensions = true;
148
+ resolve();
149
+ };
150
+ img.src = downloadUrl;
151
+ });
152
+ } else {
153
+ // For mobile, use Image.getSize from react-native
154
+ await new Promise(resolve => {
155
+ Image.getSize(downloadUrl, (width, height) => {
156
+ newDimensions[photo.id] = {
157
+ width,
158
+ height
159
+ };
160
+ hasNewDimensions = true;
161
+ resolve();
162
+ }, () => {
163
+ // Fallback dimensions
164
+ newDimensions[photo.id] = {
165
+ width: 1,
166
+ height: 1
167
+ };
168
+ hasNewDimensions = true;
169
+ resolve();
170
+ });
171
+ });
172
+ }
173
+ } catch (error) {
174
+ // Fallback dimensions for any errors
175
+ newDimensions[photo.id] = {
176
+ width: 1,
177
+ height: 1
178
+ };
179
+ hasNewDimensions = true;
180
+ }
181
+ }));
182
+ if (hasNewDimensions) {
183
+ setPhotoDimensions(newDimensions);
184
+ }
185
+ } catch (error) {
186
+ console.error('Error loading photo dimensions:', error);
187
+ } finally {
188
+ setLoadingDimensions(false);
189
+ }
190
+ }, [oxyServices, photoDimensions]);
191
+
192
+ // Create justified rows from photos with responsive algorithm
193
+ const createJustifiedRows = useCallback((photos, containerWidth) => {
194
+ if (photos.length === 0) return [];
195
+ const rows = [];
196
+ const photosPerRow = 3; // Fixed 3 photos per row for consistency
197
+
198
+ for (let i = 0; i < photos.length; i += photosPerRow) {
199
+ const rowPhotos = photos.slice(i, i + photosPerRow);
200
+ rows.push(rowPhotos);
201
+ }
202
+ return rows;
203
+ }, []);
204
+ const processFileUploads = async selectedFiles => {
205
+ if (selectedFiles.length === 0) return;
206
+ try {
207
+ // Show initial progress
208
+ setUploadProgress({
209
+ current: 0,
210
+ total: selectedFiles.length
211
+ });
212
+
213
+ // Validate file sizes (example: 50MB limit per file)
214
+ const maxSize = 50 * 1024 * 1024; // 50MB
215
+ const oversizedFiles = selectedFiles.filter(file => file.size > maxSize);
216
+ if (oversizedFiles.length > 0) {
217
+ const fileList = oversizedFiles.map(f => f.name).join('\n');
218
+ window.alert(`File Size Limit\n\nThe following files are too large (max 50MB):\n${fileList}`);
219
+ return;
220
+ }
221
+
222
+ // Option 1: Bulk upload (faster, all-or-nothing) for 5 or fewer files
223
+ if (selectedFiles.length <= 5) {
224
+ const filenames = selectedFiles.map(f => f.name);
225
+ const response = await oxyServices.uploadFiles(selectedFiles, filenames, {
226
+ userId: targetUserId,
227
+ uploadDate: new Date().toISOString()
228
+ });
229
+ toast.success(`${response.files.length} file(s) uploaded successfully`);
230
+ // Small delay to ensure backend processing is complete
231
+ setTimeout(async () => {
232
+ await loadFiles();
233
+ }, 500);
234
+ } else {
235
+ // Option 2: Individual uploads for better progress and error handling
236
+ let successCount = 0;
237
+ let failureCount = 0;
238
+ const errors = [];
239
+ for (let i = 0; i < selectedFiles.length; i++) {
240
+ const file = selectedFiles[i];
241
+ setUploadProgress({
242
+ current: i + 1,
243
+ total: selectedFiles.length
244
+ });
245
+ try {
246
+ await oxyServices.uploadFile(file, file.name, {
247
+ userId: targetUserId,
248
+ uploadDate: new Date().toISOString()
249
+ });
250
+ successCount++;
251
+ } catch (error) {
252
+ failureCount++;
253
+ errors.push(`${file.name}: ${error.message || 'Upload failed'}`);
254
+ }
255
+ }
256
+
257
+ // Show results summary
258
+ if (successCount > 0) {
259
+ toast.success(`${successCount} file(s) uploaded successfully`);
260
+ }
261
+ if (failureCount > 0) {
262
+ const errorMessage = `${failureCount} file(s) failed to upload${errors.length > 0 ? ':\n' + errors.slice(0, 3).join('\n') + (errors.length > 3 ? '\n...' : '') : ''}`;
263
+ toast.error(errorMessage);
264
+ }
265
+
266
+ // Small delay to ensure backend processing is complete
267
+ setTimeout(async () => {
268
+ await loadFiles();
269
+ }, 500);
270
+ }
271
+ } catch (error) {
272
+ console.error('Upload error:', error);
273
+ toast.error(error.message || 'Failed to upload files');
274
+ } finally {
275
+ setUploadProgress(null);
276
+ }
277
+ };
278
+ const handleFileUpload = async () => {
279
+ try {
280
+ setUploading(true);
281
+ setUploadProgress(null);
282
+ if (Platform.OS === 'web') {
283
+ // Web file picker implementation
284
+ const input = document.createElement('input');
285
+ input.type = 'file';
286
+ input.multiple = true;
287
+ input.accept = '*/*';
288
+ input.onchange = async e => {
289
+ const selectedFiles = Array.from(e.target.files);
290
+ await processFileUploads(selectedFiles);
291
+ };
292
+ input.click();
293
+ } else {
294
+ // Mobile - show info that file picker can be added
295
+ const installCommand = 'npm install expo-document-picker';
296
+ const message = `Mobile File Upload\n\nTo enable file uploads on mobile, install expo-document-picker:\n\n${installCommand}\n\nThen import and use DocumentPicker.getDocumentAsync() in this method.`;
297
+ if (window.confirm(`${message}\n\nWould you like to copy the install command?`)) {
298
+ toast.info(`Install: ${installCommand}`);
299
+ } else {
300
+ toast.info('Mobile file upload requires expo-document-picker');
301
+ }
302
+ }
303
+ } catch (error) {
304
+ toast.error(error.message || 'Failed to upload file');
305
+ } finally {
306
+ setUploading(false);
307
+ setUploadProgress(null);
308
+ }
309
+ };
310
+ const handleFileDelete = async (fileId, filename) => {
311
+ // Use web-compatible confirmation dialog
312
+ const confirmed = window.confirm(`Are you sure you want to delete "${filename}"? This action cannot be undone.`);
313
+ if (!confirmed) {
314
+ console.log('Delete cancelled by user');
315
+ return;
316
+ }
317
+ try {
318
+ console.log('Deleting file:', {
319
+ fileId,
320
+ filename
321
+ });
322
+ console.log('Target user ID:', targetUserId);
323
+ console.log('Current user ID:', user?.id);
324
+ setDeleting(fileId);
325
+ const result = await oxyServices.deleteFile(fileId);
326
+ console.log('Delete result:', result);
327
+ toast.success('File deleted successfully');
328
+
329
+ // Reload files after successful deletion
330
+ setTimeout(async () => {
331
+ await loadFiles();
332
+ }, 500);
333
+ } catch (error) {
334
+ console.error('Delete error:', error);
335
+ console.error('Error details:', error.response?.data || error.message);
336
+
337
+ // Provide specific error messages
338
+ if (error.message?.includes('File not found') || error.message?.includes('404')) {
339
+ toast.error('File not found. It may have already been deleted.');
340
+ // Still reload files to refresh the list
341
+ setTimeout(async () => {
342
+ await loadFiles();
343
+ }, 500);
344
+ } else if (error.message?.includes('permission') || error.message?.includes('403')) {
345
+ toast.error('You do not have permission to delete this file.');
346
+ } else {
347
+ toast.error(error.message || 'Failed to delete file');
348
+ }
349
+ } finally {
350
+ setDeleting(null);
351
+ }
352
+ };
353
+
354
+ // Drag and drop handlers for web
355
+ const handleDragOver = e => {
356
+ if (Platform.OS === 'web' && user?.id === targetUserId) {
357
+ e.preventDefault();
358
+ setIsDragging(true);
359
+ }
360
+ };
361
+ const handleDragLeave = e => {
362
+ if (Platform.OS === 'web') {
363
+ e.preventDefault();
364
+ setIsDragging(false);
365
+ }
366
+ };
367
+ const handleDrop = async e => {
368
+ if (Platform.OS === 'web' && user?.id === targetUserId) {
369
+ e.preventDefault();
370
+ setIsDragging(false);
371
+ setUploading(true);
372
+ try {
373
+ const files = Array.from(e.dataTransfer.files);
374
+ await processFileUploads(files);
375
+ } catch (error) {
376
+ toast.error(error.message || 'Failed to upload files');
377
+ } finally {
378
+ setUploading(false);
379
+ }
380
+ }
381
+ };
382
+ const handleFileDownload = async (fileId, filename) => {
383
+ try {
384
+ if (Platform.OS === 'web') {
385
+ console.log('Downloading file:', {
386
+ fileId,
387
+ filename
388
+ });
389
+
390
+ // Use the public download URL method
391
+ const downloadUrl = oxyServices.getFileDownloadUrl(fileId);
392
+ console.log('Download URL:', downloadUrl);
393
+ try {
394
+ // Method 1: Try simple link download first
395
+ const link = document.createElement('a');
396
+ link.href = downloadUrl;
397
+ link.download = filename;
398
+ link.target = '_blank';
399
+ document.body.appendChild(link);
400
+ link.click();
401
+ document.body.removeChild(link);
402
+ toast.success('File download started');
403
+ } catch (linkError) {
404
+ console.warn('Link download failed, trying fetch method:', linkError);
405
+
406
+ // Method 2: Fallback to fetch download
407
+ const response = await fetch(downloadUrl);
408
+ if (!response.ok) {
409
+ if (response.status === 404) {
410
+ throw new Error('File not found. It may have been deleted.');
411
+ } else {
412
+ throw new Error(`Download failed: ${response.status} ${response.statusText}`);
413
+ }
414
+ }
415
+ const blob = await response.blob();
416
+ const url = window.URL.createObjectURL(blob);
417
+ const link = document.createElement('a');
418
+ link.href = url;
419
+ link.download = filename;
420
+ document.body.appendChild(link);
421
+ link.click();
422
+ document.body.removeChild(link);
423
+
424
+ // Clean up the blob URL
425
+ window.URL.revokeObjectURL(url);
426
+ toast.success('File downloaded successfully');
427
+ }
428
+ } else {
429
+ toast.info('File download not implemented for mobile yet');
430
+ }
431
+ } catch (error) {
432
+ console.error('Download error:', error);
433
+ toast.error(error.message || 'Failed to download file');
434
+ }
435
+ };
436
+ const formatFileSize = bytes => {
437
+ if (bytes === 0) return '0 Bytes';
438
+ const k = 1024;
439
+ const sizes = ['Bytes', 'KB', 'MB', 'GB'];
440
+ const i = Math.floor(Math.log(bytes) / Math.log(k));
441
+ return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
442
+ };
443
+ const getFileIcon = contentType => {
444
+ if (contentType.startsWith('image/')) return 'image';
445
+ if (contentType.startsWith('video/')) return 'videocam';
446
+ if (contentType.startsWith('audio/')) return 'musical-notes';
447
+ if (contentType.includes('pdf')) return 'document-text';
448
+ if (contentType.includes('word') || contentType.includes('doc')) return 'document';
449
+ if (contentType.includes('excel') || contentType.includes('sheet')) return 'grid';
450
+ if (contentType.includes('zip') || contentType.includes('archive')) return 'archive';
451
+ return 'document-outline';
452
+ };
453
+ const handleFileOpen = async file => {
454
+ try {
455
+ setLoadingFileContent(true);
456
+ setOpenedFile(file);
457
+
458
+ // For text files, images, and other viewable content, try to load the content
459
+ if (file.contentType.startsWith('text/') || file.contentType.includes('json') || file.contentType.includes('xml') || file.contentType.includes('javascript') || file.contentType.includes('typescript') || file.contentType.startsWith('image/') || file.contentType.includes('pdf') || file.contentType.startsWith('video/') || file.contentType.startsWith('audio/')) {
460
+ try {
461
+ const downloadUrl = oxyServices.getFileDownloadUrl(file.id);
462
+ const response = await fetch(downloadUrl);
463
+ if (response.ok) {
464
+ if (file.contentType.startsWith('image/') || file.contentType.includes('pdf') || file.contentType.startsWith('video/') || file.contentType.startsWith('audio/')) {
465
+ // For images, PDFs, videos, and audio, we'll use the URL directly
466
+ setFileContent(downloadUrl);
467
+ } else {
468
+ // For text files, get the content
469
+ const content = await response.text();
470
+ setFileContent(content);
471
+ }
472
+ } else {
473
+ if (response.status === 404) {
474
+ toast.error('File not found. It may have been deleted.');
475
+ } else {
476
+ toast.error(`Failed to load file: ${response.status} ${response.statusText}`);
477
+ }
478
+ setFileContent(null);
479
+ }
480
+ } catch (error) {
481
+ console.error('Failed to load file content:', error);
482
+ if (error.message?.includes('404') || error.message?.includes('not found')) {
483
+ toast.error('File not found. It may have been deleted.');
484
+ } else {
485
+ toast.error('Failed to load file content');
486
+ }
487
+ setFileContent(null);
488
+ }
489
+ } else {
490
+ // For non-viewable files, don't load content
491
+ setFileContent(null);
492
+ }
493
+ } catch (error) {
494
+ console.error('Failed to open file:', error);
495
+ toast.error(error.message || 'Failed to open file');
496
+ } finally {
497
+ setLoadingFileContent(false);
498
+ }
499
+ };
500
+ const handleCloseFile = () => {
501
+ setOpenedFile(null);
502
+ setFileContent(null);
503
+ setShowFileDetailsInViewer(false);
504
+ // Don't reset view mode when closing a file
505
+ };
506
+ const showFileDetailsModal = file => {
507
+ setSelectedFile(file);
508
+ setShowFileDetails(true);
509
+ };
510
+ const renderSimplePhotoItem = useCallback((photo, index) => {
511
+ const downloadUrl = oxyServices.getFileDownloadUrl(photo.id);
512
+
513
+ // Calculate photo item width based on actual container size from bottom sheet
514
+ let itemsPerRow = 3; // Default for mobile
515
+ if (containerWidth > 768) itemsPerRow = 4; // Desktop/tablet
516
+ else if (containerWidth > 480) itemsPerRow = 3; // Large mobile
517
+
518
+ // Account for the photoScrollContainer padding (16px on each side = 32px total)
519
+ const scrollContainerPadding = 32; // Total horizontal padding from photoScrollContainer
520
+ const gaps = (itemsPerRow - 1) * 4; // Gap between items (4px)
521
+ const availableWidth = containerWidth - scrollContainerPadding;
522
+ const itemWidth = (availableWidth - gaps) / itemsPerRow;
523
+ return /*#__PURE__*/_jsx(TouchableOpacity, {
524
+ style: [styles.simplePhotoItem, {
525
+ width: itemWidth,
526
+ height: itemWidth,
527
+ marginRight: (index + 1) % itemsPerRow === 0 ? 0 : 4
528
+ }],
529
+ onPress: () => handleFileOpen(photo),
530
+ activeOpacity: 0.8,
531
+ children: /*#__PURE__*/_jsx(View, {
532
+ style: styles.simplePhotoContainer,
533
+ children: Platform.OS === 'web' ? /*#__PURE__*/_jsx("img", {
534
+ src: downloadUrl,
535
+ alt: photo.filename,
536
+ style: {
537
+ width: '100%',
538
+ height: '100%',
539
+ objectFit: 'cover',
540
+ borderRadius: 8,
541
+ transition: 'transform 0.2s ease'
542
+ },
543
+ loading: "lazy",
544
+ onError: e => {
545
+ console.error('Photo failed to load:', e);
546
+ },
547
+ onMouseEnter: e => {
548
+ e.currentTarget.style.transform = 'scale(1.05)';
549
+ },
550
+ onMouseLeave: e => {
551
+ e.currentTarget.style.transform = 'scale(1)';
552
+ }
553
+ }) : /*#__PURE__*/_jsx(Image, {
554
+ source: {
555
+ uri: downloadUrl
556
+ },
557
+ style: styles.simplePhotoImage,
558
+ resizeMode: "cover",
559
+ onError: e => {
560
+ console.error('Photo failed to load:', e);
561
+ }
562
+ })
563
+ })
564
+ }, photo.id);
565
+ }, [oxyServices, containerWidth]);
566
+ const renderJustifiedPhotoItem = useCallback((photo, width, height, isLast) => {
567
+ const downloadUrl = oxyServices.getFileDownloadUrl(photo.id);
568
+ return /*#__PURE__*/_jsx(TouchableOpacity, {
569
+ style: [styles.justifiedPhotoItem, {
570
+ width,
571
+ height
572
+ }],
573
+ onPress: () => handleFileOpen(photo),
574
+ activeOpacity: 0.8,
575
+ children: /*#__PURE__*/_jsx(View, {
576
+ style: styles.justifiedPhotoContainer,
577
+ children: Platform.OS === 'web' ? /*#__PURE__*/_jsx("img", {
578
+ src: downloadUrl,
579
+ alt: photo.filename,
580
+ style: {
581
+ width: '100%',
582
+ height: '100%',
583
+ objectFit: 'cover',
584
+ borderRadius: 6,
585
+ transition: 'transform 0.2s ease, box-shadow 0.2s ease'
586
+ },
587
+ loading: "lazy",
588
+ onError: e => {
589
+ console.error('Photo failed to load:', e);
590
+ },
591
+ onMouseEnter: e => {
592
+ e.currentTarget.style.transform = 'scale(1.02)';
593
+ e.currentTarget.style.boxShadow = '0 8px 25px rgba(0,0,0,0.15)';
594
+ e.currentTarget.style.zIndex = '10';
595
+ },
596
+ onMouseLeave: e => {
597
+ e.currentTarget.style.transform = 'scale(1)';
598
+ e.currentTarget.style.boxShadow = '0 2px 8px rgba(0,0,0,0.1)';
599
+ e.currentTarget.style.zIndex = '1';
600
+ }
601
+ }) : /*#__PURE__*/_jsx(Image, {
602
+ source: {
603
+ uri: downloadUrl
604
+ },
605
+ style: styles.justifiedPhotoImage,
606
+ resizeMode: "cover",
607
+ onError: e => {
608
+ console.error('Photo failed to load:', e);
609
+ }
610
+ })
611
+ })
612
+ }, photo.id);
613
+ }, [oxyServices]);
614
+ useEffect(() => {
615
+ loadFiles();
616
+ }, [loadFiles]);
617
+ const renderFileItem = file => {
618
+ const isImage = file.contentType.startsWith('image/');
619
+ const isPDF = file.contentType.includes('pdf');
620
+ const isVideo = file.contentType.startsWith('video/');
621
+ const isAudio = file.contentType.startsWith('audio/');
622
+ const hasPreview = isImage || isPDF || isVideo;
623
+ const borderColor = themeStyles.borderColor;
624
+ return /*#__PURE__*/_jsxs(View, {
625
+ style: [styles.fileItem, {
626
+ backgroundColor: themeStyles.secondaryBackgroundColor,
627
+ borderColor
628
+ }],
629
+ children: [/*#__PURE__*/_jsxs(TouchableOpacity, {
630
+ style: styles.fileContent,
631
+ onPress: () => handleFileOpen(file),
632
+ children: [/*#__PURE__*/_jsx(View, {
633
+ style: styles.filePreviewContainer,
634
+ children: hasPreview ? /*#__PURE__*/_jsxs(View, {
635
+ style: styles.filePreview,
636
+ ...(Platform.OS === 'web' && {
637
+ onMouseEnter: () => setHoveredPreview(file.id),
638
+ onMouseLeave: () => setHoveredPreview(null)
639
+ }),
640
+ children: [isImage && (Platform.OS === 'web' ? /*#__PURE__*/_jsx("img", {
641
+ src: oxyServices.getFileDownloadUrl(file.id),
642
+ style: {
643
+ width: '100%',
644
+ height: '100%',
645
+ objectFit: 'cover',
646
+ borderRadius: 8,
647
+ transition: 'transform 0.2s ease',
648
+ transform: hoveredPreview === file.id ? 'scale(1.05)' : 'scale(1)'
649
+ },
650
+ onError: e => {
651
+ // Show fallback icon if image fails to load
652
+ e.currentTarget.style.display = 'none';
653
+ const fallbackElement = e.currentTarget.parentElement?.querySelector('[data-fallback="true"]');
654
+ if (fallbackElement) {
655
+ fallbackElement.style.display = 'flex';
656
+ }
657
+ }
658
+ }) : /*#__PURE__*/_jsx(Image, {
659
+ source: {
660
+ uri: oxyServices.getFileDownloadUrl(file.id)
661
+ },
662
+ style: styles.previewImage,
663
+ resizeMode: "cover",
664
+ onError: () => {
665
+ // For React Native, you might want to set an error state
666
+ console.warn('Failed to load image preview for file:', file.id);
667
+ }
668
+ })), isPDF && /*#__PURE__*/_jsxs(View, {
669
+ style: styles.pdfPreview,
670
+ children: [/*#__PURE__*/_jsx(Ionicons, {
671
+ name: "document",
672
+ size: 32,
673
+ color: themeStyles.primaryColor
674
+ }), /*#__PURE__*/_jsx(Text, {
675
+ style: [styles.pdfLabel, {
676
+ color: themeStyles.primaryColor
677
+ }],
678
+ children: "PDF"
679
+ })]
680
+ }), isVideo && /*#__PURE__*/_jsxs(View, {
681
+ style: styles.videoPreview,
682
+ children: [/*#__PURE__*/_jsx(Ionicons, {
683
+ name: "play-circle",
684
+ size: 32,
685
+ color: themeStyles.primaryColor
686
+ }), /*#__PURE__*/_jsx(Text, {
687
+ style: [styles.videoLabel, {
688
+ color: themeStyles.primaryColor
689
+ }],
690
+ children: "VIDEO"
691
+ })]
692
+ }), /*#__PURE__*/_jsx(View, {
693
+ style: [styles.fallbackIcon, {
694
+ display: isImage ? 'none' : 'flex'
695
+ }],
696
+ ...(Platform.OS === 'web' && {
697
+ 'data-fallback': 'true'
698
+ }),
699
+ children: /*#__PURE__*/_jsx(Ionicons, {
700
+ name: getFileIcon(file.contentType),
701
+ size: 32,
702
+ color: themeStyles.primaryColor
703
+ })
704
+ }), Platform.OS === 'web' && hoveredPreview === file.id && isImage && /*#__PURE__*/_jsx(View, {
705
+ style: styles.previewOverlay,
706
+ children: /*#__PURE__*/_jsx(Ionicons, {
707
+ name: "eye",
708
+ size: 24,
709
+ color: "#FFFFFF"
710
+ })
711
+ })]
712
+ }) : /*#__PURE__*/_jsx(View, {
713
+ style: styles.fileIconContainer,
714
+ children: /*#__PURE__*/_jsx(Ionicons, {
715
+ name: getFileIcon(file.contentType),
716
+ size: 32,
717
+ color: themeStyles.primaryColor
718
+ })
719
+ })
720
+ }), /*#__PURE__*/_jsxs(View, {
721
+ style: styles.fileInfo,
722
+ children: [/*#__PURE__*/_jsx(Text, {
723
+ style: [styles.fileName, {
724
+ color: themeStyles.textColor
725
+ }],
726
+ numberOfLines: 1,
727
+ children: file.filename
728
+ }), /*#__PURE__*/_jsxs(Text, {
729
+ style: [styles.fileDetails, {
730
+ color: themeStyles.isDarkTheme ? '#BBBBBB' : '#666666'
731
+ }],
732
+ children: [formatFileSize(file.length), " \u2022 ", new Date(file.uploadDate).toLocaleDateString()]
733
+ }), file.metadata?.description && /*#__PURE__*/_jsx(Text, {
734
+ style: [styles.fileDescription, {
735
+ color: themeStyles.isDarkTheme ? '#AAAAAA' : '#888888'
736
+ }],
737
+ numberOfLines: 2,
738
+ children: file.metadata.description
739
+ })]
740
+ })]
741
+ }), /*#__PURE__*/_jsxs(View, {
742
+ style: styles.fileActions,
743
+ children: [hasPreview && /*#__PURE__*/_jsx(TouchableOpacity, {
744
+ style: [styles.actionButton, {
745
+ backgroundColor: themeStyles.isDarkTheme ? '#333333' : '#F0F0F0'
746
+ }],
747
+ onPress: () => handleFileOpen(file),
748
+ children: /*#__PURE__*/_jsx(Ionicons, {
749
+ name: "eye",
750
+ size: 20,
751
+ color: themeStyles.primaryColor
752
+ })
753
+ }), /*#__PURE__*/_jsx(TouchableOpacity, {
754
+ style: [styles.actionButton, {
755
+ backgroundColor: themeStyles.isDarkTheme ? '#333333' : '#F0F0F0'
756
+ }],
757
+ onPress: () => handleFileDownload(file.id, file.filename),
758
+ children: /*#__PURE__*/_jsx(Ionicons, {
759
+ name: "download",
760
+ size: 20,
761
+ color: themeStyles.primaryColor
762
+ })
763
+ }), /*#__PURE__*/_jsx(TouchableOpacity, {
764
+ style: [styles.actionButton, {
765
+ backgroundColor: themeStyles.isDarkTheme ? '#400000' : '#FFEBEE'
766
+ }],
767
+ onPress: () => {
768
+ handleFileDelete(file.id, file.filename);
769
+ },
770
+ disabled: deleting === file.id,
771
+ children: deleting === file.id ? /*#__PURE__*/_jsx(ActivityIndicator, {
772
+ size: "small",
773
+ color: themeStyles.dangerColor
774
+ }) : /*#__PURE__*/_jsx(Ionicons, {
775
+ name: "trash",
776
+ size: 20,
777
+ color: themeStyles.dangerColor
778
+ })
779
+ })]
780
+ })]
781
+ }, file.id);
782
+ };
783
+ const renderPhotoItem = (photo, index) => {
784
+ const downloadUrl = oxyServices.getFileDownloadUrl(photo.id);
785
+
786
+ // Calculate photo item width based on actual container size from bottom sheet
787
+ let itemsPerRow = 3; // Default for mobile
788
+ if (containerWidth > 768) itemsPerRow = 6; // Tablet/Desktop
789
+ else if (containerWidth > 480) itemsPerRow = 4; // Large mobile
790
+
791
+ // Account for the photoScrollContainer padding (16px on each side = 32px total)
792
+ const scrollContainerPadding = 32; // Total horizontal padding from photoScrollContainer
793
+ const gaps = (itemsPerRow - 1) * 4; // Gap between items
794
+ const availableWidth = containerWidth - scrollContainerPadding;
795
+ const itemWidth = (availableWidth - gaps) / itemsPerRow;
796
+ return /*#__PURE__*/_jsx(TouchableOpacity, {
797
+ style: [styles.photoItem, {
798
+ width: itemWidth,
799
+ height: itemWidth
800
+ }],
801
+ onPress: () => handleFileOpen(photo),
802
+ activeOpacity: 0.8,
803
+ children: /*#__PURE__*/_jsx(View, {
804
+ style: styles.photoContainer,
805
+ children: Platform.OS === 'web' ? /*#__PURE__*/_jsx("img", {
806
+ src: downloadUrl,
807
+ alt: photo.filename,
808
+ style: {
809
+ width: '100%',
810
+ height: '100%',
811
+ objectFit: 'cover',
812
+ borderRadius: 8,
813
+ transition: 'transform 0.2s ease'
814
+ },
815
+ loading: "lazy",
816
+ onError: e => {
817
+ console.error('Photo failed to load:', e);
818
+ // Could replace with placeholder image
819
+ },
820
+ onMouseEnter: e => {
821
+ e.currentTarget.style.transform = 'scale(1.02)';
822
+ },
823
+ onMouseLeave: e => {
824
+ e.currentTarget.style.transform = 'scale(1)';
825
+ }
826
+ }) : /*#__PURE__*/_jsx(Image, {
827
+ source: {
828
+ uri: downloadUrl
829
+ },
830
+ style: styles.photoImage,
831
+ resizeMode: "cover",
832
+ onError: e => {
833
+ console.error('Photo failed to load:', e);
834
+ }
835
+ })
836
+ })
837
+ }, photo.id);
838
+ };
839
+ const renderPhotoGrid = useCallback(() => {
840
+ const photos = filteredFiles.filter(file => file.contentType.startsWith('image/'));
841
+ if (photos.length === 0) {
842
+ return /*#__PURE__*/_jsxs(View, {
843
+ style: styles.emptyState,
844
+ children: [/*#__PURE__*/_jsx(Ionicons, {
845
+ name: "images-outline",
846
+ size: 64,
847
+ color: themeStyles.isDarkTheme ? '#666666' : '#CCCCCC'
848
+ }), /*#__PURE__*/_jsx(Text, {
849
+ style: [styles.emptyStateTitle, {
850
+ color: themeStyles.textColor
851
+ }],
852
+ children: "No Photos Yet"
853
+ }), /*#__PURE__*/_jsx(Text, {
854
+ style: [styles.emptyStateDescription, {
855
+ color: themeStyles.isDarkTheme ? '#BBBBBB' : '#666666'
856
+ }],
857
+ children: user?.id === targetUserId ? `Upload photos to get started. You can select multiple photos at once${Platform.OS === 'web' ? ' or drag & drop them here.' : '.'}` : "This user hasn't uploaded any photos yet"
858
+ }), user?.id === targetUserId && /*#__PURE__*/_jsx(TouchableOpacity, {
859
+ style: [styles.emptyStateButton, {
860
+ backgroundColor: themeStyles.primaryColor
861
+ }],
862
+ onPress: handleFileUpload,
863
+ disabled: uploading,
864
+ children: uploading ? /*#__PURE__*/_jsx(ActivityIndicator, {
865
+ size: "small",
866
+ color: "#FFFFFF"
867
+ }) : /*#__PURE__*/_jsxs(_Fragment, {
868
+ children: [/*#__PURE__*/_jsx(Ionicons, {
869
+ name: "cloud-upload",
870
+ size: 20,
871
+ color: "#FFFFFF"
872
+ }), /*#__PURE__*/_jsx(Text, {
873
+ style: styles.emptyStateButtonText,
874
+ children: "Upload Photos"
875
+ })]
876
+ })
877
+ })]
878
+ });
879
+ }
880
+ return /*#__PURE__*/_jsxs(ScrollView, {
881
+ style: styles.scrollView,
882
+ contentContainerStyle: styles.photoScrollContainer,
883
+ refreshControl: /*#__PURE__*/_jsx(RefreshControl, {
884
+ refreshing: refreshing,
885
+ onRefresh: () => loadFiles(true),
886
+ tintColor: themeStyles.primaryColor
887
+ }),
888
+ showsVerticalScrollIndicator: false,
889
+ children: [loadingDimensions && /*#__PURE__*/_jsxs(View, {
890
+ style: styles.dimensionsLoadingIndicator,
891
+ children: [/*#__PURE__*/_jsx(ActivityIndicator, {
892
+ size: "small",
893
+ color: themeStyles.primaryColor
894
+ }), /*#__PURE__*/_jsx(Text, {
895
+ style: [styles.dimensionsLoadingText, {
896
+ color: themeStyles.isDarkTheme ? '#BBBBBB' : '#666666'
897
+ }],
898
+ children: "Loading photo layout..."
899
+ })]
900
+ }), /*#__PURE__*/_jsx(JustifiedPhotoGrid, {
901
+ photos: photos,
902
+ photoDimensions: photoDimensions,
903
+ loadPhotoDimensions: loadPhotoDimensions,
904
+ createJustifiedRows: createJustifiedRows,
905
+ renderJustifiedPhotoItem: renderJustifiedPhotoItem,
906
+ renderSimplePhotoItem: renderPhotoItem,
907
+ textColor: themeStyles.textColor,
908
+ containerWidth: containerWidth
909
+ })]
910
+ });
911
+ }, [filteredFiles, themeStyles, user?.id, targetUserId, uploading, handleFileUpload, refreshing, loadFiles, loadingDimensions, photoDimensions, loadPhotoDimensions, createJustifiedRows, renderJustifiedPhotoItem, renderPhotoItem, containerWidth]);
912
+
913
+ // Separate component for the photo grid to optimize rendering
914
+ const JustifiedPhotoGrid = /*#__PURE__*/React.memo(({
915
+ photos,
916
+ photoDimensions,
917
+ loadPhotoDimensions,
918
+ createJustifiedRows,
919
+ renderJustifiedPhotoItem,
920
+ renderSimplePhotoItem,
921
+ textColor,
922
+ containerWidth
923
+ }) => {
924
+ // Load dimensions for new photos
925
+ React.useEffect(() => {
926
+ loadPhotoDimensions(photos);
927
+ }, [photos.map(p => p.id).join(','), loadPhotoDimensions]);
928
+
929
+ // Group photos by date
930
+ const photosByDate = React.useMemo(() => {
931
+ return photos.reduce((groups, photo) => {
932
+ const date = new Date(photo.uploadDate).toDateString();
933
+ if (!groups[date]) {
934
+ groups[date] = [];
935
+ }
936
+ groups[date].push(photo);
937
+ return groups;
938
+ }, {});
939
+ }, [photos]);
940
+ const sortedDates = React.useMemo(() => {
941
+ return Object.keys(photosByDate).sort((a, b) => new Date(b).getTime() - new Date(a).getTime());
942
+ }, [photosByDate]);
943
+ return /*#__PURE__*/_jsx(_Fragment, {
944
+ children: sortedDates.map(date => {
945
+ const dayPhotos = photosByDate[date];
946
+ const justifiedRows = createJustifiedRows(dayPhotos, containerWidth);
947
+ return /*#__PURE__*/_jsxs(View, {
948
+ style: styles.photoDateSection,
949
+ children: [/*#__PURE__*/_jsx(Text, {
950
+ style: [styles.photoDateHeader, {
951
+ color: themeStyles.textColor
952
+ }],
953
+ children: new Date(date).toLocaleDateString('en-US', {
954
+ weekday: 'long',
955
+ year: 'numeric',
956
+ month: 'long',
957
+ day: 'numeric'
958
+ })
959
+ }), /*#__PURE__*/_jsx(View, {
960
+ style: styles.justifiedPhotoGrid,
961
+ children: justifiedRows.map((row, rowIndex) => {
962
+ // Calculate row height based on available width
963
+ const gap = 4;
964
+ let totalAspectRatio = 0;
965
+
966
+ // Calculate total aspect ratio for this row
967
+ row.forEach(photo => {
968
+ const dimensions = photoDimensions[photo.id];
969
+ const aspectRatio = dimensions ? dimensions.width / dimensions.height : 1.33; // Default 4:3 ratio
970
+ totalAspectRatio += aspectRatio;
971
+ });
972
+
973
+ // Calculate the height that makes the row fill the available width
974
+ // Account for photoScrollContainer padding (32px total) and gaps between photos
975
+ const scrollContainerPadding = 32;
976
+ const availableWidth = containerWidth - scrollContainerPadding - gap * (row.length - 1);
977
+ const calculatedHeight = availableWidth / totalAspectRatio;
978
+
979
+ // Clamp height for visual consistency
980
+ const rowHeight = Math.max(120, Math.min(calculatedHeight, 300));
981
+ return /*#__PURE__*/_jsx(View, {
982
+ style: [styles.justifiedPhotoRow, {
983
+ height: rowHeight,
984
+ maxWidth: containerWidth - 32,
985
+ // Account for scroll container padding
986
+ gap: 4 // Add horizontal gap between photos in row
987
+ }],
988
+ children: row.map((photo, photoIndex) => {
989
+ const dimensions = photoDimensions[photo.id];
990
+ const aspectRatio = dimensions ? dimensions.width / dimensions.height : 1.33; // Default 4:3 ratio
991
+
992
+ const photoWidth = rowHeight * aspectRatio;
993
+ const isLast = photoIndex === row.length - 1;
994
+ return renderJustifiedPhotoItem(photo, photoWidth, rowHeight, isLast);
995
+ })
996
+ }, `row-${rowIndex}`);
997
+ })
998
+ })]
999
+ }, date);
1000
+ })
1001
+ });
1002
+ });
1003
+ const renderFileDetailsModal = () => {
1004
+ const backgroundColor = themeStyles.backgroundColor;
1005
+ const borderColor = themeStyles.borderColor;
1006
+ return /*#__PURE__*/_jsx(Modal, {
1007
+ visible: showFileDetails,
1008
+ animationType: "slide",
1009
+ presentationStyle: "pageSheet",
1010
+ onRequestClose: () => setShowFileDetails(false),
1011
+ children: /*#__PURE__*/_jsxs(View, {
1012
+ style: [styles.modalContainer, {
1013
+ backgroundColor
1014
+ }],
1015
+ children: [/*#__PURE__*/_jsxs(View, {
1016
+ style: [styles.modalHeader, {
1017
+ borderBottomColor: borderColor
1018
+ }],
1019
+ children: [/*#__PURE__*/_jsx(TouchableOpacity, {
1020
+ style: styles.modalCloseButton,
1021
+ onPress: () => setShowFileDetails(false),
1022
+ children: /*#__PURE__*/_jsx(Ionicons, {
1023
+ name: "close",
1024
+ size: 24,
1025
+ color: themeStyles.textColor
1026
+ })
1027
+ }), /*#__PURE__*/_jsx(Text, {
1028
+ style: [styles.modalTitle, {
1029
+ color: themeStyles.textColor
1030
+ }],
1031
+ children: "File Details"
1032
+ }), /*#__PURE__*/_jsx(View, {
1033
+ style: styles.modalPlaceholder
1034
+ })]
1035
+ }), selectedFile && /*#__PURE__*/_jsx(ScrollView, {
1036
+ style: styles.modalContent,
1037
+ children: /*#__PURE__*/_jsxs(View, {
1038
+ style: [styles.fileDetailCard, {
1039
+ backgroundColor: themeStyles.secondaryBackgroundColor,
1040
+ borderColor
1041
+ }],
1042
+ children: [/*#__PURE__*/_jsx(View, {
1043
+ style: styles.fileDetailIcon,
1044
+ children: /*#__PURE__*/_jsx(Ionicons, {
1045
+ name: getFileIcon(selectedFile.contentType),
1046
+ size: 64,
1047
+ color: themeStyles.primaryColor
1048
+ })
1049
+ }), /*#__PURE__*/_jsx(Text, {
1050
+ style: [styles.fileDetailName, {
1051
+ color: themeStyles.textColor
1052
+ }],
1053
+ children: selectedFile.filename
1054
+ }), /*#__PURE__*/_jsxs(View, {
1055
+ style: styles.fileDetailInfo,
1056
+ children: [/*#__PURE__*/_jsxs(View, {
1057
+ style: styles.detailRow,
1058
+ children: [/*#__PURE__*/_jsx(Text, {
1059
+ style: [styles.detailLabel, {
1060
+ color: themeStyles.isDarkTheme ? '#BBBBBB' : '#666666'
1061
+ }],
1062
+ children: "Size:"
1063
+ }), /*#__PURE__*/_jsx(Text, {
1064
+ style: [styles.detailValue, {
1065
+ color: themeStyles.textColor
1066
+ }],
1067
+ children: formatFileSize(selectedFile.length)
1068
+ })]
1069
+ }), /*#__PURE__*/_jsxs(View, {
1070
+ style: styles.detailRow,
1071
+ children: [/*#__PURE__*/_jsx(Text, {
1072
+ style: [styles.detailLabel, {
1073
+ color: themeStyles.isDarkTheme ? '#BBBBBB' : '#666666'
1074
+ }],
1075
+ children: "Type:"
1076
+ }), /*#__PURE__*/_jsx(Text, {
1077
+ style: [styles.detailValue, {
1078
+ color: themeStyles.textColor
1079
+ }],
1080
+ children: selectedFile.contentType
1081
+ })]
1082
+ }), /*#__PURE__*/_jsxs(View, {
1083
+ style: styles.detailRow,
1084
+ children: [/*#__PURE__*/_jsx(Text, {
1085
+ style: [styles.detailLabel, {
1086
+ color: themeStyles.isDarkTheme ? '#BBBBBB' : '#666666'
1087
+ }],
1088
+ children: "Uploaded:"
1089
+ }), /*#__PURE__*/_jsx(Text, {
1090
+ style: [styles.detailValue, {
1091
+ color: themeStyles.textColor
1092
+ }],
1093
+ children: new Date(selectedFile.uploadDate).toLocaleString()
1094
+ })]
1095
+ }), selectedFile.metadata?.description && /*#__PURE__*/_jsxs(View, {
1096
+ style: styles.detailRow,
1097
+ children: [/*#__PURE__*/_jsx(Text, {
1098
+ style: [styles.detailLabel, {
1099
+ color: themeStyles.isDarkTheme ? '#BBBBBB' : '#666666'
1100
+ }],
1101
+ children: "Description:"
1102
+ }), /*#__PURE__*/_jsx(Text, {
1103
+ style: [styles.detailValue, {
1104
+ color: themeStyles.textColor
1105
+ }],
1106
+ children: selectedFile.metadata.description
1107
+ })]
1108
+ })]
1109
+ }), /*#__PURE__*/_jsxs(View, {
1110
+ style: styles.modalActions,
1111
+ children: [/*#__PURE__*/_jsxs(TouchableOpacity, {
1112
+ style: [styles.modalActionButton, {
1113
+ backgroundColor: themeStyles.primaryColor
1114
+ }],
1115
+ onPress: () => {
1116
+ handleFileDownload(selectedFile.id, selectedFile.filename);
1117
+ setShowFileDetails(false);
1118
+ },
1119
+ children: [/*#__PURE__*/_jsx(Ionicons, {
1120
+ name: "download",
1121
+ size: 20,
1122
+ color: "#FFFFFF"
1123
+ }), /*#__PURE__*/_jsx(Text, {
1124
+ style: styles.modalActionText,
1125
+ children: "Download"
1126
+ })]
1127
+ }), user?.id === targetUserId && /*#__PURE__*/_jsxs(TouchableOpacity, {
1128
+ style: [styles.modalActionButton, {
1129
+ backgroundColor: themeStyles.dangerColor
1130
+ }],
1131
+ onPress: () => {
1132
+ setShowFileDetails(false);
1133
+ handleFileDelete(selectedFile.id, selectedFile.filename);
1134
+ },
1135
+ children: [/*#__PURE__*/_jsx(Ionicons, {
1136
+ name: "trash",
1137
+ size: 20,
1138
+ color: "#FFFFFF"
1139
+ }), /*#__PURE__*/_jsx(Text, {
1140
+ style: styles.modalActionText,
1141
+ children: "Delete"
1142
+ })]
1143
+ })]
1144
+ })]
1145
+ })
1146
+ })]
1147
+ })
1148
+ });
1149
+ };
1150
+ const renderFileViewer = () => {
1151
+ if (!openedFile) return null;
1152
+ const backgroundColor = themeStyles.backgroundColor;
1153
+ const borderColor = themeStyles.borderColor;
1154
+ const isImage = openedFile.contentType.startsWith('image/');
1155
+ const isText = openedFile.contentType.startsWith('text/') || openedFile.contentType.includes('json') || openedFile.contentType.includes('xml') || openedFile.contentType.includes('javascript') || openedFile.contentType.includes('typescript');
1156
+ const isPDF = openedFile.contentType.includes('pdf');
1157
+ const isVideo = openedFile.contentType.startsWith('video/');
1158
+ const isAudio = openedFile.contentType.startsWith('audio/');
1159
+ return /*#__PURE__*/_jsxs(View, {
1160
+ style: [styles.fileViewerContainer, {
1161
+ backgroundColor
1162
+ }],
1163
+ children: [/*#__PURE__*/_jsxs(View, {
1164
+ style: [styles.fileViewerHeader, {
1165
+ borderBottomColor: borderColor
1166
+ }],
1167
+ children: [/*#__PURE__*/_jsx(TouchableOpacity, {
1168
+ style: styles.backButton,
1169
+ onPress: handleCloseFile,
1170
+ children: /*#__PURE__*/_jsx(Ionicons, {
1171
+ name: "arrow-back",
1172
+ size: 24,
1173
+ color: themeStyles.textColor
1174
+ })
1175
+ }), /*#__PURE__*/_jsxs(View, {
1176
+ style: styles.fileViewerTitleContainer,
1177
+ children: [/*#__PURE__*/_jsx(Text, {
1178
+ style: [styles.fileViewerTitle, {
1179
+ color: themeStyles.textColor
1180
+ }],
1181
+ numberOfLines: 1,
1182
+ children: openedFile.filename
1183
+ }), /*#__PURE__*/_jsxs(Text, {
1184
+ style: [styles.fileViewerSubtitle, {
1185
+ color: themeStyles.isDarkTheme ? '#BBBBBB' : '#666666'
1186
+ }],
1187
+ children: [formatFileSize(openedFile.length), " \u2022 ", openedFile.contentType]
1188
+ })]
1189
+ }), /*#__PURE__*/_jsxs(View, {
1190
+ style: styles.fileViewerActions,
1191
+ children: [/*#__PURE__*/_jsx(TouchableOpacity, {
1192
+ style: [styles.actionButton, {
1193
+ backgroundColor: themeStyles.isDarkTheme ? '#333333' : '#F0F0F0'
1194
+ }],
1195
+ onPress: () => handleFileDownload(openedFile.id, openedFile.filename),
1196
+ children: /*#__PURE__*/_jsx(Ionicons, {
1197
+ name: "download",
1198
+ size: 20,
1199
+ color: themeStyles.primaryColor
1200
+ })
1201
+ }), /*#__PURE__*/_jsx(TouchableOpacity, {
1202
+ style: [styles.actionButton, {
1203
+ backgroundColor: showFileDetailsInViewer ? themeStyles.primaryColor : themeStyles.isDarkTheme ? '#333333' : '#F0F0F0'
1204
+ }],
1205
+ onPress: () => setShowFileDetailsInViewer(!showFileDetailsInViewer),
1206
+ children: /*#__PURE__*/_jsx(Ionicons, {
1207
+ name: showFileDetailsInViewer ? "chevron-up" : "information-circle",
1208
+ size: 20,
1209
+ color: showFileDetailsInViewer ? "#FFFFFF" : themeStyles.primaryColor
1210
+ })
1211
+ })]
1212
+ })]
1213
+ }), showFileDetailsInViewer && /*#__PURE__*/_jsxs(View, {
1214
+ style: [styles.fileDetailsSection, {
1215
+ backgroundColor: themeStyles.secondaryBackgroundColor,
1216
+ borderColor
1217
+ }],
1218
+ children: [/*#__PURE__*/_jsxs(View, {
1219
+ style: styles.fileDetailsSectionHeader,
1220
+ children: [/*#__PURE__*/_jsx(Text, {
1221
+ style: [styles.fileDetailsSectionTitle, {
1222
+ color: themeStyles.textColor
1223
+ }],
1224
+ children: "File Details"
1225
+ }), /*#__PURE__*/_jsx(TouchableOpacity, {
1226
+ style: styles.fileDetailsSectionToggle,
1227
+ onPress: () => setShowFileDetailsInViewer(false),
1228
+ children: /*#__PURE__*/_jsx(Ionicons, {
1229
+ name: "chevron-up",
1230
+ size: 20,
1231
+ color: themeStyles.isDarkTheme ? '#BBBBBB' : '#666666'
1232
+ })
1233
+ })]
1234
+ }), /*#__PURE__*/_jsxs(View, {
1235
+ style: styles.fileDetailInfo,
1236
+ children: [/*#__PURE__*/_jsxs(View, {
1237
+ style: styles.detailRow,
1238
+ children: [/*#__PURE__*/_jsx(Text, {
1239
+ style: [styles.detailLabel, {
1240
+ color: themeStyles.isDarkTheme ? '#BBBBBB' : '#666666'
1241
+ }],
1242
+ children: "File Name:"
1243
+ }), /*#__PURE__*/_jsx(Text, {
1244
+ style: [styles.detailValue, {
1245
+ color: themeStyles.textColor
1246
+ }],
1247
+ children: openedFile.filename
1248
+ })]
1249
+ }), /*#__PURE__*/_jsxs(View, {
1250
+ style: styles.detailRow,
1251
+ children: [/*#__PURE__*/_jsx(Text, {
1252
+ style: [styles.detailLabel, {
1253
+ color: themeStyles.isDarkTheme ? '#BBBBBB' : '#666666'
1254
+ }],
1255
+ children: "Size:"
1256
+ }), /*#__PURE__*/_jsx(Text, {
1257
+ style: [styles.detailValue, {
1258
+ color: themeStyles.textColor
1259
+ }],
1260
+ children: formatFileSize(openedFile.length)
1261
+ })]
1262
+ }), /*#__PURE__*/_jsxs(View, {
1263
+ style: styles.detailRow,
1264
+ children: [/*#__PURE__*/_jsx(Text, {
1265
+ style: [styles.detailLabel, {
1266
+ color: themeStyles.isDarkTheme ? '#BBBBBB' : '#666666'
1267
+ }],
1268
+ children: "Type:"
1269
+ }), /*#__PURE__*/_jsx(Text, {
1270
+ style: [styles.detailValue, {
1271
+ color: themeStyles.textColor
1272
+ }],
1273
+ children: openedFile.contentType
1274
+ })]
1275
+ }), /*#__PURE__*/_jsxs(View, {
1276
+ style: styles.detailRow,
1277
+ children: [/*#__PURE__*/_jsx(Text, {
1278
+ style: [styles.detailLabel, {
1279
+ color: themeStyles.isDarkTheme ? '#BBBBBB' : '#666666'
1280
+ }],
1281
+ children: "Uploaded:"
1282
+ }), /*#__PURE__*/_jsx(Text, {
1283
+ style: [styles.detailValue, {
1284
+ color: themeStyles.textColor
1285
+ }],
1286
+ children: new Date(openedFile.uploadDate).toLocaleString()
1287
+ })]
1288
+ }), openedFile.metadata?.description && /*#__PURE__*/_jsxs(View, {
1289
+ style: styles.detailRow,
1290
+ children: [/*#__PURE__*/_jsx(Text, {
1291
+ style: [styles.detailLabel, {
1292
+ color: themeStyles.isDarkTheme ? '#BBBBBB' : '#666666'
1293
+ }],
1294
+ children: "Description:"
1295
+ }), /*#__PURE__*/_jsx(Text, {
1296
+ style: [styles.detailValue, {
1297
+ color: themeStyles.textColor
1298
+ }],
1299
+ children: openedFile.metadata.description
1300
+ })]
1301
+ }), /*#__PURE__*/_jsxs(View, {
1302
+ style: styles.detailRow,
1303
+ children: [/*#__PURE__*/_jsx(Text, {
1304
+ style: [styles.detailLabel, {
1305
+ color: themeStyles.isDarkTheme ? '#BBBBBB' : '#666666'
1306
+ }],
1307
+ children: "File ID:"
1308
+ }), /*#__PURE__*/_jsx(Text, {
1309
+ style: [styles.detailValue, {
1310
+ color: themeStyles.textColor,
1311
+ fontSize: 12,
1312
+ fontFamily: Platform.OS === 'web' ? 'monospace' : 'Courier'
1313
+ }],
1314
+ children: openedFile.id
1315
+ })]
1316
+ })]
1317
+ }), /*#__PURE__*/_jsxs(View, {
1318
+ style: styles.fileDetailsActions,
1319
+ children: [/*#__PURE__*/_jsxs(TouchableOpacity, {
1320
+ style: [styles.fileDetailsActionButton, {
1321
+ backgroundColor: themeStyles.primaryColor
1322
+ }],
1323
+ onPress: () => handleFileDownload(openedFile.id, openedFile.filename),
1324
+ children: [/*#__PURE__*/_jsx(Ionicons, {
1325
+ name: "download",
1326
+ size: 16,
1327
+ color: "#FFFFFF"
1328
+ }), /*#__PURE__*/_jsx(Text, {
1329
+ style: styles.fileDetailsActionText,
1330
+ children: "Download"
1331
+ })]
1332
+ }), user?.id === targetUserId && /*#__PURE__*/_jsxs(TouchableOpacity, {
1333
+ style: [styles.fileDetailsActionButton, {
1334
+ backgroundColor: themeStyles.dangerColor
1335
+ }],
1336
+ onPress: () => {
1337
+ handleCloseFile();
1338
+ handleFileDelete(openedFile.id, openedFile.filename);
1339
+ },
1340
+ children: [/*#__PURE__*/_jsx(Ionicons, {
1341
+ name: "trash",
1342
+ size: 16,
1343
+ color: "#FFFFFF"
1344
+ }), /*#__PURE__*/_jsx(Text, {
1345
+ style: styles.fileDetailsActionText,
1346
+ children: "Delete"
1347
+ })]
1348
+ })]
1349
+ })]
1350
+ }), /*#__PURE__*/_jsx(ScrollView, {
1351
+ style: [styles.fileViewerContent, showFileDetailsInViewer && styles.fileViewerContentWithDetails],
1352
+ contentContainerStyle: styles.fileViewerContentContainer,
1353
+ children: loadingFileContent ? /*#__PURE__*/_jsxs(View, {
1354
+ style: styles.fileViewerLoading,
1355
+ children: [/*#__PURE__*/_jsx(ActivityIndicator, {
1356
+ size: "large",
1357
+ color: themeStyles.primaryColor
1358
+ }), /*#__PURE__*/_jsx(Text, {
1359
+ style: [styles.fileViewerLoadingText, {
1360
+ color: themeStyles.textColor
1361
+ }],
1362
+ children: "Loading file content..."
1363
+ })]
1364
+ }) : isImage && fileContent ? /*#__PURE__*/_jsx(View, {
1365
+ style: styles.imageContainer,
1366
+ children: Platform.OS === 'web' ? /*#__PURE__*/_jsx("img", {
1367
+ src: fileContent,
1368
+ alt: openedFile.filename,
1369
+ style: {
1370
+ maxWidth: '100%',
1371
+ maxHeight: '80vh',
1372
+ objectFit: 'contain',
1373
+ borderRadius: 8
1374
+ },
1375
+ onError: e => {
1376
+ console.error('Image failed to load:', e);
1377
+ }
1378
+ }) : /*#__PURE__*/_jsx(Image, {
1379
+ source: {
1380
+ uri: fileContent
1381
+ },
1382
+ style: {
1383
+ width: '100%',
1384
+ height: 400,
1385
+ resizeMode: 'contain',
1386
+ borderRadius: 8
1387
+ },
1388
+ onError: e => {
1389
+ console.error('Image failed to load:', e);
1390
+ }
1391
+ })
1392
+ }) : isText && fileContent ? /*#__PURE__*/_jsx(View, {
1393
+ style: [styles.textContainer, {
1394
+ backgroundColor: themeStyles.secondaryBackgroundColor,
1395
+ borderColor
1396
+ }],
1397
+ children: /*#__PURE__*/_jsx(ScrollView, {
1398
+ style: {
1399
+ flex: 1
1400
+ },
1401
+ nestedScrollEnabled: true,
1402
+ children: /*#__PURE__*/_jsx(Text, {
1403
+ style: [styles.textContent, {
1404
+ color: themeStyles.textColor
1405
+ }],
1406
+ children: fileContent
1407
+ })
1408
+ })
1409
+ }) : isPDF && fileContent && Platform.OS === 'web' ? /*#__PURE__*/_jsx(View, {
1410
+ style: styles.pdfContainer,
1411
+ children: /*#__PURE__*/_jsx("iframe", {
1412
+ src: fileContent,
1413
+ width: "100%",
1414
+ height: "600px",
1415
+ style: {
1416
+ border: 'none',
1417
+ borderRadius: 8
1418
+ },
1419
+ title: openedFile.filename
1420
+ })
1421
+ }) : isVideo && fileContent ? /*#__PURE__*/_jsx(View, {
1422
+ style: styles.mediaContainer,
1423
+ children: Platform.OS === 'web' ? /*#__PURE__*/_jsxs("video", {
1424
+ controls: true,
1425
+ style: {
1426
+ width: '100%',
1427
+ maxHeight: '70vh',
1428
+ borderRadius: 8
1429
+ },
1430
+ children: [/*#__PURE__*/_jsx("source", {
1431
+ src: fileContent,
1432
+ type: openedFile.contentType
1433
+ }), "Your browser does not support the video tag."]
1434
+ }) : /*#__PURE__*/_jsx(Text, {
1435
+ style: [styles.unsupportedText, {
1436
+ color: themeStyles.textColor
1437
+ }],
1438
+ children: "Video playback not supported on mobile"
1439
+ })
1440
+ }) : isAudio && fileContent ? /*#__PURE__*/_jsx(View, {
1441
+ style: styles.mediaContainer,
1442
+ children: Platform.OS === 'web' ? /*#__PURE__*/_jsxs("audio", {
1443
+ controls: true,
1444
+ style: {
1445
+ width: '100%',
1446
+ borderRadius: 8
1447
+ },
1448
+ children: [/*#__PURE__*/_jsx("source", {
1449
+ src: fileContent,
1450
+ type: openedFile.contentType
1451
+ }), "Your browser does not support the audio tag."]
1452
+ }) : /*#__PURE__*/_jsx(Text, {
1453
+ style: [styles.unsupportedText, {
1454
+ color: themeStyles.textColor
1455
+ }],
1456
+ children: "Audio playback not supported on mobile"
1457
+ })
1458
+ }) : /*#__PURE__*/_jsxs(View, {
1459
+ style: styles.unsupportedFileContainer,
1460
+ children: [/*#__PURE__*/_jsx(Ionicons, {
1461
+ name: getFileIcon(openedFile.contentType),
1462
+ size: 64,
1463
+ color: themeStyles.isDarkTheme ? '#666666' : '#CCCCCC'
1464
+ }), /*#__PURE__*/_jsx(Text, {
1465
+ style: [styles.unsupportedFileTitle, {
1466
+ color: themeStyles.textColor
1467
+ }],
1468
+ children: "Preview Not Available"
1469
+ }), /*#__PURE__*/_jsxs(Text, {
1470
+ style: [styles.unsupportedFileDescription, {
1471
+ color: themeStyles.isDarkTheme ? '#BBBBBB' : '#666666'
1472
+ }],
1473
+ children: ["This file type cannot be previewed in the browser.", '\n', "Download the file to view its contents."]
1474
+ }), /*#__PURE__*/_jsxs(TouchableOpacity, {
1475
+ style: [styles.downloadButtonLarge, {
1476
+ backgroundColor: themeStyles.primaryColor
1477
+ }],
1478
+ onPress: () => handleFileDownload(openedFile.id, openedFile.filename),
1479
+ children: [/*#__PURE__*/_jsx(Ionicons, {
1480
+ name: "download",
1481
+ size: 20,
1482
+ color: "#FFFFFF"
1483
+ }), /*#__PURE__*/_jsx(Text, {
1484
+ style: styles.downloadButtonText,
1485
+ children: "Download File"
1486
+ })]
1487
+ })]
1488
+ })
1489
+ })]
1490
+ });
1491
+ };
1492
+ const renderEmptyState = () => /*#__PURE__*/_jsxs(View, {
1493
+ style: styles.emptyState,
1494
+ children: [/*#__PURE__*/_jsx(Ionicons, {
1495
+ name: "folder-open-outline",
1496
+ size: 64,
1497
+ color: themeStyles.isDarkTheme ? '#666666' : '#CCCCCC'
1498
+ }), /*#__PURE__*/_jsx(Text, {
1499
+ style: [styles.emptyStateTitle, {
1500
+ color: themeStyles.textColor
1501
+ }],
1502
+ children: "No Files Yet"
1503
+ }), /*#__PURE__*/_jsx(Text, {
1504
+ style: [styles.emptyStateDescription, {
1505
+ color: themeStyles.isDarkTheme ? '#BBBBBB' : '#666666'
1506
+ }],
1507
+ children: user?.id === targetUserId ? `Upload files to get started. You can select multiple files at once${Platform.OS === 'web' ? ' or drag & drop them here.' : '.'}` : "This user hasn't uploaded any files yet"
1508
+ }), user?.id === targetUserId && /*#__PURE__*/_jsx(TouchableOpacity, {
1509
+ style: [styles.emptyStateButton, {
1510
+ backgroundColor: themeStyles.primaryColor
1511
+ }],
1512
+ onPress: handleFileUpload,
1513
+ disabled: uploading,
1514
+ children: uploading ? /*#__PURE__*/_jsx(ActivityIndicator, {
1515
+ size: "small",
1516
+ color: "#FFFFFF"
1517
+ }) : /*#__PURE__*/_jsxs(_Fragment, {
1518
+ children: [/*#__PURE__*/_jsx(Ionicons, {
1519
+ name: "cloud-upload",
1520
+ size: 20,
1521
+ color: "#FFFFFF"
1522
+ }), /*#__PURE__*/_jsx(Text, {
1523
+ style: styles.emptyStateButtonText,
1524
+ children: "Upload Files"
1525
+ })]
1526
+ })
1527
+ })]
1528
+ });
1529
+ if (loading) {
1530
+ return /*#__PURE__*/_jsxs(View, {
1531
+ style: [styles.container, styles.centerContent, {
1532
+ backgroundColor
1533
+ }],
1534
+ children: [/*#__PURE__*/_jsx(ActivityIndicator, {
1535
+ size: "large",
1536
+ color: themeStyles.primaryColor
1537
+ }), /*#__PURE__*/_jsx(Text, {
1538
+ style: [styles.loadingText, {
1539
+ color: themeStyles.textColor
1540
+ }],
1541
+ children: "Loading files..."
1542
+ })]
1543
+ });
1544
+ }
1545
+
1546
+ // If a file is opened, show the file viewer
1547
+ if (openedFile) {
1548
+ return /*#__PURE__*/_jsxs(_Fragment, {
1549
+ children: [renderFileViewer(), renderFileDetailsModal()]
1550
+ });
1551
+ }
1552
+ return /*#__PURE__*/_jsxs(View, {
1553
+ style: [styles.container, {
1554
+ backgroundColor
1555
+ }, isDragging && Platform.OS === 'web' && styles.dragOverlay],
1556
+ ...(Platform.OS === 'web' && user?.id === targetUserId ? {
1557
+ onDragOver: handleDragOver,
1558
+ onDragLeave: handleDragLeave,
1559
+ onDrop: handleDrop
1560
+ } : {}),
1561
+ children: [/*#__PURE__*/_jsxs(View, {
1562
+ style: [styles.header, {
1563
+ borderBottomColor: borderColor,
1564
+ backgroundColor: themeStyles.isDarkTheme ? '#1A1A1A' : '#FFFFFF',
1565
+ shadowColor: '#000000',
1566
+ shadowOffset: {
1567
+ width: 0,
1568
+ height: 2
1569
+ },
1570
+ shadowOpacity: themeStyles.isDarkTheme ? 0.3 : 0.1,
1571
+ shadowRadius: 8,
1572
+ elevation: 4
1573
+ }],
1574
+ children: [/*#__PURE__*/_jsx(TouchableOpacity, {
1575
+ style: [styles.backButton, {
1576
+ backgroundColor: themeStyles.isDarkTheme ? '#2A2A2A' : '#F8F9FA',
1577
+ borderRadius: 12
1578
+ }],
1579
+ onPress: onClose || goBack,
1580
+ children: /*#__PURE__*/_jsx(Ionicons, {
1581
+ name: "arrow-back",
1582
+ size: 22,
1583
+ color: themeStyles.textColor
1584
+ })
1585
+ }), /*#__PURE__*/_jsxs(View, {
1586
+ style: styles.headerTitleContainer,
1587
+ children: [/*#__PURE__*/_jsx(Text, {
1588
+ style: [styles.headerTitle, {
1589
+ color: themeStyles.textColor
1590
+ }],
1591
+ children: viewMode === 'photos' ? 'Photos' : 'File Management'
1592
+ }), /*#__PURE__*/_jsxs(Text, {
1593
+ style: [styles.headerSubtitle, {
1594
+ color: themeStyles.isDarkTheme ? '#AAAAAA' : '#666666'
1595
+ }],
1596
+ children: [filteredFiles.length, " ", filteredFiles.length === 1 ? 'item' : 'items']
1597
+ })]
1598
+ }), /*#__PURE__*/_jsxs(View, {
1599
+ style: styles.headerActions,
1600
+ children: [/*#__PURE__*/_jsxs(View, {
1601
+ style: [styles.viewModeToggle, {
1602
+ backgroundColor: themeStyles.isDarkTheme ? '#2A2A2A' : '#F8F9FA',
1603
+ borderWidth: 1,
1604
+ borderColor: themeStyles.isDarkTheme ? '#3A3A3A' : '#E8E9EA',
1605
+ shadowColor: '#000000',
1606
+ shadowOffset: {
1607
+ width: 0,
1608
+ height: 1
1609
+ },
1610
+ shadowOpacity: themeStyles.isDarkTheme ? 0.3 : 0.05,
1611
+ shadowRadius: 4,
1612
+ elevation: 2
1613
+ }],
1614
+ children: [/*#__PURE__*/_jsx(TouchableOpacity, {
1615
+ style: [styles.viewModeButton, viewMode === 'all' && {
1616
+ backgroundColor: themeStyles.primaryColor,
1617
+ shadowColor: themeStyles.primaryColor,
1618
+ shadowOffset: {
1619
+ width: 0,
1620
+ height: 2
1621
+ },
1622
+ shadowOpacity: 0.3,
1623
+ shadowRadius: 4,
1624
+ elevation: 3
1625
+ }],
1626
+ onPress: () => setViewMode('all'),
1627
+ children: /*#__PURE__*/_jsx(Ionicons, {
1628
+ name: "folder",
1629
+ size: 18,
1630
+ color: viewMode === 'all' ? '#FFFFFF' : themeStyles.textColor
1631
+ })
1632
+ }), /*#__PURE__*/_jsx(TouchableOpacity, {
1633
+ style: [styles.viewModeButton, viewMode === 'photos' && {
1634
+ backgroundColor: themeStyles.primaryColor,
1635
+ shadowColor: themeStyles.primaryColor,
1636
+ shadowOffset: {
1637
+ width: 0,
1638
+ height: 2
1639
+ },
1640
+ shadowOpacity: 0.3,
1641
+ shadowRadius: 4,
1642
+ elevation: 3
1643
+ }],
1644
+ onPress: () => setViewMode('photos'),
1645
+ children: /*#__PURE__*/_jsx(Ionicons, {
1646
+ name: "images",
1647
+ size: 18,
1648
+ color: viewMode === 'photos' ? '#FFFFFF' : themeStyles.textColor
1649
+ })
1650
+ })]
1651
+ }), user?.id === targetUserId && /*#__PURE__*/_jsx(TouchableOpacity, {
1652
+ style: [styles.uploadButton, {
1653
+ backgroundColor: themeStyles.primaryColor,
1654
+ shadowColor: themeStyles.primaryColor,
1655
+ shadowOffset: {
1656
+ width: 0,
1657
+ height: 3
1658
+ },
1659
+ shadowOpacity: 0.4,
1660
+ shadowRadius: 6,
1661
+ elevation: 5,
1662
+ transform: uploading ? [{
1663
+ scale: 0.95
1664
+ }] : [{
1665
+ scale: 1
1666
+ }]
1667
+ }],
1668
+ onPress: handleFileUpload,
1669
+ disabled: uploading,
1670
+ children: uploading ? /*#__PURE__*/_jsxs(View, {
1671
+ style: styles.uploadProgress,
1672
+ children: [/*#__PURE__*/_jsx(ActivityIndicator, {
1673
+ size: "small",
1674
+ color: "#FFFFFF"
1675
+ }), uploadProgress && /*#__PURE__*/_jsxs(Text, {
1676
+ style: styles.uploadProgressText,
1677
+ children: [uploadProgress.current, "/", uploadProgress.total]
1678
+ })]
1679
+ }) : /*#__PURE__*/_jsx(Ionicons, {
1680
+ name: "add",
1681
+ size: 26,
1682
+ color: "#FFFFFF"
1683
+ })
1684
+ })]
1685
+ })]
1686
+ }), files.length > 0 && (viewMode === 'all' || files.some(f => f.contentType.startsWith('image/'))) && /*#__PURE__*/_jsxs(View, {
1687
+ style: [styles.searchContainer, {
1688
+ backgroundColor: themeStyles.isDarkTheme ? '#1A1A1A' : '#FFFFFF',
1689
+ borderColor: themeStyles.isDarkTheme ? '#3A3A3A' : '#E8E9EA',
1690
+ shadowColor: '#000000',
1691
+ shadowOffset: {
1692
+ width: 0,
1693
+ height: 1
1694
+ },
1695
+ shadowOpacity: themeStyles.isDarkTheme ? 0.2 : 0.05,
1696
+ shadowRadius: 4,
1697
+ elevation: 2
1698
+ }],
1699
+ children: [/*#__PURE__*/_jsx(Ionicons, {
1700
+ name: "search",
1701
+ size: 22,
1702
+ color: themeStyles.isDarkTheme ? '#888888' : '#666666'
1703
+ }), /*#__PURE__*/_jsx(TextInput, {
1704
+ style: [styles.searchInput, {
1705
+ color: themeStyles.textColor
1706
+ }],
1707
+ placeholder: viewMode === 'photos' ? 'Search photos...' : 'Search files...',
1708
+ placeholderTextColor: themeStyles.isDarkTheme ? '#888888' : '#999999',
1709
+ value: searchQuery,
1710
+ onChangeText: setSearchQuery
1711
+ }), searchQuery.length > 0 && /*#__PURE__*/_jsx(TouchableOpacity, {
1712
+ onPress: () => setSearchQuery(''),
1713
+ style: styles.searchClearButton,
1714
+ children: /*#__PURE__*/_jsx(Ionicons, {
1715
+ name: "close-circle",
1716
+ size: 22,
1717
+ color: themeStyles.isDarkTheme ? '#888888' : '#666666'
1718
+ })
1719
+ })]
1720
+ }), files.length > 0 && /*#__PURE__*/_jsxs(View, {
1721
+ style: [styles.statsContainer, {
1722
+ backgroundColor: themeStyles.isDarkTheme ? '#1A1A1A' : '#FFFFFF',
1723
+ borderColor: themeStyles.isDarkTheme ? '#3A3A3A' : '#E8E9EA',
1724
+ shadowColor: '#000000',
1725
+ shadowOffset: {
1726
+ width: 0,
1727
+ height: 1
1728
+ },
1729
+ shadowOpacity: themeStyles.isDarkTheme ? 0.2 : 0.05,
1730
+ shadowRadius: 4,
1731
+ elevation: 2
1732
+ }],
1733
+ children: [/*#__PURE__*/_jsxs(View, {
1734
+ style: styles.statItem,
1735
+ children: [/*#__PURE__*/_jsx(Text, {
1736
+ style: [styles.statValue, {
1737
+ color: themeStyles.textColor
1738
+ }],
1739
+ children: filteredFiles.length
1740
+ }), /*#__PURE__*/_jsx(Text, {
1741
+ style: [styles.statLabel, {
1742
+ color: themeStyles.isDarkTheme ? '#BBBBBB' : '#666666'
1743
+ }],
1744
+ children: searchQuery.length > 0 ? 'Found' : filteredFiles.length === 1 ? viewMode === 'photos' ? 'Photo' : 'File' : viewMode === 'photos' ? 'Photos' : 'Files'
1745
+ })]
1746
+ }), /*#__PURE__*/_jsxs(View, {
1747
+ style: styles.statItem,
1748
+ children: [/*#__PURE__*/_jsx(Text, {
1749
+ style: [styles.statValue, {
1750
+ color: themeStyles.textColor
1751
+ }],
1752
+ children: formatFileSize(filteredFiles.reduce((total, file) => total + file.length, 0))
1753
+ }), /*#__PURE__*/_jsx(Text, {
1754
+ style: [styles.statLabel, {
1755
+ color: themeStyles.isDarkTheme ? '#BBBBBB' : '#666666'
1756
+ }],
1757
+ children: searchQuery.length > 0 ? 'Size' : 'Total Size'
1758
+ })]
1759
+ }), searchQuery.length > 0 && /*#__PURE__*/_jsxs(View, {
1760
+ style: styles.statItem,
1761
+ children: [/*#__PURE__*/_jsx(Text, {
1762
+ style: [styles.statValue, {
1763
+ color: themeStyles.textColor
1764
+ }],
1765
+ children: files.length
1766
+ }), /*#__PURE__*/_jsx(Text, {
1767
+ style: [styles.statLabel, {
1768
+ color: themeStyles.isDarkTheme ? '#BBBBBB' : '#666666'
1769
+ }],
1770
+ children: "Total"
1771
+ })]
1772
+ })]
1773
+ }), viewMode === 'photos' ? renderPhotoGrid() : /*#__PURE__*/_jsx(ScrollView, {
1774
+ style: styles.scrollView,
1775
+ contentContainerStyle: styles.scrollContainer,
1776
+ refreshControl: /*#__PURE__*/_jsx(RefreshControl, {
1777
+ refreshing: refreshing,
1778
+ onRefresh: () => loadFiles(true),
1779
+ tintColor: themeStyles.primaryColor
1780
+ }),
1781
+ children: filteredFiles.length === 0 && searchQuery.length > 0 ? /*#__PURE__*/_jsxs(View, {
1782
+ style: styles.emptyState,
1783
+ children: [/*#__PURE__*/_jsx(Ionicons, {
1784
+ name: "search",
1785
+ size: 64,
1786
+ color: themeStyles.isDarkTheme ? '#666666' : '#CCCCCC'
1787
+ }), /*#__PURE__*/_jsx(Text, {
1788
+ style: [styles.emptyStateTitle, {
1789
+ color: themeStyles.textColor
1790
+ }],
1791
+ children: "No Results Found"
1792
+ }), /*#__PURE__*/_jsxs(Text, {
1793
+ style: [styles.emptyStateDescription, {
1794
+ color: themeStyles.isDarkTheme ? '#BBBBBB' : '#666666'
1795
+ }],
1796
+ children: ["No files match your search for \"", searchQuery, "\""]
1797
+ }), /*#__PURE__*/_jsxs(TouchableOpacity, {
1798
+ style: [styles.emptyStateButton, {
1799
+ backgroundColor: themeStyles.primaryColor
1800
+ }],
1801
+ onPress: () => setSearchQuery(''),
1802
+ children: [/*#__PURE__*/_jsx(Ionicons, {
1803
+ name: "refresh",
1804
+ size: 20,
1805
+ color: "#FFFFFF"
1806
+ }), /*#__PURE__*/_jsx(Text, {
1807
+ style: styles.emptyStateButtonText,
1808
+ children: "Clear Search"
1809
+ })]
1810
+ })]
1811
+ }) : filteredFiles.length === 0 ? renderEmptyState() : /*#__PURE__*/_jsx(_Fragment, {
1812
+ children: filteredFiles.map(renderFileItem)
1813
+ })
1814
+ }), renderFileDetailsModal(), isDragging && Platform.OS === 'web' && /*#__PURE__*/_jsx(View, {
1815
+ style: styles.dragDropOverlay,
1816
+ children: /*#__PURE__*/_jsxs(View, {
1817
+ style: styles.dragDropContent,
1818
+ children: [/*#__PURE__*/_jsx(Ionicons, {
1819
+ name: "cloud-upload",
1820
+ size: 64,
1821
+ color: themeStyles.primaryColor
1822
+ }), /*#__PURE__*/_jsx(Text, {
1823
+ style: [styles.dragDropTitle, {
1824
+ color: themeStyles.primaryColor
1825
+ }],
1826
+ children: "Drop files to upload"
1827
+ }), /*#__PURE__*/_jsxs(Text, {
1828
+ style: [styles.dragDropSubtitle, {
1829
+ color: themeStyles.isDarkTheme ? '#BBBBBB' : '#666666'
1830
+ }],
1831
+ children: ["Release to upload", uploadProgress ? ` (${uploadProgress.current}/${uploadProgress.total})` : ' multiple files']
1832
+ })]
1833
+ })
1834
+ })]
1835
+ });
1836
+ };
1837
+ const styles = StyleSheet.create({
1838
+ container: {
1839
+ flex: 1
1840
+ },
1841
+ dragOverlay: {
1842
+ backgroundColor: 'rgba(0, 122, 255, 0.1)',
1843
+ borderWidth: 2,
1844
+ borderColor: '#007AFF',
1845
+ borderStyle: 'dashed'
1846
+ },
1847
+ centerContent: {
1848
+ justifyContent: 'center',
1849
+ alignItems: 'center'
1850
+ },
1851
+ header: {
1852
+ flexDirection: 'row',
1853
+ alignItems: 'center',
1854
+ justifyContent: 'space-between',
1855
+ paddingHorizontal: 24,
1856
+ paddingVertical: 20,
1857
+ borderBottomWidth: 1,
1858
+ position: 'relative'
1859
+ },
1860
+ backButton: {
1861
+ padding: 12,
1862
+ borderRadius: 12,
1863
+ alignItems: 'center',
1864
+ justifyContent: 'center',
1865
+ minWidth: 44,
1866
+ minHeight: 44
1867
+ },
1868
+ headerTitleContainer: {
1869
+ flex: 1,
1870
+ alignItems: 'center',
1871
+ justifyContent: 'center',
1872
+ marginHorizontal: 16
1873
+ },
1874
+ headerTitle: {
1875
+ fontSize: 22,
1876
+ fontWeight: '700',
1877
+ fontFamily: fontFamilies.phuduBold,
1878
+ letterSpacing: -0.5,
1879
+ lineHeight: 28
1880
+ },
1881
+ headerSubtitle: {
1882
+ fontSize: 13,
1883
+ fontWeight: '500',
1884
+ fontFamily: fontFamilies.phuduMedium,
1885
+ marginTop: 2,
1886
+ letterSpacing: 0.2
1887
+ },
1888
+ uploadButton: {
1889
+ width: 44,
1890
+ height: 44,
1891
+ borderRadius: 22,
1892
+ alignItems: 'center',
1893
+ justifyContent: 'center'
1894
+ },
1895
+ uploadProgress: {
1896
+ alignItems: 'center',
1897
+ justifyContent: 'center'
1898
+ },
1899
+ uploadProgressText: {
1900
+ color: '#FFFFFF',
1901
+ fontSize: 10,
1902
+ fontWeight: '600',
1903
+ marginTop: 2
1904
+ },
1905
+ searchContainer: {
1906
+ flexDirection: 'row',
1907
+ alignItems: 'center',
1908
+ paddingHorizontal: 20,
1909
+ paddingVertical: 16,
1910
+ marginHorizontal: 24,
1911
+ marginTop: 20,
1912
+ borderRadius: 16,
1913
+ borderWidth: 1,
1914
+ gap: 16
1915
+ },
1916
+ searchInput: {
1917
+ flex: 1,
1918
+ fontSize: 16,
1919
+ fontFamily: fontFamilies.phudu,
1920
+ lineHeight: 20
1921
+ },
1922
+ searchClearButton: {
1923
+ padding: 4,
1924
+ borderRadius: 12,
1925
+ alignItems: 'center',
1926
+ justifyContent: 'center'
1927
+ },
1928
+ searchIcon: {
1929
+ marginRight: 8
1930
+ },
1931
+ statsContainer: {
1932
+ flexDirection: 'row',
1933
+ paddingHorizontal: 24,
1934
+ paddingVertical: 20,
1935
+ marginHorizontal: 24,
1936
+ marginTop: 20,
1937
+ borderRadius: 16,
1938
+ borderWidth: 1
1939
+ },
1940
+ statItem: {
1941
+ flex: 1,
1942
+ alignItems: 'center',
1943
+ paddingVertical: 4
1944
+ },
1945
+ statValue: {
1946
+ fontSize: 28,
1947
+ fontWeight: '800',
1948
+ fontFamily: fontFamilies.phuduBold,
1949
+ letterSpacing: -0.5,
1950
+ lineHeight: 32
1951
+ },
1952
+ statLabel: {
1953
+ fontSize: 15,
1954
+ fontWeight: '500',
1955
+ fontFamily: fontFamilies.phuduMedium,
1956
+ marginTop: 4,
1957
+ letterSpacing: 0.3
1958
+ },
1959
+ scrollView: {
1960
+ flex: 1
1961
+ },
1962
+ scrollContainer: {
1963
+ padding: 20
1964
+ },
1965
+ fileItem: {
1966
+ flexDirection: 'row',
1967
+ alignItems: 'center',
1968
+ padding: 16,
1969
+ marginBottom: 12,
1970
+ borderRadius: 12,
1971
+ borderWidth: 1
1972
+ },
1973
+ fileContent: {
1974
+ flexDirection: 'row',
1975
+ alignItems: 'center',
1976
+ flex: 1
1977
+ },
1978
+ fileIconContainer: {
1979
+ width: 50,
1980
+ height: 50,
1981
+ alignItems: 'center',
1982
+ justifyContent: 'center',
1983
+ marginRight: 12
1984
+ },
1985
+ filePreviewContainer: {
1986
+ width: 60,
1987
+ height: 60,
1988
+ marginRight: 12
1989
+ },
1990
+ filePreview: {
1991
+ width: '100%',
1992
+ height: '100%',
1993
+ borderRadius: 8,
1994
+ backgroundColor: '#F5F5F5',
1995
+ alignItems: 'center',
1996
+ justifyContent: 'center',
1997
+ overflow: 'hidden',
1998
+ position: 'relative'
1999
+ },
2000
+ previewImage: {
2001
+ width: '100%',
2002
+ height: '100%',
2003
+ borderRadius: 8
2004
+ },
2005
+ pdfPreview: {
2006
+ alignItems: 'center',
2007
+ justifyContent: 'center',
2008
+ width: '100%',
2009
+ height: '100%',
2010
+ backgroundColor: '#FF6B6B20'
2011
+ },
2012
+ pdfLabel: {
2013
+ fontSize: 8,
2014
+ fontWeight: 'bold',
2015
+ marginTop: 2
2016
+ },
2017
+ videoPreview: {
2018
+ alignItems: 'center',
2019
+ justifyContent: 'center',
2020
+ width: '100%',
2021
+ height: '100%',
2022
+ backgroundColor: '#4ECDC420'
2023
+ },
2024
+ videoLabel: {
2025
+ fontSize: 8,
2026
+ fontWeight: 'bold',
2027
+ marginTop: 2
2028
+ },
2029
+ fallbackIcon: {
2030
+ position: 'absolute',
2031
+ top: 0,
2032
+ left: 0,
2033
+ right: 0,
2034
+ bottom: 0,
2035
+ alignItems: 'center',
2036
+ justifyContent: 'center',
2037
+ backgroundColor: '#F5F5F5',
2038
+ borderRadius: 8
2039
+ },
2040
+ previewOverlay: {
2041
+ position: 'absolute',
2042
+ top: 0,
2043
+ left: 0,
2044
+ right: 0,
2045
+ bottom: 0,
2046
+ backgroundColor: 'rgba(0, 0, 0, 0.5)',
2047
+ alignItems: 'center',
2048
+ justifyContent: 'center',
2049
+ borderRadius: 8
2050
+ },
2051
+ fileInfo: {
2052
+ flex: 1
2053
+ },
2054
+ fileName: {
2055
+ fontSize: 16,
2056
+ fontWeight: '600',
2057
+ marginBottom: 4
2058
+ },
2059
+ fileDetails: {
2060
+ fontSize: 14,
2061
+ marginBottom: 2
2062
+ },
2063
+ fileDescription: {
2064
+ fontSize: 12,
2065
+ fontStyle: 'italic'
2066
+ },
2067
+ fileActions: {
2068
+ flexDirection: 'row',
2069
+ gap: 8
2070
+ },
2071
+ actionButton: {
2072
+ width: 40,
2073
+ height: 40,
2074
+ borderRadius: 20,
2075
+ alignItems: 'center',
2076
+ justifyContent: 'center'
2077
+ },
2078
+ emptyState: {
2079
+ alignItems: 'center',
2080
+ paddingVertical: 60,
2081
+ paddingHorizontal: 40
2082
+ },
2083
+ emptyStateTitle: {
2084
+ fontSize: 24,
2085
+ fontWeight: 'bold',
2086
+ fontFamily: fontFamilies.phuduBold,
2087
+ marginTop: 16,
2088
+ marginBottom: 8
2089
+ },
2090
+ emptyStateDescription: {
2091
+ fontSize: 16,
2092
+ textAlign: 'center',
2093
+ lineHeight: 24,
2094
+ marginBottom: 32
2095
+ },
2096
+ emptyStateButton: {
2097
+ flexDirection: 'row',
2098
+ alignItems: 'center',
2099
+ paddingHorizontal: 24,
2100
+ paddingVertical: 12,
2101
+ borderRadius: 24,
2102
+ gap: 8
2103
+ },
2104
+ emptyStateButtonText: {
2105
+ color: '#FFFFFF',
2106
+ fontSize: 16,
2107
+ fontWeight: '600'
2108
+ },
2109
+ loadingText: {
2110
+ fontSize: 16,
2111
+ marginTop: 16
2112
+ },
2113
+ // Modal styles
2114
+ modalContainer: {
2115
+ flex: 1
2116
+ },
2117
+ modalHeader: {
2118
+ flexDirection: 'row',
2119
+ alignItems: 'center',
2120
+ justifyContent: 'space-between',
2121
+ paddingHorizontal: 20,
2122
+ paddingVertical: 16,
2123
+ borderBottomWidth: 1
2124
+ },
2125
+ modalCloseButton: {
2126
+ padding: 8
2127
+ },
2128
+ modalTitle: {
2129
+ fontSize: 18,
2130
+ fontWeight: '600',
2131
+ fontFamily: fontFamilies.phuduSemiBold
2132
+ },
2133
+ modalPlaceholder: {
2134
+ width: 40
2135
+ },
2136
+ modalContent: {
2137
+ flex: 1,
2138
+ padding: 20
2139
+ },
2140
+ fileDetailCard: {
2141
+ padding: 24,
2142
+ borderRadius: 16,
2143
+ borderWidth: 1,
2144
+ alignItems: 'center'
2145
+ },
2146
+ fileDetailIcon: {
2147
+ marginBottom: 16
2148
+ },
2149
+ fileDetailName: {
2150
+ fontSize: 20,
2151
+ fontWeight: 'bold',
2152
+ fontFamily: fontFamilies.phuduBold,
2153
+ textAlign: 'center',
2154
+ marginBottom: 24
2155
+ },
2156
+ fileDetailInfo: {
2157
+ width: '100%',
2158
+ marginBottom: 32
2159
+ },
2160
+ detailRow: {
2161
+ flexDirection: 'row',
2162
+ justifyContent: 'space-between',
2163
+ alignItems: 'flex-start',
2164
+ marginBottom: 12,
2165
+ flexWrap: 'wrap'
2166
+ },
2167
+ detailLabel: {
2168
+ fontSize: 16,
2169
+ fontWeight: '500',
2170
+ flex: 1,
2171
+ minWidth: 100
2172
+ },
2173
+ detailValue: {
2174
+ fontSize: 16,
2175
+ flex: 2,
2176
+ textAlign: 'right'
2177
+ },
2178
+ modalActions: {
2179
+ flexDirection: 'row',
2180
+ gap: 12,
2181
+ width: '100%'
2182
+ },
2183
+ modalActionButton: {
2184
+ flex: 1,
2185
+ flexDirection: 'row',
2186
+ alignItems: 'center',
2187
+ justifyContent: 'center',
2188
+ paddingVertical: 16,
2189
+ borderRadius: 12,
2190
+ gap: 8
2191
+ },
2192
+ modalActionText: {
2193
+ color: '#FFFFFF',
2194
+ fontSize: 16,
2195
+ fontWeight: '600'
2196
+ },
2197
+ // Drag and Drop styles
2198
+ dragDropOverlay: {
2199
+ position: 'absolute',
2200
+ top: 0,
2201
+ left: 0,
2202
+ right: 0,
2203
+ bottom: 0,
2204
+ backgroundColor: 'rgba(0, 0, 0, 0.8)',
2205
+ justifyContent: 'center',
2206
+ alignItems: 'center',
2207
+ zIndex: 1000
2208
+ },
2209
+ dragDropContent: {
2210
+ alignItems: 'center',
2211
+ backgroundColor: 'rgba(255, 255, 255, 0.9)',
2212
+ padding: 40,
2213
+ borderRadius: 20,
2214
+ borderWidth: 3,
2215
+ borderColor: '#007AFF',
2216
+ borderStyle: 'dashed'
2217
+ },
2218
+ dragDropTitle: {
2219
+ fontSize: 24,
2220
+ fontWeight: 'bold',
2221
+ marginTop: 16,
2222
+ marginBottom: 8
2223
+ },
2224
+ dragDropSubtitle: {
2225
+ fontSize: 16,
2226
+ textAlign: 'center'
2227
+ },
2228
+ // File Viewer styles
2229
+ fileViewerContainer: {
2230
+ flex: 1
2231
+ },
2232
+ fileViewerHeader: {
2233
+ flexDirection: 'row',
2234
+ alignItems: 'center',
2235
+ paddingHorizontal: 20,
2236
+ paddingVertical: 16,
2237
+ borderBottomWidth: 1
2238
+ },
2239
+ fileViewerTitleContainer: {
2240
+ flex: 1,
2241
+ marginHorizontal: 16
2242
+ },
2243
+ fileViewerTitle: {
2244
+ fontSize: 18,
2245
+ fontWeight: '600',
2246
+ fontFamily: fontFamilies.phuduSemiBold,
2247
+ marginBottom: 2
2248
+ },
2249
+ fileViewerSubtitle: {
2250
+ fontSize: 14
2251
+ },
2252
+ fileViewerActions: {
2253
+ flexDirection: 'row',
2254
+ gap: 8
2255
+ },
2256
+ fileViewerContent: {
2257
+ flex: 1
2258
+ },
2259
+ fileViewerContentWithDetails: {
2260
+ paddingBottom: 20
2261
+ },
2262
+ fileViewerContentContainer: {
2263
+ flexGrow: 1,
2264
+ padding: 20
2265
+ },
2266
+ fileViewerLoading: {
2267
+ flex: 1,
2268
+ justifyContent: 'center',
2269
+ alignItems: 'center'
2270
+ },
2271
+ fileViewerLoadingText: {
2272
+ fontSize: 16,
2273
+ marginTop: 16
2274
+ },
2275
+ imageContainer: {
2276
+ alignItems: 'center',
2277
+ justifyContent: 'center',
2278
+ flex: 1
2279
+ },
2280
+ textContainer: {
2281
+ flex: 1,
2282
+ borderRadius: 12,
2283
+ borderWidth: 1,
2284
+ padding: 16,
2285
+ minHeight: 200,
2286
+ maxHeight: '80%'
2287
+ },
2288
+ textContent: {
2289
+ fontSize: 14,
2290
+ fontFamily: Platform.OS === 'web' ? 'monospace' : 'Courier',
2291
+ lineHeight: 20
2292
+ },
2293
+ unsupportedFileContainer: {
2294
+ flex: 1,
2295
+ justifyContent: 'center',
2296
+ alignItems: 'center',
2297
+ paddingVertical: 60,
2298
+ paddingHorizontal: 40
2299
+ },
2300
+ unsupportedFileTitle: {
2301
+ fontSize: 24,
2302
+ fontWeight: 'bold',
2303
+ fontFamily: fontFamilies.phuduBold,
2304
+ marginTop: 16,
2305
+ marginBottom: 8,
2306
+ textAlign: 'center'
2307
+ },
2308
+ unsupportedFileDescription: {
2309
+ fontSize: 16,
2310
+ textAlign: 'center',
2311
+ lineHeight: 24,
2312
+ marginBottom: 32
2313
+ },
2314
+ downloadButtonLarge: {
2315
+ flexDirection: 'row',
2316
+ alignItems: 'center',
2317
+ paddingHorizontal: 24,
2318
+ paddingVertical: 16,
2319
+ borderRadius: 24,
2320
+ gap: 8
2321
+ },
2322
+ downloadButtonText: {
2323
+ color: '#FFFFFF',
2324
+ fontSize: 16,
2325
+ fontWeight: '600'
2326
+ },
2327
+ pdfContainer: {
2328
+ flex: 1,
2329
+ alignItems: 'center',
2330
+ justifyContent: 'center'
2331
+ },
2332
+ mediaContainer: {
2333
+ flex: 1,
2334
+ alignItems: 'center',
2335
+ justifyContent: 'center',
2336
+ padding: 20
2337
+ },
2338
+ unsupportedText: {
2339
+ fontSize: 16,
2340
+ textAlign: 'center',
2341
+ fontStyle: 'italic'
2342
+ },
2343
+ // File Details in Viewer styles
2344
+ fileDetailsSection: {
2345
+ margin: 16,
2346
+ marginTop: 0,
2347
+ padding: 20,
2348
+ borderRadius: 12,
2349
+ borderWidth: 1
2350
+ },
2351
+ fileDetailsSectionTitle: {
2352
+ fontSize: 18,
2353
+ fontWeight: '600',
2354
+ fontFamily: fontFamilies.phuduSemiBold,
2355
+ flex: 1
2356
+ },
2357
+ fileDetailsSectionHeader: {
2358
+ flexDirection: 'row',
2359
+ alignItems: 'center',
2360
+ justifyContent: 'space-between',
2361
+ marginBottom: 16
2362
+ },
2363
+ fileDetailsSectionToggle: {
2364
+ padding: 4
2365
+ },
2366
+ fileDetailsActions: {
2367
+ flexDirection: 'row',
2368
+ gap: 12,
2369
+ marginTop: 16
2370
+ },
2371
+ fileDetailsActionButton: {
2372
+ flex: 1,
2373
+ flexDirection: 'row',
2374
+ alignItems: 'center',
2375
+ justifyContent: 'center',
2376
+ paddingVertical: 12,
2377
+ borderRadius: 8,
2378
+ gap: 6
2379
+ },
2380
+ fileDetailsActionText: {
2381
+ color: '#FFFFFF',
2382
+ fontSize: 14,
2383
+ fontWeight: '600'
2384
+ },
2385
+ // Header styles
2386
+ headerActions: {
2387
+ flexDirection: 'row',
2388
+ alignItems: 'center',
2389
+ gap: 16
2390
+ },
2391
+ viewModeToggle: {
2392
+ flexDirection: 'row',
2393
+ borderRadius: 24,
2394
+ padding: 3,
2395
+ overflow: 'hidden'
2396
+ },
2397
+ viewModeButton: {
2398
+ paddingHorizontal: 14,
2399
+ paddingVertical: 10,
2400
+ borderRadius: 20,
2401
+ minWidth: 44,
2402
+ alignItems: 'center',
2403
+ justifyContent: 'center',
2404
+ marginHorizontal: 1
2405
+ },
2406
+ // Photo Grid styles
2407
+ photoScrollContainer: {
2408
+ padding: 16
2409
+ },
2410
+ photoDateSection: {
2411
+ marginBottom: 24
2412
+ },
2413
+ photoDateHeader: {
2414
+ fontSize: 18,
2415
+ fontWeight: '600',
2416
+ fontFamily: fontFamilies.phuduSemiBold,
2417
+ marginBottom: 12,
2418
+ paddingHorizontal: 4
2419
+ },
2420
+ photoGrid: {
2421
+ flexDirection: 'row',
2422
+ flexWrap: 'wrap',
2423
+ gap: 4,
2424
+ justifyContent: 'flex-start'
2425
+ },
2426
+ photoItem: {
2427
+ borderRadius: 8,
2428
+ overflow: 'hidden'
2429
+ },
2430
+ photoContainer: {
2431
+ width: '100%',
2432
+ height: '100%',
2433
+ position: 'relative',
2434
+ borderRadius: 8,
2435
+ overflow: 'hidden'
2436
+ },
2437
+ photoImage: {
2438
+ width: '100%',
2439
+ height: '100%'
2440
+ },
2441
+ // Justified Grid styles
2442
+ dimensionsLoadingIndicator: {
2443
+ flexDirection: 'row',
2444
+ alignItems: 'center',
2445
+ justifyContent: 'center',
2446
+ paddingVertical: 16,
2447
+ gap: 8
2448
+ },
2449
+ dimensionsLoadingText: {
2450
+ fontSize: 14,
2451
+ fontStyle: 'italic'
2452
+ },
2453
+ justifiedPhotoGrid: {
2454
+ gap: 4
2455
+ },
2456
+ justifiedPhotoRow: {
2457
+ flexDirection: 'row'
2458
+ },
2459
+ justifiedPhotoItem: {
2460
+ borderRadius: 6,
2461
+ overflow: 'hidden',
2462
+ position: 'relative'
2463
+ },
2464
+ justifiedPhotoContainer: {
2465
+ width: '100%',
2466
+ height: '100%',
2467
+ position: 'relative',
2468
+ borderRadius: 6,
2469
+ overflow: 'hidden',
2470
+ backgroundColor: '#F5F5F5'
2471
+ },
2472
+ justifiedPhotoImage: {
2473
+ width: '100%',
2474
+ height: '100%',
2475
+ borderRadius: 6
2476
+ },
2477
+ // Simple Photo Grid styles
2478
+ simplePhotoItem: {
2479
+ borderRadius: 8,
2480
+ overflow: 'hidden',
2481
+ backgroundColor: '#F5F5F5'
2482
+ },
2483
+ simplePhotoContainer: {
2484
+ width: '100%',
2485
+ height: '100%',
2486
+ position: 'relative',
2487
+ borderRadius: 8,
2488
+ overflow: 'hidden'
2489
+ },
2490
+ simplePhotoImage: {
2491
+ width: '100%',
2492
+ height: '100%',
2493
+ borderRadius: 8
2494
+ },
2495
+ // Loading skeleton styles
2496
+ photoSkeletonGrid: {
2497
+ flexDirection: 'row',
2498
+ flexWrap: 'wrap',
2499
+ gap: 4,
2500
+ marginTop: 20
2501
+ },
2502
+ photoSkeletonItem: {
2503
+ width: '32%',
2504
+ aspectRatio: 1,
2505
+ borderRadius: 8,
2506
+ marginBottom: 4
2507
+ }
2508
+ });
2509
+ export default FileManagementScreen;
2510
+ //# sourceMappingURL=FileManagementScreen.js.map