Skip to content

Commit

Permalink
[#2148] enable users to connect via instagram (#2169)
Browse files Browse the repository at this point in the history
* adding instagram source

* fixed request values

* api request change

* removed tmp.yaml and logs

* updated instagram svg

* added styling icon for instagram

* fix console.log

* fixed small bugs: title and button

* fixed avatar icon
  • Loading branch information
AudreyKj committed Jul 26, 2021
1 parent 3a0d225 commit 6dfaa7d
Show file tree
Hide file tree
Showing 22 changed files with 420 additions and 29 deletions.
2 changes: 2 additions & 0 deletions frontend/ui/handles/index.ts
Expand Up @@ -45,3 +45,5 @@ export const cyDisplayName = 'displayName';
export const cyDisplayNameInput = 'displayNameInput';
export const cyEditDisplayNameCheckmark = 'editDisplayNameCheckmark';
export const cyClickableListItem = 'clickableListItem';
export const cyChannelsInstagramAddButton = 'cyChannelsInstagramAddButton';
export const cyChannelsInstagramList = 'cyChannelsInstagramList';
8 changes: 8 additions & 0 deletions frontend/ui/src/actions/channel/index.ts
Expand Up @@ -12,6 +12,7 @@ import {
ConnectTwilioWhatsappRequestPayload,
UpdateChannelRequestPayload,
ConnectChannelGoogleRequestPayload,
ConnectChannelInstagramRequestPayload,
} from 'httpclient';

import {HttpClientInstance} from '../../InitializeAiryApi';
Expand Down Expand Up @@ -49,6 +50,13 @@ export const connectFacebookChannel =
return Promise.resolve(response);
});

export const connectInstagramChannel =
(requestPayload: ConnectChannelInstagramRequestPayload) => async (dispatch: Dispatch<any>) =>
HttpClientInstance.connectInstagramChannel(requestPayload).then((response: Channel) => {
dispatch(addChannelsAction([response]));
return Promise.resolve(response);
});

