Files
nirvana-v3/packages/desktop/src/tree/NewConversationDialog.tsx
T

209 lines
5.8 KiB
TypeScript

import {
Autocomplete,
AutocompleteChangeReason,
AutocompleteRenderOptionState,
Button,
Container,
Dialog,
FormControl,
IconButton,
InputBase,
InputLabel,
ListItem,
Select,
Stack,
TextField,
Typography,
styled,
} from '@mui/material';
import React, { HTMLAttributes, useCallback, useEffect, useState } from 'react';
import CircularProgress from '@mui/material/CircularProgress';
import { FiX } from 'react-icons/fi';
import { NirvanaRules } from '../util/rules';
import User from '@nirvana/core/models/user.model';
import UserDetailRow from '../subcomponents/UserDetailRow';
import { blueGrey } from '@mui/material/colors';
import { createConversation } from '../api/NirvanaApi';
import toast from 'react-hot-toast';
import useAuth from '../providers/AuthProvider';
import useConversations from '../providers/ConversationProvider';
import useRouter from '../providers/RouterProvider';
import useSearch from '../providers/SearchProvider';
export default function NewConversationDialog() {
const { page, handleSetPage } = useRouter();
const { user } = useAuth();
const { userResults, searchQuery, searchUsers, isSearching } = useSearch();
const [selectedUsers, setSelectedUsers] = useState<User[]>([]);
const handleChangeSelections = useCallback(
(e: React.SyntheticEvent<Element, Event>, value: User[], reason: AutocompleteChangeReason) => {
setSelectedUsers(value);
},
[],
);
const handleChangeSearchInput = useCallback(
(e: React.ChangeEvent<HTMLInputElement>, newValue: string) => {
searchUsers(newValue);
},
[searchUsers],
);
const renderOption = useCallback(
(props: HTMLAttributes<HTMLLIElement>, option: User, state: AutocompleteRenderOptionState) => (
<ListItem {...props}>
<UserDetailRow user={option} />
</ListItem>
),
[],
);
const [conversationName, setConversationName] = useState<string>('');
useEffect(() => {
if (selectedUsers.length < 2) {
setConversationName('');
}
}, [selectedUsers, setConversationName]);
const handleChangeName = useCallback(
(e: React.ChangeEvent<HTMLInputElement>) => {
setConversationName(e.target.value);
},
[setConversationName],
);
const [isSubmitting, setIsSubmitting] = useState<boolean>(false);
const { handleStartConversation } = useConversations();
const handleSubmit = useCallback(async () => {
if (selectedUsers.length === 0) {
toast.error('Must select a person!');
return;
}
if (selectedUsers.length + 1 >= NirvanaRules.maxMembersPerConversation) {
toast.error('A group can only have 8 people including you!');
return;
}
setIsSubmitting(true);
const succeeded = await handleStartConversation(selectedUsers, conversationName);
// clear form for next time
if (succeeded) {
toast('succeeded');
setSelectedUsers([]);
setConversationName('');
handleSetPage('SELECTED_CONVERSATION')();
}
setIsSubmitting(false);
}, [
selectedUsers,
setConversationName,
conversationName,
setSelectedUsers,
setIsSubmitting,
handleStartConversation,
handleSetPage,
]);
return (
<Dialog fullScreen open={page === 'START_NEW_CONVERSATION'} onClose={handleSetPage('WELCOME')}>
<Container
maxWidth={false}
sx={{
display: 'flex',
flexDirection: 'column',
justifyContent: 'center',
alignItems: 'center',
gap: 2,
flex: 1,
background: blueGrey[50],
position: 'relative',
}}
>
<IconButton
sx={{ position: 'absolute', top: 10, right: 10 }}
onClick={handleSetPage('WELCOME')}
>
<FiX />
</IconButton>
<Container
maxWidth="sm"
sx={{
display: 'flex',
flexDirection: 'column',
gap: 5,
}}
>
<Typography variant="h4">Start a Conversation</Typography>
<Autocomplete
multiple
loading={isSearching}
includeInputInList
id="tags-outlined"
autoHighlight
onInputChange={handleChangeSearchInput}
options={userResults}
renderOption={renderOption}
getOptionLabel={(option) => (typeof option === 'string' ? option : option.name)}
value={selectedUsers}
onChange={handleChangeSelections}
filterSelectedOptions
isOptionEqualToValue={(optionUser, valueUser) =>
optionUser._id.toString() === valueUser._id.toString()
}
filterOptions={(options) => options}
inputValue={searchQuery}
renderInput={(params) => (
<TextField
// eslint-disable-next-line jsx-a11y/no-autofocus
autoFocus
fullWidth
label="People"
{...params}
placeholder="Search by name or email"
/>
)}
/>
{selectedUsers.length > 1 && (
<TextField
value={conversationName}
onChange={handleChangeName}
fullWidth
label="Name (optional)"
placeholder="Channel, subject line, whatever..."
/>
)}
<Stack justifyContent={'flex-end'} direction={'row'} spacing={2}>
<Button onClick={handleSetPage('WELCOME')} variant={'text'}>
Cancel
</Button>
<Button
onClick={handleSubmit}
disabled={selectedUsers.length === 0 || isSubmitting}
variant={'contained'}
color="primary"
>
{isSubmitting ? <CircularProgress /> : 'Connect'}
</Button>
</Stack>
</Container>
</Container>
</Dialog>
);
}