@college-africa/chat-ui-native 0.1.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 (145) hide show
  1. package/dist/cache/actions/createGroup.d.ts +20 -0
  2. package/dist/cache/actions/createGroup.d.ts.map +1 -0
  3. package/dist/cache/actions/createGroup.js +47 -0
  4. package/dist/cache/actions/groups.d.ts +29 -0
  5. package/dist/cache/actions/groups.d.ts.map +1 -0
  6. package/dist/cache/actions/groups.js +76 -0
  7. package/dist/cache/actions/index.d.ts +9 -0
  8. package/dist/cache/actions/index.d.ts.map +1 -0
  9. package/dist/cache/actions/index.js +24 -0
  10. package/dist/cache/actions/messages.d.ts +17 -0
  11. package/dist/cache/actions/messages.d.ts.map +1 -0
  12. package/dist/cache/actions/messages.js +127 -0
  13. package/dist/cache/actions/summaries.d.ts +22 -0
  14. package/dist/cache/actions/summaries.d.ts.map +1 -0
  15. package/dist/cache/actions/summaries.js +95 -0
  16. package/dist/cache/actions/users.d.ts +36 -0
  17. package/dist/cache/actions/users.d.ts.map +1 -0
  18. package/dist/cache/actions/users.js +96 -0
  19. package/dist/cache/api.d.ts +15 -0
  20. package/dist/cache/api.d.ts.map +1 -0
  21. package/dist/cache/api.js +43 -0
  22. package/dist/cache/database.d.ts +15 -0
  23. package/dist/cache/database.d.ts.map +1 -0
  24. package/dist/cache/database.js +40 -0
  25. package/dist/cache/index.d.ts +15 -0
  26. package/dist/cache/index.d.ts.map +1 -0
  27. package/dist/cache/index.js +37 -0
  28. package/dist/cache/models.d.ts +61 -0
  29. package/dist/cache/models.d.ts.map +1 -0
  30. package/dist/cache/models.js +150 -0
  31. package/dist/cache/schema.d.ts +77 -0
  32. package/dist/cache/schema.d.ts.map +1 -0
  33. package/dist/cache/schema.js +122 -0
  34. package/dist/components/Avatar.d.ts +24 -0
  35. package/dist/components/Avatar.d.ts.map +1 -0
  36. package/dist/components/Avatar.js +49 -0
  37. package/dist/components/ChatApp.d.ts +34 -0
  38. package/dist/components/ChatApp.d.ts.map +1 -0
  39. package/dist/components/ChatApp.js +115 -0
  40. package/dist/components/ChatContainer.d.ts +18 -0
  41. package/dist/components/ChatContainer.d.ts.map +1 -0
  42. package/dist/components/ChatContainer.js +39 -0
  43. package/dist/components/ChatHeader.d.ts +7 -0
  44. package/dist/components/ChatHeader.d.ts.map +1 -0
  45. package/dist/components/ChatHeader.js +35 -0
  46. package/dist/components/ChatIconButton.d.ts +25 -0
  47. package/dist/components/ChatIconButton.d.ts.map +1 -0
  48. package/dist/components/ChatIconButton.js +44 -0
  49. package/dist/components/ChatView.d.ts +8 -0
  50. package/dist/components/ChatView.d.ts.map +1 -0
  51. package/dist/components/ChatView.js +92 -0
  52. package/dist/components/ConversationItem.d.ts +7 -0
  53. package/dist/components/ConversationItem.d.ts.map +1 -0
  54. package/dist/components/ConversationItem.js +51 -0
  55. package/dist/components/ConversationList.d.ts +7 -0
  56. package/dist/components/ConversationList.d.ts.map +1 -0
  57. package/dist/components/ConversationList.js +99 -0
  58. package/dist/components/ConversationListView.d.ts +7 -0
  59. package/dist/components/ConversationListView.d.ts.map +1 -0
  60. package/dist/components/ConversationListView.js +80 -0
  61. package/dist/components/CreateGroupDialog.d.ts +14 -0
  62. package/dist/components/CreateGroupDialog.d.ts.map +1 -0
  63. package/dist/components/CreateGroupDialog.js +141 -0
  64. package/dist/components/Dropdown.d.ts +37 -0
  65. package/dist/components/Dropdown.d.ts.map +1 -0
  66. package/dist/components/Dropdown.js +88 -0
  67. package/dist/components/KeyboardAvoidingContainer.d.ts +13 -0
  68. package/dist/components/KeyboardAvoidingContainer.d.ts.map +1 -0
  69. package/dist/components/KeyboardAvoidingContainer.js +23 -0
  70. package/dist/components/MessageBubble.d.ts +18 -0
  71. package/dist/components/MessageBubble.d.ts.map +1 -0
  72. package/dist/components/MessageBubble.js +153 -0
  73. package/dist/components/MessageInput.d.ts +7 -0
  74. package/dist/components/MessageInput.d.ts.map +1 -0
  75. package/dist/components/MessageInput.js +84 -0
  76. package/dist/components/MessageList.d.ts +8 -0
  77. package/dist/components/MessageList.d.ts.map +1 -0
  78. package/dist/components/MessageList.js +128 -0
  79. package/dist/components/MessageStatus.d.ts +13 -0
  80. package/dist/components/MessageStatus.d.ts.map +1 -0
  81. package/dist/components/MessageStatus.js +65 -0
  82. package/dist/components/UserAutocomplete.d.ts +16 -0
  83. package/dist/components/UserAutocomplete.d.ts.map +1 -0
  84. package/dist/components/UserAutocomplete.js +182 -0
  85. package/dist/hooks/useConversationList.d.ts +12 -0
  86. package/dist/hooks/useConversationList.d.ts.map +1 -0
  87. package/dist/hooks/useConversationList.js +185 -0
  88. package/dist/hooks/useEffectAsync.d.ts +9 -0
  89. package/dist/hooks/useEffectAsync.d.ts.map +1 -0
  90. package/dist/hooks/useEffectAsync.js +19 -0
  91. package/dist/hooks/useMessages.d.ts +20 -0
  92. package/dist/hooks/useMessages.d.ts.map +1 -0
  93. package/dist/hooks/useMessages.js +188 -0
  94. package/dist/hooks/useSenderNames.d.ts +10 -0
  95. package/dist/hooks/useSenderNames.d.ts.map +1 -0
  96. package/dist/hooks/useSenderNames.js +54 -0
  97. package/dist/hooks/useUnreadCount.d.ts +6 -0
  98. package/dist/hooks/useUnreadCount.d.ts.map +1 -0
  99. package/dist/hooks/useUnreadCount.js +46 -0
  100. package/dist/hooks/useWebSocket.d.ts +27 -0
  101. package/dist/hooks/useWebSocket.d.ts.map +1 -0
  102. package/dist/hooks/useWebSocket.js +78 -0
  103. package/dist/hooks/useWebSocketMessages.d.ts +24 -0
  104. package/dist/hooks/useWebSocketMessages.d.ts.map +1 -0
  105. package/dist/hooks/useWebSocketMessages.js +71 -0
  106. package/dist/index.d.ts +20 -0
  107. package/dist/index.d.ts.map +1 -0
  108. package/dist/index.js +44 -0
  109. package/dist/screens/ChatScreen.d.ts +10 -0
  110. package/dist/screens/ChatScreen.d.ts.map +1 -0
  111. package/dist/screens/ChatScreen.js +112 -0
  112. package/dist/screens/ConversationsScreen.d.ts +10 -0
  113. package/dist/screens/ConversationsScreen.d.ts.map +1 -0
  114. package/dist/screens/ConversationsScreen.js +25 -0
  115. package/dist/screens/CreateGroupScreen.d.ts +10 -0
  116. package/dist/screens/CreateGroupScreen.d.ts.map +1 -0
  117. package/dist/screens/CreateGroupScreen.js +263 -0
  118. package/dist/styles/index.d.ts +3 -0
  119. package/dist/styles/index.d.ts.map +1 -0
  120. package/dist/styles/index.js +18 -0
  121. package/dist/styles/responsive.d.ts +74 -0
  122. package/dist/styles/responsive.d.ts.map +1 -0
  123. package/dist/styles/responsive.js +98 -0
  124. package/dist/styles/theme.d.ts +10 -0
  125. package/dist/styles/theme.d.ts.map +1 -0
  126. package/dist/styles/theme.js +17 -0
  127. package/dist/theme/index.d.ts +16 -0
  128. package/dist/theme/index.d.ts.map +1 -0
  129. package/dist/theme/index.js +23 -0
  130. package/dist/types/index.d.ts +92 -0
  131. package/dist/types/index.d.ts.map +1 -0
  132. package/dist/types/index.js +5 -0
  133. package/dist/utils/date.d.ts +40 -0
  134. package/dist/utils/date.d.ts.map +1 -0
  135. package/dist/utils/date.js +150 -0
  136. package/dist/utils/messages.d.ts +49 -0
  137. package/dist/utils/messages.d.ts.map +1 -0
  138. package/dist/utils/messages.js +115 -0
  139. package/dist/utils/misc.d.ts +10 -0
  140. package/dist/utils/misc.d.ts.map +1 -0
  141. package/dist/utils/misc.js +31 -0
  142. package/dist/utils/sdk.d.ts +29 -0
  143. package/dist/utils/sdk.d.ts.map +1 -0
  144. package/dist/utils/sdk.js +78 -0
  145. package/package.json +52 -0
