@bigbinary/neetoui-rn 0.0.247 → 0.0.249
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/assets/icons/attachment.svg +3 -0
- package/assets/icons/canned-response.svg +5 -0
- package/assets/icons/expand.svg +5 -0
- package/assets/icons/forward.svg +3 -0
- package/assets/icons/minimize.svg +6 -0
- package/assets/icons/note.svg +4 -0
- package/assets/icons/reply.svg +5 -0
- package/index.d.ts +28 -0
- package/lib/components/Button.js +1 -1
- package/lib/components/ChatInput/AttachmentsView.js +1 -0
- package/lib/components/ChatInput/Badge.js +1 -0
- package/lib/components/ChatInput/ChatInput.js +1 -0
- package/lib/components/ChatInput/EmailFields.js +1 -0
- package/lib/components/ChatInput/IconButton.js +1 -0
- package/lib/components/InputEmailChip.js +1 -1
- package/lib/components/LineLoader.js +1 -0
- package/lib/components/Popover.js +1 -1
- package/lib/components/index.js +1 -1
- package/lib/theme/index.js +1 -1
- package/package.json +1 -1
- package/src/components/Button.jsx +7 -3
- package/src/components/ChatInput/AttachmentsView.jsx +51 -0
- package/src/components/ChatInput/Badge.jsx +24 -0
- package/src/components/ChatInput/ChatInput.jsx +500 -0
- package/src/components/ChatInput/EmailFields.jsx +122 -0
- package/src/components/ChatInput/IconButton.jsx +22 -0
- package/src/components/InputEmailChip.jsx +14 -5
- package/src/components/LineLoader.jsx +46 -0
- package/src/components/Popover.jsx +37 -20
- package/src/components/index.js +2 -0
- package/src/theme/index.js +1 -0
|
@@ -0,0 +1,500 @@
|
|
|
1
|
+
import React, {
|
|
2
|
+
useEffect,
|
|
3
|
+
useRef,
|
|
4
|
+
useCallback,
|
|
5
|
+
useState,
|
|
6
|
+
forwardRef,
|
|
7
|
+
useImperativeHandle,
|
|
8
|
+
} from "react";
|
|
9
|
+
|
|
10
|
+
import PropTypes from "prop-types";
|
|
11
|
+
import Icon from "react-native-remix-icon";
|
|
12
|
+
import { moderateScale } from "react-native-size-matters";
|
|
13
|
+
import styled from "styled-components/native";
|
|
14
|
+
import {
|
|
15
|
+
flexbox,
|
|
16
|
+
space,
|
|
17
|
+
border,
|
|
18
|
+
buttonStyle,
|
|
19
|
+
typography,
|
|
20
|
+
color,
|
|
21
|
+
} from "styled-system";
|
|
22
|
+
|
|
23
|
+
import AttachmentSVG from "@assets/icons/attachment.svg";
|
|
24
|
+
import CannedResponseSVG from "@assets/icons/canned-response.svg";
|
|
25
|
+
import ExpandSVG from "@assets/icons/expand.svg";
|
|
26
|
+
import ForwardSVG from "@assets/icons/forward.svg";
|
|
27
|
+
import MinimizeSVG from "@assets/icons/minimize.svg";
|
|
28
|
+
import NoteSVG from "@assets/icons/note.svg";
|
|
29
|
+
import ReplySVG from "@assets/icons/reply.svg";
|
|
30
|
+
import { Container, LineLoader, Popover, Button } from "@components";
|
|
31
|
+
|
|
32
|
+
import { AttachmentsView } from "./AttachmentsView";
|
|
33
|
+
import { EmailFields } from "./EmailFields";
|
|
34
|
+
import { IconButton } from "./IconButton";
|
|
35
|
+
|
|
36
|
+
import { theme } from "../../theme";
|
|
37
|
+
|
|
38
|
+
const placeholders = {
|
|
39
|
+
reply: "Type here to reply...",
|
|
40
|
+
note: "Add note here...",
|
|
41
|
+
forward: "Type here to forward...",
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
// eslint-disable-next-line @bigbinary/neeto/no-dangling-constants
|
|
45
|
+
const OPTION_TYPES = {
|
|
46
|
+
REPLY: "REPLY",
|
|
47
|
+
NOTE: "NOTE",
|
|
48
|
+
FORWARD: "FORWARD",
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
const labels = {
|
|
52
|
+
[OPTION_TYPES.REPLY]: "Reply",
|
|
53
|
+
[OPTION_TYPES.NOTE]: "Add note",
|
|
54
|
+
[OPTION_TYPES.FORWARD]: "Forward",
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
const TextInput = styled.TextInput`
|
|
58
|
+
${flexbox}
|
|
59
|
+
${space}
|
|
60
|
+
${border}
|
|
61
|
+
${buttonStyle}
|
|
62
|
+
${typography}
|
|
63
|
+
${color}
|
|
64
|
+
`;
|
|
65
|
+
/**
|
|
66
|
+
* ChatInput component supports various options like `REPLY`, `NOTE` and `FORWARD`.
|
|
67
|
+
* This component supports below props categories from [styled-system ](/styled-system).
|
|
68
|
+
* <ul>
|
|
69
|
+
* <li>flexbox</li>
|
|
70
|
+
* <li>space</li>
|
|
71
|
+
* <li>border</li>
|
|
72
|
+
* <li>buttonStyle</li>
|
|
73
|
+
* <li>brandLeft</li>
|
|
74
|
+
* <li>typography</li>
|
|
75
|
+
* </ul>
|
|
76
|
+
*
|
|
77
|
+
* <div class="screenshots">
|
|
78
|
+
* <img src="screenshots/chatInput/chatInput.png" />
|
|
79
|
+
* </div>
|
|
80
|
+
*
|
|
81
|
+
* ## Usage
|
|
82
|
+
* ```js
|
|
83
|
+
* import * as React from 'react';
|
|
84
|
+
* import { Typography, ChatInput, Container } from '@bigbinary/neetoui-rn';
|
|
85
|
+
*
|
|
86
|
+
* export default function Main() {
|
|
87
|
+
* const [value, setValue] = React.useState(
|
|
88
|
+
* "Hey Oliver, We are working on this issue. We will keep you update");
|
|
89
|
+
*
|
|
90
|
+
* return (
|
|
91
|
+
* <Container flex={1}>
|
|
92
|
+
* <Container alignItems="center" flex={1} justifyContent="center">
|
|
93
|
+
* <Typography> Desk Example</Typography>
|
|
94
|
+
* </Container>
|
|
95
|
+
* <Container align-self="end">
|
|
96
|
+
* <ChatInput
|
|
97
|
+
* shouldShowEmailFields
|
|
98
|
+
* attachmentsCount={2}
|
|
99
|
+
* toEmails="oliver@example.com"
|
|
100
|
+
* value={value}
|
|
101
|
+
* Attachments={
|
|
102
|
+
* <Container alignItems="flex-start">
|
|
103
|
+
* <AnimatedImage
|
|
104
|
+
* imageHeight={30}
|
|
105
|
+
* imageUrl="https://picsum.photos/255/139"
|
|
106
|
+
* imageWidth={30}
|
|
107
|
+
* resizeMode="cover"
|
|
108
|
+
* />
|
|
109
|
+
* </Container>
|
|
110
|
+
* }
|
|
111
|
+
* onChangeText={setValue}
|
|
112
|
+
* onCannedResponse={() => {
|
|
113
|
+
* alert("On Canned Response");
|
|
114
|
+
* }}
|
|
115
|
+
* onForward={() => {
|
|
116
|
+
* alert("On Forward");
|
|
117
|
+
* }}
|
|
118
|
+
* />
|
|
119
|
+
* </Container>
|
|
120
|
+
* </Container>
|
|
121
|
+
* );
|
|
122
|
+
* }
|
|
123
|
+
* ```
|
|
124
|
+
*/
|
|
125
|
+
|
|
126
|
+
export const ChatInput = forwardRef(
|
|
127
|
+
(
|
|
128
|
+
{
|
|
129
|
+
shouldShowEmailFields,
|
|
130
|
+
showReplyMenuOptions,
|
|
131
|
+
value = "",
|
|
132
|
+
onChangeText = () => {},
|
|
133
|
+
onForward,
|
|
134
|
+
onCannedResponse,
|
|
135
|
+
toEmails: initialToEmails,
|
|
136
|
+
onReply = () => {},
|
|
137
|
+
onAddNote = () => {},
|
|
138
|
+
onAttachment = () => {},
|
|
139
|
+
attachmentsCount,
|
|
140
|
+
Attachments,
|
|
141
|
+
showCannedResponsesFor = [OPTION_TYPES.REPLY],
|
|
142
|
+
disabled,
|
|
143
|
+
isLoading = true,
|
|
144
|
+
onOptionChange = () => {},
|
|
145
|
+
initialSelectedOption = OPTION_TYPES.REPLY,
|
|
146
|
+
...rest
|
|
147
|
+
},
|
|
148
|
+
ref
|
|
149
|
+
) => {
|
|
150
|
+
const inputRef = useRef();
|
|
151
|
+
|
|
152
|
+
const [selectedOption, setSelectedOption] = useState(initialSelectedOption);
|
|
153
|
+
const [isEmailFieldsVisible, setIsEmailFieldsVisible] = useState(false);
|
|
154
|
+
const [isAttachmentsVisible, setIsAttachmentsVisible] = useState(false);
|
|
155
|
+
|
|
156
|
+
const isReplyOptionSelected = selectedOption === OPTION_TYPES.REPLY;
|
|
157
|
+
const isNoteOptionSelected = selectedOption === OPTION_TYPES.NOTE;
|
|
158
|
+
const isForwardOptionSelected = selectedOption === OPTION_TYPES.FORWARD;
|
|
159
|
+
|
|
160
|
+
const [toEmails, setToEmails] = useState(initialToEmails ?? []);
|
|
161
|
+
const [toEmailsForForward, setToEmailsForForward] = useState([]);
|
|
162
|
+
const [ccEmails, setCcEmails] = useState([]);
|
|
163
|
+
const [bccEmails, setBccEmails] = useState([]);
|
|
164
|
+
|
|
165
|
+
const moreReplyOptions = [
|
|
166
|
+
{
|
|
167
|
+
label: "Send and set as closed",
|
|
168
|
+
Icon: () => null,
|
|
169
|
+
onPress: () => {
|
|
170
|
+
onReply({ toEmails, ccEmails, bccEmails, status: "closed" });
|
|
171
|
+
},
|
|
172
|
+
},
|
|
173
|
+
];
|
|
174
|
+
|
|
175
|
+
useImperativeHandle(
|
|
176
|
+
ref,
|
|
177
|
+
() => ({
|
|
178
|
+
clearEmailFields: () => {
|
|
179
|
+
setToEmails(initialToEmails ?? []);
|
|
180
|
+
setToEmailsForForward([]);
|
|
181
|
+
setCcEmails([]);
|
|
182
|
+
setBccEmails([]);
|
|
183
|
+
inputRef.current.blur();
|
|
184
|
+
},
|
|
185
|
+
}),
|
|
186
|
+
[initialToEmails, isReplyOptionSelected]
|
|
187
|
+
);
|
|
188
|
+
|
|
189
|
+
useEffect(() => {
|
|
190
|
+
onOptionChange(selectedOption);
|
|
191
|
+
}, [selectedOption]);
|
|
192
|
+
|
|
193
|
+
useEffect(() => {
|
|
194
|
+
setSelectedOption(initialSelectedOption);
|
|
195
|
+
}, [initialSelectedOption]);
|
|
196
|
+
|
|
197
|
+
useEffect(() => {
|
|
198
|
+
setToEmails(initialToEmails ?? []);
|
|
199
|
+
}, [initialToEmails]);
|
|
200
|
+
|
|
201
|
+
const showEmailFieldsAndAttachments = () => {
|
|
202
|
+
setIsAttachmentsVisible(true);
|
|
203
|
+
setIsEmailFieldsVisible(true);
|
|
204
|
+
};
|
|
205
|
+
|
|
206
|
+
const hideEmailFieldsAndAttachments = () => {
|
|
207
|
+
setIsAttachmentsVisible(false);
|
|
208
|
+
setIsEmailFieldsVisible(false);
|
|
209
|
+
};
|
|
210
|
+
|
|
211
|
+
const onReplyClickHandler = () => {
|
|
212
|
+
hideEmailFieldsAndAttachments();
|
|
213
|
+
inputRef.current.focus();
|
|
214
|
+
setSelectedOption(OPTION_TYPES.REPLY);
|
|
215
|
+
};
|
|
216
|
+
|
|
217
|
+
const onAddNoteClickHandler = () => {
|
|
218
|
+
hideEmailFieldsAndAttachments();
|
|
219
|
+
inputRef.current.focus();
|
|
220
|
+
setIsEmailFieldsVisible(false);
|
|
221
|
+
setSelectedOption(OPTION_TYPES.NOTE);
|
|
222
|
+
};
|
|
223
|
+
|
|
224
|
+
const onAddForwardClickHandler = () => {
|
|
225
|
+
inputRef.current.focus();
|
|
226
|
+
setIsEmailFieldsVisible(true);
|
|
227
|
+
setIsAttachmentsVisible(false);
|
|
228
|
+
setSelectedOption(OPTION_TYPES.FORWARD);
|
|
229
|
+
};
|
|
230
|
+
|
|
231
|
+
const onAddAttachmentsClickHandler = () => {
|
|
232
|
+
if (!isAttachmentsVisible && attachmentsCount > 0) {
|
|
233
|
+
// When attachments are not visible but there are few attachments then we no need to show the upload modal.
|
|
234
|
+
} else {
|
|
235
|
+
onAttachment();
|
|
236
|
+
}
|
|
237
|
+
setIsEmailFieldsVisible(false);
|
|
238
|
+
setIsAttachmentsVisible(true);
|
|
239
|
+
};
|
|
240
|
+
|
|
241
|
+
const onActionHandler = useCallback(() => {
|
|
242
|
+
({
|
|
243
|
+
[OPTION_TYPES.REPLY]: () => {
|
|
244
|
+
onReply({ toEmails, ccEmails, bccEmails });
|
|
245
|
+
},
|
|
246
|
+
[OPTION_TYPES.NOTE]: () => {
|
|
247
|
+
onAddNote({ toEmails, ccEmails, bccEmails });
|
|
248
|
+
},
|
|
249
|
+
[OPTION_TYPES.FORWARD]: () => {
|
|
250
|
+
onForward({ toEmails, ccEmails, bccEmails });
|
|
251
|
+
},
|
|
252
|
+
}[selectedOption]());
|
|
253
|
+
}, [
|
|
254
|
+
bccEmails,
|
|
255
|
+
ccEmails,
|
|
256
|
+
onAddNote,
|
|
257
|
+
onForward,
|
|
258
|
+
onReply,
|
|
259
|
+
selectedOption,
|
|
260
|
+
toEmails,
|
|
261
|
+
]);
|
|
262
|
+
|
|
263
|
+
const shouldShowExpandAndMinimizeButton =
|
|
264
|
+
attachmentsCount > 0 || toEmails.length > 0;
|
|
265
|
+
|
|
266
|
+
const shouldDisableWhenForwardAndToFieldMissing =
|
|
267
|
+
isForwardOptionSelected && toEmailsForForward.length === 0;
|
|
268
|
+
|
|
269
|
+
return (
|
|
270
|
+
<Container>
|
|
271
|
+
<LineLoader
|
|
272
|
+
backgroundColor={theme.colors.background.grey400}
|
|
273
|
+
isLoading={isLoading}
|
|
274
|
+
/>
|
|
275
|
+
<Container
|
|
276
|
+
bg={isNoteOptionSelected ? "background.oldLace" : "transparent"}
|
|
277
|
+
p={moderateScale(5)}
|
|
278
|
+
pt={0}
|
|
279
|
+
px={moderateScale(16)}
|
|
280
|
+
>
|
|
281
|
+
<Container pt={moderateScale(8)}>
|
|
282
|
+
<EmailFields
|
|
283
|
+
bccEmails={bccEmails}
|
|
284
|
+
ccEmails={ccEmails}
|
|
285
|
+
isEmailFieldsVisible={isEmailFieldsVisible}
|
|
286
|
+
isForwardOptionSelected={isForwardOptionSelected}
|
|
287
|
+
isNoteOptionSelected={isNoteOptionSelected}
|
|
288
|
+
isReplyOptionSelected={isReplyOptionSelected}
|
|
289
|
+
setBccEmails={setBccEmails}
|
|
290
|
+
setCcEmails={setCcEmails}
|
|
291
|
+
setIsEmailFieldsVisible={setIsEmailFieldsVisible}
|
|
292
|
+
setToEmails={setToEmails}
|
|
293
|
+
setToEmailsForForward={setToEmailsForForward}
|
|
294
|
+
shouldShowEmailFields={shouldShowEmailFields}
|
|
295
|
+
toEmails={toEmails}
|
|
296
|
+
toEmailsForForward={toEmailsForForward}
|
|
297
|
+
/>
|
|
298
|
+
<Container flexDirection="row" justifyContent="space-between">
|
|
299
|
+
<TextInput
|
|
300
|
+
multiline
|
|
301
|
+
flex={1}
|
|
302
|
+
maxHeight={moderateScale(150)}
|
|
303
|
+
my={moderateScale(12)}
|
|
304
|
+
overflow="hidden"
|
|
305
|
+
placeholder={placeholders[selectedOption]}
|
|
306
|
+
ref={inputRef}
|
|
307
|
+
value={value}
|
|
308
|
+
onChangeText={onChangeText}
|
|
309
|
+
onTouchStart={hideEmailFieldsAndAttachments}
|
|
310
|
+
{...rest}
|
|
311
|
+
/>
|
|
312
|
+
<Container alignSelf="center">
|
|
313
|
+
{shouldShowExpandAndMinimizeButton &&
|
|
314
|
+
(isEmailFieldsVisible || isAttachmentsVisible ? (
|
|
315
|
+
<IconButton
|
|
316
|
+
Icon={MinimizeSVG}
|
|
317
|
+
height={moderateScale(30)}
|
|
318
|
+
pt={moderateScale(8)}
|
|
319
|
+
width={moderateScale(30)}
|
|
320
|
+
onPress={hideEmailFieldsAndAttachments}
|
|
321
|
+
/>
|
|
322
|
+
) : (
|
|
323
|
+
<IconButton
|
|
324
|
+
Icon={ExpandSVG}
|
|
325
|
+
height={moderateScale(30)}
|
|
326
|
+
pt={moderateScale(8)}
|
|
327
|
+
width={moderateScale(30)}
|
|
328
|
+
onPress={showEmailFieldsAndAttachments}
|
|
329
|
+
/>
|
|
330
|
+
))}
|
|
331
|
+
</Container>
|
|
332
|
+
</Container>
|
|
333
|
+
<AttachmentsView
|
|
334
|
+
Attachments={Attachments}
|
|
335
|
+
attachmentsCount={attachmentsCount}
|
|
336
|
+
isAttachmentsVisible={isAttachmentsVisible}
|
|
337
|
+
isNoteOptionSelected={isNoteOptionSelected}
|
|
338
|
+
setIsAttachmentsVisible={setIsAttachmentsVisible}
|
|
339
|
+
/>
|
|
340
|
+
<Container
|
|
341
|
+
alignItems="center"
|
|
342
|
+
flexDirection="row"
|
|
343
|
+
justifyContent="space-between"
|
|
344
|
+
mt={moderateScale(10)}
|
|
345
|
+
>
|
|
346
|
+
<Container flexDirection="row" justifyContent="space-between">
|
|
347
|
+
<IconButton
|
|
348
|
+
Icon={ReplySVG}
|
|
349
|
+
opacity={isReplyOptionSelected ? 1 : 0.5}
|
|
350
|
+
pl={moderateScale(10)}
|
|
351
|
+
onPress={onReplyClickHandler}
|
|
352
|
+
/>
|
|
353
|
+
<IconButton
|
|
354
|
+
Icon={NoteSVG}
|
|
355
|
+
opacity={isNoteOptionSelected ? 1 : 0.5}
|
|
356
|
+
onPress={onAddNoteClickHandler}
|
|
357
|
+
/>
|
|
358
|
+
{onForward && (
|
|
359
|
+
<IconButton
|
|
360
|
+
Icon={ForwardSVG}
|
|
361
|
+
opacity={isForwardOptionSelected ? 1 : 0.5}
|
|
362
|
+
onPress={onAddForwardClickHandler}
|
|
363
|
+
/>
|
|
364
|
+
)}
|
|
365
|
+
<Container
|
|
366
|
+
bg="background.grey400"
|
|
367
|
+
mx={moderateScale(5)}
|
|
368
|
+
p={moderateScale(0.4)}
|
|
369
|
+
/>
|
|
370
|
+
{onCannedResponse &&
|
|
371
|
+
showCannedResponsesFor.includes(selectedOption) && (
|
|
372
|
+
<IconButton
|
|
373
|
+
Icon={CannedResponseSVG}
|
|
374
|
+
opacity={0.5}
|
|
375
|
+
onPress={onCannedResponse}
|
|
376
|
+
/>
|
|
377
|
+
)}
|
|
378
|
+
<IconButton
|
|
379
|
+
Icon={AttachmentSVG}
|
|
380
|
+
opacity={0.5}
|
|
381
|
+
onPress={onAddAttachmentsClickHandler}
|
|
382
|
+
/>
|
|
383
|
+
</Container>
|
|
384
|
+
<Container alignItems="center" flexDirection="row">
|
|
385
|
+
<Button
|
|
386
|
+
height={moderateScale(30)}
|
|
387
|
+
label={labels[selectedOption]}
|
|
388
|
+
pr={0}
|
|
389
|
+
variant="text"
|
|
390
|
+
disabled={
|
|
391
|
+
shouldDisableWhenForwardAndToFieldMissing || disabled
|
|
392
|
+
}
|
|
393
|
+
labelStyle={{
|
|
394
|
+
mx: moderateScale(0),
|
|
395
|
+
}}
|
|
396
|
+
onPress={onActionHandler}
|
|
397
|
+
/>
|
|
398
|
+
{showReplyMenuOptions && isReplyOptionSelected && (
|
|
399
|
+
<Popover
|
|
400
|
+
data={moreReplyOptions}
|
|
401
|
+
from={
|
|
402
|
+
<Button
|
|
403
|
+
disabled={disabled}
|
|
404
|
+
height={moderateScale(30)}
|
|
405
|
+
label=""
|
|
406
|
+
p={0}
|
|
407
|
+
variant="text"
|
|
408
|
+
RightIcon={() => (
|
|
409
|
+
<Icon
|
|
410
|
+
color={theme.colors.background.grey800}
|
|
411
|
+
name="ri-arrow-down-s-line"
|
|
412
|
+
size={moderateScale(30)}
|
|
413
|
+
/>
|
|
414
|
+
)}
|
|
415
|
+
/>
|
|
416
|
+
}
|
|
417
|
+
/>
|
|
418
|
+
)}
|
|
419
|
+
</Container>
|
|
420
|
+
</Container>
|
|
421
|
+
</Container>
|
|
422
|
+
</Container>
|
|
423
|
+
</Container>
|
|
424
|
+
);
|
|
425
|
+
}
|
|
426
|
+
);
|
|
427
|
+
|
|
428
|
+
ChatInput.displayName = "ChatInput";
|
|
429
|
+
ChatInput.propTypes = {
|
|
430
|
+
/**
|
|
431
|
+
* If true, Shows loader
|
|
432
|
+
*/
|
|
433
|
+
isLoading: PropTypes.bool,
|
|
434
|
+
/**
|
|
435
|
+
* If true, Shows to, cc and bcc email inputs.
|
|
436
|
+
*/
|
|
437
|
+
shouldShowEmailFields: PropTypes.bool,
|
|
438
|
+
/**
|
|
439
|
+
* If true, Shows reply menu options
|
|
440
|
+
*/
|
|
441
|
+
showReplyMenuOptions: PropTypes.bool,
|
|
442
|
+
/**
|
|
443
|
+
* Value to make input component controllable.
|
|
444
|
+
*/
|
|
445
|
+
value: PropTypes.string,
|
|
446
|
+
/**
|
|
447
|
+
* To set the initial selected option
|
|
448
|
+
*/
|
|
449
|
+
initialSelectedOption: PropTypes.oneOf(Object.values(OPTION_TYPES)),
|
|
450
|
+
/**
|
|
451
|
+
* Callback to be called when user selection option.
|
|
452
|
+
*/
|
|
453
|
+
onOptionChange: PropTypes.func,
|
|
454
|
+
/**
|
|
455
|
+
* Callback to be called when the input text changes.
|
|
456
|
+
*/
|
|
457
|
+
onChangeText: PropTypes.func,
|
|
458
|
+
/**
|
|
459
|
+
* Callback to be called on click of forward icon.
|
|
460
|
+
*/
|
|
461
|
+
onForward: PropTypes.func,
|
|
462
|
+
/**
|
|
463
|
+
* Callback to be called on click of canned responses icon.
|
|
464
|
+
*/
|
|
465
|
+
onCannedResponse: PropTypes.func,
|
|
466
|
+
/**
|
|
467
|
+
* Email list separated by comma.
|
|
468
|
+
*/
|
|
469
|
+
toEmails: PropTypes.arrayOf(PropTypes.string),
|
|
470
|
+
/**
|
|
471
|
+
* Callback to be called on click of reply icon.
|
|
472
|
+
*/
|
|
473
|
+
onReply: PropTypes.func,
|
|
474
|
+
/**
|
|
475
|
+
* Callback to be called on click of add note icon.
|
|
476
|
+
*/
|
|
477
|
+
onAddNote: PropTypes.func,
|
|
478
|
+
/**
|
|
479
|
+
* Callback to be called on click of attachment icon.
|
|
480
|
+
*/
|
|
481
|
+
onAttachment: PropTypes.func,
|
|
482
|
+
/**
|
|
483
|
+
* Count of attachments.
|
|
484
|
+
*/
|
|
485
|
+
attachmentsCount: PropTypes.number,
|
|
486
|
+
/**
|
|
487
|
+
* Component to render attachments.
|
|
488
|
+
*/
|
|
489
|
+
Attachments: PropTypes.any,
|
|
490
|
+
/**
|
|
491
|
+
* Array for options to show canned responses. Example: ["reply","notes","forward"]
|
|
492
|
+
*/
|
|
493
|
+
showCannedResponsesFor: PropTypes.arrayOf(
|
|
494
|
+
PropTypes.oneOf(Object.values(OPTION_TYPES))
|
|
495
|
+
),
|
|
496
|
+
/**
|
|
497
|
+
* If true, Disables the reply, forward and add note button.
|
|
498
|
+
*/
|
|
499
|
+
disabled: PropTypes.bool,
|
|
500
|
+
};
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
|
|
3
|
+
import PropTypes from "prop-types";
|
|
4
|
+
import Animated, { FadeInDown, FadeInUp } from "react-native-reanimated";
|
|
5
|
+
import { moderateScale } from "react-native-size-matters";
|
|
6
|
+
|
|
7
|
+
import { InputEmailChip } from "@components";
|
|
8
|
+
|
|
9
|
+
import { Badge } from "./Badge";
|
|
10
|
+
|
|
11
|
+
export const EmailFields = ({
|
|
12
|
+
shouldShowEmailFields,
|
|
13
|
+
setIsEmailFieldsVisible,
|
|
14
|
+
isEmailFieldsVisible,
|
|
15
|
+
toEmails,
|
|
16
|
+
toEmailsForForward,
|
|
17
|
+
ccEmails,
|
|
18
|
+
bccEmails,
|
|
19
|
+
setToEmails,
|
|
20
|
+
setToEmailsForForward,
|
|
21
|
+
setBccEmails,
|
|
22
|
+
setCcEmails,
|
|
23
|
+
isReplyOptionSelected,
|
|
24
|
+
isNoteOptionSelected,
|
|
25
|
+
isForwardOptionSelected,
|
|
26
|
+
}) => {
|
|
27
|
+
const firstToEmail = isReplyOptionSelected
|
|
28
|
+
? toEmails[0]
|
|
29
|
+
: toEmailsForForward[0];
|
|
30
|
+
|
|
31
|
+
let badge = "";
|
|
32
|
+
if (firstToEmail) {
|
|
33
|
+
badge = `To ${firstToEmail}`;
|
|
34
|
+
} else if (isForwardOptionSelected) {
|
|
35
|
+
badge = "Click here to enter email id.";
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const totalEmailsMinus1 =
|
|
39
|
+
toEmails.length +
|
|
40
|
+
toEmailsForForward.length +
|
|
41
|
+
ccEmails.length +
|
|
42
|
+
bccEmails.length -
|
|
43
|
+
1;
|
|
44
|
+
|
|
45
|
+
if (!shouldShowEmailFields) return null;
|
|
46
|
+
|
|
47
|
+
return isEmailFieldsVisible ? (
|
|
48
|
+
<Animated.View
|
|
49
|
+
entering={FadeInDown}
|
|
50
|
+
key={isEmailFieldsVisible}
|
|
51
|
+
pb={moderateScale(10)}
|
|
52
|
+
>
|
|
53
|
+
{isReplyOptionSelected && (
|
|
54
|
+
<InputEmailChip
|
|
55
|
+
disabled
|
|
56
|
+
emails={toEmails}
|
|
57
|
+
label="To:"
|
|
58
|
+
onUpdate={setToEmails}
|
|
59
|
+
/>
|
|
60
|
+
)}
|
|
61
|
+
{isForwardOptionSelected && (
|
|
62
|
+
<InputEmailChip
|
|
63
|
+
disabled={false}
|
|
64
|
+
emails={toEmailsForForward}
|
|
65
|
+
label="To:"
|
|
66
|
+
onUpdate={setToEmailsForForward}
|
|
67
|
+
/>
|
|
68
|
+
)}
|
|
69
|
+
<InputEmailChip
|
|
70
|
+
disabled={false}
|
|
71
|
+
emails={ccEmails}
|
|
72
|
+
label="Cc:"
|
|
73
|
+
onUpdate={setCcEmails}
|
|
74
|
+
/>
|
|
75
|
+
<InputEmailChip
|
|
76
|
+
disabled={false}
|
|
77
|
+
emails={bccEmails}
|
|
78
|
+
label="Bcc:"
|
|
79
|
+
onUpdate={setBccEmails}
|
|
80
|
+
/>
|
|
81
|
+
</Animated.View>
|
|
82
|
+
) : (
|
|
83
|
+
<Animated.View
|
|
84
|
+
alignItems="flex-start"
|
|
85
|
+
entering={FadeInUp}
|
|
86
|
+
flexDirection="row"
|
|
87
|
+
flexWrap="wrap"
|
|
88
|
+
key={isEmailFieldsVisible}
|
|
89
|
+
style={
|
|
90
|
+
isNoteOptionSelected && {
|
|
91
|
+
height: moderateScale(0),
|
|
92
|
+
width: moderateScale(0),
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
onTouchStart={() => setIsEmailFieldsVisible(true)}
|
|
96
|
+
>
|
|
97
|
+
{toEmails.length > 0 && (
|
|
98
|
+
<>
|
|
99
|
+
<Badge text={badge} />
|
|
100
|
+
{totalEmailsMinus1 > 1 && <Badge text={`+ ${totalEmailsMinus1}`} />}
|
|
101
|
+
</>
|
|
102
|
+
)}
|
|
103
|
+
</Animated.View>
|
|
104
|
+
);
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
EmailFields.propTypes = {
|
|
108
|
+
shouldShowEmailFields: PropTypes.bool,
|
|
109
|
+
isEmailFieldsVisible: PropTypes.bool,
|
|
110
|
+
setIsEmailFieldsVisible: PropTypes.func,
|
|
111
|
+
ccEmails: PropTypes.arrayOf(PropTypes.string),
|
|
112
|
+
toEmails: PropTypes.arrayOf(PropTypes.string),
|
|
113
|
+
toEmailsForForward: PropTypes.arrayOf(PropTypes.string),
|
|
114
|
+
bccEmails: PropTypes.arrayOf(PropTypes.string),
|
|
115
|
+
setBccEmails: PropTypes.func,
|
|
116
|
+
setCcEmails: PropTypes.func,
|
|
117
|
+
setToEmails: PropTypes.func,
|
|
118
|
+
setToEmailsForForward: PropTypes.func,
|
|
119
|
+
isReplyOptionSelected: PropTypes.bool,
|
|
120
|
+
isNoteOptionSelected: PropTypes.bool,
|
|
121
|
+
isForwardOptionSelected: PropTypes.bool,
|
|
122
|
+
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
|
|
3
|
+
import PropTypes from "prop-types";
|
|
4
|
+
import { moderateScale } from "react-native-size-matters";
|
|
5
|
+
|
|
6
|
+
import { Touchable } from "@components";
|
|
7
|
+
|
|
8
|
+
export const IconButton = ({ Icon, ...rest }) => (
|
|
9
|
+
<Touchable
|
|
10
|
+
alignItems="center"
|
|
11
|
+
height={moderateScale(22)}
|
|
12
|
+
px={moderateScale(18)}
|
|
13
|
+
width={moderateScale(22)}
|
|
14
|
+
{...rest}
|
|
15
|
+
>
|
|
16
|
+
{<Icon />}
|
|
17
|
+
</Touchable>
|
|
18
|
+
);
|
|
19
|
+
|
|
20
|
+
IconButton.propTypes = {
|
|
21
|
+
Icon: PropTypes.elementType,
|
|
22
|
+
};
|
|
@@ -25,6 +25,7 @@ export const InputEmailChip = ({
|
|
|
25
25
|
emails = [],
|
|
26
26
|
onUpdate,
|
|
27
27
|
delimiters = [" ", ","],
|
|
28
|
+
...rest
|
|
28
29
|
}) => {
|
|
29
30
|
const theme = useContext(ThemeContext);
|
|
30
31
|
const inputRef = useRef();
|
|
@@ -80,7 +81,7 @@ export const InputEmailChip = ({
|
|
|
80
81
|
};
|
|
81
82
|
|
|
82
83
|
const handleOnEndEditing = event => {
|
|
83
|
-
|
|
84
|
+
checkAndUpdateEmails(event.nativeEvent.text);
|
|
84
85
|
};
|
|
85
86
|
|
|
86
87
|
const checkAndUpdateEmails = text => {
|
|
@@ -127,12 +128,14 @@ export const InputEmailChip = ({
|
|
|
127
128
|
minHeight={moderateScale(30)}
|
|
128
129
|
py={moderateScale(2)}
|
|
129
130
|
width="100%"
|
|
131
|
+
{...rest}
|
|
130
132
|
>
|
|
131
133
|
{!!label && (
|
|
132
134
|
<Typography
|
|
133
135
|
color={disabled ? "font.grey400" : "font.grey600"}
|
|
134
136
|
fontSize="xs"
|
|
135
|
-
|
|
137
|
+
textAlign="left"
|
|
138
|
+
width={moderateScale(40)}
|
|
136
139
|
mt={Platform.select({
|
|
137
140
|
android: moderateScale(10),
|
|
138
141
|
ios: moderateScale(8),
|
|
@@ -152,9 +155,10 @@ export const InputEmailChip = ({
|
|
|
152
155
|
<Chip
|
|
153
156
|
isDisabled={disabled}
|
|
154
157
|
label={email}
|
|
155
|
-
containerStyle={
|
|
156
|
-
index === emailIndexForDeletion
|
|
157
|
-
|
|
158
|
+
containerStyle={{
|
|
159
|
+
...getChipContainerStyle(index === emailIndexForDeletion),
|
|
160
|
+
height: moderateScale(25),
|
|
161
|
+
}}
|
|
158
162
|
onClose={disabled ? null : () => removeEmail({ email })}
|
|
159
163
|
/>
|
|
160
164
|
</Container>
|
|
@@ -175,6 +179,9 @@ export const InputEmailChip = ({
|
|
|
175
179
|
noBorder
|
|
176
180
|
disabled={disabled}
|
|
177
181
|
value={textValue}
|
|
182
|
+
containerProps={{
|
|
183
|
+
borderRadius: 0,
|
|
184
|
+
}}
|
|
178
185
|
inputProps={{
|
|
179
186
|
...inputProps,
|
|
180
187
|
ref: inputRef,
|
|
@@ -184,6 +191,8 @@ export const InputEmailChip = ({
|
|
|
184
191
|
onFocus: handleOnFocus,
|
|
185
192
|
onBlur: handleOnBlur,
|
|
186
193
|
onEndEditing: handleOnEndEditing,
|
|
194
|
+
borderBottomWidth: moderateScale(2),
|
|
195
|
+
borderColor: "background.grey200",
|
|
187
196
|
}}
|
|
188
197
|
onChangeText={handleTextChange}
|
|
189
198
|
/>
|