@syra.fm/sdk 0.4.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (307) hide show
  1. package/lib/commonjs/client.js +268 -0
  2. package/lib/commonjs/client.js.map +1 -0
  3. package/lib/commonjs/errors.js +22 -0
  4. package/lib/commonjs/errors.js.map +1 -0
  5. package/lib/commonjs/index.js +63 -0
  6. package/lib/commonjs/index.js.map +1 -0
  7. package/lib/commonjs/index.native.js +28 -0
  8. package/lib/commonjs/index.native.js.map +1 -0
  9. package/lib/commonjs/live/assets/icons/spaces-icon.js +42 -0
  10. package/lib/commonjs/live/assets/icons/spaces-icon.js.map +1 -0
  11. package/lib/commonjs/live/assets/icons/syra-icon.js +43 -0
  12. package/lib/commonjs/live/assets/icons/syra-icon.js.map +1 -0
  13. package/lib/commonjs/live/components/AnimatedPulse.js +38 -0
  14. package/lib/commonjs/live/components/AnimatedPulse.js.map +1 -0
  15. package/lib/commonjs/live/components/AnimatedSpeakerRing.js +90 -0
  16. package/lib/commonjs/live/components/AnimatedSpeakerRing.js.map +1 -0
  17. package/lib/commonjs/live/components/CreateRoomSheet.js +688 -0
  18. package/lib/commonjs/live/components/CreateRoomSheet.js.map +1 -0
  19. package/lib/commonjs/live/components/InsightsPanel.js +333 -0
  20. package/lib/commonjs/live/components/InsightsPanel.js.map +1 -0
  21. package/lib/commonjs/live/components/LiveRoomSheet.js +1195 -0
  22. package/lib/commonjs/live/components/LiveRoomSheet.js.map +1 -0
  23. package/lib/commonjs/live/components/MiniRoomBar.js +161 -0
  24. package/lib/commonjs/live/components/MiniRoomBar.js.map +1 -0
  25. package/lib/commonjs/live/components/PanelHeader.js +57 -0
  26. package/lib/commonjs/live/components/PanelHeader.js.map +1 -0
  27. package/lib/commonjs/live/components/PodcastStreamPicker.js +1190 -0
  28. package/lib/commonjs/live/components/PodcastStreamPicker.js.map +1 -0
  29. package/lib/commonjs/live/components/RecordingCard.js +192 -0
  30. package/lib/commonjs/live/components/RecordingCard.js.map +1 -0
  31. package/lib/commonjs/live/components/RecordingsPanel.js +304 -0
  32. package/lib/commonjs/live/components/RecordingsPanel.js.map +1 -0
  33. package/lib/commonjs/live/components/RoomCard.js +553 -0
  34. package/lib/commonjs/live/components/RoomCard.js.map +1 -0
  35. package/lib/commonjs/live/components/StreamConfigModal.js +656 -0
  36. package/lib/commonjs/live/components/StreamConfigModal.js.map +1 -0
  37. package/lib/commonjs/live/components/StreamConfigPanel.js +822 -0
  38. package/lib/commonjs/live/components/StreamConfigPanel.js.map +1 -0
  39. package/lib/commonjs/live/context/LiveConfigContext.js +46 -0
  40. package/lib/commonjs/live/context/LiveConfigContext.js.map +1 -0
  41. package/lib/commonjs/live/context/LiveRoomContext.js +195 -0
  42. package/lib/commonjs/live/context/LiveRoomContext.js.map +1 -0
  43. package/lib/commonjs/live/hooks/useActiveSpeakers.js +35 -0
  44. package/lib/commonjs/live/hooks/useActiveSpeakers.js.map +1 -0
  45. package/lib/commonjs/live/hooks/useRoomAudio.js +129 -0
  46. package/lib/commonjs/live/hooks/useRoomAudio.js.map +1 -0
  47. package/lib/commonjs/live/hooks/useRoomConnection.js +177 -0
  48. package/lib/commonjs/live/hooks/useRoomConnection.js.map +1 -0
  49. package/lib/commonjs/live/hooks/useRoomManager.js +37 -0
  50. package/lib/commonjs/live/hooks/useRoomManager.js.map +1 -0
  51. package/lib/commonjs/live/hooks/useRoomUsers.js +52 -0
  52. package/lib/commonjs/live/hooks/useRoomUsers.js.map +1 -0
  53. package/lib/commonjs/live/index.js +310 -0
  54. package/lib/commonjs/live/index.js.map +1 -0
  55. package/lib/commonjs/live/services/livekitService.js +20 -0
  56. package/lib/commonjs/live/services/livekitService.js.map +1 -0
  57. package/lib/commonjs/live/services/spaceSocketService.js +181 -0
  58. package/lib/commonjs/live/services/spaceSocketService.js.map +1 -0
  59. package/lib/commonjs/live/services/spacesService.js +642 -0
  60. package/lib/commonjs/live/services/spacesService.js.map +1 -0
  61. package/lib/commonjs/live/types.js +6 -0
  62. package/lib/commonjs/live/types.js.map +1 -0
  63. package/lib/commonjs/live/validation.js +238 -0
  64. package/lib/commonjs/live/validation.js.map +1 -0
  65. package/lib/commonjs/package.json +1 -0
  66. package/{dist/cjs → lib/commonjs}/schema.js +55 -47
  67. package/lib/commonjs/schema.js.map +1 -0
  68. package/lib/module/client.js +264 -0
  69. package/lib/module/client.js.map +1 -0
  70. package/lib/module/errors.js +17 -0
  71. package/lib/module/errors.js.map +1 -0
  72. package/lib/module/index.js +6 -0
  73. package/lib/module/index.js.map +1 -0
  74. package/lib/module/index.native.js +5 -0
  75. package/lib/module/index.native.js.map +1 -0
  76. package/lib/module/live/assets/icons/spaces-icon.js +34 -0
  77. package/lib/module/live/assets/icons/spaces-icon.js.map +1 -0
  78. package/lib/module/live/assets/icons/syra-icon.js +36 -0
  79. package/lib/module/live/assets/icons/syra-icon.js.map +1 -0
  80. package/lib/module/live/components/AnimatedPulse.js +33 -0
  81. package/lib/module/live/components/AnimatedPulse.js.map +1 -0
  82. package/lib/module/live/components/AnimatedSpeakerRing.js +85 -0
  83. package/lib/module/live/components/AnimatedSpeakerRing.js.map +1 -0
  84. package/lib/module/live/components/CreateRoomSheet.js +682 -0
  85. package/lib/module/live/components/CreateRoomSheet.js.map +1 -0
  86. package/lib/module/live/components/InsightsPanel.js +327 -0
  87. package/lib/module/live/components/InsightsPanel.js.map +1 -0
  88. package/lib/module/live/components/LiveRoomSheet.js +1189 -0
  89. package/lib/module/live/components/LiveRoomSheet.js.map +1 -0
  90. package/lib/module/live/components/MiniRoomBar.js +154 -0
  91. package/lib/module/live/components/MiniRoomBar.js.map +1 -0
  92. package/lib/module/live/components/PanelHeader.js +52 -0
  93. package/lib/module/live/components/PanelHeader.js.map +1 -0
  94. package/lib/module/live/components/PodcastStreamPicker.js +1183 -0
  95. package/lib/module/live/components/PodcastStreamPicker.js.map +1 -0
  96. package/lib/module/live/components/RecordingCard.js +187 -0
  97. package/lib/module/live/components/RecordingCard.js.map +1 -0
  98. package/lib/module/live/components/RecordingsPanel.js +298 -0
  99. package/lib/module/live/components/RecordingsPanel.js.map +1 -0
  100. package/lib/module/live/components/RoomCard.js +548 -0
  101. package/lib/module/live/components/RoomCard.js.map +1 -0
  102. package/lib/module/live/components/StreamConfigModal.js +650 -0
  103. package/lib/module/live/components/StreamConfigModal.js.map +1 -0
  104. package/lib/module/live/components/StreamConfigPanel.js +816 -0
  105. package/lib/module/live/components/StreamConfigPanel.js.map +1 -0
  106. package/lib/module/live/context/LiveConfigContext.js +40 -0
  107. package/lib/module/live/context/LiveConfigContext.js.map +1 -0
  108. package/lib/module/live/context/LiveRoomContext.js +189 -0
  109. package/lib/module/live/context/LiveRoomContext.js.map +1 -0
  110. package/lib/module/live/hooks/useActiveSpeakers.js +31 -0
  111. package/lib/module/live/hooks/useActiveSpeakers.js.map +1 -0
  112. package/lib/module/live/hooks/useRoomAudio.js +125 -0
  113. package/lib/module/live/hooks/useRoomAudio.js.map +1 -0
  114. package/lib/module/live/hooks/useRoomConnection.js +173 -0
  115. package/lib/module/live/hooks/useRoomConnection.js.map +1 -0
  116. package/lib/module/live/hooks/useRoomManager.js +32 -0
  117. package/lib/module/live/hooks/useRoomManager.js.map +1 -0
  118. package/lib/module/live/hooks/useRoomUsers.js +46 -0
  119. package/lib/module/live/hooks/useRoomUsers.js.map +1 -0
  120. package/lib/module/live/index.js +38 -0
  121. package/lib/module/live/index.js.map +1 -0
  122. package/lib/module/live/services/livekitService.js +16 -0
  123. package/lib/module/live/services/livekitService.js.map +1 -0
  124. package/lib/module/live/services/spaceSocketService.js +176 -0
  125. package/lib/module/live/services/spaceSocketService.js.map +1 -0
  126. package/lib/module/live/services/spacesService.js +639 -0
  127. package/lib/module/live/services/spacesService.js.map +1 -0
  128. package/lib/module/live/types.js +4 -0
  129. package/lib/module/live/types.js.map +1 -0
  130. package/lib/module/live/validation.js +229 -0
  131. package/lib/module/live/validation.js.map +1 -0
  132. package/lib/module/package.json +1 -0
  133. package/{dist/esm → lib/module}/schema.js +47 -39
  134. package/lib/module/schema.js.map +1 -0
  135. package/{dist/types → lib/typescript/commonjs}/client.d.ts +1 -0
  136. package/lib/typescript/commonjs/client.d.ts.map +1 -0
  137. package/{dist/types → lib/typescript/commonjs}/errors.d.ts +1 -0
  138. package/lib/typescript/commonjs/errors.d.ts.map +1 -0
  139. package/{dist/types → lib/typescript/commonjs}/index.d.ts +1 -0
  140. package/lib/typescript/commonjs/index.d.ts.map +1 -0
  141. package/lib/typescript/commonjs/index.native.d.ts +3 -0
  142. package/lib/typescript/commonjs/index.native.d.ts.map +1 -0
  143. package/lib/typescript/commonjs/live/assets/icons/spaces-icon.d.ts +13 -0
  144. package/lib/typescript/commonjs/live/assets/icons/spaces-icon.d.ts.map +1 -0
  145. package/lib/typescript/commonjs/live/assets/icons/syra-icon.d.ts +13 -0
  146. package/lib/typescript/commonjs/live/assets/icons/syra-icon.d.ts.map +1 -0
  147. package/lib/typescript/commonjs/live/components/AnimatedPulse.d.ts +8 -0
  148. package/lib/typescript/commonjs/live/components/AnimatedPulse.d.ts.map +1 -0
  149. package/lib/typescript/commonjs/live/components/AnimatedSpeakerRing.d.ts +10 -0
  150. package/lib/typescript/commonjs/live/components/AnimatedSpeakerRing.d.ts.map +1 -0
  151. package/lib/typescript/commonjs/live/components/CreateRoomSheet.d.ts +26 -0
  152. package/lib/typescript/commonjs/live/components/CreateRoomSheet.d.ts.map +1 -0
  153. package/lib/typescript/commonjs/live/components/InsightsPanel.d.ts +11 -0
  154. package/lib/typescript/commonjs/live/components/InsightsPanel.d.ts.map +1 -0
  155. package/lib/typescript/commonjs/live/components/LiveRoomSheet.d.ts +11 -0
  156. package/lib/typescript/commonjs/live/components/LiveRoomSheet.d.ts.map +1 -0
  157. package/lib/typescript/commonjs/live/components/MiniRoomBar.d.ts +15 -0
  158. package/lib/typescript/commonjs/live/components/MiniRoomBar.d.ts.map +1 -0
  159. package/lib/typescript/commonjs/live/components/PanelHeader.d.ts +10 -0
  160. package/lib/typescript/commonjs/live/components/PanelHeader.d.ts.map +1 -0
  161. package/lib/typescript/commonjs/live/components/PodcastStreamPicker.d.ts +54 -0
  162. package/lib/typescript/commonjs/live/components/PodcastStreamPicker.d.ts.map +1 -0
  163. package/lib/typescript/commonjs/live/components/RecordingCard.d.ts +11 -0
  164. package/lib/typescript/commonjs/live/components/RecordingCard.d.ts.map +1 -0
  165. package/lib/typescript/commonjs/live/components/RecordingsPanel.d.ts +12 -0
  166. package/lib/typescript/commonjs/live/components/RecordingsPanel.d.ts.map +1 -0
  167. package/lib/typescript/commonjs/live/components/RoomCard.d.ts +38 -0
  168. package/lib/typescript/commonjs/live/components/RoomCard.d.ts.map +1 -0
  169. package/lib/typescript/commonjs/live/components/StreamConfigModal.d.ts +11 -0
  170. package/lib/typescript/commonjs/live/components/StreamConfigModal.d.ts.map +1 -0
  171. package/lib/typescript/commonjs/live/components/StreamConfigPanel.d.ts +13 -0
  172. package/lib/typescript/commonjs/live/components/StreamConfigPanel.d.ts.map +1 -0
  173. package/lib/typescript/commonjs/live/context/LiveConfigContext.d.ts +78 -0
  174. package/lib/typescript/commonjs/live/context/LiveConfigContext.d.ts.map +1 -0
  175. package/lib/typescript/commonjs/live/context/LiveRoomContext.d.ts +12 -0
  176. package/lib/typescript/commonjs/live/context/LiveRoomContext.d.ts.map +1 -0
  177. package/lib/typescript/commonjs/live/hooks/useActiveSpeakers.d.ts +3 -0
  178. package/lib/typescript/commonjs/live/hooks/useActiveSpeakers.d.ts.map +1 -0
  179. package/lib/typescript/commonjs/live/hooks/useRoomAudio.d.ts +16 -0
  180. package/lib/typescript/commonjs/live/hooks/useRoomAudio.d.ts.map +1 -0
  181. package/lib/typescript/commonjs/live/hooks/useRoomConnection.d.ts +29 -0
  182. package/lib/typescript/commonjs/live/hooks/useRoomConnection.d.ts.map +1 -0
  183. package/lib/typescript/commonjs/live/hooks/useRoomManager.d.ts +11 -0
  184. package/lib/typescript/commonjs/live/hooks/useRoomManager.d.ts.map +1 -0
  185. package/lib/typescript/commonjs/live/hooks/useRoomUsers.d.ts +5 -0
  186. package/lib/typescript/commonjs/live/hooks/useRoomUsers.d.ts.map +1 -0
  187. package/lib/typescript/commonjs/live/index.d.ts +24 -0
  188. package/lib/typescript/commonjs/live/index.d.ts.map +1 -0
  189. package/lib/typescript/commonjs/live/services/livekitService.d.ts +7 -0
  190. package/lib/typescript/commonjs/live/services/livekitService.d.ts.map +1 -0
  191. package/lib/typescript/commonjs/live/services/spaceSocketService.d.ts +69 -0
  192. package/lib/typescript/commonjs/live/services/spaceSocketService.d.ts.map +1 -0
  193. package/lib/typescript/commonjs/live/services/spacesService.d.ts +181 -0
  194. package/lib/typescript/commonjs/live/services/spacesService.d.ts.map +1 -0
  195. package/lib/typescript/commonjs/live/types.d.ts +100 -0
  196. package/lib/typescript/commonjs/live/types.d.ts.map +1 -0
  197. package/lib/typescript/commonjs/live/validation.d.ts +658 -0
  198. package/lib/typescript/commonjs/live/validation.d.ts.map +1 -0
  199. package/lib/typescript/commonjs/package.json +1 -0
  200. package/{dist/types → lib/typescript/commonjs}/schema.d.ts +1 -0
  201. package/lib/typescript/commonjs/schema.d.ts.map +1 -0
  202. package/lib/typescript/module/client.d.ts +141 -0
  203. package/lib/typescript/module/client.d.ts.map +1 -0
  204. package/lib/typescript/module/errors.d.ts +9 -0
  205. package/lib/typescript/module/errors.d.ts.map +1 -0
  206. package/lib/typescript/module/index.d.ts +6 -0
  207. package/lib/typescript/module/index.d.ts.map +1 -0
  208. package/lib/typescript/module/index.native.d.ts +3 -0
  209. package/lib/typescript/module/index.native.d.ts.map +1 -0
  210. package/lib/typescript/module/live/assets/icons/spaces-icon.d.ts +13 -0
  211. package/lib/typescript/module/live/assets/icons/spaces-icon.d.ts.map +1 -0
  212. package/lib/typescript/module/live/assets/icons/syra-icon.d.ts +13 -0
  213. package/lib/typescript/module/live/assets/icons/syra-icon.d.ts.map +1 -0
  214. package/lib/typescript/module/live/components/AnimatedPulse.d.ts +8 -0
  215. package/lib/typescript/module/live/components/AnimatedPulse.d.ts.map +1 -0
  216. package/lib/typescript/module/live/components/AnimatedSpeakerRing.d.ts +10 -0
  217. package/lib/typescript/module/live/components/AnimatedSpeakerRing.d.ts.map +1 -0
  218. package/lib/typescript/module/live/components/CreateRoomSheet.d.ts +26 -0
  219. package/lib/typescript/module/live/components/CreateRoomSheet.d.ts.map +1 -0
  220. package/lib/typescript/module/live/components/InsightsPanel.d.ts +11 -0
  221. package/lib/typescript/module/live/components/InsightsPanel.d.ts.map +1 -0
  222. package/lib/typescript/module/live/components/LiveRoomSheet.d.ts +11 -0
  223. package/lib/typescript/module/live/components/LiveRoomSheet.d.ts.map +1 -0
  224. package/lib/typescript/module/live/components/MiniRoomBar.d.ts +15 -0
  225. package/lib/typescript/module/live/components/MiniRoomBar.d.ts.map +1 -0
  226. package/lib/typescript/module/live/components/PanelHeader.d.ts +10 -0
  227. package/lib/typescript/module/live/components/PanelHeader.d.ts.map +1 -0
  228. package/lib/typescript/module/live/components/PodcastStreamPicker.d.ts +54 -0
  229. package/lib/typescript/module/live/components/PodcastStreamPicker.d.ts.map +1 -0
  230. package/lib/typescript/module/live/components/RecordingCard.d.ts +11 -0
  231. package/lib/typescript/module/live/components/RecordingCard.d.ts.map +1 -0
  232. package/lib/typescript/module/live/components/RecordingsPanel.d.ts +12 -0
  233. package/lib/typescript/module/live/components/RecordingsPanel.d.ts.map +1 -0
  234. package/lib/typescript/module/live/components/RoomCard.d.ts +38 -0
  235. package/lib/typescript/module/live/components/RoomCard.d.ts.map +1 -0
  236. package/lib/typescript/module/live/components/StreamConfigModal.d.ts +11 -0
  237. package/lib/typescript/module/live/components/StreamConfigModal.d.ts.map +1 -0
  238. package/lib/typescript/module/live/components/StreamConfigPanel.d.ts +13 -0
  239. package/lib/typescript/module/live/components/StreamConfigPanel.d.ts.map +1 -0
  240. package/lib/typescript/module/live/context/LiveConfigContext.d.ts +78 -0
  241. package/lib/typescript/module/live/context/LiveConfigContext.d.ts.map +1 -0
  242. package/lib/typescript/module/live/context/LiveRoomContext.d.ts +12 -0
  243. package/lib/typescript/module/live/context/LiveRoomContext.d.ts.map +1 -0
  244. package/lib/typescript/module/live/hooks/useActiveSpeakers.d.ts +3 -0
  245. package/lib/typescript/module/live/hooks/useActiveSpeakers.d.ts.map +1 -0
  246. package/lib/typescript/module/live/hooks/useRoomAudio.d.ts +16 -0
  247. package/lib/typescript/module/live/hooks/useRoomAudio.d.ts.map +1 -0
  248. package/lib/typescript/module/live/hooks/useRoomConnection.d.ts +29 -0
  249. package/lib/typescript/module/live/hooks/useRoomConnection.d.ts.map +1 -0
  250. package/lib/typescript/module/live/hooks/useRoomManager.d.ts +11 -0
  251. package/lib/typescript/module/live/hooks/useRoomManager.d.ts.map +1 -0
  252. package/lib/typescript/module/live/hooks/useRoomUsers.d.ts +5 -0
  253. package/lib/typescript/module/live/hooks/useRoomUsers.d.ts.map +1 -0
  254. package/lib/typescript/module/live/index.d.ts +24 -0
  255. package/lib/typescript/module/live/index.d.ts.map +1 -0
  256. package/lib/typescript/module/live/services/livekitService.d.ts +7 -0
  257. package/lib/typescript/module/live/services/livekitService.d.ts.map +1 -0
  258. package/lib/typescript/module/live/services/spaceSocketService.d.ts +69 -0
  259. package/lib/typescript/module/live/services/spaceSocketService.d.ts.map +1 -0
  260. package/lib/typescript/module/live/services/spacesService.d.ts +181 -0
  261. package/lib/typescript/module/live/services/spacesService.d.ts.map +1 -0
  262. package/lib/typescript/module/live/types.d.ts +100 -0
  263. package/lib/typescript/module/live/types.d.ts.map +1 -0
  264. package/lib/typescript/module/live/validation.d.ts +658 -0
  265. package/lib/typescript/module/live/validation.d.ts.map +1 -0
  266. package/lib/typescript/module/package.json +1 -0
  267. package/lib/typescript/module/schema.d.ts +1072 -0
  268. package/lib/typescript/module/schema.d.ts.map +1 -0
  269. package/package.json +133 -21
  270. package/src/index.native.ts +2 -0
  271. package/src/live/assets/icons/spaces-icon.tsx +15 -0
  272. package/src/live/assets/icons/syra-icon.tsx +13 -0
  273. package/src/live/assets/sounds/intro.mp3 +0 -0
  274. package/src/live/components/AnimatedPulse.tsx +52 -0
  275. package/src/live/components/AnimatedSpeakerRing.tsx +101 -0
  276. package/src/live/components/CreateRoomSheet.tsx +654 -0
  277. package/src/live/components/InsightsPanel.tsx +202 -0
  278. package/src/live/components/LiveRoomSheet.tsx +969 -0
  279. package/src/live/components/MiniRoomBar.tsx +166 -0
  280. package/src/live/components/PanelHeader.tsx +36 -0
  281. package/src/live/components/PodcastStreamPicker.tsx +1155 -0
  282. package/src/live/components/RecordingCard.tsx +154 -0
  283. package/src/live/components/RecordingsPanel.tsx +251 -0
  284. package/src/live/components/RoomCard.tsx +494 -0
  285. package/src/live/components/StreamConfigModal.tsx +600 -0
  286. package/src/live/components/StreamConfigPanel.tsx +729 -0
  287. package/src/live/context/LiveConfigContext.tsx +96 -0
  288. package/src/live/context/LiveRoomContext.tsx +235 -0
  289. package/src/live/hooks/useActiveSpeakers.ts +39 -0
  290. package/src/live/hooks/useRoomAudio.ts +103 -0
  291. package/src/live/hooks/useRoomConnection.ts +162 -0
  292. package/src/live/hooks/useRoomManager.ts +17 -0
  293. package/src/live/hooks/useRoomUsers.ts +52 -0
  294. package/src/live/index.ts +92 -0
  295. package/src/live/services/livekitService.ts +11 -0
  296. package/src/live/services/spaceSocketService.ts +136 -0
  297. package/src/live/services/spacesService.ts +692 -0
  298. package/src/live/types.ts +119 -0
  299. package/src/live/validation.ts +279 -0
  300. package/dist/cjs/client.js +0 -244
  301. package/dist/cjs/errors.js +0 -16
  302. package/dist/cjs/index.js +0 -15
  303. package/dist/cjs/package.json +0 -3
  304. package/dist/esm/client.js +0 -240
  305. package/dist/esm/errors.js +0 -12
  306. package/dist/esm/index.js +0 -3
  307. package/dist/esm/package.json +0 -3
