@messenger-box/platform-mobile 10.0.3-alpha.20 → 10.0.3-alpha.23
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +8 -0
- package/lib/screens/inbox/DialogThreads.js +52 -12
- package/lib/screens/inbox/DialogThreads.js.map +1 -1
- package/lib/screens/inbox/components/CachedImage/index.js +0 -19
- package/lib/screens/inbox/components/CachedImage/index.js.map +1 -1
- package/lib/screens/inbox/components/ThreadsViewItem.js +66 -44
- package/lib/screens/inbox/components/ThreadsViewItem.js.map +1 -1
- package/lib/screens/inbox/containers/ConversationView.js +36 -34
- package/lib/screens/inbox/containers/ConversationView.js.map +1 -1
- package/lib/screens/inbox/containers/Dialogs.js +82 -37
- package/lib/screens/inbox/containers/Dialogs.js.map +1 -1
- package/lib/screens/inbox/containers/ThreadConversationView.js +282 -219
- package/lib/screens/inbox/containers/ThreadConversationView.js.map +1 -1
- package/lib/screens/inbox/containers/ThreadsView.js +83 -50
- package/lib/screens/inbox/containers/ThreadsView.js.map +1 -1
- package/lib/screens/inbox/hooks/useSafeDialogThreadsMachine.js +108 -0
- package/lib/screens/inbox/hooks/useSafeDialogThreadsMachine.js.map +1 -0
- package/lib/screens/inbox/workflow/dialog-threads-xstate.js +151 -0
- package/lib/screens/inbox/workflow/dialog-threads-xstate.js.map +1 -0
- package/package.json +2 -2
- package/src/screens/inbox/DialogThreads.tsx +49 -53
- package/src/screens/inbox/components/CachedImage/index.tsx +9 -9
- package/src/screens/inbox/components/SmartLoader.tsx +61 -0
- package/src/screens/inbox/components/ThreadsViewItem.tsx +177 -265
- package/src/screens/inbox/containers/ConversationView.tsx +32 -30
- package/src/screens/inbox/containers/Dialogs.tsx +57 -22
- package/src/screens/inbox/containers/ThreadConversationView.tsx +467 -484
- package/src/screens/inbox/containers/ThreadsView.tsx +102 -183
- package/src/screens/inbox/hooks/useSafeDialogThreadsMachine.ts +136 -0
- package/src/screens/inbox/index.ts +37 -0
- package/src/screens/inbox/machines/threadsMachine.ts +147 -0
- package/src/screens/inbox/workflow/dialog-threads-xstate.ts +163 -0
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,14 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
## [10.0.3-alpha.23](https://github.com/CDEBase/messenger-box/compare/v10.0.3-alpha.22...v10.0.3-alpha.23) (2025-04-14)
|
|
7
|
+
|
|
8
|
+
**Note:** Version bump only for package @messenger-box/platform-mobile
|
|
9
|
+
|
|
10
|
+
## [10.0.3-alpha.22](https://github.com/CDEBase/messenger-box/compare/v10.0.3-alpha.21...v10.0.3-alpha.22) (2025-04-14)
|
|
11
|
+
|
|
12
|
+
**Note:** Version bump only for package @messenger-box/platform-mobile
|
|
13
|
+
|
|
6
14
|
## [10.0.3-alpha.20](https://github.com/CDEBase/messenger-box/compare/v10.0.3-alpha.19...v10.0.3-alpha.20) (2025-04-12)
|
|
7
15
|
|
|
8
16
|
**Note:** Version bump only for package @messenger-box/platform-mobile
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import*as React from'react';import {Spinner,Box}from'@admin-layout/gluestack-ui-mobile';import {ThreadsView}from'./containers/ThreadsView.js';import {useViewChannelDetailQuery,useThreadMessagesQuery}from'common/graphql';import {useFocusEffect}from'@react-navigation/native';import {config}from'./config/config.js';import colors from'tailwindcss/colors';const {
|
|
1
|
+
import*as React from'react';import {Spinner,Box}from'@admin-layout/gluestack-ui-mobile';import {ThreadsView}from'./containers/ThreadsView.js';import {useViewChannelDetailQuery,useThreadMessagesQuery}from'common/graphql';import {useFocusEffect}from'@react-navigation/native';import {config}from'./config/config.js';import colors from'tailwindcss/colors';import {useSafeDialogThreadsMachine}from'./hooks/useSafeDialogThreadsMachine.js';import {Actions,BaseState}from'./workflow/dialog-threads-xstate.js';const {
|
|
2
2
|
MESSAGES_PER_PAGE
|
|
3
3
|
} = config;
|
|
4
4
|
function DialogThreads({
|
|
@@ -6,6 +6,16 @@ function DialogThreads({
|
|
|
6
6
|
postParentId,
|
|
7
7
|
role
|
|
8
8
|
}) {
|
|
9
|
+
const [state, send] = useSafeDialogThreadsMachine();
|
|
10
|
+
const {
|
|
11
|
+
context,
|
|
12
|
+
value
|
|
13
|
+
} = state;
|
|
14
|
+
const {
|
|
15
|
+
channelsDetail,
|
|
16
|
+
loading,
|
|
17
|
+
error
|
|
18
|
+
} = context;
|
|
9
19
|
const {
|
|
10
20
|
data: channelData,
|
|
11
21
|
loading: channelLoading,
|
|
@@ -29,11 +39,47 @@ function DialogThreads({
|
|
|
29
39
|
repliesLimit2: 5
|
|
30
40
|
}
|
|
31
41
|
});
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
42
|
+
React.useEffect(() => {
|
|
43
|
+
send({
|
|
44
|
+
type: Actions.INITIALIZE,
|
|
45
|
+
data: {
|
|
46
|
+
channelId,
|
|
47
|
+
postParentId,
|
|
48
|
+
role
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
}, [channelId, postParentId, role]);
|
|
52
|
+
React.useEffect(() => {
|
|
53
|
+
if (channelData == null ? void 0 : channelData.viewChannelDetail) {
|
|
54
|
+
send({
|
|
55
|
+
type: Actions.SET_CHANNEL_DETAIL,
|
|
56
|
+
data: {
|
|
57
|
+
channelsDetail: channelData.viewChannelDetail
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
}
|
|
36
61
|
}, [channelData]);
|
|
62
|
+
React.useEffect(() => {
|
|
63
|
+
var _a;
|
|
64
|
+
if (threadsData) {
|
|
65
|
+
send({
|
|
66
|
+
type: Actions.SET_THREADS,
|
|
67
|
+
data: {
|
|
68
|
+
threadData: ((_a = threadsData == null ? void 0 : threadsData.threadMessages) == null ? void 0 : _a.data) || []
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
}, [threadsData]);
|
|
73
|
+
React.useEffect(() => {
|
|
74
|
+
if (threadsError) {
|
|
75
|
+
send({
|
|
76
|
+
type: Actions.ERROR,
|
|
77
|
+
data: {
|
|
78
|
+
error: threadsError
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
}, [threadsError]);
|
|
37
83
|
const refetchChannelDetail = React.useCallback((id) => {
|
|
38
84
|
return channelRefetch({
|
|
39
85
|
id: id == null ? void 0 : id.toString()
|
|
@@ -45,11 +91,5 @@ function DialogThreads({
|
|
|
45
91
|
return () => {
|
|
46
92
|
};
|
|
47
93
|
}, []));
|
|
48
|
-
return /* @__PURE__ */ React.createElement(React.Fragment, null, channelLoading ? /* @__PURE__ */ React.createElement(Spinner, { color: colors.blue[500] }) : /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(
|
|
49
|
-
Box,
|
|
50
|
-
{
|
|
51
|
-
className: "flex-1 bg-gray-200 dark:border-gray-500 dark:bg-gray-500 "
|
|
52
|
-
},
|
|
53
|
-
/* @__PURE__ */ React.createElement(ThreadsView, { data: threadsData, loading: threadLoading, refetch: threadsRefetch, subscribeToMore: threadsSubscribeToMore, error: threadsError, channelId, role, channelsDetail, refetchChannelDetail })
|
|
54
|
-
)));
|
|
94
|
+
return /* @__PURE__ */ React.createElement(React.Fragment, null, state.matches(BaseState.LoadingChannel) || channelLoading ? /* @__PURE__ */ React.createElement(Spinner, { color: colors.blue[500] }) : /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(Box, { className: "flex-1 bg-gray-200 dark:border-gray-500 dark:bg-gray-500" }, /* @__PURE__ */ React.createElement(ThreadsView, { data: threadsData, loading: threadLoading || state.matches(BaseState.LoadingThreads), refetch: threadsRefetch, subscribeToMore: threadsSubscribeToMore, error: error || threadsError, channelId, role, channelsDetail, refetchChannelDetail }))));
|
|
55
95
|
}export{DialogThreads,DialogThreads as default};//# sourceMappingURL=DialogThreads.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DialogThreads.js","sources":["../../../src/screens/inbox/DialogThreads.tsx"],"sourcesContent":["import * as React from 'react';\nimport { Box, Spinner, Text } from '@admin-layout/gluestack-ui-mobile';\nimport { ThreadConversationView } from './containers/ThreadConversationView';\nimport { ThreadsView } from './containers/ThreadsView';\nimport { useViewChannelDetailQuery, useThreadMessagesQuery } from 'common/graphql';\nimport { useFocusEffect } from '@react-navigation/native';\nimport { useSelector } from 'react-redux';\nimport { config } from './config';\nimport colors from 'tailwindcss/colors';\nconst { MESSAGES_PER_PAGE } = config;\n\nexport function DialogThreads({ channelId, postParentId, role }) {\n const {\n data: channelData,\n loading: channelLoading,\n refetch: channelRefetch,\n } = useViewChannelDetailQuery({\n variables: {\n id: channelId?.toString(),\n },\n });\n\n const {\n data: threadsData,\n loading: threadLoading,\n error: threadsError,\n refetch: threadsRefetch,\n subscribeToMore: threadsSubscribeToMore,\n } = useThreadMessagesQuery({\n variables: {\n channelId: channelId?.toString(),\n role: role?.toString(),\n limit: MESSAGES_PER_PAGE,\n repliesLimit2: 5,\n },\n
|
|
1
|
+
{"version":3,"file":"DialogThreads.js","sources":["../../../src/screens/inbox/DialogThreads.tsx"],"sourcesContent":["import * as React from 'react';\nimport { Box, Spinner, Text } from '@admin-layout/gluestack-ui-mobile';\nimport { ThreadConversationView } from './containers/ThreadConversationView';\nimport { ThreadsView } from './containers/ThreadsView';\nimport { useViewChannelDetailQuery, useThreadMessagesQuery } from 'common/graphql';\nimport { useFocusEffect } from '@react-navigation/native';\nimport { useSelector } from 'react-redux';\nimport { config } from './config';\nimport colors from 'tailwindcss/colors';\nimport { useSafeDialogThreadsMachine } from './hooks/useSafeDialogThreadsMachine';\nimport { Actions, BaseState } from './workflow/dialog-threads-xstate';\nconst { MESSAGES_PER_PAGE } = config;\n\nexport function DialogThreads({ channelId, postParentId, role }) {\n // Use the XState machine for state management\n const [state, send] = useSafeDialogThreadsMachine();\n const { context, value } = state;\n const { channelsDetail, loading, error } = context;\n\n // Fetch channel details\n const {\n data: channelData,\n loading: channelLoading,\n refetch: channelRefetch,\n } = useViewChannelDetailQuery({\n variables: {\n id: channelId?.toString(),\n },\n });\n\n // Fetch thread messages\n const {\n data: threadsData,\n loading: threadLoading,\n error: threadsError,\n refetch: threadsRefetch,\n subscribeToMore: threadsSubscribeToMore,\n } = useThreadMessagesQuery({\n variables: {\n channelId: channelId?.toString(),\n role: role?.toString(),\n limit: MESSAGES_PER_PAGE,\n repliesLimit2: 5,\n },\n });\n\n // Initialize the machine with props\n React.useEffect(() => {\n send({\n type: Actions.INITIALIZE,\n data: { channelId, postParentId, role },\n });\n }, [channelId, postParentId, role]);\n\n // Update channel detail in state when data changes\n React.useEffect(() => {\n if (channelData?.viewChannelDetail) {\n send({\n type: Actions.SET_CHANNEL_DETAIL,\n data: { channelsDetail: channelData.viewChannelDetail },\n });\n }\n }, [channelData]);\n\n // Update thread data in state when data changes\n React.useEffect(() => {\n if (threadsData) {\n send({\n type: Actions.SET_THREADS,\n data: { threadData: threadsData?.threadMessages?.data || [] },\n });\n }\n }, [threadsData]);\n\n // Handle errors\n React.useEffect(() => {\n if (threadsError) {\n send({\n type: Actions.ERROR,\n data: { error: threadsError },\n });\n }\n }, [threadsError]);\n\n const refetchChannelDetail = React.useCallback(\n (id: string) => {\n return channelRefetch({ id: id?.toString() });\n },\n [channelId],\n );\n\n useFocusEffect(\n React.useCallback(() => {\n // Do something when the screen is focused\n if (channelId) refetchChannelDetail(channelId);\n return () => {};\n }, []),\n );\n\n return (\n <>\n {state.matches(BaseState.LoadingChannel) || channelLoading ? (\n <Spinner color={colors.blue[500]} />\n ) : (\n <>\n <Box className=\"flex-1 bg-gray-200 dark:border-gray-500 dark:bg-gray-500\">\n <ThreadsView\n data={threadsData}\n loading={threadLoading || state.matches(BaseState.LoadingThreads)}\n refetch={threadsRefetch}\n subscribeToMore={threadsSubscribeToMore}\n error={error || threadsError}\n channelId={channelId}\n role={role}\n channelsDetail={channelsDetail}\n refetchChannelDetail={refetchChannelDetail}\n />\n </Box>\n </>\n )}\n </>\n );\n}\n\nexport default DialogThreads;\n"],"names":[],"mappings":"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"}
|
|
@@ -82,7 +82,6 @@ const CachedImage = (props) => {
|
|
|
82
82
|
setLoadError(true);
|
|
83
83
|
}
|
|
84
84
|
};
|
|
85
|
-
console.log("CachedImage loading with URI:", uri);
|
|
86
85
|
console.log("Cache key:", cacheKey);
|
|
87
86
|
initCache();
|
|
88
87
|
return () => {
|
|
@@ -97,13 +96,6 @@ const CachedImage = (props) => {
|
|
|
97
96
|
expiresIn,
|
|
98
97
|
expired
|
|
99
98
|
});
|
|
100
|
-
console.log({
|
|
101
|
-
modificationTime: metadata.modificationTime,
|
|
102
|
-
currentTime: new Date().getTime() / 1e3
|
|
103
|
-
});
|
|
104
|
-
console.log({
|
|
105
|
-
metadata
|
|
106
|
-
});
|
|
107
99
|
if (!metadata.exists || (metadata == null ? void 0 : metadata.size) === 0 || expired) {
|
|
108
100
|
if (componentIsMounted.current) {
|
|
109
101
|
setImgUri(null);
|
|
@@ -113,9 +105,7 @@ const CachedImage = (props) => {
|
|
|
113
105
|
});
|
|
114
106
|
}
|
|
115
107
|
setImgUri(null);
|
|
116
|
-
console.log("Downloading image from URI:", uri);
|
|
117
108
|
if (!uri) {
|
|
118
|
-
console.log("Image URI is undefined or null");
|
|
119
109
|
setLoadError(true);
|
|
120
110
|
return;
|
|
121
111
|
}
|
|
@@ -127,10 +117,8 @@ const CachedImage = (props) => {
|
|
|
127
117
|
}
|
|
128
118
|
try {
|
|
129
119
|
const response = await downloadResumableRef.current.downloadAsync();
|
|
130
|
-
console.log("Download response:", response);
|
|
131
120
|
if (componentIsMounted.current && response && response.status === 200) {
|
|
132
121
|
setImgUri(`${fileURI}?`);
|
|
133
|
-
console.log("Image cached successfully, new URI:", `${fileURI}?`);
|
|
134
122
|
} else {
|
|
135
123
|
console.log("Failed to download image, status:", response == null ? void 0 : response.status);
|
|
136
124
|
console.log("Falling back to original URI");
|
|
@@ -148,7 +136,6 @@ const CachedImage = (props) => {
|
|
|
148
136
|
}
|
|
149
137
|
}
|
|
150
138
|
} else {
|
|
151
|
-
console.log("Using cached image at:", fileURI);
|
|
152
139
|
}
|
|
153
140
|
} catch (err) {
|
|
154
141
|
console.log({
|
|
@@ -159,12 +146,6 @@ const CachedImage = (props) => {
|
|
|
159
146
|
setImgUri(uri);
|
|
160
147
|
}
|
|
161
148
|
};
|
|
162
|
-
console.log({
|
|
163
|
-
placeholderContent,
|
|
164
|
-
imgUri,
|
|
165
|
-
loadError,
|
|
166
|
-
useFallbackUri
|
|
167
|
-
});
|
|
168
149
|
const defaultPlaceholder = /* @__PURE__ */ React__default.createElement(View, { style: {
|
|
169
150
|
width: "100%",
|
|
170
151
|
height: "100%",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":["../../../../../src/screens/inbox/components/CachedImage/index.tsx"],"sourcesContent":["import React, { useEffect, useState, useRef } from 'react';\nimport { Image, View, Text } from 'react-native';\n// import { Image } from \"react-native\"\nimport * as FileSystem from 'expo-file-system';\n\nimport * as CONST from './consts';\n\n// Ensure the cache directory exists\nconst ensureCacheDirectory = async () => {\n try {\n const dirInfo = await FileSystem.getInfoAsync(CONST.IMAGE_CACHE_FOLDER);\n if (!dirInfo.exists) {\n console.log('Creating cache directory:', CONST.IMAGE_CACHE_FOLDER);\n await FileSystem.makeDirectoryAsync(CONST.IMAGE_CACHE_FOLDER, { intermediates: true });\n }\n } catch (error) {\n console.error('Failed to create cache directory:', error);\n }\n};\n\n// Validate and sanitize the image URL\nconst validateImageUri = (uri: string): string | null => {\n if (!uri) return null;\n\n // Trim whitespace\n uri = uri.trim();\n\n // Check if it's a valid URL format\n try {\n new URL(uri);\n } catch (e) {\n console.log('Invalid URL format:', uri);\n return null;\n }\n\n // Add more validation as needed for your specific case\n return uri;\n};\n\nconst CachedImage = (props: any) => {\n const { source, cacheKey, placeholderContent } = props;\n const { uri: originalUri, headers, expiresIn } = source;\n\n // Validate and sanitize the URI\n const uri = validateImageUri(originalUri);\n\n const fileURI = `${CONST.IMAGE_CACHE_FOLDER}${cacheKey}`;\n\n const [imgUri, setImgUri] = useState<any>(fileURI);\n const [loadError, setLoadError] = useState<boolean>(false);\n const [useFallbackUri, setUseFallbackUri] = useState<boolean>(false);\n\n const componentIsMounted = useRef(true);\n const requestOption = headers ? { headers } : {};\n\n const _callback = (downloadProgress: any) => {\n if (componentIsMounted.current === false) {\n downloadResumableRef.current?.pauseAsync();\n FileSystem.deleteAsync(fileURI, { idempotent: true }); // delete file locally if it was not downloaded properly\n }\n };\n\n const downloadResumableRef = useRef(\n uri ? FileSystem.createDownloadResumable(uri, fileURI, requestOption, _callback) : null,\n );\n\n useEffect(() => {\n const initCache = async () => {\n await ensureCacheDirectory();\n if (uri) {\n loadImage();\n } else {\n console.log('Image URI is invalid, not loading');\n setLoadError(true);\n }\n };\n\n console.log('CachedImage loading with URI:', uri);\n console.log('Cache key:', cacheKey);\n\n initCache();\n\n return () => {\n componentIsMounted.current = false;\n };\n }, []); // eslint-disable-line react-hooks/exhaustive-deps\n\n const loadImage = async () => {\n try {\n // Use the cached image if it exists\n const metadata: any = await FileSystem.getInfoAsync(fileURI);\n const expired = expiresIn && new Date().getTime() / 1000 - metadata?.modificationTime > expiresIn;\n console.log({ expiresIn, expired });\n\n console.log({ modificationTime: metadata.modificationTime, currentTime: new Date().getTime() / 1000 });\n console.log({ metadata });\n\n if (!metadata.exists || metadata?.size === 0 || expired) {\n if (componentIsMounted.current) {\n setImgUri(null);\n\n if (expired) {\n await FileSystem.deleteAsync(fileURI, { idempotent: true });\n }\n // download to cache\n setImgUri(null);\n\n console.log('Downloading image from URI:', uri);\n if (!uri) {\n console.log('Image URI is undefined or null');\n setLoadError(true);\n return;\n }\n\n if (!downloadResumableRef.current) {\n console.log('Download resumable is null');\n setUseFallbackUri(true);\n setImgUri(uri);\n return;\n }\n\n try {\n const response: any = await downloadResumableRef.current.downloadAsync();\n console.log('Download response:', response);\n\n if (componentIsMounted.current && response && response.status === 200) {\n setImgUri(`${fileURI}?`); // deep clone to force re-render\n console.log('Image cached successfully, new URI:', `${fileURI}?`);\n } else {\n console.log('Failed to download image, status:', response?.status);\n console.log('Falling back to original URI');\n setUseFallbackUri(true);\n setImgUri(uri);\n FileSystem.deleteAsync(fileURI, { idempotent: true }); // delete file locally if it was not downloaded properly\n }\n } catch (downloadError) {\n console.log('Error downloading image:', downloadError);\n console.log('Falling back to original URI');\n setUseFallbackUri(true);\n setImgUri(uri);\n }\n }\n } else {\n console.log('Using cached image at:', fileURI);\n }\n } catch (err) {\n console.log({ err });\n console.log('Falling back to original URI');\n setUseFallbackUri(true);\n setImgUri(uri);\n }\n };\n\n console.log({ placeholderContent, imgUri, loadError, useFallbackUri });\n\n // Default placeholder if none is provided\n const defaultPlaceholder = (\n <View\n style={{\n width: '100%',\n height: '100%',\n backgroundColor: '#e1e1e1',\n justifyContent: 'center',\n alignItems: 'center',\n borderRadius: 3,\n }}\n >\n <Text>Image not available</Text>\n </View>\n );\n\n if (!imgUri) {\n return placeholderContent || defaultPlaceholder;\n }\n\n return (\n <Image\n // eslint-disable-next-line react/jsx-props-no-spreading\n {...props}\n source={{\n ...source,\n uri: useFallbackUri ? uri : imgUri,\n }}\n onError={(e) => {\n console.log('Image loading error:', e.nativeEvent.error);\n // If we're already using the fallback URI and still getting an error,\n // then show the placeholder\n if (useFallbackUri) {\n setLoadError(true);\n setImgUri(null);\n } else {\n console.log('Falling back to original URI after onError');\n setUseFallbackUri(true);\n setImgUri(uri);\n }\n }}\n />\n );\n};\n\nexport const CacheManager = {\n addToCache: async ({ file, key }: any) => {\n await FileSystem.copyAsync({\n from: file,\n to: `${CONST.IMAGE_CACHE_FOLDER}${key}`,\n });\n // const uri = await FileSystem.getContentUriAsync(`${CONST.IMAGE_CACHE_FOLDER}${key}`)\n // return uri\n const uri = await CacheManager.getCachedUri({ key });\n return uri;\n },\n\n getCachedUri: async ({ key }: any) => {\n const uri = await FileSystem.getContentUriAsync(`${CONST.IMAGE_CACHE_FOLDER}${key}`);\n return uri;\n },\n\n downloadAsync: async ({ uri, key, options }: any) => {\n return await FileSystem.downloadAsync(uri, `${CONST.IMAGE_CACHE_FOLDER}${key}`, options);\n },\n};\n\nexport default CachedImage;\n"],"names":["CONST.IMAGE_CACHE_FOLDER","React"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../../../../../src/screens/inbox/components/CachedImage/index.tsx"],"sourcesContent":["import React, { useEffect, useState, useRef } from 'react';\nimport { Image, View, Text } from 'react-native';\n// import { Image } from \"react-native\"\nimport * as FileSystem from 'expo-file-system';\n\nimport * as CONST from './consts';\n\n// Ensure the cache directory exists\nconst ensureCacheDirectory = async () => {\n try {\n const dirInfo = await FileSystem.getInfoAsync(CONST.IMAGE_CACHE_FOLDER);\n if (!dirInfo.exists) {\n console.log('Creating cache directory:', CONST.IMAGE_CACHE_FOLDER);\n await FileSystem.makeDirectoryAsync(CONST.IMAGE_CACHE_FOLDER, { intermediates: true });\n }\n } catch (error) {\n console.error('Failed to create cache directory:', error);\n }\n};\n\n// Validate and sanitize the image URL\nconst validateImageUri = (uri: string): string | null => {\n if (!uri) return null;\n\n // Trim whitespace\n uri = uri.trim();\n\n // Check if it's a valid URL format\n try {\n new URL(uri);\n } catch (e) {\n console.log('Invalid URL format:', uri);\n return null;\n }\n\n // Add more validation as needed for your specific case\n return uri;\n};\n\nconst CachedImage = (props: any) => {\n const { source, cacheKey, placeholderContent } = props;\n const { uri: originalUri, headers, expiresIn } = source;\n\n // Validate and sanitize the URI\n const uri = validateImageUri(originalUri);\n\n const fileURI = `${CONST.IMAGE_CACHE_FOLDER}${cacheKey}`;\n\n const [imgUri, setImgUri] = useState<any>(fileURI);\n const [loadError, setLoadError] = useState<boolean>(false);\n const [useFallbackUri, setUseFallbackUri] = useState<boolean>(false);\n\n const componentIsMounted = useRef(true);\n const requestOption = headers ? { headers } : {};\n\n const _callback = (downloadProgress: any) => {\n if (componentIsMounted.current === false) {\n downloadResumableRef.current?.pauseAsync();\n FileSystem.deleteAsync(fileURI, { idempotent: true }); // delete file locally if it was not downloaded properly\n }\n };\n\n const downloadResumableRef = useRef(\n uri ? FileSystem.createDownloadResumable(uri, fileURI, requestOption, _callback) : null,\n );\n\n useEffect(() => {\n const initCache = async () => {\n await ensureCacheDirectory();\n if (uri) {\n loadImage();\n } else {\n console.log('Image URI is invalid, not loading');\n setLoadError(true);\n }\n };\n\n // console.log('CachedImage loading with URI:', uri);\n console.log('Cache key:', cacheKey);\n\n initCache();\n\n return () => {\n componentIsMounted.current = false;\n };\n }, []); // eslint-disable-line react-hooks/exhaustive-deps\n\n const loadImage = async () => {\n try {\n // Use the cached image if it exists\n const metadata: any = await FileSystem.getInfoAsync(fileURI);\n const expired = expiresIn && new Date().getTime() / 1000 - metadata?.modificationTime > expiresIn;\n console.log({ expiresIn, expired });\n\n // console.log({ modificationTime: metadata.modificationTime, currentTime: new Date().getTime() / 1000 });\n // console.log({ metadata });\n\n if (!metadata.exists || metadata?.size === 0 || expired) {\n if (componentIsMounted.current) {\n setImgUri(null);\n\n if (expired) {\n await FileSystem.deleteAsync(fileURI, { idempotent: true });\n }\n // download to cache\n setImgUri(null);\n\n // console.log('Downloading image from URI:', uri);\n if (!uri) {\n // console.log('Image URI is undefined or null');\n setLoadError(true);\n return;\n }\n\n if (!downloadResumableRef.current) {\n console.log('Download resumable is null');\n setUseFallbackUri(true);\n setImgUri(uri);\n return;\n }\n\n try {\n const response: any = await downloadResumableRef.current.downloadAsync();\n // console.log('Download response:', response);\n\n if (componentIsMounted.current && response && response.status === 200) {\n setImgUri(`${fileURI}?`); // deep clone to force re-render\n // console.log('Image cached successfully, new URI:', `${fileURI}?`);\n } else {\n console.log('Failed to download image, status:', response?.status);\n console.log('Falling back to original URI');\n setUseFallbackUri(true);\n setImgUri(uri);\n FileSystem.deleteAsync(fileURI, { idempotent: true }); // delete file locally if it was not downloaded properly\n }\n } catch (downloadError) {\n console.log('Error downloading image:', downloadError);\n console.log('Falling back to original URI');\n setUseFallbackUri(true);\n setImgUri(uri);\n }\n }\n } else {\n //console.log('Using cached image at:', fileURI);\n }\n } catch (err) {\n console.log({ err });\n console.log('Falling back to original URI');\n setUseFallbackUri(true);\n setImgUri(uri);\n }\n };\n\n //console.log({ placeholderContent, imgUri, loadError, useFallbackUri });\n\n // Default placeholder if none is provided\n const defaultPlaceholder = (\n <View\n style={{\n width: '100%',\n height: '100%',\n backgroundColor: '#e1e1e1',\n justifyContent: 'center',\n alignItems: 'center',\n borderRadius: 3,\n }}\n >\n <Text>Image not available</Text>\n </View>\n );\n\n if (!imgUri) {\n return placeholderContent || defaultPlaceholder;\n }\n\n return (\n <Image\n // eslint-disable-next-line react/jsx-props-no-spreading\n {...props}\n source={{\n ...source,\n uri: useFallbackUri ? uri : imgUri,\n }}\n onError={(e) => {\n console.log('Image loading error:', e.nativeEvent.error);\n // If we're already using the fallback URI and still getting an error,\n // then show the placeholder\n if (useFallbackUri) {\n setLoadError(true);\n setImgUri(null);\n } else {\n console.log('Falling back to original URI after onError');\n setUseFallbackUri(true);\n setImgUri(uri);\n }\n }}\n />\n );\n};\n\nexport const CacheManager = {\n addToCache: async ({ file, key }: any) => {\n await FileSystem.copyAsync({\n from: file,\n to: `${CONST.IMAGE_CACHE_FOLDER}${key}`,\n });\n // const uri = await FileSystem.getContentUriAsync(`${CONST.IMAGE_CACHE_FOLDER}${key}`)\n // return uri\n const uri = await CacheManager.getCachedUri({ key });\n return uri;\n },\n\n getCachedUri: async ({ key }: any) => {\n const uri = await FileSystem.getContentUriAsync(`${CONST.IMAGE_CACHE_FOLDER}${key}`);\n return uri;\n },\n\n downloadAsync: async ({ uri, key, options }: any) => {\n return await FileSystem.downloadAsync(uri, `${CONST.IMAGE_CACHE_FOLDER}${key}`, options);\n },\n};\n\nexport default CachedImage;\n"],"names":["CONST.IMAGE_CACHE_FOLDER","React"],"mappings":";;;;;;;;;;;;;;;;;;;AAOA,MAAM,uBAAuB,YAAY;AACvC,EAAI,IAAA;AACF,IAAA,MAAM,OAAU,GAAA,MAAM,UAAW,CAAA,YAAA,CAAaA,kBAAwB,CAAA;AACtE,IAAI,IAAA,CAAC,QAAQ,MAAQ,EAAA;AACnB,MAAQ,OAAA,CAAA,GAAA,CAAI,2BAA6B,EAAAA,kBAAwB,CAAA;AACjE,MAAM,MAAA,UAAA,CAAW,kBAAmB,CAAAA,kBAA0B,EAAA;AAAA,QAC5D,aAAe,EAAA;AAAA,OAChB,CAAA;AAAA;AACH,WACO,KAAP,EAAA;AACA,IAAQ,OAAA,CAAA,KAAA,CAAM,qCAAqC,KAAK,CAAA;AAAA;AAE5D,CAAA;AAGA,MAAM,gBAAA,GAAmB,CAAC,GAA+B,KAAA;AACvD,EAAA,IAAI,CAAC,GAAA;AAAK,IAAO,OAAA,IAAA;AAGjB,EAAA,GAAA,GAAM,IAAI,IAAK,EAAA;AAGf,EAAI,IAAA;AACF,IAAA,IAAI,IAAI,GAAG,CAAA;AAAA,WACJ,CAAP,EAAA;AACA,IAAQ,OAAA,CAAA,GAAA,CAAI,uBAAuB,GAAG,CAAA;AACtC,IAAO,OAAA,IAAA;AAAA;AAIT,EAAO,OAAA,GAAA;AACT,CAAA;AACM,MAAA,WAAA,GAAc,CAAC,KAAe,KAAA;AAClC,EAAM,MAAA;AAAA,IACJ,MAAA;AAAA,IACA,QAAA;AAAA,IACA;AAAA,GACE,GAAA,KAAA;AACJ,EAAM,MAAA;AAAA,IACJ,GAAK,EAAA,WAAA;AAAA,IACL,OAAA;AAAA,IACA;AAAA,GACE,GAAA,MAAA;AAGJ,EAAM,MAAA,GAAA,GAAM,iBAAiB,WAAW,CAAA;AACxC,EAAM,MAAA,OAAA,GAAU,CAAG,EAAAA,kBAA2B,CAAA,EAAA,QAAA,CAAA,CAAA;AAC9C,EAAA,MAAM,CAAC,MAAA,EAAQ,SAAS,CAAA,GAAI,SAAc,OAAO,CAAA;AACjD,EAAA,MAAM,CAAC,SAAA,EAAW,YAAY,CAAA,GAAI,SAAkB,KAAK,CAAA;AACzD,EAAA,MAAM,CAAC,cAAA,EAAgB,iBAAiB,CAAA,GAAI,SAAkB,KAAK,CAAA;AACnE,EAAM,MAAA,kBAAA,GAAqB,OAAO,IAAI,CAAA;AACtC,EAAA,MAAM,gBAAgB,OAAU,GAAA;AAAA,IAC9B;AAAA,MACE,EAAC;AACL,EAAM,MAAA,SAAA,GAAY,CAAC,gBAA0B,KAAA;AA7D/C,IAAA,IAAA,EAAA;AA8DI,IAAI,IAAA,kBAAA,CAAmB,YAAY,KAAO,EAAA;AACxC,MAAA,CAAA,EAAA,GAAA,oBAAA,CAAqB,YAArB,IAA8B,GAAA,MAAA,GAAA,EAAA,CAAA,UAAA,EAAA;AAC9B,MAAA,UAAA,CAAW,YAAY,OAAS,EAAA;AAAA,QAC9B,UAAY,EAAA;AAAA,OACb,CAAA;AAAA;AACH,GACF;AACA,EAAM,MAAA,oBAAA,GAAuB,MAAO,CAAA,GAAA,GAAM,UAAW,CAAA,uBAAA,CAAwB,KAAK,OAAS,EAAA,aAAA,EAAe,SAAS,CAAA,GAAI,IAAI,CAAA;AAC3H,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,MAAM,YAAY,YAAY;AAC5B,MAAA,MAAM,oBAAqB,EAAA;AAC3B,MAAA,IAAI,GAAK,EAAA;AACP,QAAU,SAAA,EAAA;AAAA,OACL,MAAA;AACL,QAAA,OAAA,CAAQ,IAAI,mCAAmC,CAAA;AAC/C,QAAA,YAAA,CAAa,IAAI,CAAA;AAAA;AACnB,KACF;AAGA,IAAQ,OAAA,CAAA,GAAA,CAAI,cAAc,QAAQ,CAAA;AAClC,IAAU,SAAA,EAAA;AACV,IAAA,OAAO,MAAM;AACX,MAAA,kBAAA,CAAmB,OAAU,GAAA,KAAA;AAAA,KAC/B;AAAA,GACF,EAAG,EAAE,CAAA;AAEL,EAAA,MAAM,YAAY,YAAY;AAC5B,IAAI,IAAA;AAEF,MAAA,MAAM,QAAgB,GAAA,MAAM,UAAW,CAAA,YAAA,CAAa,OAAO,CAAA;AAC3D,MAAM,MAAA,OAAA,GAAU,aAAa,IAAI,IAAA,GAAO,OAAQ,EAAA,GAAI,GAAO,IAAA,QAAA,IAAA,IAAA,GAAA,KAAA,CAAA,GAAA,QAAA,CAAU,gBAAmB,CAAA,GAAA,SAAA;AACxF,MAAA,OAAA,CAAQ,GAAI,CAAA;AAAA,QACV,SAAA;AAAA,QACA;AAAA,OACD,CAAA;AAKD,MAAA,IAAI,CAAC,QAAS,CAAA,MAAA,IAAA,CAAU,QAAU,IAAA,IAAA,GAAA,KAAA,CAAA,GAAA,QAAA,CAAA,IAAA,MAAS,KAAK,OAAS,EAAA;AACvD,QAAA,IAAI,mBAAmB,OAAS,EAAA;AAC9B,UAAA,SAAA,CAAU,IAAI,CAAA;AACd,UAAA,IAAI,OAAS,EAAA;AACX,YAAM,MAAA,UAAA,CAAW,YAAY,OAAS,EAAA;AAAA,cACpC,UAAY,EAAA;AAAA,aACb,CAAA;AAAA;AAGH,UAAA,SAAA,CAAU,IAAI,CAAA;AAGd,UAAA,IAAI,CAAC,GAAK,EAAA;AAER,YAAA,YAAA,CAAa,IAAI,CAAA;AACjB,YAAA;AAAA;AAEF,UAAI,IAAA,CAAC,qBAAqB,OAAS,EAAA;AACjC,YAAA,OAAA,CAAQ,IAAI,4BAA4B,CAAA;AACxC,YAAA,iBAAA,CAAkB,IAAI,CAAA;AACtB,YAAA,SAAA,CAAU,GAAG,CAAA;AACb,YAAA;AAAA;AAEF,UAAI,IAAA;AACF,YAAA,MAAM,QAAgB,GAAA,MAAM,oBAAqB,CAAA,OAAA,CAAQ,aAAc,EAAA;AAGvE,YAAA,IAAI,kBAAmB,CAAA,OAAA,IAAW,QAAY,IAAA,QAAA,CAAS,WAAW,GAAK,EAAA;AACrE,cAAA,SAAA,CAAU,GAAG,OAAU,CAAA,CAAA,CAAA,CAAA;AAAA,aAElB,MAAA;AACL,cAAQ,OAAA,CAAA,GAAA,CAAI,mCAAqC,EAAA,QAAA,IAAA,IAAA,GAAA,KAAA,CAAA,GAAA,QAAA,CAAU,MAAM,CAAA;AACjE,cAAA,OAAA,CAAQ,IAAI,8BAA8B,CAAA;AAC1C,cAAA,iBAAA,CAAkB,IAAI,CAAA;AACtB,cAAA,SAAA,CAAU,GAAG,CAAA;AACb,cAAA,UAAA,CAAW,YAAY,OAAS,EAAA;AAAA,gBAC9B,UAAY,EAAA;AAAA,eACb,CAAA;AAAA;AACH,mBACO,aAAP,EAAA;AACA,YAAQ,OAAA,CAAA,GAAA,CAAI,4BAA4B,aAAa,CAAA;AACrD,YAAA,OAAA,CAAQ,IAAI,8BAA8B,CAAA;AAC1C,YAAA,iBAAA,CAAkB,IAAI,CAAA;AACtB,YAAA,SAAA,CAAU,GAAG,CAAA;AAAA;AACf;AACF,OACK,MAAA;AAAA;AAEP,aACO,GAAP,EAAA;AACA,MAAA,OAAA,CAAQ,GAAI,CAAA;AAAA,QACV;AAAA,OACD,CAAA;AACD,MAAA,OAAA,CAAQ,IAAI,8BAA8B,CAAA;AAC1C,MAAA,iBAAA,CAAkB,IAAI,CAAA;AACtB,MAAA,SAAA,CAAU,GAAG,CAAA;AAAA;AACf,GACF;AAKA,EAAM,MAAA,kBAAA,mBAAsBC,cAAA,CAAA,aAAA,CAAA,IAAA,EAAA,EAAK,KAAO,EAAA;AAAA,IACtC,KAAO,EAAA,MAAA;AAAA,IACP,MAAQ,EAAA,MAAA;AAAA,IACR,eAAiB,EAAA,SAAA;AAAA,IACjB,cAAgB,EAAA,QAAA;AAAA,IAChB,UAAY,EAAA,QAAA;AAAA,IACZ,YAAc,EAAA;AAAA,GAEN,EAAA,kBAAAA,cAAA,CAAA,aAAA,CAAC,IAAK,EAAA,IAAA,EAAA,qBAAmB,CAC7B,CAAA;AACN,EAAA,IAAI,CAAC,MAAQ,EAAA;AACX,IAAA,OAAO,kBAAsB,IAAA,kBAAA;AAAA;AAE/B,EAAO,uBAAAA,cAAA,CAAA,aAAA;AAAA,IAAC,KAAA;AAAA,IAAA,aAAA,CAAA,cAAA,CAAA,EAAA,EAEJ,KAFI,CAAA,EAAA;AAAA,MAEG,MAAA,EAAQ,iCACd,MADc,CAAA,EAAA;AAAA,QAEjB,GAAA,EAAK,iBAAiB,GAAM,GAAA;AAAA,OAC9B,CAAA;AAAA,MAAG,SAAS,CAAK,CAAA,KAAA;AACf,QAAA,OAAA,CAAQ,GAAI,CAAA,sBAAA,EAAwB,CAAE,CAAA,WAAA,CAAY,KAAK,CAAA;AAGvD,QAAA,IAAI,cAAgB,EAAA;AAClB,UAAA,YAAA,CAAa,IAAI,CAAA;AACjB,UAAA,SAAA,CAAU,IAAI,CAAA;AAAA,SACT,MAAA;AACL,UAAA,OAAA,CAAQ,IAAI,4CAA4C,CAAA;AACxD,UAAA,iBAAA,CAAkB,IAAI,CAAA;AACtB,UAAA,SAAA,CAAU,GAAG,CAAA;AAAA;AACf;AACF,KAAA;AAAA,GAAG;AACL"}
|
|
@@ -1,54 +1,76 @@
|
|
|
1
|
-
import React__default
|
|
1
|
+
import React__default,{useMemo}from'react';import {Pressable,Box,VStack,Text,HStack,Avatar,AvatarFallbackText,AvatarImage,Link,LinkText,Button,ButtonText}from'@admin-layout/gluestack-ui-mobile';import {isToday,format}from'date-fns';import {startCase}from'lodash-es';import colors from'tailwindcss/colors';import {useSelector}from'react-redux';import {userSelector}from'@adminide-stack/user-auth0-client';const timeFormat = (value) => {
|
|
2
2
|
if (!value)
|
|
3
3
|
return "";
|
|
4
4
|
let date = new Date(value);
|
|
5
5
|
if (isToday(date))
|
|
6
|
-
return "
|
|
7
|
-
|
|
8
|
-
return "Yesterday";
|
|
9
|
-
return format(new Date(value), "MMM dd, yyyy");
|
|
6
|
+
return format(date, "h:mm a").toUpperCase();
|
|
7
|
+
return format(date, "MMM do").toUpperCase();
|
|
10
8
|
};
|
|
11
|
-
const ThreadViewItemComponent = function
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
9
|
+
const ThreadViewItemComponent = function ThreadViewItem2({
|
|
10
|
+
id,
|
|
11
|
+
post,
|
|
12
|
+
channel,
|
|
13
|
+
replies,
|
|
14
|
+
onPress,
|
|
15
|
+
channelId,
|
|
16
|
+
channelsDetail
|
|
17
17
|
}) {
|
|
18
|
-
var _a, _b;
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
}, [])
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
return null;
|
|
26
|
-
return thread == null ? void 0 : thread.replies;
|
|
27
|
-
}, [thread]);
|
|
28
|
-
if (!threadPostReply || (threadPostReply == null ? void 0 : threadPostReply.length) == 0) {
|
|
29
|
-
return /* @__PURE__ */ React__default.createElement(React__default.Fragment, null);
|
|
18
|
+
var _a, _b, _c, _d;
|
|
19
|
+
const currentUser = useSelector(userSelector);
|
|
20
|
+
const threadReplies = useMemo(() => {
|
|
21
|
+
return replies || [];
|
|
22
|
+
}, [replies]);
|
|
23
|
+
if (!threadReplies || threadReplies.length === 0) {
|
|
24
|
+
return null;
|
|
30
25
|
}
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
26
|
+
const lastReply = threadReplies[0];
|
|
27
|
+
const totalReplies = threadReplies.length;
|
|
28
|
+
const primaryUser = ((_a = channel == null ? void 0 : channel.users) == null ? void 0 : _a[0]) || (lastReply == null ? void 0 : lastReply.author);
|
|
29
|
+
(channel == null ? void 0 : channel.title) || `${(primaryUser == null ? void 0 : primaryUser.givenName) || ""} ${(primaryUser == null ? void 0 : primaryUser.familyName) || ""}`;
|
|
30
|
+
(_b = channel == null ? void 0 : channel.users) == null ? void 0 : _b.some((user) => user.id === (currentUser == null ? void 0 : currentUser.id));
|
|
31
|
+
return /* @__PURE__ */ React__default.createElement(Pressable, { onPress: () => onPress(channel == null ? void 0 : channel.id, "Thread", post == null ? void 0 : post.id), style: {
|
|
32
|
+
marginVertical: 5,
|
|
33
|
+
backgroundColor: "white",
|
|
34
|
+
borderRadius: 10,
|
|
35
|
+
paddingVertical: 5,
|
|
36
|
+
elevation: 1,
|
|
37
|
+
shadowColor: "#000",
|
|
38
|
+
shadowOffset: {
|
|
39
|
+
width: 0,
|
|
40
|
+
height: 1
|
|
41
|
+
},
|
|
42
|
+
shadowOpacity: 0.1,
|
|
43
|
+
shadowRadius: 2
|
|
44
|
+
} }, /* @__PURE__ */ React__default.createElement(Box, { className: "mb-3" }, /* @__PURE__ */ React__default.createElement(VStack, { space: "md" }, /* @__PURE__ */ React__default.createElement(Text, { className: "text-sm font-medium text-gray-600 px-4 pt-2" }, (_d = (_c = channel == null ? void 0 : channel.users) == null ? void 0 : _c.map((user) => (user == null ? void 0 : user.givenName) || (user == null ? void 0 : user.username))) == null ? void 0 : _d.join(", ")), threadReplies.slice(0, 3).map((reply, index) => {
|
|
45
|
+
var _a2, _b2, _c2, _d2, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n;
|
|
46
|
+
const previousReply = index > 0 ? threadReplies.slice(0, 3)[index - 1] : null;
|
|
47
|
+
const isConsecutiveReply = previousReply && ((_a2 = previousReply.author) == null ? void 0 : _a2.id) === ((_b2 = reply.author) == null ? void 0 : _b2.id);
|
|
48
|
+
return /* @__PURE__ */ React__default.createElement(HStack, { key: reply.id || index, space: "md", className: "px-4 py-1" }, !isConsecutiveReply ? /* @__PURE__ */ React__default.createElement(Avatar, { size: "md", style: {
|
|
49
|
+
width: 40,
|
|
50
|
+
height: 40,
|
|
51
|
+
backgroundColor: ((_c2 = reply == null ? void 0 : reply.author) == null ? void 0 : _c2.id) === (currentUser == null ? void 0 : currentUser.id) ? "#2EB67D" : "#E8A54A"
|
|
52
|
+
} }, /* @__PURE__ */ React__default.createElement(AvatarFallbackText, null, startCase(((_e = (_d2 = reply == null ? void 0 : reply.author) == null ? void 0 : _d2.username) == null ? void 0 : _e.charAt(0)) || "U")), ((_f = reply == null ? void 0 : reply.author) == null ? void 0 : _f.picture) && /* @__PURE__ */ React__default.createElement(AvatarImage, { alt: ((_g = reply == null ? void 0 : reply.author) == null ? void 0 : _g.username) || "User", source: {
|
|
53
|
+
uri: (_h = reply == null ? void 0 : reply.author) == null ? void 0 : _h.picture
|
|
54
|
+
} })) : /* @__PURE__ */ React__default.createElement(Box, { style: {
|
|
55
|
+
width: 40
|
|
56
|
+
} }), /* @__PURE__ */ React__default.createElement(VStack, { space: "xs", className: "flex-1" }, !isConsecutiveReply && /* @__PURE__ */ React__default.createElement(HStack, { space: "sm", className: "items-center" }, /* @__PURE__ */ React__default.createElement(Text, { className: "font-bold text-gray-900" }, ((_i = reply == null ? void 0 : reply.author) == null ? void 0 : _i.givenName) || ((_j = reply == null ? void 0 : reply.author) == null ? void 0 : _j.username) || "User"), /* @__PURE__ */ React__default.createElement(Text, { className: "text-xs text-gray-500" }, timeFormat(reply == null ? void 0 : reply.createdAt))), (reply == null ? void 0 : reply.message) && /* @__PURE__ */ React__default.createElement(Text, { color: colors.gray[700], numberOfLines: 2, className: "text-base" }, reply == null ? void 0 : reply.message, (reply == null ? void 0 : reply.edited) && /* @__PURE__ */ React__default.createElement(Text, { className: "text-xs text-gray-500" }, " (edited)")), reply.email && /* @__PURE__ */ React__default.createElement(Text, { className: "text-blue-500" }, reply.email), ((_l = (_k = reply == null ? void 0 : reply.files) == null ? void 0 : _k.data) == null ? void 0 : _l.length) > 0 && /* @__PURE__ */ React__default.createElement(HStack, { space: "sm", className: "my-1" }, (_n = (_m = reply == null ? void 0 : reply.files) == null ? void 0 : _m.data) == null ? void 0 : _n.map((file, fileIndex) => /* @__PURE__ */ React__default.createElement(Box, { key: fileIndex, className: "overflow-hidden", style: {
|
|
57
|
+
width: 80,
|
|
58
|
+
height: 80
|
|
59
|
+
} }, /* @__PURE__ */ React__default.createElement(AvatarImage, { alt: "attachment", className: "rounded-none border-none", style: {
|
|
60
|
+
width: "100%",
|
|
61
|
+
height: "100%"
|
|
37
62
|
}, source: {
|
|
38
|
-
uri:
|
|
39
|
-
} })))
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
color: "#000"
|
|
51
|
-
} }, "Reply"))));
|
|
52
|
-
})))))));
|
|
63
|
+
uri: file == null ? void 0 : file.url
|
|
64
|
+
} }))))));
|
|
65
|
+
}), totalReplies > 3 && /* @__PURE__ */ React__default.createElement(HStack, { className: "px-4 items-center", space: "sm" }, /* @__PURE__ */ React__default.createElement(Box, { style: {
|
|
66
|
+
width: 40
|
|
67
|
+
} }), /* @__PURE__ */ React__default.createElement(Link, { onPress: () => onPress(channel == null ? void 0 : channel.id, "Thread", post == null ? void 0 : post.id) }, /* @__PURE__ */ React__default.createElement(LinkText, { className: "text-blue-600 mt-1" }, totalReplies - 3, " more ", totalReplies - 3 === 1 ? "reply" : "replies"))), /* @__PURE__ */ React__default.createElement(Box, { className: "px-4 pb-2" }, /* @__PURE__ */ React__default.createElement(Button, { size: "sm", className: "self-start rounded-full", variant: "outline", style: {
|
|
68
|
+
borderColor: "#E2E8F0",
|
|
69
|
+
paddingHorizontal: 16,
|
|
70
|
+
paddingVertical: 6
|
|
71
|
+
}, onPress: () => onPress(channel == null ? void 0 : channel.id, "Thread", post == null ? void 0 : post.id) }, /* @__PURE__ */ React__default.createElement(ButtonText, { style: {
|
|
72
|
+
fontSize: 14,
|
|
73
|
+
color: colors.gray[800]
|
|
74
|
+
} }, "Reply"))))));
|
|
53
75
|
};
|
|
54
76
|
const ThreadViewItem = React__default.memo(ThreadViewItemComponent);export{ThreadViewItem,ThreadViewItemComponent};//# sourceMappingURL=ThreadsViewItem.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ThreadsViewItem.js","sources":["../../../../src/screens/inbox/components/ThreadsViewItem.tsx"],"sourcesContent":["import React, { useMemo } from 'react';\nimport {\n VStack,\n Text,\n Image,\n Pressable,\n HStack,\n Box,\n AvatarGroup,\n Avatar,\n AvatarFallbackText,\n AvatarImage,\n AvatarBadge,\n View,\n Button,\n ButtonText,\n} from '@admin-layout/gluestack-ui-mobile';\nimport { format, isToday, isYesterday } from 'date-fns';\nimport { useFocusEffect } from '@react-navigation/native';\nimport { IChannel, IUserAccount } from 'common';\nimport {\n useThreadMessagesQuery,\n useMessagesQuery,\n useUserAccountQuery,\n useOnThreadChatMessageAddedSubscription,\n useOnThreadCreatedUpdatedSubscription,\n} from 'common/graphql';\nimport { startCase } from 'lodash-es';\nimport colors from 'tailwindcss/colors';\n\nconst createdAtText = (value: string) => {\n if (!value) return '';\n let date = new Date(value);\n if (isToday(date)) return 'Today';\n if (isYesterday(date)) return 'Yesterday';\n return format(new Date(value), 'MMM dd, yyyy');\n};\n\nexport interface IDialogListChannel extends IChannel {\n users: IUserAccount[];\n}\n\nexport interface IDialogListItemProps {\n currentUser?: any;\n users?: any;\n thread?: any;\n onOpen: (id: any, title: any, postParentId?: any) => void;\n role?: any;\n setData?: any;\n}\n\n/**\n * TODO:\n * - Get Reservation info: reservation date, status\n * - Add ability to get property information: name, logo\n */\nexport const ThreadViewItemComponent: React.FC<IDialogListItemProps> = function DialogsListItem({\n currentUser,\n // users,\n thread,\n onOpen,\n role,\n setData,\n}) {\n // const { data: threadCreatedUpdated } = useOnThreadCreatedUpdatedSubscription({\n // variables: {\n // channelId: thread?.channel?.id?.toString(),\n // postParentId: thread?.post?.id?.toString(),\n // },\n // });\n\n useFocusEffect(\n React.useCallback(() => {\n // Do something when the screen is focused\n return () => {\n // Do something when the screen is unfocused\n // Useful for cleanup functions\n };\n }, []),\n );\n\n const threadPostReply = React.useMemo(() => {\n if (!thread?.replies) return null;\n return thread?.replies;\n }, [thread]);\n\n // React.useEffect(() => {\n // if (threadCreatedUpdated?.threadCreatedUpdated?.data) setData(threadCreatedUpdated?.threadCreatedUpdated?.data);\n // }, [threadCreatedUpdated?.threadCreatedUpdated]);\n\n // const threadPostReply = React.useMemo(() => {\n // if (!thread?.replies) return null;\n // if (threadCreatedUpdated?.threadCreatedUpdated?.data?.replies?.length) {\n // return threadCreatedUpdated?.threadCreatedUpdated?.data?.replies;\n // } else return thread?.replies;\n // }, [thread, threadCreatedUpdated]);\n\n // const lastMessage = useMemo(() => {\n // if (!threadPost) {\n // return null;\n // }\n // const replies = threadPost?.replies?.filter((p: any) => p?.message !== '') ?? [];\n // if (replies?.length) {\n // return replies[0];\n // // return replies[replies.length - 1];\n // } else {\n // const post = threadPost?.post ?? null;\n // return post ? post?.post : null;\n // }\n // }, [threadPost]);\n\n // const participants: any = React.useMemo(() => {\n // if (!thread?.participants?.length) return null;\n // return thread?.participants?.filter((u: any) => u?.user?.id !== currentUser?.id) ?? [];\n // }, [thread]);\n\n // const allParticipantsNames: any = React.useMemo(() => {\n // if (!participants?.length) return null;\n // return (\n // participants\n // ?.map((p: any) => {\n // return p?.user?.givenName + ' ' + p?.user?.familyName ?? '';\n // })\n // ?.join(', ') ?? ''\n // );\n // }, [participants]);\n\n if (!threadPostReply || threadPostReply?.length == 0) {\n return <></>;\n }\n\n return (\n <VStack\n space={'sm'}\n className=\"flex-1 py-2 px-2 border rounded-md bg-white border-gray-200 dark:border-white dark:bg-white\"\n >\n <HStack space={'sm'} className=\"py-2 w-[100%] flex-1 justify-between items-center\">\n <Box className=\"flex-1\">\n {/* <HStack flex={1} space={5} py={2} alignItems={'baseline'}>\n <Box>\n <Avatar.Badge size={4} left={0} zIndex={1} bg=\"green.800\" />\n </Box>\n <Box>\n <Text color=\"gray.600\" fontSize=\"lg\" flexWrap={'wrap'} fontWeight=\"semibold\">\n {allParticipantsNames || ''}\n </Text>\n </Box>\n </HStack> */}\n <HStack space={'sm'} className=\"flex-1 justify-center items-center\">\n <Box className=\"flex-1\">\n {/* <HStack space={2} py={2}>\n <Box>\n <Avatar\n bg={'transparent'}\n size={8}\n _image={{ borderRadius: 6, borderWidth: 2, borderColor: '#fff' }}\n source={{\n uri: thread?.post?.author?.picture,\n }}\n >\n {startCase(thread?.post?.author?.username?.charAt(0))}\n </Avatar>\n </Box>\n <Box>\n <HStack space={4}>\n <Text>\n {thread?.post?.author?.givenName + ' ' + thread?.post?.author?.familyName ??\n ''}\n </Text>\n <Text color=\"gray.500\">\n {thread?.post ? createdAtText(thread?.post?.createdAt) : ''}\n </Text>\n </HStack>\n <Text color=\"gray.600\" noOfLines={2}>\n {thread?.post?.message ?? ''}\n </Text>\n {!thread?.replies?.length && (\n <Button\n size={'xs'}\n w={150}\n variant={'outline'}\n _text={{ fontSize: 12, color: '#000' }}\n onPress={() =>\n onOpen(thread?.channel?.id, thread?.channel?.title, thread?.post?.id)\n }\n >\n Reply\n </Button>\n )}\n </Box>\n </HStack> */}\n {threadPostReply?.length > 0 && (\n <>\n {threadPostReply\n ?.slice(0, 2)\n ?.reverse()\n ?.map((reply: any, index: any) => (\n <HStack key={index} space={'sm'} className=\"pb-2 pt-1\">\n <Box>\n <Avatar\n key={'thread-view-key-' + index}\n size={'md'}\n className=\"bg-transparent top-0 right-0 z-[1]\"\n >\n <AvatarFallbackText>\n {' '}\n {startCase(reply?.author?.username?.charAt(0))}\n </AvatarFallbackText>\n <AvatarImage\n alt=\"image\"\n style={{\n borderRadius: 6,\n borderWidth: 2,\n borderColor: '#fff',\n }}\n source={{\n uri: reply?.author?.picture,\n }}\n />\n </Avatar>\n </Box>\n <Box>\n <HStack space={'md'}>\n <Text>\n {reply?.author?.givenName ?? '' ?? ''}{' '}\n {reply?.author?.familyName ?? '' ?? ''}\n {/* {lastMessage?.author?.givenName +\n ' ' +\n lastMessage?.author?.familyName ?? ''} */}\n </Text>\n <Text color={colors.gray[500]}>\n {reply?.createdAt ? createdAtText(reply?.createdAt) : ''}\n {/* {lastMessage ? createdAtText(lastMessage?.createdAt) : ''} */}\n </Text>\n </HStack>\n <VStack space={'sm'}>\n {reply?.message && (\n <Text color={colors.gray[600]} numberOfLines={2}>\n {reply?.message.length < 70\n ? `${reply?.message}`\n : `${reply?.message.substring(0, 68)}....`}\n </Text>\n )}\n {/* <Text color=\"gray.600\" noOfLines={2}>\n {reply?.message\n ? reply?.message.length < 70\n ? `${reply?.message}`\n : `${reply?.message.substring(0, 68)}....`\n : ''}\n </Text> */}\n\n <>\n {reply?.files?.data?.length > 0 &&\n reply?.files?.data?.map((f: any, index: any) => (\n <Box>\n <Avatar\n key={'thread-view-other-key-' + index}\n className=\"bg-transparent\"\n size={'md'}\n >\n <AvatarFallbackText> I</AvatarFallbackText>\n <AvatarImage\n alt=\"image\"\n style={{\n borderRadius: 6,\n borderWidth: 2,\n borderColor: '#fff',\n }}\n source={{\n uri: f?.url,\n }}\n />\n </Avatar>\n </Box>\n ))}\n </>\n </VStack>\n\n {(threadPostReply?.length == 1 || index !== 0) && (\n <Button\n size={'xs'}\n className=\"w-[150]\"\n variant={'outline'}\n onPress={() =>\n onOpen(\n thread?.channel?.id,\n thread?.channel?.title,\n thread?.post?.id,\n )\n }\n >\n <ButtonText style={{ fontSize: 12, color: '#000' }}>\n Reply\n </ButtonText>\n </Button>\n )}\n </Box>\n </HStack>\n ))}\n </>\n )}\n </Box>\n </HStack>\n </Box>\n </HStack>\n {/* <HStack>\n <Box flex={0.06} alignItems={'flex-start'}></Box>\n <Button\n size={'xs'}\n variant={'outline'}\n _text={{ fontSize: 12, color: '#000' }}\n onPress={() => onOpen(thread?.channel?.id, thread?.channel?.title, postParentId)}\n >\n Reply\n </Button>\n </HStack> */}\n </VStack>\n );\n};\n\nexport const ThreadViewItem = React.memo(ThreadViewItemComponent);\n"],"names":["React","_a","_b","index","_c"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ThreadsViewItem.js","sources":["../../../../src/screens/inbox/components/ThreadsViewItem.tsx"],"sourcesContent":["import React, { useMemo } from 'react';\nimport {\n VStack,\n Text,\n Pressable,\n HStack,\n Box,\n Avatar,\n AvatarFallbackText,\n AvatarImage,\n Button,\n ButtonText,\n Icon,\n Badge,\n BadgeText,\n Link,\n LinkText,\n} from '@admin-layout/gluestack-ui-mobile';\nimport { format, isToday, isYesterday } from 'date-fns';\nimport { useFocusEffect } from '@react-navigation/native';\nimport { IChannel, IUserAccount } from 'common';\nimport { startCase } from 'lodash-es';\nimport colors from 'tailwindcss/colors';\nimport { useSelector } from 'react-redux';\nimport { userSelector } from '@adminide-stack/user-auth0-client';\n\nconst timeFormat = (value: string) => {\n if (!value) return '';\n let date = new Date(value);\n if (isToday(date)) return format(date, 'h:mm a').toUpperCase();\n return format(date, 'MMM do').toUpperCase();\n};\n\nexport interface IDialogListChannel extends IChannel {\n users: IUserAccount[];\n}\n\nexport interface ThreadViewItemProps {\n id: string;\n post: any;\n channel: any;\n replies: any[];\n onPress: (id: any, title: any, postParentId?: any) => void;\n channelId?: string;\n channelsDetail?: any;\n}\n\n/**\n * TODO:\n * - Get Reservation info: reservation date, status\n * - Add ability to get property information: name, logo\n */\nexport const ThreadViewItemComponent: React.FC<ThreadViewItemProps> = function ThreadViewItem({\n id,\n post,\n channel,\n replies,\n onPress,\n channelId,\n channelsDetail,\n}) {\n const currentUser = useSelector(userSelector);\n\n // Prepare thread replies for display\n const threadReplies = useMemo(() => {\n return replies || [];\n }, [replies]);\n\n if (!threadReplies || threadReplies.length === 0) {\n return null;\n }\n\n // Get the last reply for the thread preview\n const lastReply = threadReplies[0]; // Most recent reply should be first in the array\n // Get total number of replies\n const totalReplies = threadReplies.length;\n\n // Get the first user in the thread as the primary user\n const primaryUser = channel?.users?.[0] || lastReply?.author;\n const channelName = channel?.title || `${primaryUser?.givenName || ''} ${primaryUser?.familyName || ''}`;\n\n // Determine if the current user is in the thread\n const userIsInThread = channel?.users?.some((user: any) => user.id === currentUser?.id);\n\n return (\n <Pressable\n onPress={() => onPress(channel?.id, 'Thread', post?.id)}\n style={{\n marginVertical: 5,\n backgroundColor: 'white',\n borderRadius: 10,\n paddingVertical: 5,\n elevation: 1,\n shadowColor: '#000',\n shadowOffset: { width: 0, height: 1 },\n shadowOpacity: 0.1,\n shadowRadius: 2,\n }}\n >\n <Box className=\"mb-3\">\n <VStack space=\"md\">\n {/* Thread header with green dot and users */}\n {/* <HStack space=\"sm\" className=\"px-4 items-center\">\n <Box \n className=\"bg-green-500 rounded-full\" \n style={{ width: 8, height: 8 }}\n />\n <Text className=\"text-base text-gray-900\">{channelName}</Text>\n </HStack> */}\n\n {/* Thread members */}\n <Text className=\"text-sm font-medium text-gray-600 px-4 pt-2\">\n {channel?.users?.map((user: any) => user?.givenName || user?.username)?.join(', ')}\n </Text>\n\n {/* Thread messages preview - show up to 3 most recent messages */}\n {threadReplies.slice(0, 3).map((reply: any, index: number) => {\n // Group consecutive messages from the same user\n const previousReply = index > 0 ? threadReplies.slice(0, 3)[index - 1] : null;\n const isConsecutiveReply = previousReply && previousReply.author?.id === reply.author?.id;\n\n return (\n <HStack key={reply.id || index} space=\"md\" className=\"px-4 py-1\">\n {!isConsecutiveReply ? (\n <Avatar\n size=\"md\"\n style={{\n width: 40,\n height: 40,\n backgroundColor:\n reply?.author?.id === currentUser?.id ? '#2EB67D' : '#E8A54A',\n }}\n >\n <AvatarFallbackText>\n {startCase(reply?.author?.username?.charAt(0) || 'U')}\n </AvatarFallbackText>\n {reply?.author?.picture && (\n <AvatarImage\n alt={reply?.author?.username || 'User'}\n source={{\n uri: reply?.author?.picture,\n }}\n />\n )}\n </Avatar>\n ) : (\n <Box style={{ width: 40 }} />\n )}\n\n <VStack space=\"xs\" className=\"flex-1\">\n {!isConsecutiveReply && (\n <HStack space=\"sm\" className=\"items-center\">\n <Text className=\"font-bold text-gray-900\">\n {reply?.author?.givenName || reply?.author?.username || 'User'}\n </Text>\n <Text className=\"text-xs text-gray-500\">\n {timeFormat(reply?.createdAt)}\n </Text>\n </HStack>\n )}\n\n {reply?.message && (\n <Text color={colors.gray[700]} numberOfLines={2} className=\"text-base\">\n {reply?.message}\n {reply?.edited && <Text className=\"text-xs text-gray-500\"> (edited)</Text>}\n </Text>\n )}\n\n {reply.email && <Text className=\"text-blue-500\">{reply.email}</Text>}\n\n {reply?.files?.data?.length > 0 && (\n <HStack space=\"sm\" className=\"my-1\">\n {reply?.files?.data?.map((file: any, fileIndex: number) => (\n <Box\n key={fileIndex}\n className=\"overflow-hidden\"\n style={{ width: 80, height: 80 }}\n >\n <AvatarImage\n alt=\"attachment\"\n className=\"rounded-none border-none\"\n style={{\n width: '100%',\n height: '100%',\n }}\n source={{\n uri: file?.url,\n }}\n />\n </Box>\n ))}\n </HStack>\n )}\n </VStack>\n </HStack>\n );\n })}\n\n {/* Show more replies indicator */}\n {totalReplies > 3 && (\n <HStack className=\"px-4 items-center\" space=\"sm\">\n <Box style={{ width: 40 }} />\n <Link onPress={() => onPress(channel?.id, 'Thread', post?.id)}>\n <LinkText className=\"text-blue-600 mt-1\">\n {totalReplies - 3} more {totalReplies - 3 === 1 ? 'reply' : 'replies'}\n </LinkText>\n </Link>\n </HStack>\n )}\n\n {/* Reply button */}\n <Box className=\"px-4 pb-2\">\n <Button\n size=\"sm\"\n className=\"self-start rounded-full\"\n variant=\"outline\"\n style={{\n borderColor: '#E2E8F0',\n paddingHorizontal: 16,\n paddingVertical: 6,\n }}\n onPress={() => onPress(channel?.id, 'Thread', post?.id)}\n >\n <ButtonText style={{ fontSize: 14, color: colors.gray[800] }}>Reply</ButtonText>\n </Button>\n </Box>\n </VStack>\n </Box>\n </Pressable>\n );\n};\n\nexport const ThreadViewItem = React.memo(ThreadViewItemComponent);\n"],"names":["ThreadViewItem","React","_a","_b","_c","_d"],"mappings":"oZASA,MAAM,UAAA,GAAa,CAAC,KAAkB,KAAA;AACpC,EAAA,IAAI,CAAC,KAAA;AAAO,IAAO,OAAA,EAAA;AACnB,EAAI,IAAA,IAAA,GAAO,IAAI,IAAA,CAAK,KAAK,CAAA;AACzB,EAAA,IAAI,QAAQ,IAAI,CAAA;AAAG,IAAA,OAAO,MAAO,CAAA,IAAA,EAAM,QAAQ,CAAA,CAAE,WAAY,EAAA;AAC7D,EAAA,OAAO,MAAO,CAAA,IAAA,EAAM,QAAQ,CAAA,CAAE,WAAY,EAAA;AAC5C,CAAA;AAmBa,MAAA,uBAAA,GAAyD,SAASA,eAAe,CAAA;AAAA,EAC5F,EAAA;AAAA,EACA,IAAA;AAAA,EACA,OAAA;AAAA,EACA,OAAA;AAAA,EACA,OAAA;AAAA,EACA,SAAA;AAAA,EACA;AACF,CAAG,EAAA;AAzCH,EAAA,IAAA,EAAA,EAAA,EAAA,EAAA,EAAA,EAAA,EAAA;AA0CE,EAAM,MAAA,WAAA,GAAc,YAAY,YAAY,CAAA;AAG5C,EAAM,MAAA,aAAA,GAAgB,QAAQ,MAAM;AAClC,IAAA,OAAO,WAAW,EAAC;AAAA,GACrB,EAAG,CAAC,OAAO,CAAC,CAAA;AACZ,EAAA,IAAI,CAAC,aAAA,IAAiB,aAAc,CAAA,MAAA,KAAW,CAAG,EAAA;AAChD,IAAO,OAAA,IAAA;AAAA;AAIT,EAAA,MAAM,YAAY,aAAc,CAAA,CAAA,CAAA;AAEhC,EAAA,MAAM,eAAe,aAAc,CAAA,MAAA;AAGnC,EAAA,MAAM,WAAc,GAAA,CAAA,CAAA,EAAA,GAAA,OAAA,IAAA,IAAA,GAAA,MAAA,GAAA,OAAA,CAAS,KAAT,KAAA,IAAA,GAAA,MAAA,GAAA,EAAA,CAAiB,QAAM,SAAW,IAAA,IAAA,GAAA,MAAA,GAAA,SAAA,CAAA,MAAA,CAAA;AACtD,EAAM,CAAc,mCAAS,KAAS,KAAA,CAAA,EAAA,CAAG,2CAAa,SAAa,KAAA,EAAA,CAAA,CAAA,EAAA,CAAM,2CAAa,UAAc,KAAA,EAAA,CAAA;AAGpG,EAAM,CAAiB,wCAAS,KAAT,KAAA,IAAA,GAAA,MAAA,GAAA,EAAA,CAAgB,KAAK,CAAC,IAAA,KAAc,IAAK,CAAA,EAAA,MAAO,WAAa,IAAA,IAAA,GAAA,MAAA,GAAA,WAAA,CAAA,EAAA,CAAA;AACpF,EAAO,uBAAAC,cAAA,CAAA,aAAA,CAAC,SAAU,EAAA,EAAA,OAAA,EAAS,MAAM,OAAA,CAAQ,OAAS,IAAA,IAAA,GAAA,MAAA,GAAA,OAAA,CAAA,EAAA,EAAI,QAAU,EAAA,IAAA,IAAA,IAAA,GAAA,MAAA,GAAA,IAAA,CAAM,EAAE,CAAA,EAAG,KAAO,EAAA;AAAA,IAChF,cAAgB,EAAA,CAAA;AAAA,IAChB,eAAiB,EAAA,OAAA;AAAA,IACjB,YAAc,EAAA,EAAA;AAAA,IACd,eAAiB,EAAA,CAAA;AAAA,IACjB,SAAW,EAAA,CAAA;AAAA,IACX,WAAa,EAAA,MAAA;AAAA,IACb,YAAc,EAAA;AAAA,MACZ,KAAO,EAAA,CAAA;AAAA,MACP,MAAQ,EAAA;AAAA,KACV;AAAA,IACA,aAAe,EAAA,GAAA;AAAA,IACf,YAAc,EAAA;AAAA,GAEN,EAAA,kBAAAA,cAAA,CAAA,aAAA,CAAC,GAAI,EAAA,EAAA,SAAA,EAAU,0BACVA,cAAA,CAAA,aAAA,CAAA,MAAA,EAAA,EAAO,KAAM,EAAA,IAAA,EAAA,+CAWT,IAAK,EAAA,EAAA,SAAA,EAAU,6CACX,EAAA,EAAA,CAAA,EAAA,GAAA,CAAA,EAAA,GAAA,OAAA,IAAA,IAAA,GAAA,MAAA,GAAA,OAAA,CAAS,UAAT,IAAgB,GAAA,MAAA,GAAA,EAAA,CAAA,GAAA,CAAI,CAAC,IAAA,KAAA,CAAc,6BAAM,SAAa,MAAA,IAAA,IAAA,IAAA,GAAA,MAAA,GAAA,IAAA,CAAM,QAA5D,CAAA,CAAA,KAAA,IAAA,GAAA,MAAA,GAAA,EAAA,CAAuE,KAAK,IACjF,CAAA,CAAA,EAGC,aAAc,CAAA,KAAA,CAAM,GAAG,CAAC,CAAA,CAAE,GAAI,CAAA,CAAC,OAAY,KAAkB,KAAA;AA9FlF,IAAAC,IAAAA,GAAAA,EAAAC,GAAAC,EAAAA,GAAAA,EAAAC,GAAA,EAAA,EAAA,EAAA,EAAA,EAAA,EAAA,EAAA,EAAA,EAAA,EAAA,EAAA,EAAA,EAAA,EAAA,EAAA,EAAA,EAAA,EAAA,EAAA,EAAA;AAgGU,IAAM,MAAA,aAAA,GAAgB,QAAQ,CAAI,GAAA,aAAA,CAAc,MAAM,CAAG,EAAA,CAAC,CAAE,CAAA,KAAA,GAAQ,CAAK,CAAA,GAAA,IAAA;AACzE,IAAA,MAAM,kBAAqB,GAAA,aAAA,IAAA,CAAA,CAAiBH,GAAA,GAAA,aAAA,CAAc,MAAd,KAAA,IAAA,GAAA,MAAA,GAAAA,GAAsB,CAAA,EAAA,OAAA,CAAOC,GAAA,GAAA,KAAA,CAAM,MAAN,KAAA,IAAA,GAAA,MAAA,GAAAA,GAAc,CAAA,EAAA,CAAA;AACvF,IAAA,oDAAQ,MAAO,EAAA,EAAA,GAAA,EAAK,KAAM,CAAA,EAAA,IAAM,OAAO,KAAM,EAAA,IAAA,EAAK,SAAU,EAAA,WAAA,EAAA,EACrC,CAAC,kBAAqB,mBAAAF,cAAA,CAAA,aAAA,CAAC,MAAO,EAAA,EAAA,IAAA,EAAK,MAAK,KAAO,EAAA;AAAA,MAClE,KAAO,EAAA,EAAA;AAAA,MACP,MAAQ,EAAA,EAAA;AAAA,MACR,eAAA,EAAA,CAAA,CAAiBG,MAAA,KAAO,IAAA,IAAA,GAAA,MAAA,GAAA,KAAA,CAAA,MAAA,KAAP,gBAAAA,GAAe,CAAA,EAAA,OAAO,WAAa,IAAA,IAAA,GAAA,MAAA,GAAA,WAAA,CAAA,EAAA,CAAA,GAAK,SAAY,GAAA;AAAA,KAE3C,EAAA,kBAAAH,cAAA,CAAA,aAAA,CAAC,kBACI,EAAA,IAAA,EAAA,SAAA,CAAA,CAAA,CAAU,EAAAI,GAAAA,CAAAA,GAAAA,GAAA,KAAO,IAAA,IAAA,GAAA,MAAA,GAAA,KAAA,CAAA,MAAA,KAAP,IAAAA,GAAAA,MAAAA,GAAAA,GAAAA,CAAe,QAAf,KAAA,IAAA,GAAA,MAAA,GAAA,EAAA,CAAyB,MAAO,CAAA,CAAA,CAAA,KAAM,GAAG,CACxD,CACC,EAAA,CAAA,CAAA,EAAA,GAAA,KAAA,IAAA,IAAA,GAAA,MAAA,GAAA,KAAA,CAAO,MAAP,KAAA,IAAA,GAAA,MAAA,GAAA,EAAA,CAAe,OAAW,qBAAAJ,cAAA,CAAA,aAAA,CAAC,WAAY,EAAA,EAAA,GAAA,EAAA,CAAA,CAAK,EAAO,GAAA,KAAA,IAAA,IAAA,GAAA,MAAA,GAAA,KAAA,CAAA,MAAA,KAAP,IAAe,GAAA,MAAA,GAAA,EAAA,CAAA,QAAA,KAAY,QAAQ,MAAQ,EAAA;AAAA,MAChH,GAAA,EAAA,CAAK,EAAO,GAAA,KAAA,IAAA,IAAA,GAAA,MAAA,GAAA,KAAA,CAAA,MAAA,KAAP,IAAe,GAAA,MAAA,GAAA,EAAA,CAAA;AAAA,KACnB,EAAA,CACmB,CAAY,mBAAAA,cAAA,CAAA,aAAA,CAAC,OAAI,KAAO,EAAA;AAAA,MAC9C,KAAO,EAAA;AAAA,KACT,EAAG,mBAEkBA,cAAA,CAAA,aAAA,CAAA,MAAA,EAAA,EAAO,OAAM,IAAK,EAAA,SAAA,EAAU,QACxB,EAAA,EAAA,CAAC,kBAAsB,oBAAAA,cAAA,CAAA,aAAA,CAAC,UAAO,KAAM,EAAA,IAAA,EAAK,WAAU,cAC7C,EAAA,kBAAAA,cAAA,CAAA,aAAA,CAAC,QAAK,SAAU,EAAA,yBAAA,EAAA,EAAA,CAAA,CACX,EAAO,GAAA,KAAA,IAAA,IAAA,GAAA,MAAA,GAAA,KAAA,CAAA,MAAA,KAAP,IAAe,GAAA,MAAA,GAAA,EAAA,CAAA,SAAA,MAAA,CAAa,oCAAO,MAAP,KAAA,IAAA,GAAA,MAAA,GAAA,EAAA,CAAe,aAAY,MAC5D,CAAA,+CACC,IAAK,EAAA,EAAA,SAAA,EAAU,uBACX,EAAA,EAAA,UAAA,CAAW,KAAO,IAAA,IAAA,GAAA,MAAA,GAAA,KAAA,CAAA,SAAS,CAChC,CACJ,CAAA,EAAA,CAEH,+BAAO,OAAW,qBAAAA,cAAA,CAAA,aAAA,CAAC,QAAK,KAAO,EAAA,MAAA,CAAO,IAAK,CAAA,GAAA,CAAA,EAAM,aAAe,EAAA,CAAA,EAAG,WAAU,WACrE,EAAA,EAAA,KAAA,IAAA,IAAA,GAAA,MAAA,GAAA,KAAA,CAAO,UACP,KAAO,IAAA,IAAA,GAAA,MAAA,GAAA,KAAA,CAAA,MAAA,kDAAW,IAAK,EAAA,EAAA,SAAA,EAAU,uBAAwB,EAAA,EAAA,WAAS,CACvE,CAAA,EAEH,MAAM,KAAS,oBAAAA,cAAA,CAAA,aAAA,CAAC,QAAK,SAAU,EAAA,eAAA,EAAA,EAAiB,MAAM,KAAM,CAAA,EAAA,CAAA,CAE5D,EAAO,GAAA,CAAA,EAAA,GAAA,KAAA,IAAA,IAAA,GAAA,MAAA,GAAA,KAAA,CAAA,KAAA,KAAP,IAAc,GAAA,MAAA,GAAA,EAAA,CAAA,IAAA,KAAd,mBAAoB,MAAS,IAAA,CAAA,iDAAM,MAAO,EAAA,EAAA,KAAA,EAAM,MAAK,SAAU,EAAA,MAAA,EAAA,EAAA,CACvD,EAAO,GAAA,CAAA,EAAA,GAAA,KAAA,IAAA,IAAA,GAAA,MAAA,GAAA,KAAA,CAAA,KAAA,KAAP,IAAc,GAAA,MAAA,GAAA,EAAA,CAAA,IAAA,KAAd,mBAAoB,GAAI,CAAA,CAAC,MAAW,SAAsB,qBAAAA,cAAA,CAAA,aAAA,CAAC,OAAI,GAAK,EAAA,SAAA,EAAW,SAAU,EAAA,iBAAA,EAAkB,KAAO,EAAA;AAAA,MAC7I,KAAO,EAAA,EAAA;AAAA,MACP,MAAQ,EAAA;AAAA,yBAE2BA,cAAA,CAAA,aAAA,CAAA,WAAA,EAAA,EAAY,KAAI,YAAa,EAAA,SAAA,EAAU,4BAA2B,KAAO,EAAA;AAAA,MAC1G,KAAO,EAAA,MAAA;AAAA,MACP,MAAQ,EAAA;AAAA,OACP,MAAQ,EAAA;AAAA,MACT,KAAK,IAAM,IAAA,IAAA,GAAA,MAAA,GAAA,IAAA,CAAA;AAAA,KACV,EAAA,CAC2B,CACR,CAAA,CACR,CACJ,CAAA;AAAA,GACnB,CAAA,EAGY,YAAe,GAAA,CAAA,oBAAMA,cAAA,CAAA,aAAA,CAAA,MAAA,EAAA,EAAO,SAAU,EAAA,mBAAA,EAAoB,KAAM,EAAA,IAAA,EAAA,kBACxDA,cAAA,CAAA,aAAA,CAAA,GAAA,EAAA,EAAI,KAAO,EAAA;AAAA,IAC5B,KAAO,EAAA;AAAA,KACN,CACe,kBAAAA,cAAA,CAAA,aAAA,CAAC,QAAK,OAAS,EAAA,MAAM,QAAQ,OAAS,IAAA,IAAA,GAAA,MAAA,GAAA,OAAA,CAAA,EAAA,EAAI,QAAU,EAAA,IAAA,IAAA,IAAA,GAAA,MAAA,GAAA,IAAA,CAAM,EAAE,CACxD,EAAA,kBAAAA,cAAA,CAAA,aAAA,CAAC,YAAS,SAAU,EAAA,oBAAA,EAAA,EACf,eAAe,CAAE,EAAA,QAAA,EAAO,YAAe,GAAA,CAAA,KAAM,IAAI,OAAU,GAAA,SAChE,CACJ,CACJ,CAAA,+CAGH,GAAI,EAAA,EAAA,SAAA,EAAU,WACX,EAAA,kBAAAA,cAAA,CAAA,aAAA,CAAC,UAAO,IAAK,EAAA,IAAA,EAAK,WAAU,yBAA0B,EAAA,OAAA,EAAQ,WAAU,KAAO,EAAA;AAAA,IAC3F,WAAa,EAAA,SAAA;AAAA,IACb,iBAAmB,EAAA,EAAA;AAAA,IACnB,eAAiB,EAAA;AAAA,GAChB,EAAA,OAAA,EAAS,MAAM,OAAA,CAAQ,OAAS,IAAA,IAAA,GAAA,MAAA,GAAA,OAAA,CAAA,EAAA,EAAI,QAAU,EAAA,IAAA,IAAA,IAAA,GAAA,MAAA,GAAA,IAAA,CAAM,EAAE,CAAA,EAAA,kBACtCA,cAAA,CAAA,aAAA,CAAA,UAAA,EAAA,EAAW,KAAO,EAAA;AAAA,IACjC,QAAU,EAAA,EAAA;AAAA,IACV,KAAA,EAAO,OAAO,IAAK,CAAA,GAAA;AAAA,OAClB,OAAK,CACI,CACJ,CACJ,CACJ,CACJ,CAAA;AACR;AACa,MAAA,cAAA,GAAiBA,cAAM,CAAA,IAAA,CAAK,uBAAuB"}
|