@planningcenter/chat-react-native 3.2.0-rc.26 → 3.2.0-rc.27
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/build/components/conversation/message_form/message_form_attachment_image.d.ts +13 -0
- package/build/components/conversation/message_form/message_form_attachment_image.d.ts.map +1 -0
- package/build/components/conversation/message_form/message_form_attachment_image.js +78 -0
- package/build/components/conversation/message_form/message_form_attachment_image.js.map +1 -0
- package/build/components/conversation/message_form.d.ts.map +1 -1
- package/build/components/conversation/message_form.js +128 -16
- package/build/components/conversation/message_form.js.map +1 -1
- package/build/hooks/attachments/supported_extensions.d.ts +2 -0
- package/build/hooks/attachments/supported_extensions.d.ts.map +1 -0
- package/build/hooks/attachments/supported_extensions.js +48 -0
- package/build/hooks/attachments/supported_extensions.js.map +1 -0
- package/build/hooks/use_attachment_uploader.d.ts +26 -0
- package/build/hooks/use_attachment_uploader.d.ts.map +1 -0
- package/build/hooks/use_attachment_uploader.js +111 -0
- package/build/hooks/use_attachment_uploader.js.map +1 -0
- package/build/hooks/use_upload_client.d.ts +28 -0
- package/build/hooks/use_upload_client.d.ts.map +1 -0
- package/build/hooks/use_upload_client.js +32 -0
- package/build/hooks/use_upload_client.js.map +1 -0
- package/build/screens/conversation_screen.js +1 -1
- package/build/screens/conversation_screen.js.map +1 -1
- package/build/utils/native_adapters/configuration.d.ts +4 -1
- package/build/utils/native_adapters/configuration.d.ts.map +1 -1
- package/build/utils/native_adapters/configuration.js +13 -1
- package/build/utils/native_adapters/configuration.js.map +1 -1
- package/build/utils/native_adapters/image_picker.d.ts +25 -0
- package/build/utils/native_adapters/image_picker.d.ts.map +1 -0
- package/build/utils/native_adapters/image_picker.js +9 -0
- package/build/utils/native_adapters/image_picker.js.map +1 -0
- package/build/utils/native_adapters/index.d.ts +1 -0
- package/build/utils/native_adapters/index.d.ts.map +1 -1
- package/build/utils/native_adapters/index.js +1 -0
- package/build/utils/native_adapters/index.js.map +1 -1
- package/build/utils/upload_uri.d.ts +23 -0
- package/build/utils/upload_uri.d.ts.map +1 -0
- package/build/utils/upload_uri.js +60 -0
- package/build/utils/upload_uri.js.map +1 -0
- package/package.json +2 -2
- package/src/components/conversation/message_form/message_form_attachment_image.tsx +121 -0
- package/src/components/conversation/message_form.tsx +197 -31
- package/src/hooks/attachments/supported_extensions.ts +47 -0
- package/src/hooks/use_attachment_uploader.ts +179 -0
- package/src/hooks/use_upload_client.ts +67 -0
- package/src/screens/conversation_screen.tsx +1 -1
- package/src/utils/native_adapters/configuration.ts +15 -1
- package/src/utils/native_adapters/image_picker.ts +31 -0
- package/src/utils/native_adapters/index.ts +1 -0
- package/src/utils/upload_uri.ts +69 -0
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { FileAttachment } from '../../../hooks/use_attachment_uploader';
|
|
3
|
+
interface Props {
|
|
4
|
+
uri: string;
|
|
5
|
+
alt: string;
|
|
6
|
+
status: FileAttachment['status'];
|
|
7
|
+
width?: number;
|
|
8
|
+
height?: number;
|
|
9
|
+
removeAttachment: () => void;
|
|
10
|
+
}
|
|
11
|
+
export declare function MessageFormAttachmentImage({ uri, alt, status, removeAttachment }: Props): React.JSX.Element;
|
|
12
|
+
export {};
|
|
13
|
+
//# sourceMappingURL=message_form_attachment_image.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"message_form_attachment_image.d.ts","sourceRoot":"","sources":["../../../../src/components/conversation/message_form/message_form_attachment_image.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAQzB,OAAO,EAAE,cAAc,EAAE,MAAM,wCAAwC,CAAA;AAIvE,UAAU,KAAK;IACb,GAAG,EAAE,MAAM,CAAA;IACX,GAAG,EAAE,MAAM,CAAA;IACX,MAAM,EAAE,cAAc,CAAC,QAAQ,CAAC,CAAA;IAChC,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,gBAAgB,EAAE,MAAM,IAAI,CAAA;CAC7B;AAED,wBAAgB,0BAA0B,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,MAAM,EAAE,gBAAgB,EAAE,EAAE,KAAK,qBA8CvF"}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Image as ReactNativeImage, StyleSheet, View, } from 'react-native';
|
|
3
|
+
import { useTheme } from '../../../hooks';
|
|
4
|
+
import { Icon, IconButton, Spinner } from '../../display';
|
|
5
|
+
export function MessageFormAttachmentImage({ uri, alt, status, removeAttachment }) {
|
|
6
|
+
function opacity() {
|
|
7
|
+
if (status === 'uploading') {
|
|
8
|
+
return 0.5;
|
|
9
|
+
}
|
|
10
|
+
return 1;
|
|
11
|
+
}
|
|
12
|
+
const styles = useStyles({
|
|
13
|
+
width: 50,
|
|
14
|
+
height: 50,
|
|
15
|
+
borderRadius: 8,
|
|
16
|
+
});
|
|
17
|
+
const loading = status === 'uploading';
|
|
18
|
+
const error = status === 'error';
|
|
19
|
+
const ready = status === 'success';
|
|
20
|
+
return (<View accessible={Boolean(alt)} accessibilityRole="image" accessibilityState={{ busy: loading }}>
|
|
21
|
+
<ReactNativeImage source={{ uri }} style={[styles.image, { opacity: opacity() }]} alt={alt}/>
|
|
22
|
+
{ready && (<IconButton name="general.x" accessibilityLabel="Remove Attachment" size="md" style={styles.removeAttachmentIcon} onPress={removeAttachment}/>)}
|
|
23
|
+
{loading && (<View style={[styles.loadingBackground]}>
|
|
24
|
+
<Spinner size={24}/>
|
|
25
|
+
</View>)}
|
|
26
|
+
{error && (<View style={styles.errorBackground}>
|
|
27
|
+
<View style={styles.errorIconBackground}>
|
|
28
|
+
<Icon name="churchCenter.exclamationCircle" size={18} color="red"/>
|
|
29
|
+
</View>
|
|
30
|
+
</View>)}
|
|
31
|
+
</View>);
|
|
32
|
+
}
|
|
33
|
+
const useStyles = ({ width, height, borderRadius }) => {
|
|
34
|
+
const { colors } = useTheme();
|
|
35
|
+
return StyleSheet.create({
|
|
36
|
+
image: {
|
|
37
|
+
backgroundColor: colors.fillColorNeutral070,
|
|
38
|
+
width,
|
|
39
|
+
height,
|
|
40
|
+
borderRadius,
|
|
41
|
+
},
|
|
42
|
+
removeAttachmentIcon: {
|
|
43
|
+
position: 'absolute',
|
|
44
|
+
top: 4,
|
|
45
|
+
right: 4,
|
|
46
|
+
backgroundColor: 'rgba(255, 255, 255, 0.5)',
|
|
47
|
+
borderRadius: 24,
|
|
48
|
+
width: 24,
|
|
49
|
+
height: 24,
|
|
50
|
+
justifyContent: 'center',
|
|
51
|
+
alignItems: 'center',
|
|
52
|
+
},
|
|
53
|
+
loadingBackground: {
|
|
54
|
+
position: 'absolute',
|
|
55
|
+
top: 0,
|
|
56
|
+
left: 0,
|
|
57
|
+
borderRadius,
|
|
58
|
+
width,
|
|
59
|
+
height,
|
|
60
|
+
},
|
|
61
|
+
errorBackground: {
|
|
62
|
+
position: 'absolute',
|
|
63
|
+
top: 0,
|
|
64
|
+
left: 0,
|
|
65
|
+
borderRadius,
|
|
66
|
+
width,
|
|
67
|
+
height,
|
|
68
|
+
justifyContent: 'center',
|
|
69
|
+
alignItems: 'center',
|
|
70
|
+
},
|
|
71
|
+
errorIconBackground: {
|
|
72
|
+
backgroundColor: 'white',
|
|
73
|
+
padding: 2,
|
|
74
|
+
borderRadius: 50,
|
|
75
|
+
},
|
|
76
|
+
});
|
|
77
|
+
};
|
|
78
|
+
//# sourceMappingURL=message_form_attachment_image.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"message_form_attachment_image.js","sourceRoot":"","sources":["../../../../src/components/conversation/message_form/message_form_attachment_image.tsx"],"names":[],"mappings":"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","sourcesContent":["import React from 'react'\nimport {\n AnimatableNumericValue,\n DimensionValue,\n Image as ReactNativeImage,\n StyleSheet,\n View,\n} from 'react-native'\nimport { FileAttachment } from '../../../hooks/use_attachment_uploader'\nimport { useTheme } from '../../../hooks'\nimport { Icon, IconButton, Spinner } from '../../display'\n\ninterface Props {\n uri: string\n alt: string\n status: FileAttachment['status']\n width?: number\n height?: number\n removeAttachment: () => void\n}\n\nexport function MessageFormAttachmentImage({ uri, alt, status, removeAttachment }: Props) {\n function opacity() {\n if (status === 'uploading') {\n return 0.5\n }\n return 1\n }\n const styles = useStyles({\n width: 50,\n height: 50,\n borderRadius: 8,\n })\n const loading = status === 'uploading'\n const error = status === 'error'\n const ready = status === 'success'\n\n return (\n <View\n accessible={Boolean(alt)}\n accessibilityRole=\"image\"\n accessibilityState={{ busy: loading }}\n >\n <ReactNativeImage source={{ uri }} style={[styles.image, { opacity: opacity() }]} alt={alt} />\n {ready && (\n <IconButton\n name=\"general.x\"\n accessibilityLabel=\"Remove Attachment\"\n size=\"md\"\n style={styles.removeAttachmentIcon}\n onPress={removeAttachment}\n />\n )}\n {loading && (\n <View style={[styles.loadingBackground]}>\n <Spinner size={24} />\n </View>\n )}\n {error && (\n <View style={styles.errorBackground}>\n <View style={styles.errorIconBackground}>\n <Icon name=\"churchCenter.exclamationCircle\" size={18} color=\"red\" />\n </View>\n </View>\n )}\n </View>\n )\n}\n\ninterface Styles {\n width: DimensionValue\n height: DimensionValue\n borderRadius: AnimatableNumericValue | string\n}\n\nconst useStyles = ({ width, height, borderRadius }: Styles) => {\n const { colors } = useTheme()\n\n return StyleSheet.create({\n image: {\n backgroundColor: colors.fillColorNeutral070,\n width,\n height,\n borderRadius,\n },\n removeAttachmentIcon: {\n position: 'absolute',\n top: 4,\n right: 4,\n backgroundColor: 'rgba(255, 255, 255, 0.5)',\n borderRadius: 24,\n width: 24,\n height: 24,\n justifyContent: 'center',\n alignItems: 'center',\n },\n loadingBackground: {\n position: 'absolute',\n top: 0,\n left: 0,\n borderRadius,\n width,\n height,\n },\n errorBackground: {\n position: 'absolute',\n top: 0,\n left: 0,\n borderRadius,\n width,\n height,\n justifyContent: 'center',\n alignItems: 'center',\n },\n errorIconBackground: {\n backgroundColor: 'white',\n padding: 2,\n borderRadius: 50,\n },\n })\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"message_form.d.ts","sourceRoot":"","sources":["../../../src/components/conversation/message_form.tsx"],"names":[],"mappings":"AACA,OAAO,
|
|
1
|
+
{"version":3,"file":"message_form.d.ts","sourceRoot":"","sources":["../../../src/components/conversation/message_form.tsx"],"names":[],"mappings":"AACA,OAAO,KAAuD,MAAM,OAAO,CAAA;AAC3E,OAAO,EAA+B,SAAS,EAAE,MAAM,cAAc,CAAA;AAGrE,OAAO,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAA;AAYlD,eAAO,MAAM,WAAW;;;;;;CAMvB,CAAA;AAED,UAAU,qBAAsB,SAAQ,SAAS;IAC/C,YAAY,EAAE,oBAAoB,CAAA;CACnC;AAqBD,iBAAS,eAAe,CAAC,EAAE,YAAY,EAAE,QAAQ,EAAE,EAAE,qBAAqB,qBAkGzE;AAiCD,iBAAS,gBAAgB,sBA4BxB;AAED,iBAAS,oBAAoB,sBAe5B;AAED,iBAAS,2BAA2B,6BA8EnC;AAED,iBAAS,mBAAmB,6BA4B3B"}
|
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
import { useNavigation, useTheme as useNavigationTheme, useRoute } from '@react-navigation/native';
|
|
2
|
-
import React, { useContext, useEffect, useState } from 'react';
|
|
2
|
+
import React, { useCallback, useContext, useEffect, useState } from 'react';
|
|
3
3
|
import { StyleSheet, TextInput, View } from 'react-native';
|
|
4
4
|
import { IconButton, Text } from '../../components';
|
|
5
5
|
import { useTheme } from '../../hooks';
|
|
6
6
|
import { useMessageCreate } from '../../hooks/use_message_create';
|
|
7
7
|
import { ChatContext } from '../../contexts/chat_context';
|
|
8
|
+
import { ImagePicker } from '../../utils/native_adapters';
|
|
9
|
+
import { useAttachmentUploader } from '../../hooks/use_attachment_uploader';
|
|
10
|
+
import { MessageFormAttachmentImage } from './message_form/message_form_attachment_image';
|
|
8
11
|
export const MessageForm = {
|
|
9
12
|
Root: MessageFormRoot,
|
|
10
13
|
TextInput: MessageFormInput,
|
|
@@ -29,7 +32,19 @@ function MessageFormRoot({ conversation, children }) {
|
|
|
29
32
|
const [usingGiphy, setUsingGiphy] = useState(false);
|
|
30
33
|
const navigation = useNavigation();
|
|
31
34
|
const route = useRoute();
|
|
32
|
-
const { status, isPending, reset, mutate } = useMessageCreate({
|
|
35
|
+
const { status, isPending, reset: resetMutation, mutate, } = useMessageCreate({
|
|
36
|
+
conversationId: conversation.id,
|
|
37
|
+
});
|
|
38
|
+
const attachmentUploader = useAttachmentUploader({
|
|
39
|
+
conversationId: conversation.id,
|
|
40
|
+
});
|
|
41
|
+
const resetAttachmentUploader = attachmentUploader.reset;
|
|
42
|
+
const reset = useCallback(() => {
|
|
43
|
+
resetAttachmentUploader();
|
|
44
|
+
resetMutation();
|
|
45
|
+
setText('');
|
|
46
|
+
setUsingGiphy(false);
|
|
47
|
+
}, [resetAttachmentUploader, resetMutation]);
|
|
33
48
|
useEffect(() => {
|
|
34
49
|
if (canGiphy && !usingGiphy && text.startsWith('/giphy ')) {
|
|
35
50
|
setUsingGiphy(true);
|
|
@@ -39,23 +54,25 @@ function MessageFormRoot({ conversation, children }) {
|
|
|
39
54
|
useEffect(() => {
|
|
40
55
|
switch (status) {
|
|
41
56
|
case 'success':
|
|
42
|
-
setText('');
|
|
43
57
|
reset();
|
|
44
58
|
break;
|
|
45
59
|
}
|
|
46
60
|
}, [reset, status]);
|
|
47
61
|
useEffect(() => {
|
|
48
62
|
if (route.params.clear_input) {
|
|
49
|
-
|
|
50
|
-
setUsingGiphy(false);
|
|
63
|
+
reset();
|
|
51
64
|
navigation.setParams({ ...route.params, clear_input: false });
|
|
52
65
|
}
|
|
53
|
-
}, [navigation, route.params]);
|
|
66
|
+
}, [reset, navigation, route.params]);
|
|
54
67
|
const canSubmit = (() => {
|
|
55
68
|
if (isPending)
|
|
56
69
|
return false;
|
|
70
|
+
if (attachmentUploader?.pendingUploads)
|
|
71
|
+
return false;
|
|
57
72
|
if (text.length > 0)
|
|
58
73
|
return true;
|
|
74
|
+
if (attachmentUploader?.attachments?.length)
|
|
75
|
+
return true;
|
|
59
76
|
return false;
|
|
60
77
|
})();
|
|
61
78
|
const disabled = !canSubmit;
|
|
@@ -70,7 +87,14 @@ function MessageFormRoot({ conversation, children }) {
|
|
|
70
87
|
});
|
|
71
88
|
}
|
|
72
89
|
else {
|
|
73
|
-
|
|
90
|
+
let attachmentsForSubmit = [];
|
|
91
|
+
if (attachmentUploader?.attachmentIds) {
|
|
92
|
+
attachmentsForSubmit = attachmentUploader.attachmentIds.map((id) => ({
|
|
93
|
+
type: 'MessageAttachment',
|
|
94
|
+
id,
|
|
95
|
+
}));
|
|
96
|
+
}
|
|
97
|
+
mutate({ text, attachments: attachmentsForSubmit });
|
|
74
98
|
}
|
|
75
99
|
};
|
|
76
100
|
return (<MessageFormContext.Provider value={{
|
|
@@ -81,19 +105,42 @@ function MessageFormRoot({ conversation, children }) {
|
|
|
81
105
|
canGiphy,
|
|
82
106
|
usingGiphy,
|
|
83
107
|
setUsingGiphy,
|
|
108
|
+
attachmentUploader,
|
|
84
109
|
}}>
|
|
85
110
|
<View style={styles.textInputContainer}>{children}</View>
|
|
86
111
|
</MessageFormContext.Provider>);
|
|
87
112
|
}
|
|
113
|
+
function MessageFormAttachments() {
|
|
114
|
+
const styles = useMessageFormStyles();
|
|
115
|
+
const { attachmentUploader } = React.useContext(MessageFormContext);
|
|
116
|
+
const numberOfAttachments = attachmentUploader?.attachments?.length || 0;
|
|
117
|
+
const attachments = attachmentUploader?.attachments || [];
|
|
118
|
+
if (numberOfAttachments === 0) {
|
|
119
|
+
return null;
|
|
120
|
+
}
|
|
121
|
+
return (<View style={styles.messageFormAttachments}>
|
|
122
|
+
{attachments.map(attachment => {
|
|
123
|
+
return (<MessageFormAttachmentImage key={attachment.file.uri} uri={attachment.file.uri} alt={attachment.file.name} status={attachment.status} width={attachment.file.width} height={attachment.file.height} removeAttachment={() => {
|
|
124
|
+
attachmentUploader?.removeAttachment(attachment);
|
|
125
|
+
}}/>);
|
|
126
|
+
})}
|
|
127
|
+
</View>);
|
|
128
|
+
}
|
|
88
129
|
function MessageFormInput() {
|
|
89
130
|
const styles = useMessageFormStyles();
|
|
90
|
-
const { text, setText, onSubmit, usingGiphy } = React.useContext(MessageFormContext);
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
131
|
+
const { text, setText, onSubmit, usingGiphy, attachmentUploader } = React.useContext(MessageFormContext);
|
|
132
|
+
const attachmentError = attachmentUploader?.errorMessage;
|
|
133
|
+
return (<View style={styles.textInputBoundary}>
|
|
134
|
+
<MessageFormAttachments />
|
|
135
|
+
<View style={styles.textInput}>
|
|
136
|
+
{usingGiphy ? (<View style={styles.giphyBadge}>
|
|
137
|
+
<Text>/Giphy</Text>
|
|
138
|
+
</View>) : null}
|
|
95
139
|
|
|
96
|
-
|
|
140
|
+
<TextInput aria-disabled={true} placeholder="Send a message" onChangeText={setText} value={text} onSubmitEditing={onSubmit}/>
|
|
141
|
+
</View>
|
|
142
|
+
|
|
143
|
+
{attachmentError ? <Text style={styles.inputErrorMessage}>{attachmentError}</Text> : null}
|
|
97
144
|
</View>);
|
|
98
145
|
}
|
|
99
146
|
function MessageFormSubmitBtn() {
|
|
@@ -102,11 +149,55 @@ function MessageFormSubmitBtn() {
|
|
|
102
149
|
return (<IconButton disabled={disabled} accessibilityLabel={usingGiphy ? 'Search Giphy' : 'Send message'} size="md" appearance="neutral" style={styles.textInputSend} name={usingGiphy ? 'general.search' : 'general.upArrow'} onPress={onSubmit}/>);
|
|
103
150
|
}
|
|
104
151
|
function MessageFormAttachmentPicker() {
|
|
105
|
-
const
|
|
152
|
+
const styles = useMessageFormStyles();
|
|
153
|
+
const { usingGiphy, attachmentUploader } = React.useContext(MessageFormContext);
|
|
154
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
155
|
+
function uploadImagePickerResult(result) {
|
|
156
|
+
if (result.canceled) {
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
const filteredAssets = result.assets
|
|
160
|
+
.filter(asset => {
|
|
161
|
+
return asset.fileSize && asset.fileName && asset.mimeType;
|
|
162
|
+
})
|
|
163
|
+
.map(asset => {
|
|
164
|
+
return {
|
|
165
|
+
uri: asset.uri,
|
|
166
|
+
name: asset.fileName,
|
|
167
|
+
type: asset.mimeType,
|
|
168
|
+
size: asset.fileSize,
|
|
169
|
+
height: asset.height,
|
|
170
|
+
width: asset.width,
|
|
171
|
+
};
|
|
172
|
+
});
|
|
173
|
+
attachmentUploader?.handleFilesAttached(filteredAssets);
|
|
174
|
+
}
|
|
175
|
+
const openCamera = async () => {
|
|
176
|
+
setIsOpen(false);
|
|
177
|
+
let result = await ImagePicker.openCameraAsync();
|
|
178
|
+
if (!result.canceled) {
|
|
179
|
+
uploadImagePickerResult(result);
|
|
180
|
+
}
|
|
181
|
+
};
|
|
182
|
+
const pickImage = async () => {
|
|
183
|
+
setIsOpen(false);
|
|
184
|
+
let result = await ImagePicker.openImageLibraryAsync();
|
|
185
|
+
if (!result.canceled) {
|
|
186
|
+
uploadImagePickerResult(result);
|
|
187
|
+
}
|
|
188
|
+
};
|
|
106
189
|
if (usingGiphy) {
|
|
107
190
|
return null;
|
|
108
191
|
}
|
|
109
|
-
return (
|
|
192
|
+
return (
|
|
193
|
+
// TODO: Design Pass
|
|
194
|
+
<View style={styles.attachmentPicker}>
|
|
195
|
+
{isOpen && (<View style={styles.attachmentPickerButtons}>
|
|
196
|
+
<IconButton accessibilityLabel="Take a photo" size="md" appearance="neutral" name={'general.videoCamera'} onPress={openCamera}/>
|
|
197
|
+
<IconButton accessibilityLabel="Choose a photo" size="md" appearance="neutral" name={'churchCenter.photosIos'} onPress={pickImage}/>
|
|
198
|
+
</View>)}
|
|
199
|
+
<IconButton accessibilityLabel="File Menu" size="md" appearance="neutral" name={'general.outlinedPlusCircle'} onPress={() => setIsOpen(!isOpen)}/>
|
|
200
|
+
</View>);
|
|
110
201
|
}
|
|
111
202
|
function MessageFormCommands() {
|
|
112
203
|
const { canGiphy, usingGiphy, setUsingGiphy } = React.useContext(MessageFormContext);
|
|
@@ -131,13 +222,16 @@ const useMessageFormStyles = () => {
|
|
|
131
222
|
alignItems: 'center',
|
|
132
223
|
gap: 12,
|
|
133
224
|
},
|
|
134
|
-
|
|
225
|
+
textInputBoundary: {
|
|
135
226
|
borderRadius: 24,
|
|
136
227
|
borderWidth: 1,
|
|
137
228
|
padding: 12,
|
|
138
229
|
paddingHorizontal: 20,
|
|
139
230
|
borderColor: theme.colors.fillColorNeutral050Base,
|
|
140
231
|
flex: 1,
|
|
232
|
+
gap: 12,
|
|
233
|
+
},
|
|
234
|
+
textInput: {
|
|
141
235
|
flexDirection: 'row',
|
|
142
236
|
gap: 12,
|
|
143
237
|
},
|
|
@@ -152,6 +246,24 @@ const useMessageFormStyles = () => {
|
|
|
152
246
|
height: 36,
|
|
153
247
|
width: 36,
|
|
154
248
|
},
|
|
249
|
+
attachmentPicker: {
|
|
250
|
+
position: 'relative',
|
|
251
|
+
},
|
|
252
|
+
attachmentPickerButtons: {
|
|
253
|
+
position: 'absolute',
|
|
254
|
+
left: 0,
|
|
255
|
+
bottom: 40,
|
|
256
|
+
zIndex: 10,
|
|
257
|
+
gap: 16,
|
|
258
|
+
},
|
|
259
|
+
messageFormAttachments: {
|
|
260
|
+
flexDirection: 'row',
|
|
261
|
+
gap: 8,
|
|
262
|
+
},
|
|
263
|
+
inputErrorMessage: {
|
|
264
|
+
color: theme.colors.statusErrorText,
|
|
265
|
+
fontSize: 14,
|
|
266
|
+
},
|
|
155
267
|
});
|
|
156
268
|
};
|
|
157
269
|
//# sourceMappingURL=message_form.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"message_form.js","sourceRoot":"","sources":["../../../src/components/conversation/message_form.tsx"],"names":[],"mappings":"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","sourcesContent":["import { useNavigation, useTheme as useNavigationTheme, useRoute } from '@react-navigation/native'\nimport React, { useContext, useEffect, useState } from 'react'\nimport { StyleSheet, TextInput, View, ViewProps } from 'react-native'\nimport { IconButton, Text } from '../../components'\nimport { useTheme } from '../../hooks'\nimport { ConversationResource } from '../../types'\nimport { useMessageCreate } from '../../hooks/use_message_create'\nimport { ConversationScreenProps } from '../../screens/conversation_screen'\nimport { ChatContext } from '../../contexts/chat_context'\n\nexport const MessageForm = {\n Root: MessageFormRoot,\n TextInput: MessageFormInput,\n SubmitButton: MessageFormSubmitBtn,\n AttachmentPicker: MessageFormAttachmentPicker,\n Commands: MessageFormCommands,\n}\n\ninterface MessagesFormRootProps extends ViewProps {\n conversation: ConversationResource\n}\n\nconst MessageFormContext = React.createContext({\n text: '',\n setText: (_text: string) => {},\n onSubmit: () => {},\n disabled: false,\n canGiphy: false,\n usingGiphy: false,\n setUsingGiphy: (_usingGiphy: boolean) => {},\n})\n\nfunction MessageFormRoot({ conversation, children }: MessagesFormRootProps) {\n const { giphyApiKey } = useContext(ChatContext)\n const canGiphy = !!giphyApiKey\n const styles = useMessageFormStyles()\n const [text, setText] = React.useState('')\n const [usingGiphy, setUsingGiphy] = useState(false)\n const navigation = useNavigation()\n const route = useRoute() as ConversationScreenProps['route']\n const { status, isPending, reset, mutate } = useMessageCreate({ conversationId: conversation.id })\n\n useEffect(() => {\n if (canGiphy && !usingGiphy && text.startsWith('/giphy ')) {\n setUsingGiphy(true)\n setText('')\n }\n }, [canGiphy, text, usingGiphy])\n\n useEffect(() => {\n switch (status) {\n case 'success':\n setText('')\n reset()\n break\n }\n }, [reset, status])\n\n useEffect(() => {\n if (route.params.clear_input) {\n setText('')\n setUsingGiphy(false)\n navigation.setParams({ ...route.params, clear_input: false })\n }\n }, [navigation, route.params])\n\n const canSubmit = (() => {\n if (isPending) return false\n if (text.length > 0) return true\n return false\n })()\n const disabled = !canSubmit\n\n const handleSubmit = () => {\n if (!canSubmit) return\n\n if (canGiphy && usingGiphy) {\n TextInput.State.blurTextInput(TextInput.State.currentlyFocusedInput())\n navigation.navigate('SendGiphy', {\n conversation_id: conversation.id,\n search_term: text,\n })\n } else {\n mutate({ text })\n }\n }\n\n return (\n <MessageFormContext.Provider\n value={{\n text,\n setText,\n onSubmit: handleSubmit,\n disabled,\n canGiphy,\n usingGiphy,\n setUsingGiphy,\n }}\n >\n <View style={styles.textInputContainer}>{children}</View>\n </MessageFormContext.Provider>\n )\n}\n\nfunction MessageFormInput() {\n const styles = useMessageFormStyles()\n const { text, setText, onSubmit, usingGiphy } = React.useContext(MessageFormContext)\n\n return (\n <View style={styles.textInput}>\n {usingGiphy ? (\n <View style={styles.giphyBadge}>\n <Text>/Giphy</Text>\n </View>\n ) : null}\n\n <TextInput\n aria-disabled={true}\n placeholder=\"Send a message\"\n onChangeText={setText}\n value={text}\n onSubmitEditing={onSubmit}\n />\n </View>\n )\n}\n\nfunction MessageFormSubmitBtn() {\n const styles = useMessageFormStyles()\n const { onSubmit, disabled, usingGiphy } = React.useContext(MessageFormContext)\n\n return (\n <IconButton\n disabled={disabled}\n accessibilityLabel={usingGiphy ? 'Search Giphy' : 'Send message'}\n size=\"md\"\n appearance=\"neutral\"\n style={styles.textInputSend}\n name={usingGiphy ? 'general.search' : 'general.upArrow'}\n onPress={onSubmit}\n />\n )\n}\n\nfunction MessageFormAttachmentPicker() {\n const { usingGiphy } = React.useContext(MessageFormContext)\n\n if (usingGiphy) {\n return null\n }\n\n return (\n <IconButton\n accessibilityLabel=\"Shazam\"\n size=\"md\"\n appearance=\"neutral\"\n name={'general.paperclip'}\n />\n )\n}\n\nfunction MessageFormCommands() {\n const { canGiphy, usingGiphy, setUsingGiphy } = React.useContext(MessageFormContext)\n\n if (!canGiphy) {\n return null\n }\n\n if (usingGiphy) {\n return (\n <IconButton\n accessibilityLabel=\"Exit Giphy Search\"\n size=\"md\"\n appearance=\"neutral\"\n name={'general.x'}\n onPress={() => setUsingGiphy(false)}\n />\n )\n }\n\n return (\n <IconButton\n accessibilityLabel=\"Search Giphy\"\n size=\"md\"\n appearance=\"neutral\"\n name={'general.bolt'}\n onPress={() => setUsingGiphy(true)}\n />\n )\n}\n\nconst useMessageFormStyles = () => {\n const theme = useTheme()\n const navigationTheme = useNavigationTheme()\n\n return StyleSheet.create({\n textInputContainer: {\n borderColor: theme.colors.fillColorNeutral050Base,\n borderTopWidth: 1,\n padding: 12,\n backgroundColor: navigationTheme.colors.card,\n flexDirection: 'row',\n alignItems: 'center',\n gap: 12,\n },\n textInput: {\n borderRadius: 24,\n borderWidth: 1,\n padding: 12,\n paddingHorizontal: 20,\n borderColor: theme.colors.fillColorNeutral050Base,\n flex: 1,\n flexDirection: 'row',\n gap: 12,\n },\n giphyBadge: {\n backgroundColor: theme.colors.fillColorNeutral050Base,\n borderRadius: 24,\n padding: 8,\n paddingHorizontal: 12,\n },\n textInputSend: {\n borderRadius: 24,\n height: 36,\n width: 36,\n },\n })\n}\n"]}
|
|
1
|
+
{"version":3,"file":"message_form.js","sourceRoot":"","sources":["../../../src/components/conversation/message_form.tsx"],"names":[],"mappings":"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","sourcesContent":["import { useNavigation, useTheme as useNavigationTheme, useRoute } from '@react-navigation/native'\nimport React, { useCallback, useContext, useEffect, useState } from 'react'\nimport { StyleSheet, TextInput, View, ViewProps } from 'react-native'\nimport { IconButton, Text } from '../../components'\nimport { useTheme } from '../../hooks'\nimport { ConversationResource } from '../../types'\nimport { useMessageCreate } from '../../hooks/use_message_create'\nimport { ConversationScreenProps } from '../../screens/conversation_screen'\nimport { ChatContext } from '../../contexts/chat_context'\nimport { ImagePicker, ImagePickerResult } from '../../utils/native_adapters'\nimport { useAttachmentUploader } from '../../hooks/use_attachment_uploader'\nimport {\n DenormalizedAttachmentResourceForCreate,\n DenormalizedMessageAttachmentResourceForCreate,\n} from '../../types/resources/denormalized_attachment_resource'\nimport { MessageFormAttachmentImage } from './message_form/message_form_attachment_image'\n\nexport const MessageForm = {\n Root: MessageFormRoot,\n TextInput: MessageFormInput,\n SubmitButton: MessageFormSubmitBtn,\n AttachmentPicker: MessageFormAttachmentPicker,\n Commands: MessageFormCommands,\n}\n\ninterface MessagesFormRootProps extends ViewProps {\n conversation: ConversationResource\n}\n\nconst MessageFormContext = React.createContext<{\n text: string\n setText: (text: string) => void\n onSubmit: () => void\n disabled: boolean\n canGiphy: boolean\n usingGiphy: boolean\n setUsingGiphy: (usingGiphy: boolean) => void\n attachmentUploader?: ReturnType<typeof useAttachmentUploader>\n}>({\n text: '',\n setText: (_text: string) => {},\n onSubmit: () => {},\n disabled: false,\n canGiphy: false,\n usingGiphy: false,\n setUsingGiphy: (_usingGiphy: boolean) => {},\n})\n\nfunction MessageFormRoot({ conversation, children }: MessagesFormRootProps) {\n const { giphyApiKey } = useContext(ChatContext)\n const canGiphy = !!giphyApiKey\n const styles = useMessageFormStyles()\n const [text, setText] = React.useState('')\n const [usingGiphy, setUsingGiphy] = useState(false)\n const navigation = useNavigation()\n const route = useRoute() as ConversationScreenProps['route']\n const {\n status,\n isPending,\n reset: resetMutation,\n mutate,\n } = useMessageCreate({\n conversationId: conversation.id,\n })\n const attachmentUploader = useAttachmentUploader({\n conversationId: conversation.id,\n })\n const resetAttachmentUploader = attachmentUploader.reset\n\n const reset = useCallback(() => {\n resetAttachmentUploader()\n resetMutation()\n setText('')\n setUsingGiphy(false)\n }, [resetAttachmentUploader, resetMutation])\n\n useEffect(() => {\n if (canGiphy && !usingGiphy && text.startsWith('/giphy ')) {\n setUsingGiphy(true)\n setText('')\n }\n }, [canGiphy, text, usingGiphy])\n\n useEffect(() => {\n switch (status) {\n case 'success':\n reset()\n break\n }\n }, [reset, status])\n\n useEffect(() => {\n if (route.params.clear_input) {\n reset()\n navigation.setParams({ ...route.params, clear_input: false })\n }\n }, [reset, navigation, route.params])\n\n const canSubmit = (() => {\n if (isPending) return false\n if (attachmentUploader?.pendingUploads) return false\n if (text.length > 0) return true\n if (attachmentUploader?.attachments?.length) return true\n return false\n })()\n const disabled = !canSubmit\n\n const handleSubmit = () => {\n if (!canSubmit) return\n\n if (canGiphy && usingGiphy) {\n TextInput.State.blurTextInput(TextInput.State.currentlyFocusedInput())\n navigation.navigate('SendGiphy', {\n conversation_id: conversation.id,\n search_term: text,\n })\n } else {\n let attachmentsForSubmit: DenormalizedAttachmentResourceForCreate[] = []\n if (attachmentUploader?.attachmentIds) {\n attachmentsForSubmit = attachmentUploader.attachmentIds.map(\n (id: string): DenormalizedMessageAttachmentResourceForCreate => ({\n type: 'MessageAttachment',\n id,\n })\n )\n }\n mutate({ text, attachments: attachmentsForSubmit })\n }\n }\n\n return (\n <MessageFormContext.Provider\n value={{\n text,\n setText,\n onSubmit: handleSubmit,\n disabled,\n canGiphy,\n usingGiphy,\n setUsingGiphy,\n attachmentUploader,\n }}\n >\n <View style={styles.textInputContainer}>{children}</View>\n </MessageFormContext.Provider>\n )\n}\n\nfunction MessageFormAttachments() {\n const styles = useMessageFormStyles()\n const { attachmentUploader } = React.useContext(MessageFormContext)\n const numberOfAttachments = attachmentUploader?.attachments?.length || 0\n const attachments = attachmentUploader?.attachments || []\n\n if (numberOfAttachments === 0) {\n return null\n }\n\n return (\n <View style={styles.messageFormAttachments}>\n {attachments.map(attachment => {\n return (\n <MessageFormAttachmentImage\n key={attachment.file.uri}\n uri={attachment.file.uri}\n alt={attachment.file.name}\n status={attachment.status}\n width={attachment.file.width}\n height={attachment.file.height}\n removeAttachment={() => {\n attachmentUploader?.removeAttachment(attachment)\n }}\n />\n )\n })}\n </View>\n )\n}\n\nfunction MessageFormInput() {\n const styles = useMessageFormStyles()\n const { text, setText, onSubmit, usingGiphy, attachmentUploader } =\n React.useContext(MessageFormContext)\n const attachmentError = attachmentUploader?.errorMessage\n\n return (\n <View style={styles.textInputBoundary}>\n <MessageFormAttachments />\n <View style={styles.textInput}>\n {usingGiphy ? (\n <View style={styles.giphyBadge}>\n <Text>/Giphy</Text>\n </View>\n ) : null}\n\n <TextInput\n aria-disabled={true}\n placeholder=\"Send a message\"\n onChangeText={setText}\n value={text}\n onSubmitEditing={onSubmit}\n />\n </View>\n\n {attachmentError ? <Text style={styles.inputErrorMessage}>{attachmentError}</Text> : null}\n </View>\n )\n}\n\nfunction MessageFormSubmitBtn() {\n const styles = useMessageFormStyles()\n const { onSubmit, disabled, usingGiphy } = React.useContext(MessageFormContext)\n\n return (\n <IconButton\n disabled={disabled}\n accessibilityLabel={usingGiphy ? 'Search Giphy' : 'Send message'}\n size=\"md\"\n appearance=\"neutral\"\n style={styles.textInputSend}\n name={usingGiphy ? 'general.search' : 'general.upArrow'}\n onPress={onSubmit}\n />\n )\n}\n\nfunction MessageFormAttachmentPicker() {\n const styles = useMessageFormStyles()\n const { usingGiphy, attachmentUploader } = React.useContext(MessageFormContext)\n const [isOpen, setIsOpen] = useState(false)\n\n function uploadImagePickerResult(result: ImagePickerResult) {\n if (result.canceled) {\n return\n }\n\n const filteredAssets = result.assets\n .filter(asset => {\n return asset.fileSize && asset.fileName && asset.mimeType\n })\n .map(asset => {\n return {\n uri: asset.uri,\n name: asset.fileName as string,\n type: asset.mimeType as string,\n size: asset.fileSize as number,\n height: asset.height,\n width: asset.width,\n }\n })\n\n attachmentUploader?.handleFilesAttached(filteredAssets)\n }\n\n const openCamera = async () => {\n setIsOpen(false)\n let result = await ImagePicker.openCameraAsync()\n if (!result.canceled) {\n uploadImagePickerResult(result)\n }\n }\n\n const pickImage = async () => {\n setIsOpen(false)\n let result = await ImagePicker.openImageLibraryAsync()\n if (!result.canceled) {\n uploadImagePickerResult(result)\n }\n }\n\n if (usingGiphy) {\n return null\n }\n\n return (\n // TODO: Design Pass\n <View style={styles.attachmentPicker}>\n {isOpen && (\n <View style={styles.attachmentPickerButtons}>\n <IconButton\n accessibilityLabel=\"Take a photo\"\n size=\"md\"\n appearance=\"neutral\"\n name={'general.videoCamera'}\n onPress={openCamera}\n />\n <IconButton\n accessibilityLabel=\"Choose a photo\"\n size=\"md\"\n appearance=\"neutral\"\n name={'churchCenter.photosIos'}\n onPress={pickImage}\n />\n </View>\n )}\n <IconButton\n accessibilityLabel=\"File Menu\"\n size=\"md\"\n appearance=\"neutral\"\n name={'general.outlinedPlusCircle'}\n onPress={() => setIsOpen(!isOpen)}\n />\n </View>\n )\n}\n\nfunction MessageFormCommands() {\n const { canGiphy, usingGiphy, setUsingGiphy } = React.useContext(MessageFormContext)\n\n if (!canGiphy) {\n return null\n }\n\n if (usingGiphy) {\n return (\n <IconButton\n accessibilityLabel=\"Exit Giphy Search\"\n size=\"md\"\n appearance=\"neutral\"\n name={'general.x'}\n onPress={() => setUsingGiphy(false)}\n />\n )\n }\n\n return (\n <IconButton\n accessibilityLabel=\"Search Giphy\"\n size=\"md\"\n appearance=\"neutral\"\n name={'general.bolt'}\n onPress={() => setUsingGiphy(true)}\n />\n )\n}\n\nconst useMessageFormStyles = () => {\n const theme = useTheme()\n const navigationTheme = useNavigationTheme()\n\n return StyleSheet.create({\n textInputContainer: {\n borderColor: theme.colors.fillColorNeutral050Base,\n borderTopWidth: 1,\n padding: 12,\n backgroundColor: navigationTheme.colors.card,\n flexDirection: 'row',\n alignItems: 'center',\n gap: 12,\n },\n textInputBoundary: {\n borderRadius: 24,\n borderWidth: 1,\n padding: 12,\n paddingHorizontal: 20,\n borderColor: theme.colors.fillColorNeutral050Base,\n flex: 1,\n gap: 12,\n },\n textInput: {\n flexDirection: 'row',\n gap: 12,\n },\n giphyBadge: {\n backgroundColor: theme.colors.fillColorNeutral050Base,\n borderRadius: 24,\n padding: 8,\n paddingHorizontal: 12,\n },\n textInputSend: {\n borderRadius: 24,\n height: 36,\n width: 36,\n },\n attachmentPicker: {\n position: 'relative',\n },\n attachmentPickerButtons: {\n position: 'absolute',\n left: 0,\n bottom: 40,\n zIndex: 10,\n gap: 16,\n },\n messageFormAttachments: {\n flexDirection: 'row',\n gap: 8,\n },\n inputErrorMessage: {\n color: theme.colors.statusErrorText,\n fontSize: 14,\n },\n })\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"supported_extensions.d.ts","sourceRoot":"","sources":["../../../src/hooks/attachments/supported_extensions.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,oBAAoB,UA8ChC,CAAA"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
export const SUPPORTED_EXTENSIONS = [
|
|
2
|
+
'.3ga',
|
|
3
|
+
'.3gp',
|
|
4
|
+
'.aac',
|
|
5
|
+
'.amr',
|
|
6
|
+
'.avi',
|
|
7
|
+
'.bmp',
|
|
8
|
+
'.doc',
|
|
9
|
+
'.docx',
|
|
10
|
+
'.gif',
|
|
11
|
+
'.h263',
|
|
12
|
+
'.h264',
|
|
13
|
+
'.heic',
|
|
14
|
+
'.heif',
|
|
15
|
+
'.jpeg',
|
|
16
|
+
'.jpg',
|
|
17
|
+
'.key',
|
|
18
|
+
'.m4a',
|
|
19
|
+
'.m4b',
|
|
20
|
+
'.m4p',
|
|
21
|
+
'.m4r',
|
|
22
|
+
'.m4v',
|
|
23
|
+
'.mkv',
|
|
24
|
+
'.mov',
|
|
25
|
+
'.mp3',
|
|
26
|
+
'.mp4',
|
|
27
|
+
'.mp4-latm',
|
|
28
|
+
'.mpeg',
|
|
29
|
+
'.mpeg4',
|
|
30
|
+
'.mpg',
|
|
31
|
+
'.numbers',
|
|
32
|
+
'.ogg',
|
|
33
|
+
'.pages',
|
|
34
|
+
'.pdf',
|
|
35
|
+
'.png',
|
|
36
|
+
'.ppt',
|
|
37
|
+
'.pptx',
|
|
38
|
+
'.rtf',
|
|
39
|
+
'.txt',
|
|
40
|
+
'.vcf',
|
|
41
|
+
'.wav',
|
|
42
|
+
'.webm',
|
|
43
|
+
'.webp',
|
|
44
|
+
'.wmv',
|
|
45
|
+
'.xls',
|
|
46
|
+
'.xlsx',
|
|
47
|
+
];
|
|
48
|
+
//# sourceMappingURL=supported_extensions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"supported_extensions.js","sourceRoot":"","sources":["../../../src/hooks/attachments/supported_extensions.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,oBAAoB,GAAG;IAClC,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,OAAO;IACP,MAAM;IACN,OAAO;IACP,OAAO;IACP,OAAO;IACP,OAAO;IACP,OAAO;IACP,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,WAAW;IACX,OAAO;IACP,QAAQ;IACR,MAAM;IACN,UAAU;IACV,MAAM;IACN,QAAQ;IACR,MAAM;IACN,MAAM;IACN,MAAM;IACN,OAAO;IACP,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,OAAO;IACP,OAAO;IACP,MAAM;IACN,MAAM;IACN,OAAO;CACR,CAAA","sourcesContent":["export const SUPPORTED_EXTENSIONS = [\n '.3ga',\n '.3gp',\n '.aac',\n '.amr',\n '.avi',\n '.bmp',\n '.doc',\n '.docx',\n '.gif',\n '.h263',\n '.h264',\n '.heic',\n '.heif',\n '.jpeg',\n '.jpg',\n '.key',\n '.m4a',\n '.m4b',\n '.m4p',\n '.m4r',\n '.m4v',\n '.mkv',\n '.mov',\n '.mp3',\n '.mp4',\n '.mp4-latm',\n '.mpeg',\n '.mpeg4',\n '.mpg',\n '.numbers',\n '.ogg',\n '.pages',\n '.pdf',\n '.png',\n '.ppt',\n '.pptx',\n '.rtf',\n '.txt',\n '.vcf',\n '.wav',\n '.webm',\n '.webp',\n '.wmv',\n '.xls',\n '.xlsx',\n]\n"]}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { FileForUploadClient } from './use_upload_client';
|
|
2
|
+
type AttachmentStatus = 'uploading' | 'success' | 'error';
|
|
3
|
+
interface AttachmentFile extends FileForUploadClient {
|
|
4
|
+
size: number;
|
|
5
|
+
width?: number;
|
|
6
|
+
height?: number;
|
|
7
|
+
}
|
|
8
|
+
export interface FileAttachment {
|
|
9
|
+
id?: string;
|
|
10
|
+
file: AttachmentFile;
|
|
11
|
+
status: AttachmentStatus;
|
|
12
|
+
}
|
|
13
|
+
export declare function useAttachmentUploader({ conversationId }: {
|
|
14
|
+
conversationId: number;
|
|
15
|
+
}): {
|
|
16
|
+
attachments: FileAttachment[];
|
|
17
|
+
attachmentIds: string[];
|
|
18
|
+
handleFilesAttached: (files: AttachmentFile[]) => void;
|
|
19
|
+
removeAttachment: (attachment: FileAttachment) => void;
|
|
20
|
+
reset: () => void;
|
|
21
|
+
pendingUploads: boolean;
|
|
22
|
+
errorMessage: string | null;
|
|
23
|
+
remainingAttachable: number;
|
|
24
|
+
};
|
|
25
|
+
export {};
|
|
26
|
+
//# sourceMappingURL=use_attachment_uploader.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use_attachment_uploader.d.ts","sourceRoot":"","sources":["../../src/hooks/use_attachment_uploader.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,mBAAmB,EAAmB,MAAM,qBAAqB,CAAA;AAI1E,KAAK,gBAAgB,GAAG,WAAW,GAAG,SAAS,GAAG,OAAO,CAAA;AAEzD,UAAU,cAAe,SAAQ,mBAAmB;IAClD,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB;AAED,MAAM,WAAW,cAAc;IAC7B,EAAE,CAAC,EAAE,MAAM,CAAA;IACX,IAAI,EAAE,cAAc,CAAA;IACpB,MAAM,EAAE,gBAAgB,CAAA;CACzB;AAkBD,wBAAgB,qBAAqB,CAAC,EAAE,cAAc,EAAE,EAAE;IAAE,cAAc,EAAE,MAAM,CAAA;CAAE;;;iCAUxE,cAAc,EAAE;mCA4FwB,cAAc;;;;;EA4BjE"}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
2
|
+
import { SUPPORTED_EXTENSIONS } from './attachments/supported_extensions';
|
|
3
|
+
import { useUploadClient } from './use_upload_client';
|
|
4
|
+
import { useApiClient } from './use_api_client';
|
|
5
|
+
const MAX_FILE_SIZE_IN_MB = 50;
|
|
6
|
+
const MAX_FILE_SIZE_IN_BYTES = MAX_FILE_SIZE_IN_MB * 1024 * 1024;
|
|
7
|
+
const MAX_NUMBER_OF_ATTACHMENTS = 10;
|
|
8
|
+
export function useAttachmentUploader({ conversationId }) {
|
|
9
|
+
const apiClient = useApiClient();
|
|
10
|
+
const uploadApi = useUploadClient();
|
|
11
|
+
const [attachments, setAttachments] = useState([]);
|
|
12
|
+
const uploadState = useRef({});
|
|
13
|
+
const [lastUploadId, setLastUploadId] = useState();
|
|
14
|
+
const numberOfAttachments = attachments.length;
|
|
15
|
+
const [errorMessage, setErrorMessage] = useState(null);
|
|
16
|
+
const handleFilesAttached = useCallback((files) => {
|
|
17
|
+
const fileErrors = {};
|
|
18
|
+
const validFiles = files.filter(file => {
|
|
19
|
+
const extension = file.name.split('.').pop();
|
|
20
|
+
const isValidExtension = SUPPORTED_EXTENSIONS.includes(`.${extension}`);
|
|
21
|
+
const isValidFileSize = file.size <= MAX_FILE_SIZE_IN_BYTES;
|
|
22
|
+
if (!isValidExtension) {
|
|
23
|
+
fileErrors.file_type ||= [];
|
|
24
|
+
fileErrors.file_type.push(extension);
|
|
25
|
+
}
|
|
26
|
+
if (!isValidFileSize) {
|
|
27
|
+
fileErrors.file_size = true;
|
|
28
|
+
}
|
|
29
|
+
return isValidFileSize && isValidExtension;
|
|
30
|
+
});
|
|
31
|
+
const errorMessages = [];
|
|
32
|
+
if (fileErrors.file_type) {
|
|
33
|
+
errorMessages.push(`The following file types are not supported: ${fileErrors.file_type.join(', ')}`);
|
|
34
|
+
}
|
|
35
|
+
if (fileErrors.file_size) {
|
|
36
|
+
errorMessages.push(`File size exceeds ${MAX_FILE_SIZE_IN_MB} MB`);
|
|
37
|
+
}
|
|
38
|
+
if (numberOfAttachments + validFiles.length > MAX_NUMBER_OF_ATTACHMENTS) {
|
|
39
|
+
errorMessages.push(`You can't attach more than ${MAX_NUMBER_OF_ATTACHMENTS} files at once.`);
|
|
40
|
+
}
|
|
41
|
+
if (errorMessages.length > 0) {
|
|
42
|
+
setErrorMessage(errorMessages.join('\n'));
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
const newAttachments = validFiles.map(file => ({
|
|
46
|
+
file,
|
|
47
|
+
status: 'uploading',
|
|
48
|
+
}));
|
|
49
|
+
if (newAttachments && newAttachments.length > 0) {
|
|
50
|
+
setAttachments(prevAttachments => [...prevAttachments, ...newAttachments]);
|
|
51
|
+
newAttachments.forEach(attachment => {
|
|
52
|
+
uploadApi
|
|
53
|
+
.uploadFile(attachment.file)
|
|
54
|
+
.then(({ id: uploadedFileId }) => apiClient.chat.post({
|
|
55
|
+
url: `/me/conversations/${conversationId}/message_attachments`,
|
|
56
|
+
data: {
|
|
57
|
+
data: {
|
|
58
|
+
type: 'MessageAttachment',
|
|
59
|
+
attributes: { uploaded_file_id: uploadedFileId },
|
|
60
|
+
},
|
|
61
|
+
},
|
|
62
|
+
}))
|
|
63
|
+
.then(({ data: { id: messageAttachmentId } }) => {
|
|
64
|
+
uploadState.current[attachment.file.name] = {
|
|
65
|
+
status: 'success',
|
|
66
|
+
id: messageAttachmentId,
|
|
67
|
+
};
|
|
68
|
+
setLastUploadId(messageAttachmentId);
|
|
69
|
+
})
|
|
70
|
+
.catch(() => {
|
|
71
|
+
uploadState.current[attachment.file.name] = {
|
|
72
|
+
status: 'error',
|
|
73
|
+
};
|
|
74
|
+
setLastUploadId(attachment.file.name);
|
|
75
|
+
});
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
}, [numberOfAttachments, uploadApi, apiClient.chat, conversationId]);
|
|
79
|
+
useEffect(() => {
|
|
80
|
+
if (!lastUploadId)
|
|
81
|
+
return;
|
|
82
|
+
setLastUploadId(undefined);
|
|
83
|
+
setAttachments(attachments.map(attachment => {
|
|
84
|
+
const state = uploadState.current[attachment.file.name];
|
|
85
|
+
if (state) {
|
|
86
|
+
return { ...attachment, id: state.id, status: state.status };
|
|
87
|
+
}
|
|
88
|
+
return attachment;
|
|
89
|
+
}));
|
|
90
|
+
}, [attachments, lastUploadId]);
|
|
91
|
+
const removeAttachment = useCallback((attachment) => {
|
|
92
|
+
setAttachments(prevAttachments => prevAttachments.filter(a => a.file.uri !== attachment.file.uri));
|
|
93
|
+
}, []);
|
|
94
|
+
const reset = useCallback(() => {
|
|
95
|
+
setAttachments([]);
|
|
96
|
+
setErrorMessage(null);
|
|
97
|
+
}, []);
|
|
98
|
+
const pendingUploads = attachments.filter(a => a.status === 'uploading').length > 0;
|
|
99
|
+
const attachmentIds = useMemo(() => attachments.filter(a => a.status === 'success' && a.id).map(a => a.id), [attachments]);
|
|
100
|
+
return {
|
|
101
|
+
attachments,
|
|
102
|
+
attachmentIds,
|
|
103
|
+
handleFilesAttached,
|
|
104
|
+
removeAttachment,
|
|
105
|
+
reset,
|
|
106
|
+
pendingUploads,
|
|
107
|
+
errorMessage,
|
|
108
|
+
remainingAttachable: MAX_NUMBER_OF_ATTACHMENTS - numberOfAttachments,
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
//# sourceMappingURL=use_attachment_uploader.js.map
|