Skip to content
This repository was archived by the owner on Nov 6, 2023. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
216 changes: 189 additions & 27 deletions packages/ui-inbox/src/settings/integrations/components/mail/MailForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,13 @@ import Tip from '@erxes/ui/src/components/Tip';
import Uploader from '@erxes/ui/src/components/Uploader';
import dayjs from 'dayjs';
import { generateEmailTemplateParams } from '@erxes/ui-engage/src/utils';
import {
MailColumn,
MailSuggestionContainer,
MailSuggestionItem
} from '../../styles';
import { Avatar } from '@erxes/ui/src/components/SelectWithSearch';
import { IContact } from '../../types';

type Props = {
emailTemplates: any[] /*change type*/;
Expand All @@ -53,6 +60,7 @@ type Props = {
replyAll?: boolean;
brandId?: string;
mails?: IMessage[];
contacts?: IContact[];
messageId?: string;
totalCount?: number;
closeModal?: () => void;
Expand Down Expand Up @@ -99,12 +107,13 @@ type State = {
name: string;
showReply: string;
isRepliesRetrieved: boolean;
selectedSuggestionIndex: number;
focusInput: string;
};

class MailForm extends React.Component<Props, State> {
constructor(props: Props) {
super(props);

const { isForward, replyAll, mailData = {} as IMail, emailTo } = props;

const mailWidget = JSON.parse(localStorage.getItem('emailWidgetData'));
Expand Down Expand Up @@ -176,7 +185,9 @@ class MailForm extends React.Component<Props, State> {

name: `mail_${mailKey}`,
showReply: `reply_${mailKey}`,
isRepliesRetrieved: false
isRepliesRetrieved: false,
selectedSuggestionIndex: 0,
focusInput: ''
};
}

Expand Down Expand Up @@ -449,10 +460,9 @@ class MailForm extends React.Component<Props, State> {
};

onSelectChange = <T extends keyof State>(name: T, e: any) => {
this.setState(({ [name]: e.currentTarget.value } as unknown) as Pick<
State,
keyof State
>);
this.setState(({
[name]: e.currentTarget.value
} as unknown) as Pick<State, keyof State>);

this.prepareData();
};
Expand Down Expand Up @@ -551,17 +561,155 @@ class MailForm extends React.Component<Props, State> {
);
}

getFilteredContacts = (fieldName: string) => {
const field = this.state[fieldName];
const { contacts } = this.props;

if (
field.trim() === '' ||
field.substr(field.lastIndexOf(',') + 1).trim() === ''
) {
return [];
}

const filterLowerCase = field
.toLowerCase()
.substr(field.lastIndexOf(',') + 1)
.trim();

return (contacts || [])
.filter(contact =>
[contact.primaryEmail, contact.primaryName].some(
prop =>
prop?.toLowerCase().includes(filterLowerCase) &&
!field?.includes(contact.primaryEmail)
)
)
.slice(0, 5);
};

handleSuggestionClick = (contact: IContact, fieldName: string) => {
const field = this.state[fieldName];
const updatedField = field
? field.replace(
new RegExp(`${field.substr(field.lastIndexOf(',') + 1).trim()}$`),
''
) +
contact.primaryEmail +
', '
: contact.primaryEmail + ', ';

this.setState(({
[fieldName]: updatedField,
focusInput: fieldName
} as unknown) as Pick<State, keyof State>);
};

handleKeyDown = (e: any, fieldName: string) => {
const { selectedSuggestionIndex } = this.state;
const filterContacts = this.getFilteredContacts(fieldName);

if (e.keyCode === 38 && selectedSuggestionIndex > 0) {
e.preventDefault();
this.setState({
selectedSuggestionIndex: selectedSuggestionIndex - 1
});
}

if (
e.keyCode === 40 &&
selectedSuggestionIndex < filterContacts.length - 1
) {
e.preventDefault();
this.setState({
selectedSuggestionIndex: selectedSuggestionIndex + 1
});
}

if (e.keyCode === 13) {
const selectedItem = filterContacts[selectedSuggestionIndex];
selectedItem && this.handleSuggestionClick(selectedItem, fieldName);
}
};

renderMailSuggestions(fieldName: string) {
const filterContacts = this.getFilteredContacts(fieldName);

if (filterContacts.length === 0) {
return null;
}

return (
<MailSuggestionContainer>
{filterContacts.map((contact, index) =>
this.renderMailSuggestionsRow(contact, index, fieldName)
)}
</MailSuggestionContainer>
);
}

renderMailSuggestionsRow(
contact: IContact,
index: number,
fieldName: string
) {
const { selectedSuggestionIndex } = this.state;
const { primaryName, primaryEmail, avatar } = contact;
const field = this.state[fieldName];
const fieldRegex = new RegExp(
`(${field.substr(field.lastIndexOf(',') + 1).trim()})`,
'gi'
);

return (
<MailSuggestionItem
key={index}
onMouseDown={e => {
e.preventDefault();
this.handleSuggestionClick(contact, fieldName);
}}
className={`${index === selectedSuggestionIndex ? 'selected' : ''}`}
>
<Avatar
src={avatar ? readFile(avatar, 40) : '/images/avatar-colored.svg'}
/>
<Column>
{primaryName && (
<p
dangerouslySetInnerHTML={{
__html: primaryName.replace(
fieldRegex,
'<span style="font-weight: bold;">$1</span>'
)
}}
/>
)}
<p>{primaryEmail}</p>
</Column>
</MailSuggestionItem>
);
}

renderTo() {
return (
<FlexRow isEmail={true}>
<label>To:</label>
<FormControl
autoFocus={this.props.isForward}
value={this.state.to}
onChange={this.onSelectChange.bind(this, 'to')}
name="to"
required={true}
/>
<MailColumn>
<FormControl
autoFocus={this.props.isForward}
value={this.state.to}
onChange={e => this.onSelectChange('to', e)}
name="to"
required={true}
autoComplete="off"
onKeyDown={e => {
this.handleKeyDown(e, 'to');
}}
onFocus={() => this.setState({ focusInput: 'to' })}
onBlur={() => this.setState({ focusInput: '' })}
/>
{this.state.focusInput === 'to' && this.renderMailSuggestions('to')}
</MailColumn>
{this.renderRightSide()}
</FlexRow>
);
Expand All @@ -577,13 +725,20 @@ class MailForm extends React.Component<Props, State> {
return (
<FlexRow>
<label>Cc:</label>
<FormControl
autoFocus={true}
componentClass="textarea"
onChange={this.onSelectChange.bind(this, 'cc')}
name="cc"
value={cc}
/>
<MailColumn>
<FormControl
autoFocus={true}
onChange={this.onSelectChange.bind(this, 'cc')}
name="cc"
value={cc}
onKeyDown={e => {
this.handleKeyDown(e, 'cc');
}}
onFocus={() => this.setState({ focusInput: 'cc' })}
onBlur={() => this.setState({ focusInput: '' })}
/>
{this.state.focusInput === 'cc' && this.renderMailSuggestions('cc')}
</MailColumn>
</FlexRow>
);
}
Expand All @@ -598,13 +753,20 @@ class MailForm extends React.Component<Props, State> {
return (
<FlexRow>
<label>Bcc:</label>
<FormControl
autoFocus={true}
onChange={this.onSelectChange.bind(this, 'bcc')}
componentClass="textarea"
name="bcc"
value={bcc}
/>
<MailColumn>
<FormControl
autoFocus={true}
onChange={this.onSelectChange.bind(this, 'bcc')}
name="bcc"
value={bcc}
onKeyDown={e => {
this.handleKeyDown(e, 'bcc');
}}
onFocus={() => this.setState({ focusInput: 'bcc' })}
onBlur={() => this.setState({ focusInput: '' })}
/>
{this.state.focusInput === 'bcc' && this.renderMailSuggestions('bcc')}
</MailColumn>
</FlexRow>
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import { isEnabled } from '@erxes/ui/src/utils/core';
import queryString from 'query-string';
import withCurrentUser from '@erxes/ui/src/auth/containers/withCurrentUser';
import { withRouter } from 'react-router-dom';
import { ContactQueryResponse } from '../../types';

type Props = {
detailQuery?: any;
Expand Down Expand Up @@ -52,6 +53,7 @@ type FinalProps = {
currentUser: IUser;
emailTemplatesQuery: any /*change type*/;
emailTemplatesTotalCountQuery: any /*change type*/;
contactsMainQuery: ContactQueryResponse;
} & Props;

class MailFormContainer extends React.Component<
Expand Down Expand Up @@ -82,6 +84,7 @@ class MailFormContainer extends React.Component<
closeModal,
emailTemplatesQuery,
emailTemplatesTotalCountQuery,
contactsMainQuery,
currentUser,
mails,
messageId
Expand Down Expand Up @@ -254,6 +257,35 @@ class MailFormContainer extends React.Component<
});
};

const contacts = !contactsMainQuery.loading
? [
...contactsMainQuery?.customers?.list,
...contactsMainQuery?.companies?.list,
...contactsMainQuery?.leads?.list
]
.filter(contact => {
return contact.primaryEmail !== null;
})
.map(contact => {
const {
_id,
firstName,
lastName,
primaryName,
primaryEmail,
avatar
} = contact;

return {
primaryName:
primaryName || `${firstName || ''} ${lastName || ''}`,
primaryEmail: primaryEmail,
avatar: avatar,
id: _id
};
})
: [];

const updatedProps = {
...this.props,
sendMail,
Expand All @@ -265,7 +297,8 @@ class MailFormContainer extends React.Component<
mails,
messageId,
verifiedImapEmails: verifiedImapEmails || [],
verifiedEngageEmails: verifiedEngageEmails || []
verifiedEngageEmails: verifiedEngageEmails || [],
contacts: contacts || []
};

return <MailForm {...updatedProps} />;
Expand Down Expand Up @@ -293,6 +326,19 @@ const WithMailForm = withProps<Props>(
fetchPolicy: 'cache-first'
}),
skip: !isEnabled('emailtemplates')
}),
graphql<Props, any>(gql(queries.contacts), {
name: 'contactsMainQuery',
options: ({ queryParams }) => ({
variables: {
page: 1,
perPage: 20,
leadType: 'lead',
customerType: 'customer'
},
fetchPolicy: 'cache-first'
}),
skip: !isEnabled('contacts')
})
)(withCurrentUser(MailFormContainer))
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ import { queries } from '../graphql';
import sanitizeHtml from 'sanitize-html';

export const formatStr = (emailString?: string) => {
return emailString ? emailString.split(/[ ,]+/) : [];
return emailString
? emailString.split(/[ , ]+/).filter(email => email !== '')
: [];
};

export const formatObj = (emailArray: IEmail[]) => {
Expand Down
Loading