@sendbird/uikit-react-native-foundation 2.3.0 → 2.4.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 (105) hide show
  1. package/lib/commonjs/components/Box/index.js +46 -0
  2. package/lib/commonjs/components/Box/index.js.map +1 -0
  3. package/lib/commonjs/components/ImageWithPlaceholder/index.js +92 -0
  4. package/lib/commonjs/components/ImageWithPlaceholder/index.js.map +1 -0
  5. package/lib/commonjs/components/PressBox/index.js +60 -0
  6. package/lib/commonjs/components/PressBox/index.js.map +1 -0
  7. package/lib/commonjs/index.js +39 -5
  8. package/lib/commonjs/index.js.map +1 -1
  9. package/lib/commonjs/theme/DarkUIKitTheme.js +220 -179
  10. package/lib/commonjs/theme/DarkUIKitTheme.js.map +1 -1
  11. package/lib/commonjs/theme/LightUIKitTheme.js +220 -179
  12. package/lib/commonjs/theme/LightUIKitTheme.js.map +1 -1
  13. package/lib/commonjs/types.js.map +1 -1
  14. package/lib/commonjs/ui/Header/index.js +4 -2
  15. package/lib/commonjs/ui/Header/index.js.map +1 -1
  16. package/lib/commonjs/ui/OpenChannelMessage/Message.admin.js +40 -0
  17. package/lib/commonjs/ui/OpenChannelMessage/Message.admin.js.map +1 -0
  18. package/lib/commonjs/ui/OpenChannelMessage/Message.file.image.js +57 -0
  19. package/lib/commonjs/ui/OpenChannelMessage/Message.file.image.js.map +1 -0
  20. package/lib/commonjs/ui/OpenChannelMessage/Message.file.js +90 -0
  21. package/lib/commonjs/ui/OpenChannelMessage/Message.file.js.map +1 -0
  22. package/lib/commonjs/ui/OpenChannelMessage/Message.file.video.js +134 -0
  23. package/lib/commonjs/ui/OpenChannelMessage/Message.file.video.js.map +1 -0
  24. package/lib/commonjs/ui/OpenChannelMessage/Message.unknown.js +55 -0
  25. package/lib/commonjs/ui/OpenChannelMessage/Message.unknown.js.map +1 -0
  26. package/lib/commonjs/ui/OpenChannelMessage/Message.user.js +83 -0
  27. package/lib/commonjs/ui/OpenChannelMessage/Message.user.js.map +1 -0
  28. package/lib/commonjs/ui/OpenChannelMessage/Message.user.og.js +140 -0
  29. package/lib/commonjs/ui/OpenChannelMessage/Message.user.og.js.map +1 -0
  30. package/lib/commonjs/ui/OpenChannelMessage/MessageContainer.js +136 -0
  31. package/lib/commonjs/ui/OpenChannelMessage/MessageContainer.js.map +1 -0
  32. package/lib/commonjs/ui/OpenChannelMessage/index.js +35 -0
  33. package/lib/commonjs/ui/OpenChannelMessage/index.js.map +1 -0
  34. package/lib/commonjs/ui/OpenChannelPreview/index.js +134 -0
  35. package/lib/commonjs/ui/OpenChannelPreview/index.js.map +1 -0
  36. package/lib/module/components/Box/index.js +33 -0
  37. package/lib/module/components/Box/index.js.map +1 -0
  38. package/lib/module/components/ImageWithPlaceholder/index.js +71 -0
  39. package/lib/module/components/ImageWithPlaceholder/index.js.map +1 -0
  40. package/lib/module/components/PressBox/index.js +45 -0
  41. package/lib/module/components/PressBox/index.js.map +1 -0
  42. package/lib/module/index.js +6 -1
  43. package/lib/module/index.js.map +1 -1
  44. package/lib/module/theme/DarkUIKitTheme.js +220 -179
  45. package/lib/module/theme/DarkUIKitTheme.js.map +1 -1
  46. package/lib/module/theme/LightUIKitTheme.js +220 -179
  47. package/lib/module/theme/LightUIKitTheme.js.map +1 -1
  48. package/lib/module/types.js.map +1 -1
  49. package/lib/module/ui/Header/index.js +4 -2
  50. package/lib/module/ui/Header/index.js.map +1 -1
  51. package/lib/module/ui/OpenChannelMessage/Message.admin.js +27 -0
  52. package/lib/module/ui/OpenChannelMessage/Message.admin.js.map +1 -0
  53. package/lib/module/ui/OpenChannelMessage/Message.file.image.js +41 -0
  54. package/lib/module/ui/OpenChannelMessage/Message.file.image.js.map +1 -0
  55. package/lib/module/ui/OpenChannelMessage/Message.file.js +71 -0
  56. package/lib/module/ui/OpenChannelMessage/Message.file.js.map +1 -0
  57. package/lib/module/ui/OpenChannelMessage/Message.file.video.js +112 -0
  58. package/lib/module/ui/OpenChannelMessage/Message.file.video.js.map +1 -0
  59. package/lib/module/ui/OpenChannelMessage/Message.unknown.js +41 -0
  60. package/lib/module/ui/OpenChannelMessage/Message.unknown.js.map +1 -0
  61. package/lib/module/ui/OpenChannelMessage/Message.user.js +67 -0
  62. package/lib/module/ui/OpenChannelMessage/Message.user.js.map +1 -0
  63. package/lib/module/ui/OpenChannelMessage/Message.user.og.js +121 -0
  64. package/lib/module/ui/OpenChannelMessage/Message.user.og.js.map +1 -0
  65. package/lib/module/ui/OpenChannelMessage/MessageContainer.js +116 -0
  66. package/lib/module/ui/OpenChannelMessage/MessageContainer.js.map +1 -0
  67. package/lib/module/ui/OpenChannelMessage/index.js +18 -0
  68. package/lib/module/ui/OpenChannelMessage/index.js.map +1 -0
  69. package/lib/module/ui/OpenChannelPreview/index.js +117 -0
  70. package/lib/module/ui/OpenChannelPreview/index.js.map +1 -0
  71. package/lib/typescript/src/components/Box/index.d.ts +11 -0
  72. package/lib/typescript/src/components/ImageWithPlaceholder/index.d.ts +11 -0
  73. package/lib/typescript/src/components/PressBox/index.d.ts +16 -0
  74. package/lib/typescript/src/index.d.ts +8 -1
  75. package/lib/typescript/src/types.d.ts +21 -5
  76. package/lib/typescript/src/ui/Header/index.d.ts +1 -0
  77. package/lib/typescript/src/ui/OpenChannelMessage/Message.admin.d.ts +4 -0
  78. package/lib/typescript/src/ui/OpenChannelMessage/Message.file.d.ts +5 -0
  79. package/lib/typescript/src/ui/OpenChannelMessage/Message.file.image.d.ts +4 -0
  80. package/lib/typescript/src/ui/OpenChannelMessage/Message.file.video.d.ts +9 -0
  81. package/lib/typescript/src/ui/OpenChannelMessage/Message.unknown.d.ts +4 -0
  82. package/lib/typescript/src/ui/OpenChannelMessage/Message.user.d.ts +5 -0
  83. package/lib/typescript/src/ui/OpenChannelMessage/Message.user.og.d.ts +5 -0
  84. package/lib/typescript/src/ui/OpenChannelMessage/MessageContainer.d.ts +7 -0
  85. package/lib/typescript/src/ui/OpenChannelMessage/index.d.ts +136 -0
  86. package/lib/typescript/src/ui/OpenChannelPreview/index.d.ts +10 -0
  87. package/package.json +4 -4
  88. package/src/components/Box/index.tsx +65 -0
  89. package/src/components/ImageWithPlaceholder/index.tsx +83 -0
  90. package/src/components/PressBox/index.tsx +53 -0
  91. package/src/index.ts +8 -1
  92. package/src/theme/DarkUIKitTheme.ts +213 -171
  93. package/src/theme/LightUIKitTheme.ts +213 -171
  94. package/src/types.ts +41 -6
  95. package/src/ui/Header/index.tsx +7 -2
  96. package/src/ui/OpenChannelMessage/Message.admin.tsx +24 -0
  97. package/src/ui/OpenChannelMessage/Message.file.image.tsx +34 -0
  98. package/src/ui/OpenChannelMessage/Message.file.tsx +67 -0
  99. package/src/ui/OpenChannelMessage/Message.file.video.tsx +93 -0
  100. package/src/ui/OpenChannelMessage/Message.unknown.tsx +31 -0
  101. package/src/ui/OpenChannelMessage/Message.user.og.tsx +120 -0
  102. package/src/ui/OpenChannelMessage/Message.user.tsx +61 -0
  103. package/src/ui/OpenChannelMessage/MessageContainer.tsx +121 -0
  104. package/src/ui/OpenChannelMessage/index.ts +42 -0
  105. package/src/ui/OpenChannelPreview/index.tsx +97 -0