export const connectChatPlugin = (requestPayload: ConnectChatPluginRequestPayload) => async (dispatch: Dispatch<any>) =>
HttpClientInstance.connectChatPluginChannel(requestPayload).then((response: Channel) => {
dispatch(addChannelsAction([response]));
Expand Down
3 changes: 3 additions & 0 deletions frontend/ui/src/components/ChannelAvatar/index.tsx
Expand Up @@ -4,6 +4,7 @@ import {ReactComponent as WhatsappAvatar} from 'assets/images/icons/whatsapp_ava
import {ReactComponent as SmsAvatar} from 'assets/images/icons/sms_avatar.svg';
import {ReactComponent as FacebookAvatar} from 'assets/images/icons/messenger_avatar.svg';
import {ReactComponent as AiryAvatar} from 'assets/images/icons/airy_avatar.svg';
import {ReactComponent as InstagramAvatar} from 'assets/images/icons/instagram_avatar.svg';
import {Channel, Source} from 'model';
import styles from './index.module.scss';

Expand Down Expand Up @@ -41,6 +42,8 @@ const ChannelAvatar = (props: ChannelAvatarProps) => {
return <SmsAvatar />;
case Source.twilioWhatsApp:
return <WhatsappAvatar />;
case Source.instagram:
return <InstagramAvatar />;
default:
return <AiryAvatar />;
}
Expand Down
2 changes: 1 addition & 1 deletion frontend/ui/src/components/SourceIcon/index.tsx
Expand Up @@ -5,7 +5,7 @@ import {ReactComponent as WhatsappIcon} from 'assets/images/icons/whatsapp_avata
import {ReactComponent as SmsIcon} from 'assets/images/icons/sms_avatar.svg';
import {ReactComponent as FacebookIcon} from 'assets/images/icons/messenger_avatar.svg';
import {ReactComponent as AiryAvatar} from 'assets/images/icons/airy_avatar.svg';
import {ReactComponent as InstagramIcon} from 'assets/images/icons/instagramSource.svg';
import {ReactComponent as InstagramIcon} from 'assets/images/icons/instagram_avatar.svg';
import {ReactComponent as BubbleIcon} from 'assets/images/icons/bubble.svg';

const sourceIconsMap = {
Expand Down
Expand Up @@ -23,6 +23,7 @@ import {
CHANNELS_TWILIO_SMS_ROUTE,
CHANNELS_TWILIO_WHATSAPP_ROUTE,
CHANNELS_GOOGLE_ROUTE,
CHANNELS_INSTAGRAM_ROUTE,
} from '../../../routes/routes';

type ConnectedChannelsListProps = {} & ConnectedProps<typeof connector> & RouteComponentProps<{source: string}>;
Expand Down Expand Up @@ -75,6 +76,10 @@ const ConnectedChannelsList = (props: ConnectedChannelsListProps) => {
setName('Chat Plugin');
setPath(CHANNELS_CHAT_PLUGIN_ROUTE + '/new');
break;
case Source.instagram:
setName('Instagram');
setPath(CHANNELS_INSTAGRAM_ROUTE + '/new');
break;
}
};

Expand Down
20 changes: 20 additions & 0 deletions frontend/ui/src/pages/Channels/MainPage/index.tsx
Expand Up @@ -3,6 +3,7 @@ import {withRouter, RouteComponentProps} from 'react-router-dom';

import {Source, Channel, Config} from 'model';
import {FacebookMessengerRequirementsDialog} from '../Providers/Facebook/Messenger/FacebookMessengerRequirementsDialog';
import {InstagramRequirementsDialog} from '../Providers/Instagram/InstagramRequirementsDialog';
import {GoogleBusinessMessagesRequirementsDialog} from '../Providers/Google/GoogleBusinessMessagesRequirementsDialog';
import {TwilioRequirementsDialog} from '../Providers/Twilio/TwilioRequirementsDialog';
import SourceDescriptionCard from '../SourceDescriptionCard';
Expand All @@ -13,6 +14,7 @@ import {ReactComponent as MessengerAvatarIcon} from 'assets/images/icons/messeng
import {ReactComponent as SMSAvatarIcon} from 'assets/images/icons/sms_avatar.svg';
import {ReactComponent as WhatsAppAvatarIcon} from 'assets/images/icons/whatsapp_avatar.svg';
import {ReactComponent as GoogleAvatarIcon} from 'assets/images/icons/google_avatar.svg';
import {ReactComponent as InstagramIcon} from 'assets/images/icons/instagram_avatar.svg';

import styles from './index.module.scss';
import {
Expand All @@ -26,6 +28,8 @@ import {
cyChannelsTwilioSmsList,
cyChannelsTwilioWhatsappAddButton,
cyChannelsTwilioWhatsappList,
cyChannelsInstagramAddButton,
cyChannelsInstagramList,
} from 'handles';
import {
CHANNELS_FACEBOOK_ROUTE,
Expand All @@ -34,6 +38,7 @@ import {
CHANNELS_CONNECTED_ROUTE,
CHANNELS_CHAT_PLUGIN_ROUTE,
CHANNELS_GOOGLE_ROUTE,
CHANNELS_INSTAGRAM_ROUTE,
} from '../../../routes/routes';

type MainPageProps = {
Expand Down Expand Up @@ -121,6 +126,19 @@ const SourcesInfo: SourceInfo[] = [
dataCyAddChannelButton: cyChannelsGoogleAddButton,
dataCyChannelList: cyChannelsGoogleList,
},
{
type: Source.instagram,
title: 'Instagram',
description: 'Connect multiple Instagram pages',
image: <InstagramIcon />,
newChannelRoute: CHANNELS_INSTAGRAM_ROUTE,
channelsListRoute: CHANNELS_CONNECTED_ROUTE + '/instagram',
configKey: 'sources-facebook',
channelsToShow: 4,
itemInfoString: 'channels',
dataCyAddChannelButton: cyChannelsInstagramAddButton,
dataCyChannelList: cyChannelsInstagramList,
},
];

const MainPage = (props: MainPageProps & RouteComponentProps) => {
Expand All @@ -136,6 +154,8 @@ const MainPage = (props: MainPageProps & RouteComponentProps) => {
case Source.twilioSMS:
case Source.twilioWhatsApp:
return <TwilioRequirementsDialog onClose={() => setDisplayDialogFromSource('')} />;
case Source.instagram:
return <InstagramRequirementsDialog onClose={() => setDisplayDialogFromSource('')} />;
}

return null;
Expand Down
@@ -0,0 +1,66 @@
@import 'assets/scss/fonts.scss';
@import 'assets/scss/colors.scss';

.wrapper {
background: white;
display: block;
border-radius: 10px;
padding-left: 96px;
padding-top: 88px;
width: 100%;
padding: 32px;
margin: 88px 1.5em 0 100px;
min-height: calc(100vh - 170px);
}

.headline {
@include font-xl;
font-weight: bold;
margin-bottom: 8px;
}

.backButton {
display: block;
margin-bottom: 16px;
cursor: pointer;
text-decoration: none;
&:hover {
text-decoration: underline;
}
}

.backIcon {
height: 13px;
width: 17px;
path {
fill: var(--color-airy-blue);
}
margin-right: 8px;
}

.inputContainer {
display: flex;
flex-direction: column;
margin-bottom: 32px;
width: 474px;
margin-top: 16px;

label {
margin-top: 24px;
}

input {
@include font-base;
}
}

.subtitle {
display: flex;
flex-direction: column;
@include font-s;
color: var(--color-airy-blue);
img {
width: 17px;
height: 13px;
}
}
@@ -0,0 +1,152 @@
import React, {useEffect, useState} from 'react';
import {withRouter, RouteComponentProps} from 'react-router-dom';
import _, {connect, ConnectedProps} from 'react-redux';

import {connectInstagramChannel} from '../../../../actions/channel';
import {StateModel} from '../../../../reducers';

import {Button, Input, LinkButton, InfoButton} from 'components';
import {ConnectChannelInstagramRequestPayload} from 'httpclient';
import {ReactComponent as ArrowLeftIcon} from 'assets/images/icons/arrow-left-2.svg';

import styles from './InstagramConnect.module.scss';

import {CHANNELS_CONNECTED_ROUTE} from '../../../../routes/routes';

type InstagramProps = {
channelId?: string;
} & RouteComponentProps<{channelId: string}> &
ConnectedProps<typeof connector>;

const mapStateToProps = (state: StateModel, props: RouteComponentProps<{channelId: string}>) => ({
channel: state.data.channels[props.match.params.channelId],
});

const mapDispatchToProps = {
connectInstagramChannel,
};

const connector = connect(mapStateToProps, mapDispatchToProps);

const InstagramConnect = (props: InstagramProps) => {
const {connectInstagramChannel, channel} = props;
const [id, setId] = useState(channel?.sourceChannelId || '');
const [token, setToken] = useState('');
const [accountId, setAccountId] = useState('');
const [name, setName] = useState(channel?.metadata?.name || '');
const [image, setImage] = useState(channel?.metadata?.imageUrl || '');
const [buttonTitle, setButtonTitle] = useState('Connect Page');
const [errorMessage, setErrorMessage] = useState('');

const buttonStatus = () => {
return !(id.length > 5 && token != '');
};

useEffect(() => {
if (channel) {
setButtonTitle('Update Page');
}
}, []);

const connectNewChannel = () => {
const connectPayload: ConnectChannelInstagramRequestPayload = {
pageId: id,
pageToken: token,
accountId: accountId,
...(name &&
name !== '' && {
name,
}),
...(image &&
image !== '' && {
imageUrl: image,
}),
};

connectInstagramChannel(connectPayload)
.then(() => {
props.history.replace(CHANNELS_CONNECTED_ROUTE + '/instagram');
})
.catch(() => {
setErrorMessage('Please check entered value');
});
};

return (
<div className={styles.wrapper}>
<h1 className={styles.headline}>Instagram</h1>
<div>
<InfoButton
link="https://airy.co/docs/core/sources/instagram"
text="more information about this source"
color="grey"></InfoButton>

<LinkButton onClick={props.history.goBack} type="button">
<ArrowLeftIcon className={styles.backIcon} />
Back
</LinkButton>
</div>
<div className={styles.inputContainer}>
<Input
id="id"
label="Facebook Page ID connected to the Instagram account"
placeholder="Add the Facebook Page ID"
value={id}
onChange={(event: React.ChangeEvent<HTMLInputElement>) => setId(event.target.value)}
minLength={6}
required={true}
height={32}
hint={errorMessage}
fontClass="font-base"
/>
<Input
id="token"
label="Token"
placeholder="Add the page Access Token"
value={token}
onChange={(event: React.ChangeEvent<HTMLInputElement>) => setToken(event.target.value)}
required={true}
height={32}
hint={errorMessage}
fontClass="font-base"
/>
<Input
id="account_id"
label="ID of the Instagram account"
placeholder="Add the ID of the Instagram account"
value={accountId}
onChange={(event: React.ChangeEvent<HTMLInputElement>) => setAccountId(event.target.value)}
required={true}
height={32}
hint={errorMessage}
fontClass="font-base"
/>
<Input
id="name"
label="Name (optional)"
placeholder="Add a name"
hint="The standard name will be the same as the Facebook Page"
value={name}
onChange={(event: React.ChangeEvent<HTMLInputElement>) => setName(event.target.value)}
height={32}
fontClass="font-base"
/>
<Input
id="image"
label="Image URL (optional)"
placeholder="Add an URL"
hint="The standard picture is the same as the Facebook Page"
value={image}
onChange={(event: React.ChangeEvent<HTMLInputElement>) => setImage(event.target.value)}
height={32}
fontClass="font-base"
/>
</div>
<Button styleVariant="normal" disabled={buttonStatus()} onClick={() => connectNewChannel()}>
{buttonTitle}
</Button>
</div>
);
};

export default withRouter(connector(InstagramConnect));

0 comments on commit 6dfaa7d

Please sign in to comment.