@@ -0,0 +1,24 @@
1
+ /**
2
+ * useWebSocketMessages - Hook for tracking WebSocket connection status
3
+ * Phase 6: Real-time updates
4
+ *
5
+ * Note: Message handling is already implemented in SDK initialization (utils/sdk.ts)
6
+ * This hook only provides connection status and event callbacks
7
+ */
8
+ export interface UseWebSocketMessagesParams {
9
+ /** Callback when WebSocket connection opens */
10
+ onConnect?: () => void;
11
+ /** Callback when WebSocket connection closes */
12
+ onDisconnect?: () => void;
13
+ /** Callback when WebSocket error occurs */
14
+ onError?: (error: Error) => void;
15
+ }
16
+ /**
17
+ * Hook for tracking WebSocket connection status
18
+ * Message handling is automatically done by SDK initialization
19
+ * Returns connection status for UI indicators
20
+ */
21
+ export declare function useWebSocketMessages({ onConnect, onDisconnect, onError }?: UseWebSocketMessagesParams): {
22
+ isConnected: boolean;
23
+ };
24
+ //# sourceMappingURL=useWebSocketMessages.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useWebSocketMessages.d.ts","sourceRoot":"","sources":["../../src/hooks/useWebSocketMessages.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAMH,MAAM,WAAW,0BAA0B;IACzC,+CAA+C;IAC/C,SAAS,CAAC,EAAE,MAAM,IAAI,CAAC;IACvB,gDAAgD;IAChD,YAAY,CAAC,EAAE,MAAM,IAAI,CAAC;IAC1B,2CAA2C;IAC3C,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;CAClC;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,EACnC,SAAS,EACT,YAAY,EACZ,OAAO,EACR,GAAE,0BAA+B;;EA+DjC"}
@@ -0,0 +1,71 @@
1
+ "use strict";
2
+ /**
3
+ * useWebSocketMessages - Hook for tracking WebSocket connection status
4
+ * Phase 6: Real-time updates
5
+ *
6
+ * Note: Message handling is already implemented in SDK initialization (utils/sdk.ts)
7
+ * This hook only provides connection status and event callbacks
8
+ */
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ exports.useWebSocketMessages = useWebSocketMessages;
11
+ const react_1 = require("react");
12
+ const sdk_1 = require("../utils/sdk");
13
+ /**
14
+ * Hook for tracking WebSocket connection status
15
+ * Message handling is automatically done by SDK initialization
16
+ * Returns connection status for UI indicators
17
+ */
18
+ function useWebSocketMessages({ onConnect, onDisconnect, onError } = {}) {
19
+ const [isConnected, setIsConnected] = (0, react_1.useState)(false);
20
+ /**
21
+ * Handle WebSocket open event
22
+ */
23
+ const handleOpen = (0, react_1.useCallback)(() => {
24
+ setIsConnected(true);
25
+ onConnect?.();
26
+ }, [onConnect]);
27
+ /**
28
+ * Handle WebSocket close event
29
+ */
30
+ const handleClose = (0, react_1.useCallback)(() => {
31
+ setIsConnected(false);
32
+ onDisconnect?.();
33
+ }, [onDisconnect]);
34
+ /**
35
+ * Handle WebSocket error event
36
+ */
37
+ const handleError = (0, react_1.useCallback)((error) => {
38
+ console.error("[WS] WebSocket error:", error);
39
+ onError?.(error);
40
+ }, [onError]);
41
+ /**
42
+ * Subscribe to WebSocket connection events
43
+ */
44
+ (0, react_1.useEffect)(() => {
45
+ if (!(0, sdk_1.isSDKInitialized)())
46
+ return;
47
+ try {
48
+ const sdk = (0, sdk_1.getSDK)();
49
+ // Check initial connection state
50
+ setIsConnected(sdk.isConnected());
51
+ // Subscribe to connection events
52
+ // @ts-ignore
53
+ sdk.on("open", handleOpen); // @ts-ignore
54
+ sdk.on("close", handleClose); // @ts-ignore
55
+ sdk.on("error", handleError);
56
+ // Cleanup on unmount
57
+ return () => {
58
+ // @ts-ignore
59
+ sdk.off("open", handleOpen); // @ts-ignore
60
+ sdk.off("close", handleClose); // @ts-ignore
61
+ sdk.off("error", handleError);
62
+ };
63
+ }
64
+ catch (error) {
65
+ console.error("Failed to setup WebSocket listeners:", error);
66
+ }
67
+ }, [handleOpen, handleClose, handleError]);
68
+ return {
69
+ isConnected
70
+ };
71
+ }
@@ -0,0 +1,20 @@
1
+ /**
2
+ * @college-africa/chat-ui-native
3
+ * React Native chat UI library for College Africa
4
+ *
5
+ * Only export utils and object that may be used to embed library or manage data
6
+ */
7
+ import "event-target-polyfill";
8
+ export { ChatApp } from "./components/ChatApp";
9
+ export type { ChatAppProps } from "./components/ChatApp";
10
+ export { ChatIconButton } from "./components/ChatIconButton";
11
+ export type { ChatIconButtonProps } from "./components/ChatIconButton";
12
+ export { MessageStatus } from "./components/MessageStatus";
13
+ export type { MessageStatusProps } from "./components/MessageStatus";
14
+ export { KeyboardAvoidingContainer } from "./components/KeyboardAvoidingContainer";
15
+ export { getRealm, closeRealm, isRealmInitialized } from "./cache/database";
16
+ export { deleteDatabase, resetCache, logout } from "./cache";
17
+ export { lightTheme, darkTheme, getTheme, useStyleSheet } from "./styles";
18
+ export { initSDK, getSDK, disconnectSDK, isSDKInitialized } from "./utils/sdk";
19
+ export { normaliseError } from "./utils/misc";
20
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,uBAAuB,CAAC;AAG/B,OAAO,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAC;AAC/C,YAAY,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACzD,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAC7D,YAAY,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AAGvE,OAAO,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAC3D,YAAY,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AACrE,OAAO,EAAE,yBAAyB,EAAE,MAAM,wCAAwC,CAAC;AAGnF,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAC5E,OAAO,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAG7D,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAG1E,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAC/E,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,44 @@
1
+ "use strict";
2
+ /**
3
+ * @college-africa/chat-ui-native
4
+ * React Native chat UI library for College Africa
5
+ *
6
+ * Only export utils and object that may be used to embed library or manage data
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.normaliseError = exports.isSDKInitialized = exports.disconnectSDK = exports.getSDK = exports.initSDK = exports.useStyleSheet = exports.getTheme = exports.darkTheme = exports.lightTheme = exports.logout = exports.resetCache = exports.deleteDatabase = exports.isRealmInitialized = exports.closeRealm = exports.getRealm = exports.KeyboardAvoidingContainer = exports.MessageStatus = exports.ChatIconButton = exports.ChatApp = void 0;
10
+ // Apply polyfills for React Native environment
11
+ require("event-target-polyfill");
12
+ // Main Components
13
+ var ChatApp_1 = require("./components/ChatApp");
14
+ Object.defineProperty(exports, "ChatApp", { enumerable: true, get: function () { return ChatApp_1.ChatApp; } });
15
+ var ChatIconButton_1 = require("./components/ChatIconButton");
16
+ Object.defineProperty(exports, "ChatIconButton", { enumerable: true, get: function () { return ChatIconButton_1.ChatIconButton; } });
17
+ // Chat Components
18
+ var MessageStatus_1 = require("./components/MessageStatus");
19
+ Object.defineProperty(exports, "MessageStatus", { enumerable: true, get: function () { return MessageStatus_1.MessageStatus; } });
20
+ var KeyboardAvoidingContainer_1 = require("./components/KeyboardAvoidingContainer");
21
+ Object.defineProperty(exports, "KeyboardAvoidingContainer", { enumerable: true, get: function () { return KeyboardAvoidingContainer_1.KeyboardAvoidingContainer; } });
22
+ // Cache
23
+ var database_1 = require("./cache/database");
24
+ Object.defineProperty(exports, "getRealm", { enumerable: true, get: function () { return database_1.getRealm; } });
25
+ Object.defineProperty(exports, "closeRealm", { enumerable: true, get: function () { return database_1.closeRealm; } });
26
+ Object.defineProperty(exports, "isRealmInitialized", { enumerable: true, get: function () { return database_1.isRealmInitialized; } });
27
+ var cache_1 = require("./cache");
28
+ Object.defineProperty(exports, "deleteDatabase", { enumerable: true, get: function () { return cache_1.deleteDatabase; } });
29
+ Object.defineProperty(exports, "resetCache", { enumerable: true, get: function () { return cache_1.resetCache; } });
30
+ Object.defineProperty(exports, "logout", { enumerable: true, get: function () { return cache_1.logout; } });
31
+ // Theme
32
+ var styles_1 = require("./styles");
33
+ Object.defineProperty(exports, "lightTheme", { enumerable: true, get: function () { return styles_1.lightTheme; } });
34
+ Object.defineProperty(exports, "darkTheme", { enumerable: true, get: function () { return styles_1.darkTheme; } });
35
+ Object.defineProperty(exports, "getTheme", { enumerable: true, get: function () { return styles_1.getTheme; } });
36
+ Object.defineProperty(exports, "useStyleSheet", { enumerable: true, get: function () { return styles_1.useStyleSheet; } });
37
+ // Utilities
38
+ var sdk_1 = require("./utils/sdk");
39
+ Object.defineProperty(exports, "initSDK", { enumerable: true, get: function () { return sdk_1.initSDK; } });
40
+ Object.defineProperty(exports, "getSDK", { enumerable: true, get: function () { return sdk_1.getSDK; } });
41
+ Object.defineProperty(exports, "disconnectSDK", { enumerable: true, get: function () { return sdk_1.disconnectSDK; } });
42
+ Object.defineProperty(exports, "isSDKInitialized", { enumerable: true, get: function () { return sdk_1.isSDKInitialized; } });
43
+ var misc_1 = require("./utils/misc");
44
+ Object.defineProperty(exports, "normaliseError", { enumerable: true, get: function () { return misc_1.normaliseError; } });
@@ -0,0 +1,10 @@
1
+ /**
2
+ * ChatScreen - Navigation screen wrapper for individual chat view with connection status
3
+ */
4
+ import React from "react";
5
+ import type { NativeStackScreenProps } from "@react-navigation/native-stack";
6
+ import type { RootStackParamList } from "../types";
7
+ type Props = NativeStackScreenProps<RootStackParamList, "Chat">;
8
+ export declare function ChatScreen({ route, navigation }: Props): React.JSX.Element;
9
+ export {};
10
+ //# sourceMappingURL=ChatScreen.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ChatScreen.d.ts","sourceRoot":"","sources":["../../src/screens/ChatScreen.tsx"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAoC,MAAM,OAAO,CAAC;AAEzD,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,gCAAgC,CAAC;AAU7E,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAC;AAGnD,KAAK,KAAK,GAAG,sBAAsB,CAAC,kBAAkB,EAAE,MAAM,CAAC,CAAC;AAoBhE,wBAAgB,UAAU,CAAC,EAAE,KAAK,EAAE,UAAU,EAAE,EAAE,KAAK,qBAqEtD"}
@@ -0,0 +1,112 @@
1
+ "use strict";
2
+ /**
3
+ * ChatScreen - Navigation screen wrapper for individual chat view with connection status
4
+ */
5
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
6
+ if (k2 === undefined) k2 = k;
7
+ var desc = Object.getOwnPropertyDescriptor(m, k);
8
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
9
+ desc = { enumerable: true, get: function() { return m[k]; } };
10
+ }
11
+ Object.defineProperty(o, k2, desc);
12
+ }) : (function(o, m, k, k2) {
13
+ if (k2 === undefined) k2 = k;
14
+ o[k2] = m[k];
15
+ }));
16
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
17
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
18
+ }) : function(o, v) {
19
+ o["default"] = v;
20
+ });
21
+ var __importStar = (this && this.__importStar) || (function () {
22
+ var ownKeys = function(o) {
23
+ ownKeys = Object.getOwnPropertyNames || function (o) {
24
+ var ar = [];
25
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
26
+ return ar;
27
+ };
28
+ return ownKeys(o);
29
+ };
30
+ return function (mod) {
31
+ if (mod && mod.__esModule) return mod;
32
+ var result = {};
33
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
34
+ __setModuleDefault(result, mod);
35
+ return result;
36
+ };
37
+ })();
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.ChatScreen = ChatScreen;
40
+ const react_1 = __importStar(require("react"));
41
+ // @ts-ignore - react-native is a peer dependency
42
+ const react_native_1 = require("react-native");
43
+ // @ts-ignore - react-native-paper is a peer dependency
44
+ const react_native_paper_1 = require("react-native-paper");
45
+ const ChatView_1 = require("../components/ChatView");
46
+ const useWebSocket_1 = require("../hooks/useWebSocket");
47
+ const users_1 = require("../cache/actions/users");
48
+ const groups_1 = require("../cache/actions/groups");
49
+ const database_1 = require("../cache/database");
50
+ /**
51
+ * Connection status indicator component
52
+ */
53
+ function ConnectionIndicator({ isConnected }) {
54
+ const theme = (0, react_native_paper_1.useTheme)();
55
+ if (isConnected)
56
+ return null;
57
+ return (<react_native_paper_1.IconButton icon="cloud-off-outline" iconColor={theme.colors.error} size={20} style={styles.indicator}/>);
58
+ }
59
+ function ChatScreen({ route, navigation }) {
60
+ const { conversationId, isGroup, groupId } = route.params;
61
+ const { isConnected } = (0, useWebSocket_1.useWebSocket)();
62
+ const [menuVisible, setMenuVisible] = (0, react_1.useState)(false);
63
+ const [isJoining, setIsJoining] = (0, react_1.useState)(false);
64
+ const currentUser = (0, users_1.getCurrentUser)();
65
+ // Check if user is admin and not a member of the group
66
+ const isAdmin = currentUser?.role === "admin" || currentUser?.role === "system";
67
+ const realm = (0, database_1.getRealm)();
68
+ const group = isGroup && groupId
69
+ ? realm.objectForPrimaryKey("Group", groupId)
70
+ : null;
71
+ const canJoinGroup = isAdmin && isGroup && group && !group.is_member;
72
+ const handleJoinGroup = async (role) => {
73
+ if (!groupId)
74
+ return;
75
+ setIsJoining(true);
76
+ setMenuVisible(false);
77
+ try {
78
+ await (0, groups_1.joinGroup)(groupId, role);
79
+ }
80
+ catch (error) {
81
+ console.error("Failed to join group:", error);
82
+ // TODO: Show error toast in Phase 7
83
+ }
84
+ finally {
85
+ setIsJoining(false);
86
+ }
87
+ };
88
+ // Update header to show connection status indicator and join button
89
+ (0, react_1.useLayoutEffect)(() => {
90
+ navigation.setOptions({
91
+ headerRight: () => (<react_native_1.View style={styles.headerRight}>
92
+ <ConnectionIndicator isConnected={isConnected}/>
93
+ {canJoinGroup && (<react_native_paper_1.Menu visible={menuVisible} onDismiss={() => setMenuVisible(false)} anchor={<react_native_paper_1.Button icon="account-plus" onPress={() => setMenuVisible(true)} disabled={isJoining}>
94
+ Join
95
+ </react_native_paper_1.Button>}>
96
+ <react_native_paper_1.Menu.Item onPress={() => handleJoinGroup("member")} title="as member"/>
97
+ <react_native_paper_1.Menu.Item onPress={() => handleJoinGroup("moderator")} title="as moderator"/>
98
+ </react_native_paper_1.Menu>)}
99
+ </react_native_1.View>)
100
+ });
101
+ }, [isConnected, navigation, canJoinGroup, menuVisible, isJoining]);
102
+ return <ChatView_1.ChatView conversationId={conversationId}/>;
103
+ }
104
+ const styles = react_native_1.StyleSheet.create({
105
+ indicator: {
106
+ margin: 0
107
+ },
108
+ headerRight: {
109
+ flexDirection: "row",
110
+ alignItems: "center"
111
+ }
112
+ });
@@ -0,0 +1,10 @@
1
+ /**
2
+ * ConversationsScreen - Navigation screen wrapper for conversation list
3
+ */
4
+ import React from "react";
5
+ import type { NativeStackScreenProps } from "@react-navigation/native-stack";
6
+ import type { RootStackParamList } from "../types";
7
+ type Props = NativeStackScreenProps<RootStackParamList, "Conversations">;
8
+ export declare function ConversationsScreen({ navigation }: Props): React.JSX.Element;
9
+ export {};
10
+ //# sourceMappingURL=ConversationsScreen.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ConversationsScreen.d.ts","sourceRoot":"","sources":["../../src/screens/ConversationsScreen.tsx"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,gCAAgC,CAAC;AAE7E,OAAO,KAAK,EAAE,kBAAkB,EAAoB,MAAM,UAAU,CAAC;AAErE,KAAK,KAAK,GAAG,sBAAsB,CAAC,kBAAkB,EAAE,eAAe,CAAC,CAAC;AAEzE,wBAAgB,mBAAmB,CAAC,EAAE,UAAU,EAAE,EAAE,KAAK,qBAoBxD"}
@@ -0,0 +1,25 @@
1
+ "use strict";
2
+ /**
3
+ * ConversationsScreen - Navigation screen wrapper for conversation list
4
+ */
5
+ var __importDefault = (this && this.__importDefault) || function (mod) {
6
+ return (mod && mod.__esModule) ? mod : { "default": mod };
7
+ };
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.ConversationsScreen = ConversationsScreen;
10
+ const react_1 = __importDefault(require("react"));
11
+ const ConversationList_1 = require("../components/ConversationList");
12
+ function ConversationsScreen({ navigation }) {
13
+ const handleSelectConversation = (conversation) => {
14
+ navigation.navigate("Chat", {
15
+ conversationId: conversation.id,
16
+ conversationName: conversation.name,
17
+ isGroup: conversation.isGroup,
18
+ groupId: conversation.group
19
+ });
20
+ };
21
+ const handleCreateGroup = () => {
22
+ navigation.navigate("CreateGroup");
23
+ };
24
+ return (<ConversationList_1.ConversationList onSelectConversation={handleSelectConversation} onCreateGroup={handleCreateGroup}/>);
25
+ }
@@ -0,0 +1,10 @@
1
+ /**
2
+ * CreateGroupScreen - Admin-only screen for creating new groups
3
+ */
4
+ import React from "react";
5
+ import type { NativeStackScreenProps } from "@react-navigation/native-stack";
6
+ import type { RootStackParamList } from "../types";
7
+ type Props = NativeStackScreenProps<RootStackParamList, "CreateGroup">;
8
+ export declare function CreateGroupScreen({ navigation }: Props): React.JSX.Element;
9
+ export {};
10
+ //# sourceMappingURL=CreateGroupScreen.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CreateGroupScreen.d.ts","sourceRoot":"","sources":["../../src/screens/CreateGroupScreen.tsx"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,MAAM,OAAO,CAAC;AAG1B,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,gCAAgC,CAAC;AAiB7E,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAC;AAMnD,KAAK,KAAK,GAAG,sBAAsB,CAAC,kBAAkB,EAAE,aAAa,CAAC,CAAC;AA6BvE,wBAAgB,iBAAiB,CAAC,EAAE,UAAU,EAAE,EAAE,KAAK,qBA2LtD"}
@@ -0,0 +1,263 @@
1
+ "use strict";
2
+ /**
3
+ * CreateGroupScreen - Admin-only screen for creating new groups
4
+ */
5
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
6
+ if (k2 === undefined) k2 = k;
7
+ var desc = Object.getOwnPropertyDescriptor(m, k);
8
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
9
+ desc = { enumerable: true, get: function() { return m[k]; } };
10
+ }
11
+ Object.defineProperty(o, k2, desc);
12
+ }) : (function(o, m, k, k2) {
13
+ if (k2 === undefined) k2 = k;
14
+ o[k2] = m[k];
15
+ }));
16
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
17
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
18
+ }) : function(o, v) {
19
+ o["default"] = v;
20
+ });
21
+ var __importStar = (this && this.__importStar) || (function () {
22
+ var ownKeys = function(o) {
23
+ ownKeys = Object.getOwnPropertyNames || function (o) {
24
+ var ar = [];
25
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
26
+ return ar;
27
+ };
28
+ return ownKeys(o);
29
+ };
30
+ return function (mod) {
31
+ if (mod && mod.__esModule) return mod;
32
+ var result = {};
33
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
34
+ __setModuleDefault(result, mod);
35
+ return result;
36
+ };
37
+ })();
38
+ var __importDefault = (this && this.__importDefault) || function (mod) {
39
+ return (mod && mod.__esModule) ? mod : { "default": mod };
40
+ };
41
+ Object.defineProperty(exports, "__esModule", { value: true });
42
+ exports.CreateGroupScreen = CreateGroupScreen;
43
+ const react_1 = __importDefault(require("react"));
44
+ const react_native_1 = require("react-native");
45
+ // @ts-ignore - react-native-paper is a peer dependency
46
+ const react_native_paper_1 = require("react-native-paper");
47
+ const formik_1 = require("formik");
48
+ const Yup = __importStar(require("yup"));
49
+ const styles_1 = require("../styles");
50
+ const groups_1 = require("../cache/actions/groups");
51
+ const UserAutocomplete_1 = require("../components/UserAutocomplete");
52
+ const KeyboardAvoidingContainer_1 = require("../components/KeyboardAvoidingContainer");
53
+ const Dropdown_1 = require("../components/Dropdown");
54
+ const createGroupSchema = Yup.object().shape({
55
+ name: Yup.string()
56
+ .required("Group name is required")
57
+ .min(3, "Name must be at least 3 characters")
58
+ .max(100, "Name must be less than 100 characters"),
59
+ read_only: Yup.boolean().required(),
60
+ members: Yup.array().of(Yup.object().shape({
61
+ userId: Yup.number().required(),
62
+ role: Yup.string().oneOf(["moderator", "member"]).required(),
63
+ user: Yup.object().required()
64
+ }))
65
+ });
66
+ function CreateGroupScreen({ navigation }) {
67
+ const styles = useStyles();
68
+ const theme = (0, react_native_paper_1.useTheme)();
69
+ const handleSubmit = async (values) => {
70
+ try {
71
+ await (0, groups_1.createGroup)({
72
+ name: values.name,
73
+ read_only: values.read_only,
74
+ members: values.members.map(m => ({
75
+ userId: m.userId,
76
+ role: m.role
77
+ }))
78
+ });
79
+ navigation.goBack();
80
+ }
81
+ catch (error) {
82
+ console.error("Failed to create group:", error);
83
+ // TODO: Show error toast
84
+ }
85
+ };
86
+ const formik = (0, formik_1.useFormik)({
87
+ initialValues: { name: "", read_only: false, members: [] },
88
+ validationSchema: createGroupSchema,
89
+ onSubmit: handleSubmit
90
+ });
91
+ const { values, errors, touched, handleChange, handleBlur, setFieldValue, isSubmitting } = formik;
92
+ const handleSetMemberRole = (userId, role) => {
93
+ setFieldValue("members", values.members.map(m => (m.userId === userId ? { ...m, role } : m)));
94
+ };
95
+ const handleRemoveMember = (userId) => {
96
+ setFieldValue("members", values.members.filter(m => m.userId !== userId));
97
+ };
98
+ return (<KeyboardAvoidingContainer_1.KeyboardAvoidingContainer style={styles.container}>
99
+ <react_native_1.ScrollView style={styles.scrollView} contentContainerStyle={styles.content}>
100
+ <react_native_1.View style={styles.form}>
101
+ <react_native_paper_1.TextInput label="Group Name" value={values.name} onChangeText={handleChange("name")} onBlur={handleBlur("name")} error={touched.name && !!errors.name} disabled={isSubmitting} mode="outlined" style={styles.input}/>
102
+ {touched.name && errors.name && (<react_native_paper_1.HelperText type="error" visible={true}>
103
+ {errors.name}
104
+ </react_native_paper_1.HelperText>)}
105
+
106
+ <react_native_1.View style={styles.switchContainer}>
107
+ <react_native_1.View style={styles.switchLabelContainer}>
108
+ <react_native_paper_1.Text variant="bodyLarge">Read-only group</react_native_paper_1.Text>
109
+ <react_native_paper_1.Text variant="bodySmall" style={styles.helperText}>
110
+ Members can only read messages. Moderators can post.
111
+ </react_native_paper_1.Text>
112
+ </react_native_1.View>
113
+ <react_native_paper_1.Switch value={values.read_only} onValueChange={value => {
114
+ setFieldValue("read_only", value);
115
+ }} disabled={isSubmitting}/>
116
+ </react_native_1.View>
117
+
118
+ <react_native_paper_1.Divider style={styles.divider}/>
119
+
120
+ <react_native_paper_1.Text variant="titleMedium" style={styles.sectionTitle}>
121
+ Add Members
122
+ </react_native_paper_1.Text>
123
+
124
+ <react_native_paper_1.Text variant="bodySmall" style={styles.warningText}>
125
+ You cannot add members later. Only admins can join a group after it
126
+ is created. This will be fixed later.
127
+ </react_native_paper_1.Text>
128
+
129
+ <UserAutocomplete_1.UserAutocomplete multiple showChips={false} value={values.members.map(m => m.user)} onChange={(users) => {
130
+ setFieldValue("members", users.map(user => ({
131
+ userId: user.id,
132
+ role: "member",
133
+ user
134
+ })));
135
+ }} disabled={isSubmitting} placeholder="Search users to add..."/>
136
+
137
+ {values.members.length > 0 && (<react_native_1.View style={styles.membersListContainer}>
138
+ <react_native_paper_1.Text variant="titleSmall" style={styles.membersListTitle}>
139
+ Selected Members ({values.members.length})
140
+ </react_native_paper_1.Text>
141
+
142
+ {values.members.map(member => (<react_native_1.View key={member.userId} style={styles.memberItem}>
143
+ <react_native_1.View style={styles.memberInfo}>
144
+ <react_native_paper_1.Text variant="bodyLarge">{member.user.name}</react_native_paper_1.Text>
145
+ <react_native_paper_1.Text variant="bodySmall" style={styles.memberEmail}>
146
+ {member.user.email}
147
+ </react_native_paper_1.Text>
148
+ </react_native_1.View>
149
+
150
+ <react_native_1.View style={styles.memberActions}>
151
+ <Dropdown_1.Dropdown label={member.role === "moderator" ? "Moderator" : "Member"} mode="text" disabled={isSubmitting}>
152
+ <react_native_paper_1.Menu.Item onPress={() => handleSetMemberRole(member.userId, "member")} title="Member"/>
153
+ <react_native_paper_1.Menu.Item onPress={() => handleSetMemberRole(member.userId, "moderator")} title="Moderator"/>
154
+ </Dropdown_1.Dropdown>
155
+
156
+ <react_native_paper_1.IconButton icon="close" iconColor={theme.colors.error} size={20} onPress={() => handleRemoveMember(member.userId)} disabled={isSubmitting}/>
157
+ </react_native_1.View>
158
+ </react_native_1.View>))}
159
+ </react_native_1.View>)}
160
+ </react_native_1.View>
161
+ </react_native_1.ScrollView>
162
+
163
+ <react_native_1.View style={styles.footer}>
164
+ <react_native_paper_1.Button mode="contained" onPress={() => formik.handleSubmit()} disabled={isSubmitting || !formik.isValid} loading={isSubmitting} style={styles.button}>
165
+ Create Group
166
+ </react_native_paper_1.Button>
167
+ </react_native_1.View>
168
+ </KeyboardAvoidingContainer_1.KeyboardAvoidingContainer>);
169
+ }
170
+ const useStyles = () => {
171
+ const theme = (0, react_native_paper_1.useTheme)();
172
+ return (0, styles_1.useStyleSheet)({
173
+ container: {
174
+ flex: 1,
175
+ backgroundColor: theme.colors.surface
176
+ },
177
+ scrollView: {
178
+ flex: 1
179
+ },
180
+ content: {
181
+ paddingHorizontal: 25,
182
+ paddingVertical: 16
183
+ },
184
+ form: {
185
+ flex: 1
186
+ },
187
+ input: {
188
+ marginBottom: 4
189
+ },
190
+ switchContainer: {
191
+ flexDirection: "row",
192
+ justifyContent: "space-between",
193
+ alignItems: "center",
194
+ marginTop: 24,
195
+ marginBottom: 32,
196
+ paddingVertical: 8
197
+ },
198
+ switchLabelContainer: {
199
+ flex: 1,
200
+ marginRight: 16
201
+ },
202
+ helperText: {
203
+ color: theme.colors.onSurfaceVariant,
204
+ marginTop: 4
205
+ },
206
+ divider: {
207
+ marginTop: 0,
208
+ marginBottom: 24
209
+ },
210
+ sectionTitle: {
211
+ marginBottom: 8,
212
+ fontWeight: "600"
213
+ },
214
+ warningText: {
215
+ color: theme.colors.error,
216
+ marginBottom: 16,
217
+ padding: 12,
218
+ backgroundColor: theme.colors.errorContainer,
219
+ borderRadius: 8
220
+ },
221
+ membersListContainer: {
222
+ marginTop: 16
223
+ },
224
+ membersListTitle: {
225
+ marginBottom: 12,
226
+ fontWeight: "600"
227
+ },
228
+ memberItem: {
229
+ flexDirection: "row",
230
+ justifyContent: "space-between",
231
+ alignItems: "center",
232
+ paddingVertical: 12,
233
+ paddingLeft: 16,
234
+ paddingRight: 4,
235
+ backgroundColor: theme.colors.surfaceVariant,
236
+ borderRadius: 8,
237
+ marginBottom: 2
238
+ },
239
+ memberInfo: {
240
+ flex: 1,
241
+ marginRight: 8
242
+ },
243
+ memberActions: {
244
+ flexDirection: "row",
245
+ alignItems: "center",
246
+ gap: 4
247
+ },
248
+ memberEmail: {
249
+ color: theme.colors.onSurfaceVariant,
250
+ marginTop: 2
251
+ },
252
+ footer: {
253
+ paddingHorizontal: 30,
254
+ paddingVertical: 16,
255
+ borderTopWidth: 1,
256
+ borderTopColor: theme.colors.surfaceVariant,
257
+ backgroundColor: theme.colors.surface
258
+ },
259
+ button: {
260
+ width: "100%"
261
+ }
262
+ });
263
+ };
@@ -0,0 +1,3 @@
1
+ export * from "./theme";
2
+ export * from "./responsive";
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/styles/index.ts"],"names":[],"mappings":"AAAA,cAAc,SAAS,CAAC;AACxB,cAAc,cAAc,CAAC"}
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./theme"), exports);
18
+ __exportStar(require("./responsive"), exports);