@@ -0,0 +1,67 @@
1
+ import React from 'react';
2
+
3
+ import { SendbirdFileMessage, getFileTypeFromMessage } from '@sendbird/uikit-utils';
4
+
5
+ import Box from '../../components/Box';
6
+ import Icon from '../../components/Icon';
7
+ import PressBox from '../../components/PressBox';
8
+ import Text from '../../components/Text';
9
+ import createStyleSheet from '../../styles/createStyleSheet';
10
+ import useUIKitTheme from '../../theme/useUIKitTheme';
11
+ import MessageContainer from './MessageContainer';
12
+ import type { OpenChannelMessageProps } from './index';
13
+
14
+ const iconMapper = { audio: 'file-audio', image: 'photo', video: 'play', file: 'file-document' } as const;
15
+
16
+ type Props = {};
17
+ const FileMessage = (props: OpenChannelMessageProps<SendbirdFileMessage, Props>) => {
18
+ const { colors } = useUIKitTheme();
19
+ const { onPress, onLongPress, ...rest } = props;
20
+ const type = getFileTypeFromMessage(props.message);
21
+ const color = colors.ui.openChannelMessage.default;
22
+
23
+ return (
24
+ <MessageContainer {...rest}>
25
+ <PressBox onPress={onPress} onLongPress={onLongPress}>
26
+ {({ pressed }) => {
27
+ return (
28
+ <Box
29
+ padding={8}
30
+ borderRadius={8}
31
+ flexDirection={'row'}
32
+ alignItems={'center'}
33
+ justifyContent={'flex-start'}
34
+ style={{ backgroundColor: pressed ? color.pressed.bubbleBackground : color.enabled.bubbleBackground }}
35
+ >
36
+ <Box
37
+ padding={4}
38
+ marginRight={8}
39
+ borderRadius={8}
40
+ alignItems={'flex-start'}
41
+ backgroundColor={colors.background}
42
+ >
43
+ <Icon icon={iconMapper[type]} size={32} />
44
+ </Box>
45
+ <Text
46
+ body3
47
+ numberOfLines={1}
48
+ ellipsizeMode={'middle'}
49
+ color={color.enabled.textMsg}
50
+ style={styles.fileName}
51
+ >
52
+ {props.strings?.fileName || props.message.name}
53
+ </Text>
54
+ </Box>
55
+ );
56
+ }}
57
+ </PressBox>
58
+ </MessageContainer>
59
+ );
60
+ };
61
+
62
+ const styles = createStyleSheet({
63
+ fileName: {
64
+ flexShrink: 1,
65
+ },
66
+ });
67
+ export default FileMessage;
@@ -0,0 +1,93 @@
1
+ import React, { useEffect, useRef, useState } from 'react';
2
+
3
+ import type { SendbirdFileMessage } from '@sendbird/uikit-utils';
4
+ import { getAvailableUriFromFileMessage } from '@sendbird/uikit-utils';
5
+
6
+ import Box from '../../components/Box';
7
+ import Icon from '../../components/Icon';
8
+ import ImageWithPlaceholder from '../../components/ImageWithPlaceholder';
9
+ import PressBox from '../../components/PressBox';
10
+ import createStyleSheet from '../../styles/createStyleSheet';
11
+ import useUIKitTheme from '../../theme/useUIKitTheme';
12
+ import MessageContainer from './MessageContainer';
13
+ import type { OpenChannelMessageProps } from './index';
14
+
15
+ type Props = {
16
+ fetchThumbnailFromVideoSource: (uri: string) => Promise<{ path: string } | null>;
17
+ };
18
+ const VideoFileMessage = (props: OpenChannelMessageProps<SendbirdFileMessage, Props>) => {
19
+ const { colors, palette } = useUIKitTheme();
20
+ const { onPress, onLongPress, ...rest } = props;
21
+ const uri = getAvailableUriFromFileMessage(props.message);
22
+ const { thumbnail, loading } = useRetry(() => props.fetchThumbnailFromVideoSource(uri));
23
+
24
+ return (
25
+ <MessageContainer {...rest}>
26
+ <PressBox style={styles.container} activeOpacity={0.8} onPress={onPress} onLongPress={onLongPress}>
27
+ <Box borderRadius={8} overflow={'hidden'} style={styles.container}>
28
+ {loading ? (
29
+ <Box backgroundColor={colors.onBackground04} style={{ width: '100%', height: '100%' }} />
30
+ ) : (
31
+ <ImageWithPlaceholder source={{ uri: thumbnail ?? 'invalid-image' }} width={'100%'} height={'100%'} />
32
+ )}
33
+
34
+ {(loading || thumbnail !== null) && (
35
+ <Box style={styles.iconContainer} alignItems={'center'} justifyContent={'center'}>
36
+ <Icon
37
+ icon={'play'}
38
+ size={28}
39
+ color={palette.onBackgroundLight02}
40
+ containerStyle={[styles.playIcon, { backgroundColor: palette.onBackgroundDark01 }]}
41
+ />
42
+ </Box>
43
+ )}
44
+ </Box>
45
+ </PressBox>
46
+ </MessageContainer>
47
+ );
48
+ };
49
+ const useRetry = (fetch: () => Promise<{ path: string } | null>, retryCount = 5) => {
50
+ const [state, setState] = useState({ thumbnail: null as null | string, loading: true });
51
+ const retryCountRef = useRef(0);
52
+ const retryTimeoutRef = useRef<NodeJS.Timeout>();
53
+ const fetchThumbnail = useRef(fetch);
54
+ fetchThumbnail.current = fetch;
55
+
56
+ useEffect(() => {
57
+ if (!state.thumbnail) {
58
+ const reloadReservation = () => {
59
+ if (retryCountRef.current < retryCount) {
60
+ retryTimeoutRef.current = setTimeout(() => {
61
+ retryCountRef.current++;
62
+ reloadReservation();
63
+ fetchThumbnail.current().then((result) => {
64
+ setState({ loading: false, thumbnail: result?.path ?? null });
65
+ });
66
+ }, retryCountRef.current * 5000);
67
+ }
68
+ };
69
+
70
+ return reloadReservation();
71
+ } else {
72
+ return clearTimeout(retryTimeoutRef.current);
73
+ }
74
+ }, [state.thumbnail]);
75
+
76
+ return state;
77
+ };
78
+ const styles = createStyleSheet({
79
+ container: {
80
+ maxWidth: 296,
81
+ height: 196,
82
+ },
83
+ iconContainer: {
84
+ position: 'absolute',
85
+ width: '100%',
86
+ height: '100%',
87
+ },
88
+ playIcon: {
89
+ padding: 10,
90
+ borderRadius: 50,
91
+ },
92
+ });
93
+ export default VideoFileMessage;
@@ -0,0 +1,31 @@
1
+ import React from 'react';
2
+
3
+ import type { SendbirdMessage } from '@sendbird/uikit-utils';
4
+
5
+ import PressBox from '../../components/PressBox';
6
+ import Text from '../../components/Text';
7
+ import useUIKitTheme from '../../theme/useUIKitTheme';
8
+ import MessageContainer from './MessageContainer';
9
+ import type { OpenChannelMessageProps } from './index';
10
+
11
+ const UnknownMessage = (props: OpenChannelMessageProps<SendbirdMessage>) => {
12
+ const { colors } = useUIKitTheme();
13
+ const { onPress, onLongPress, ...rest } = props;
14
+ const color = colors.ui.openChannelMessage.default;
15
+ return (
16
+ <PressBox onPress={onPress} onLongPress={onLongPress}>
17
+ {({ pressed }) => (
18
+ <MessageContainer pressed={pressed} {...rest}>
19
+ <Text body3 color={color.enabled.textMsg}>
20
+ {props.strings?.unknownTitle ?? '(Unknown message type)'}
21
+ </Text>
22
+ <Text body3 color={color.enabled.textMsgPostfix}>
23
+ {props.strings?.unknownDescription ?? 'Cannot read this message.'}
24
+ </Text>
25
+ </MessageContainer>
26
+ )}
27
+ </PressBox>
28
+ );
29
+ };
30
+
31
+ export default UnknownMessage;
@@ -0,0 +1,120 @@
1
+ import React from 'react';
2
+
3
+ import type { SendbirdUserMessage } from '@sendbird/uikit-utils';
4
+ import { urlRegexRough } from '@sendbird/uikit-utils';
5
+
6
+ import Box from '../../components/Box';
7
+ import ImageWithPlaceholder from '../../components/ImageWithPlaceholder';
8
+ import PressBox from '../../components/PressBox';
9
+ import RegexText from '../../components/RegexText';
10
+ import Text from '../../components/Text';
11
+ import createStyleSheet from '../../styles/createStyleSheet';
12
+ import useUIKitTheme from '../../theme/useUIKitTheme';
13
+ import MessageContainer from './MessageContainer';
14
+ import type { OpenChannelMessageProps } from './index';
15
+
16
+ type Props = {};
17
+ const OpenGraphUserMessage = (props: OpenChannelMessageProps<SendbirdUserMessage, Props>) => {
18
+ const { colors } = useUIKitTheme();
19
+ const { onPress, onLongPress, onPressURL, ...rest } = props;
20
+ const color = colors.ui.openChannelMessage.default;
21
+
22
+ return (
23
+ <Box>
24
+ <PressBox onPress={onPress} onLongPress={onLongPress}>
25
+ {({ pressed }) => (
26
+ <MessageContainer pressed={pressed} {...rest}>
27
+ <Text body3 color={color.enabled.textMsg}>
28
+ <RegexText
29
+ body3
30
+ color={color.enabled.textMsg}
31
+ patterns={[
32
+ {
33
+ regex: urlRegexRough,
34
+ replacer({ match, parentProps, keyPrefix, index }) {
35
+ return (
36
+ <Text
37
+ {...parentProps}
38
+ key={`${keyPrefix}-${index}`}
39
+ onPress={onPressURL}
40
+ onLongPress={onLongPress}
41
+ color={colors.primary}
42
+ style={parentProps?.style}
43
+ >
44
+ {match}
45
+ </Text>
46
+ );
47
+ },
48
+ },
49
+ ]}
50
+ >
51
+ {props.message.message}
52
+ </RegexText>
53
+ {Boolean(props.message.updatedAt) && (
54
+ <Text body3 color={color.enabled.textMsgPostfix}>
55
+ {props.strings?.edited ?? ' (edited)'}
56
+ </Text>
57
+ )}
58
+ </Text>
59
+ </MessageContainer>
60
+ )}
61
+ </PressBox>
62
+ {props.message.ogMetaData && (
63
+ <MessageContainer {...rest} grouped>
64
+ <PressBox style={styles.ogContainer} onPress={onPressURL} onLongPress={onLongPress}>
65
+ {({ pressed }) =>
66
+ props.message.ogMetaData && (
67
+ <Box
68
+ padding={8}
69
+ borderRadius={8}
70
+ style={styles.ogContainer}
71
+ backgroundColor={pressed ? color.pressed.bubbleBackground : color.enabled.bubbleBackground}
72
+ >
73
+ <Text numberOfLines={1} caption2 color={colors.onBackground02} style={styles.ogUrl}>
74
+ {props.message.ogMetaData.url}
75
+ </Text>
76
+
77
+ <Text numberOfLines={2} body2 color={colors.primary} style={styles.ogTitle}>
78
+ {props.message.ogMetaData.title}
79
+ </Text>
80
+
81
+ {Boolean(props.message.ogMetaData.description) && (
82
+ <Text numberOfLines={2} caption2 color={colors.onBackground01}>
83
+ {props.message.ogMetaData.description}
84
+ </Text>
85
+ )}
86
+
87
+ {Boolean(props.message.ogMetaData.defaultImage) && (
88
+ <ImageWithPlaceholder
89
+ style={styles.ogImage}
90
+ source={{ uri: props.message.ogMetaData.defaultImage.url }}
91
+ />
92
+ )}
93
+ </Box>
94
+ )
95
+ }
96
+ </PressBox>
97
+ </MessageContainer>
98
+ )}
99
+ </Box>
100
+ );
101
+ };
102
+
103
+ const styles = createStyleSheet({
104
+ ogContainer: {
105
+ maxWidth: 296,
106
+ },
107
+ ogUrl: {
108
+ marginBottom: 4,
109
+ },
110
+ ogTitle: {
111
+ marginBottom: 8,
112
+ },
113
+ ogImage: {
114
+ width: '100%',
115
+ height: 156,
116
+ marginTop: 12,
117
+ },
118
+ });
119
+
120
+ export default OpenGraphUserMessage;
@@ -0,0 +1,61 @@
1
+ import React from 'react';
2
+
3
+ import type { SendbirdUserMessage } from '@sendbird/uikit-utils';
4
+ import { urlRegexStrict } from '@sendbird/uikit-utils';
5
+
6
+ import PressBox from '../../components/PressBox';
7
+ import RegexText from '../../components/RegexText';
8
+ import Text from '../../components/Text';
9
+ import useUIKitTheme from '../../theme/useUIKitTheme';
10
+ import MessageContainer from './MessageContainer';
11
+ import type { OpenChannelMessageProps } from './index';
12
+
13
+ type Props = {};
14
+ const UserMessage = (props: OpenChannelMessageProps<SendbirdUserMessage, Props>) => {
15
+ const { colors } = useUIKitTheme();
16
+ const { onPress, onLongPress, onPressURL, ...rest } = props;
17
+ const color = colors.ui.openChannelMessage.default;
18
+
19
+ return (
20
+ <PressBox onPress={onPress} onLongPress={onLongPress}>
21
+ {({ pressed }) => (
22
+ <MessageContainer pressed={pressed} {...rest}>
23
+ <Text body3 color={color.enabled.textMsg}>
24
+ <RegexText
25
+ body3
26
+ color={color.enabled.textMsg}
27
+ patterns={[
28
+ {
29
+ regex: urlRegexStrict,
30
+ replacer({ match, parentProps, keyPrefix, index }) {
31
+ return (
32
+ <Text
33
+ {...parentProps}
34
+ key={`${keyPrefix}-${index}`}
35
+ onPress={onPressURL}
36
+ onLongPress={onLongPress}
37
+ color={colors.primary}
38
+ style={parentProps?.style}
39
+ >
40
+ {match}
41
+ </Text>
42
+ );
43
+ },
44
+ },
45
+ ]}
46
+ >
47
+ {props.message.message}
48
+ </RegexText>
49
+ {Boolean(props.message.updatedAt) && (
50
+ <Text body3 color={color.enabled.textMsgPostfix}>
51
+ {props.strings?.edited ?? ' (edited)'}
52
+ </Text>
53
+ )}
54
+ </Text>
55
+ </MessageContainer>
56
+ )}
57
+ </PressBox>
58
+ );
59
+ };
60
+
61
+ export default UserMessage;
@@ -0,0 +1,121 @@
1
+ import React from 'react';
2
+
3
+ import { SendingStatus } from '@sendbird/chat/message';
4
+ import type { SendbirdMessage } from '@sendbird/uikit-utils';
5
+ import { getMessageTimeFormat } from '@sendbird/uikit-utils';
6
+
7
+ import Box from '../../components/Box';
8
+ import Icon from '../../components/Icon';
9
+ import PressBox from '../../components/PressBox';
10
+ import Text from '../../components/Text';
11
+ import createStyleSheet from '../../styles/createStyleSheet';
12
+ import useUIKitTheme from '../../theme/useUIKitTheme';
13
+ import Avatar from '../Avatar';
14
+ import LoadingSpinner from '../LoadingSpinner';
15
+ import type { OpenChannelMessageProps } from './index';
16
+
17
+ type Props = {
18
+ pressed?: boolean;
19
+ };
20
+
21
+ const MessageContainer = ({
22
+ children,
23
+ channel,
24
+ grouped,
25
+ pressed,
26
+ ...props
27
+ }: OpenChannelMessageProps<SendbirdMessage, Props>) => {
28
+ const { colors } = useUIKitTheme();
29
+ const color = colors.ui.openChannelMessage.default;
30
+
31
+ const renderSendingStatus = () => {
32
+ if (!('sendingStatus' in props.message)) return null;
33
+
34
+ switch (props.message.sendingStatus) {
35
+ case SendingStatus.PENDING: {
36
+ return (
37
+ <SendingStatusContainer>
38
+ <LoadingSpinner color={colors.primary} size={16} />
39
+ </SendingStatusContainer>
40
+ );
41
+ }
42
+ case SendingStatus.FAILED: {
43
+ return (
44
+ <SendingStatusContainer>
45
+ <Icon icon={'error'} color={colors.error} size={16} />
46
+ </SendingStatusContainer>
47
+ );
48
+ }
49
+ default: {
50
+ return null;
51
+ }
52
+ }
53
+ };
54
+
55
+ return (
56
+ <Box
57
+ flexDirection={'row'}
58
+ paddingVertical={grouped ? 5 : 6}
59
+ paddingLeft={12}
60
+ paddingRight={12}
61
+ backgroundColor={pressed ? color.pressed.background : color.enabled.background}
62
+ >
63
+ <Box marginRight={12}>
64
+ {!grouped && 'sender' in props.message ? (
65
+ <PressBox onPress={props.onPressAvatar}>
66
+ <Avatar size={styles.avatar.width} uri={props.message.sender.profileUrl} />
67
+ </PressBox>
68
+ ) : (
69
+ <Box style={styles.avatar} />
70
+ )}
71
+ </Box>
72
+ <Box flexShrink={1} flex={1} flexDirection={'column'} alignItems={'flex-start'}>
73
+ {!grouped && 'sender' in props.message && (
74
+ <Box flexDirection={'row'} alignItems={'center'} marginBottom={2}>
75
+ <Box marginRight={4} flexShrink={1}>
76
+ <Text
77
+ caption1
78
+ ellipsizeMode={'middle'}
79
+ numberOfLines={1}
80
+ color={
81
+ channel.isOperator(props.message.sender.userId)
82
+ ? color.enabled.textOperator
83
+ : color.enabled.textSenderName
84
+ }
85
+ >
86
+ {props.strings?.senderName ?? props.message.sender.nickname}
87
+ </Text>
88
+ </Box>
89
+ <Box>
90
+ <Text caption4 color={color.enabled.textTime}>
91
+ {props.strings?.sentDate ?? getMessageTimeFormat(new Date(props.message.createdAt))}
92
+ </Text>
93
+ </Box>
94
+ </Box>
95
+ )}
96
+ <Box style={styles.message}>{children}</Box>
97
+
98
+ {renderSendingStatus()}
99
+ </Box>
100
+ </Box>
101
+ );
102
+ };
103
+
104
+ const SendingStatusContainer = ({ children }: { children: React.ReactElement }) => {
105
+ return (
106
+ <Box flexDirection={'row'}>
107
+ <Box marginTop={2}>{children}</Box>
108
+ </Box>
109
+ );
110
+ };
111
+
112
+ const styles = createStyleSheet({
113
+ avatar: {
114
+ width: 28,
115
+ },
116
+ message: {
117
+ width: '100%',
118
+ },
119
+ });
120
+
121
+ export default MessageContainer;
@@ -0,0 +1,42 @@
1
+ import type React from 'react';
2
+
3
+ import type { SendbirdMessage, SendbirdOpenChannel } from '@sendbird/uikit-utils';
4
+
5
+ import AdminMessage from './Message.admin';
6
+ import FileMessage from './Message.file';
7
+ import ImageFileMessage from './Message.file.image';
8
+ import VideoFileMessage from './Message.file.video';
9
+ import UnknownMessage from './Message.unknown';
10
+ import UserMessage from './Message.user';
11
+ import OpenGraphUserMessage from './Message.user.og';
12
+
13
+ export type OpenChannelMessageProps<T extends SendbirdMessage, AdditionalProps = unknown> = {
14
+ channel: SendbirdOpenChannel;
15
+ message: T;
16
+ strings?: {
17
+ senderName?: string;
18
+ sentDate?: string;
19
+ edited?: string;
20
+ fileName?: string;
21
+ unknownTitle?: string;
22
+ unknownDescription?: string;
23
+ };
24
+ children?: React.ReactNode;
25
+ grouped?: boolean;
26
+ onPress?: () => void;
27
+ onLongPress?: () => void;
28
+ onPressAvatar?: () => void;
29
+ onPressURL?: () => void;
30
+ } & AdditionalProps;
31
+
32
+ const OpenChannelMessage = {
33
+ User: UserMessage,
34
+ OpenGraphUser: OpenGraphUserMessage,
35
+ File: FileMessage,
36
+ ImageFile: ImageFileMessage,
37
+ VideoFile: VideoFileMessage,
38
+ Admin: AdminMessage,
39
+ Unknown: UnknownMessage,
40
+ };
41
+
42
+ export default OpenChannelMessage;
@@ -0,0 +1,97 @@
1
+ import React from 'react';
2
+
3
+ import { conditionChaining, truncatedCount } from '@sendbird/uikit-utils';
4
+
5
+ import Box from '../../components/Box';
6
+ import Icon from '../../components/Icon';
7
+ import Image from '../../components/Image';
8
+ import Text from '../../components/Text';
9
+ import createStyleSheet from '../../styles/createStyleSheet';
10
+ import useUIKitTheme from '../../theme/useUIKitTheme';
11
+
12
+ type Props = {
13
+ customCover?: React.ReactElement;
14
+ coverUrl: string;
15
+ title: string;
16
+ participantsCount?: number;
17
+ frozen?: boolean;
18
+ };
19
+ const OpenChannelPreview = ({ customCover, coverUrl, participantsCount = 0, title, frozen }: Props) => {
20
+ const { colors } = useUIKitTheme();
21
+ const color = colors.ui.openChannelPreview.default.none;
22
+
23
+ return (
24
+ <Box
25
+ backgroundColor={color.background}
26
+ width={'100%'}
27
+ height={62}
28
+ flexDirection={'row'}
29
+ alignItems={'center'}
30
+ paddingHorizontal={16}
31
+ >
32
+ <Box
33
+ width={styles.channelCover.width}
34
+ height={styles.channelCover.height}
35
+ borderRadius={styles.channelCover.width}
36
+ overflow={'hidden'}
37
+ marginRight={16}
38
+ >
39
+ {conditionChaining(
40
+ [Boolean(customCover)],
41
+ [
42
+ customCover,
43
+ <Image
44
+ resizeMode={'cover'}
45
+ style={[styles.channelCover, { backgroundColor: color.coverBackground }]}
46
+ source={{ uri: coverUrl }}
47
+ />,
48
+ ],
49
+ )}
50
+ </Box>
51
+ <Box flex={1} height={'100%'} justifyContent={'center'}>
52
+ <Box flexDirection={'row'} flexShrink={1} marginBottom={4} alignItems={'center'}>
53
+ <Text subtitle1 style={styles.channelInfoTitle} numberOfLines={1} color={color.textTitle}>
54
+ {title}
55
+ </Text>
56
+ {frozen && <Icon size={16} icon={'freeze'} color={color.frozenIcon} containerStyle={styles.marginLeft} />}
57
+ </Box>
58
+ <Box flexDirection={'row'} flexShrink={1} alignItems={'center'} justifyContent={'flex-start'}>
59
+ <Box flexDirection={'row'} alignItems={'center'}>
60
+ <Icon size={16} icon={'members'} color={color.participantsIcon} containerStyle={styles.marginRight} />
61
+ <Text caption2 color={color.textParticipants}>
62
+ {truncatedCount(participantsCount, 999)}
63
+ </Text>
64
+ </Box>
65
+ </Box>
66
+ <Separator color={color.separator} />
67
+ </Box>
68
+ </Box>
69
+ );
70
+ };
71
+
72
+ const Separator = ({ color }: { color: string }) => <Box style={[styles.separator, { backgroundColor: color }]} />;
73
+
74
+ const styles = createStyleSheet({
75
+ channelCover: {
76
+ width: 32,
77
+ height: 32,
78
+ },
79
+ channelInfoTitle: {
80
+ flexShrink: 1,
81
+ },
82
+ marginRight: {
83
+ marginRight: 4,
84
+ },
85
+ marginLeft: {
86
+ marginLeft: 4,
87
+ },
88
+ separator: {
89
+ position: 'absolute',
90
+ left: 0,
91
+ right: -16,
92
+ bottom: 0,
93
+ height: 1,
94
+ },
95
+ });
96
+
97
+ export default OpenChannelPreview;