@@ -0,0 +1,494 @@
1
+ import React, { useMemo } from 'react';
2
+ import { View, Text, StyleSheet, TouchableOpacity, StyleProp, ViewStyle } from 'react-native';
3
+ import MaterialCommunityIcons from '@expo/vector-icons/MaterialCommunityIcons';
4
+ import { useAuth } from '@oxyhq/services';
5
+
6
+ import { useLiveConfig } from '../context/LiveConfigContext';
7
+ import { AnimatedPulse } from './AnimatedPulse';
8
+ import { useRoomUsers, getAvatarUrl } from '../hooks/useRoomUsers';
9
+
10
+ // --- Utility helpers ---
11
+
12
+ function formatCompact(num: number): string {
13
+ if (num >= 1_000_000) return `${(num / 1_000_000).toFixed(1).replace(/\.0$/, '')}M`;
14
+ if (num >= 1_000) return `${(num / 1_000).toFixed(1).replace(/\.0$/, '')}k`;
15
+ return String(num);
16
+ }
17
+
18
+ function formatDuration(startedAt: string, endedAt: string): string {
19
+ const ms = new Date(endedAt).getTime() - new Date(startedAt).getTime();
20
+ const totalMin = Math.round(ms / 60_000);
21
+ if (totalMin < 60) return `${totalMin} min`;
22
+ const h = Math.floor(totalMin / 60);
23
+ const m = totalMin % 60;
24
+ return m > 0 ? `${h}h ${m}m` : `${h}h`;
25
+ }
26
+
27
+ const MONTH_SHORT = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
28
+
29
+ function formatDate(dateStr: string): string {
30
+ const d = new Date(dateStr);
31
+ return `${d.getDate()} ${MONTH_SHORT[d.getMonth()]} ${d.getFullYear()}`;
32
+ }
33
+
34
+ function getTimeLabel(room: RoomCardProps['room']): string {
35
+ if (room.status === 'ended' && room.startedAt && room.endedAt) {
36
+ return `${formatDuration(room.startedAt, room.endedAt)} · ${formatDate(room.endedAt)}`;
37
+ }
38
+ if (room.status === 'live' && room.startedAt) {
39
+ return `Live · Started ${formatDate(room.startedAt)}`;
40
+ }
41
+ if (room.status === 'scheduled' && room.scheduledStart) {
42
+ return formatDate(room.scheduledStart);
43
+ }
44
+ if (room.createdAt) {
45
+ return formatDate(room.createdAt);
46
+ }
47
+ return '';
48
+ }
49
+
50
+ // --- Constants ---
51
+
52
+ const ROOM_TYPE_META: Record<string, { icon: 'account-voice' | 'broadcast'; label: string; color: string }> = {
53
+ stage: { icon: 'account-voice', label: 'Stage', color: '#3B82F6' },
54
+ broadcast: { icon: 'broadcast', label: 'Broadcast', color: '#FF6B35' },
55
+ };
56
+
57
+ const MAX_SPEAKER_AVATARS = 4;
58
+ const SPEAKER_AVATAR_SIZE = 44;
59
+
60
+ // --- Types ---
61
+
62
+ interface RoomCardProps {
63
+ room: {
64
+ _id: string;
65
+ title: string;
66
+ status: 'scheduled' | 'live' | 'ended';
67
+ type?: 'talk' | 'stage' | 'broadcast';
68
+ topic?: string | null;
69
+ participants?: string[];
70
+ speakers?: string[];
71
+ host: string;
72
+ houseId?: string | null;
73
+ scheduledStart?: string | null;
74
+ startedAt?: string | null;
75
+ endedAt?: string | null;
76
+ createdAt?: string;
77
+ stats?: { peakListeners?: number; totalJoined?: number };
78
+ };
79
+ onPress?: () => void;
80
+ variant?: 'default' | 'compact';
81
+ house?: { name: string; avatarUrl?: string } | null;
82
+ hostName?: string;
83
+ hostAvatarUri?: string;
84
+ onMenuPress?: () => void;
85
+ onSave?: () => void;
86
+ isSaved?: boolean;
87
+ style?: StyleProp<ViewStyle>;
88
+ }
89
+
90
+ // --- Component ---
91
+
92
+ export const RoomCard: React.FC<RoomCardProps> = ({
93
+ room,
94
+ onPress,
95
+ variant = 'default',
96
+ house,
97
+ hostName: hostNameProp,
98
+ hostAvatarUri: hostAvatarUriProp,
99
+ onMenuPress,
100
+ onSave,
101
+ isSaved,
102
+ style,
103
+ }) => {
104
+ const { useTheme, useUserById, AvatarComponent, getCachedFileDownloadUrlSync } = useLiveConfig();
105
+ const theme = useTheme();
106
+ const { oxyServices } = useAuth();
107
+ const hostProfile = useUserById(room.host);
108
+
109
+ const isLive = room.status === 'live';
110
+ const isScheduled = room.status === 'scheduled';
111
+ const isCompact = variant === 'compact';
112
+
113
+ // Resolve host display: an explicit prop wins, then the @handle, then the
114
+ // canonical API-owned `name.displayName` from the Oxy user DTO (never a
115
+ // recompute from name parts), then a not-yet-resolved userId fallback.
116
+ const hostProfileName = hostProfile?.name;
117
+ const hostName = hostNameProp
118
+ ?? (hostProfile?.username
119
+ ? `@${hostProfile.username}`
120
+ : (typeof hostProfileName === 'object' ? hostProfileName?.displayName : null)
121
+ || room.host?.slice(0, 10)
122
+ || 'Unknown');
123
+ const hostAvatarUri = hostAvatarUriProp ?? getAvatarUrl(hostProfile, oxyServices, getCachedFileDownloadUrlSync);
124
+
125
+ // Resolve speaker avatars (default variant only)
126
+ const speakerIds = useMemo(() => {
127
+ if (isCompact) return [];
128
+ const ids = room.speakers?.length ? room.speakers : [room.host];
129
+ return ids.slice(0, MAX_SPEAKER_AVATARS);
130
+ }, [room.speakers, room.host, isCompact]);
131
+
132
+ useRoomUsers(speakerIds);
133
+
134
+ const typeMeta = room.type && room.type !== 'talk' ? ROOM_TYPE_META[room.type] : null;
135
+ const listenerCount = room.participants?.length || room.stats?.totalJoined || 0;
136
+ const timeLabel = getTimeLabel(room);
137
+
138
+ // --- Compact variant (kept simple) ---
139
+ if (isCompact) {
140
+ return (
141
+ <TouchableOpacity
142
+ style={[styles.compactCard, { backgroundColor: theme.colors.card, borderColor: theme.colors.border }, style]}
143
+ onPress={onPress}
144
+ activeOpacity={onPress ? 0.7 : 1}
145
+ disabled={!onPress}
146
+ >
147
+ <View style={styles.compactHeader}>
148
+ {house && (
149
+ <Text style={[styles.compactHouseName, { color: theme.colors.textSecondary }]} numberOfLines={1}>
150
+ {house.name.toUpperCase()}
151
+ </Text>
152
+ )}
153
+ <Text style={[styles.compactTitle, { color: theme.colors.text }]} numberOfLines={2}>
154
+ {room.title}
155
+ </Text>
156
+ {(isLive || isScheduled || typeMeta) && (
157
+ <View style={styles.compactBadgeRow}>
158
+ {isLive && (
159
+ <View style={[styles.liveBadge, { backgroundColor: '#FF4458' }]}>
160
+ <AnimatedPulse size={6} />
161
+ <Text style={styles.liveText}>LIVE</Text>
162
+ </View>
163
+ )}
164
+ {isScheduled && (
165
+ <View style={[styles.scheduledBadge, { backgroundColor: theme.colors.backgroundSecondary }]}>
166
+ <MaterialCommunityIcons name="calendar" size={10} color={theme.colors.textSecondary} />
167
+ <Text style={[styles.scheduledText, { color: theme.colors.textSecondary }]}>SCHEDULED</Text>
168
+ </View>
169
+ )}
170
+ {typeMeta && (
171
+ <View style={[styles.typeBadge, { backgroundColor: typeMeta.color + '20' }]}>
172
+ <MaterialCommunityIcons name={typeMeta.icon} size={10} color={typeMeta.color} />
173
+ <Text style={[styles.typeText, { color: typeMeta.color }]}>{typeMeta.label}</Text>
174
+ </View>
175
+ )}
176
+ </View>
177
+ )}
178
+ </View>
179
+ <View style={styles.compactFooter}>
180
+ <MaterialCommunityIcons name="account-group" size={14} color={theme.colors.textSecondary} />
181
+ <Text style={[styles.compactCount, { color: theme.colors.textSecondary }]}>
182
+ {listenerCount} listening
183
+ </Text>
184
+ <Text style={{ color: theme.colors.textSecondary, fontSize: 10 }}>•</Text>
185
+ {hostAvatarUri && (
186
+ <AvatarComponent size={14} source={hostAvatarUri} shape="squircle" style={{ marginRight: 2 }} />
187
+ )}
188
+ <Text style={[styles.compactHost, { color: theme.colors.textSecondary }]} numberOfLines={1}>
189
+ {hostName}
190
+ </Text>
191
+ </View>
192
+ </TouchableOpacity>
193
+ );
194
+ }
195
+
196
+ // --- Default variant ---
197
+ return (
198
+ <TouchableOpacity
199
+ style={[styles.card, { backgroundColor: theme.colors.card, borderColor: theme.colors.border }, style]}
200
+ onPress={onPress}
201
+ activeOpacity={onPress ? 0.7 : 1}
202
+ disabled={!onPress}
203
+ >
204
+ {/* Section 1: House header + menu */}
205
+ {(house || onMenuPress) && (
206
+ <View style={styles.houseRow}>
207
+ {house && (
208
+ <>
209
+ <MaterialCommunityIcons name="home" size={16} color={theme.colors.primary} />
210
+ <Text style={[styles.houseName, { color: theme.colors.textSecondary }]} numberOfLines={1}>
211
+ {house.name.toUpperCase()}
212
+ </Text>
213
+ </>
214
+ )}
215
+ <View style={{ flex: 1 }} />
216
+ {onMenuPress && (
217
+ <TouchableOpacity onPress={onMenuPress} hitSlop={{ top: 8, bottom: 8, left: 8, right: 8 }}>
218
+ <MaterialCommunityIcons name="dots-horizontal" size={20} color={theme.colors.textSecondary} />
219
+ </TouchableOpacity>
220
+ )}
221
+ </View>
222
+ )}
223
+
224
+ {/* Section 2: Title + status badges */}
225
+ <View>
226
+ <Text style={[styles.title, { color: theme.colors.text }]} numberOfLines={2}>
227
+ {room.title}
228
+ </Text>
229
+ {(isLive || isScheduled || typeMeta) && (
230
+ <View style={styles.badgeRow}>
231
+ {isLive && (
232
+ <View style={[styles.liveBadge, { backgroundColor: '#FF4458' }]}>
233
+ <AnimatedPulse size={6} />
234
+ <Text style={styles.liveText}>LIVE</Text>
235
+ </View>
236
+ )}
237
+ {isScheduled && (
238
+ <View style={[styles.scheduledBadge, { backgroundColor: theme.colors.backgroundSecondary }]}>
239
+ <MaterialCommunityIcons name="calendar" size={12} color={theme.colors.textSecondary} />
240
+ <Text style={[styles.scheduledText, { color: theme.colors.textSecondary }]}>SCHEDULED</Text>
241
+ </View>
242
+ )}
243
+ {typeMeta && (
244
+ <View style={[styles.typeBadge, { backgroundColor: typeMeta.color + '20' }]}>
245
+ <MaterialCommunityIcons name={typeMeta.icon} size={10} color={typeMeta.color} />
246
+ <Text style={[styles.typeText, { color: typeMeta.color }]}>{typeMeta.label}</Text>
247
+ </View>
248
+ )}
249
+ </View>
250
+ )}
251
+ </View>
252
+
253
+ {/* Section 3: Speaker avatars + listener count */}
254
+ <SpeakerRow
255
+ speakerIds={speakerIds}
256
+ listenerCount={listenerCount}
257
+ theme={theme}
258
+ />
259
+
260
+ {/* Section 4: Metadata + save */}
261
+ {(timeLabel || onSave) && (
262
+ <View style={styles.metaRow}>
263
+ {timeLabel ? (
264
+ <Text style={[styles.metaText, { color: theme.colors.textSecondary }]}>{timeLabel}</Text>
265
+ ) : (
266
+ <View />
267
+ )}
268
+ {onSave && (
269
+ <TouchableOpacity onPress={onSave} style={styles.saveButton} hitSlop={{ top: 8, bottom: 8, left: 8, right: 8 }}>
270
+ <MaterialCommunityIcons
271
+ name={isSaved ? 'bookmark' : 'bookmark-outline'}
272
+ size={18}
273
+ color={isSaved ? theme.colors.primary : theme.colors.textSecondary}
274
+ />
275
+ <Text style={[styles.saveText, { color: isSaved ? theme.colors.primary : theme.colors.textSecondary }]}>
276
+ Save
277
+ </Text>
278
+ </TouchableOpacity>
279
+ )}
280
+ </View>
281
+ )}
282
+ </TouchableOpacity>
283
+ );
284
+ };
285
+
286
+ // --- Speaker row sub-component ---
287
+
288
+ function SpeakerRow({
289
+ speakerIds,
290
+ listenerCount,
291
+ theme,
292
+ }: {
293
+ speakerIds: string[];
294
+ listenerCount: number;
295
+ theme: ReturnType<ReturnType<typeof useLiveConfig>['useTheme']>;
296
+ }) {
297
+ return (
298
+ <View style={styles.avatarRow}>
299
+ {speakerIds.map((id) => (
300
+ <SpeakerAvatar key={id} userId={id} />
301
+ ))}
302
+ {listenerCount > 0 && (
303
+ <View style={[styles.countTile, { backgroundColor: theme.colors.backgroundSecondary, borderColor: theme.colors.border }]}>
304
+ <Text style={[styles.countTileText, { color: theme.colors.textSecondary }]}>
305
+ +{formatCompact(listenerCount)}
306
+ </Text>
307
+ </View>
308
+ )}
309
+ </View>
310
+ );
311
+ }
312
+
313
+ function SpeakerAvatar({ userId }: { userId: string }) {
314
+ const { useUserById, AvatarComponent, getCachedFileDownloadUrlSync, useTheme } = useLiveConfig();
315
+ const theme = useTheme();
316
+ const { oxyServices } = useAuth();
317
+ const profile = useUserById(userId);
318
+ const avatarUri = getAvatarUrl(profile, oxyServices, getCachedFileDownloadUrlSync);
319
+
320
+ return (
321
+ <View style={[styles.avatarRing, { borderColor: theme.colors.border }]}>
322
+ <AvatarComponent
323
+ size={SPEAKER_AVATAR_SIZE}
324
+ source={avatarUri}
325
+ shape="squircle"
326
+ />
327
+ </View>
328
+ );
329
+ }
330
+
331
+ // --- Styles ---
332
+
333
+ const styles = StyleSheet.create({
334
+ card: {
335
+ borderRadius: 12,
336
+ borderWidth: 1,
337
+ padding: 16,
338
+ marginBottom: 12,
339
+ gap: 12,
340
+ },
341
+ compactCard: {
342
+ width: 200,
343
+ minHeight: 140,
344
+ borderRadius: 14,
345
+ borderWidth: 1,
346
+ padding: 12,
347
+ justifyContent: 'space-between',
348
+ },
349
+
350
+ // House header
351
+ houseRow: {
352
+ flexDirection: 'row',
353
+ alignItems: 'center',
354
+ gap: 6,
355
+ },
356
+ houseName: {
357
+ fontSize: 11,
358
+ fontWeight: '700',
359
+ letterSpacing: 0.5,
360
+ },
361
+
362
+ // Title
363
+ title: {
364
+ fontSize: 32,
365
+ fontWeight: '700',
366
+ lineHeight: 38,
367
+ },
368
+
369
+ // Badges
370
+ badgeRow: {
371
+ flexDirection: 'row',
372
+ alignItems: 'center',
373
+ gap: 6,
374
+ marginTop: 6,
375
+ },
376
+ liveBadge: {
377
+ flexDirection: 'row',
378
+ alignItems: 'center',
379
+ paddingHorizontal: 8,
380
+ paddingVertical: 4,
381
+ borderRadius: 4,
382
+ gap: 4,
383
+ },
384
+ liveText: {
385
+ fontSize: 10,
386
+ fontWeight: '700',
387
+ color: '#FFFFFF',
388
+ },
389
+ scheduledBadge: {
390
+ flexDirection: 'row',
391
+ alignItems: 'center',
392
+ paddingHorizontal: 8,
393
+ paddingVertical: 4,
394
+ borderRadius: 4,
395
+ gap: 4,
396
+ },
397
+ scheduledText: {
398
+ fontSize: 10,
399
+ fontWeight: '700',
400
+ },
401
+ typeBadge: {
402
+ flexDirection: 'row',
403
+ alignItems: 'center',
404
+ paddingHorizontal: 6,
405
+ paddingVertical: 3,
406
+ borderRadius: 4,
407
+ gap: 3,
408
+ },
409
+ typeText: {
410
+ fontSize: 9,
411
+ fontWeight: '700',
412
+ },
413
+
414
+ // Speaker avatars
415
+ avatarRow: {
416
+ flexDirection: 'row',
417
+ alignItems: 'center',
418
+ gap: 8,
419
+ },
420
+ avatarRing: {
421
+ borderRadius: 14,
422
+ padding: 2,
423
+ borderWidth: 2,
424
+ },
425
+ countTile: {
426
+ width: SPEAKER_AVATAR_SIZE + 4,
427
+ height: SPEAKER_AVATAR_SIZE + 4,
428
+ borderRadius: 14,
429
+ borderWidth: 2,
430
+ alignItems: 'center',
431
+ justifyContent: 'center',
432
+ gap: 2,
433
+ },
434
+ countTileText: {
435
+ fontSize: 14,
436
+ fontWeight: '700',
437
+ },
438
+
439
+ // Metadata
440
+ metaRow: {
441
+ flexDirection: 'row',
442
+ alignItems: 'center',
443
+ justifyContent: 'space-between',
444
+ },
445
+ metaText: {
446
+ fontSize: 13,
447
+ },
448
+ saveButton: {
449
+ flexDirection: 'row',
450
+ alignItems: 'center',
451
+ gap: 4,
452
+ },
453
+ saveText: {
454
+ fontSize: 13,
455
+ fontWeight: '500',
456
+ },
457
+
458
+ // Compact variant
459
+ compactHeader: {
460
+ flex: 1,
461
+ },
462
+ compactHouseName: {
463
+ fontSize: 9,
464
+ fontWeight: '700',
465
+ letterSpacing: 0.5,
466
+ marginBottom: 4,
467
+ },
468
+ compactTitle: {
469
+ fontSize: 14,
470
+ fontWeight: '600',
471
+ lineHeight: 18,
472
+ },
473
+ compactBadgeRow: {
474
+ flexDirection: 'row',
475
+ marginTop: 4,
476
+ gap: 4,
477
+ flexWrap: 'wrap',
478
+ },
479
+ compactFooter: {
480
+ flexDirection: 'row',
481
+ alignItems: 'center',
482
+ gap: 4,
483
+ marginTop: 8,
484
+ },
485
+ compactCount: {
486
+ fontSize: 11,
487
+ },
488
+ compactHost: {
489
+ fontSize: 11,
490
+ flex: 1,
491
+ },
492
+ });
493
+
494
+ export default RoomCard;