diff options
Diffstat (limited to 'src/components')
-rw-r--r-- | src/components/common/SocialIcon.tsx | 3 | ||||
-rw-r--r-- | src/components/onboarding/LinkSocialMedia.tsx | 204 | ||||
-rw-r--r-- | src/components/onboarding/RegistrationWizard.tsx | 12 | ||||
-rw-r--r-- | src/components/onboarding/index.ts | 1 |
4 files changed, 218 insertions, 2 deletions
diff --git a/src/components/common/SocialIcon.tsx b/src/components/common/SocialIcon.tsx index 5c1098af..a46b1445 100644 --- a/src/components/common/SocialIcon.tsx +++ b/src/components/common/SocialIcon.tsx @@ -40,6 +40,9 @@ const SocialIcon: React.FC<SocialIconProps> = ({ case 'Youtube': var icon = require('../../assets/images/youtube-icon.png'); break; + case 'TikTok': + var icon = require('../../assets/images/tiktok-icon.png'); + break; default: var icon = require('../../assets/images/logo.png'); break; diff --git a/src/components/onboarding/LinkSocialMedia.tsx b/src/components/onboarding/LinkSocialMedia.tsx new file mode 100644 index 00000000..5f95fac8 --- /dev/null +++ b/src/components/onboarding/LinkSocialMedia.tsx @@ -0,0 +1,204 @@ +/** + * This is a duplicate file, adding this now to avoid conflicts with incoming changes on the original 'SocialMediaLinker' + */ + +import AsyncStorage from '@react-native-community/async-storage'; +import React from 'react'; +import { + Alert, + Image, + StyleSheet, + Text, + TouchableOpacity, + TouchableOpacityProps, +} from 'react-native'; +import InAppBrowser from 'react-native-inappbrowser-reborn'; +import {LinkerType} from 'src/types'; +import { + LINK_FB_ENDPOINT, + LINK_FB_OAUTH, + LINK_IG_ENDPOINT, + LINK_IG_OAUTH, + LINK_TWITTER_ENDPOINT, + LINK_TWITTER_OAUTH, +} from '../../constants'; +import {SOCIAL_FONT_COLORS} from '../../constants/constants'; +import SocialIcon from '../common/SocialIcon'; + +interface SocialMediaLinkerProps extends TouchableOpacityProps { + social: LinkerType; +} + +const SocialMediaLinker: React.FC<SocialMediaLinkerProps> = ({ + social: {label}, +}) => { + const [state, setState] = React.useState({ + authenticated: false, + }); + + const integrated_endpoints: {[label: string]: [string, string]} = { + Instagram: [LINK_IG_OAUTH, LINK_IG_ENDPOINT], + Facebook: [LINK_FB_OAUTH, LINK_FB_ENDPOINT], + Twitter: [LINK_TWITTER_OAUTH, LINK_TWITTER_ENDPOINT], + }; + + const registerSocialLink: (token: string) => Promise<boolean> = async ( + callback_url, + ) => { + if (!(label in integrated_endpoints)) { + // This error is already handled earlier, more of a safety check here + return false; + } + const user_token = await AsyncStorage.getItem('token'); + const response = await fetch(integrated_endpoints[label][1], { + method: 'POST', + headers: { + Authorization: `Token ${user_token}`, + }, + body: JSON.stringify({ + callback_url: callback_url, + }), + }); + if (!(response.status === 201)) { + console.log(await response.json()); + } + return response.status === 201; + }; + + const handlePress = async () => { + try { + const isAvailable = await InAppBrowser.isAvailable(); + if (!(label in integrated_endpoints)) { + // TODO handle non-integrated social links with a modal + // TODO remove the alert below + Alert.alert('Coming soon!'); + return; + } + let url = integrated_endpoints[label][0]; + + // We will need to do an extra step for twitter sign-in + if (label === 'Twitter') { + const user_token = await AsyncStorage.getItem('token'); + const response = await fetch(url, { + method: 'GET', + headers: { + Authorization: `Token ${user_token}`, + }, + }); + url = response.url; + } + + if (isAvailable) { + InAppBrowser.openAuth(url, 'taggid://callback', { + ephemeralWebSession: true, + }) + .then(async (response) => { + console.log(response); + if (response.type === 'success' && response.url) { + const success = await registerSocialLink(response.url); + if (!success) { + throw new Error('Unable to register with backend'); + } + setState({ + ...state, + authenticated: true, + }); + Alert.alert(`Successfully linked ${label} 🎉`); + } else { + throw new Error(`Unable to link with ${label} API`); + } + }) + .catch((error) => { + console.log(error); + Alert.alert(`Something went wrong, we can't link with ${label} 😔`); + }); + } else { + // Okay... to open an external browser and have it link back to + // the app is a bit tricky, we will need to have navigation routes + // setup for this screen and have it hooked up. + // See https://github.com/proyecto26/react-native-inappbrowser#authentication-flow-using-deep-linking + // Though this isn't the end of the world, from the documentation, + // the in-app browser should be supported from iOS 11, which + // is about 98.5% of all iOS devices in the world. + // See https://support.apple.com/en-gb/HT209574 + Alert.alert( + 'Sorry! Your device was unable to open a browser to let you sign-in! 😔', + ); + } + } catch (error) { + console.log(error); + Alert.alert(`Something went wrong, we can't link with ${label} 😔`); + } + }; + + switch (label) { + case 'Instagram': + var font_color = SOCIAL_FONT_COLORS.INSTAGRAM; + break; + case 'Facebook': + var font_color = SOCIAL_FONT_COLORS.FACEBOOK; + break; + case 'Twitter': + var font_color = SOCIAL_FONT_COLORS.TWITTER; + break; + case 'Twitch': + var font_color = SOCIAL_FONT_COLORS.TWITCH; + break; + case 'Pinterest': + var font_color = SOCIAL_FONT_COLORS.PINTEREST; + break; + case 'Whatsapp': + var font_color = SOCIAL_FONT_COLORS.WHATSAPP; + break; + case 'Linkedin': + var font_color = SOCIAL_FONT_COLORS.LINKEDIN; + break; + case 'Snapchat': + var font_color = SOCIAL_FONT_COLORS.SNAPCHAT; + break; + case 'Youtube': + var font_color = SOCIAL_FONT_COLORS.YOUTUBE; + break; + default: + var font_color = '#fff'; + } + + return ( + <TouchableOpacity + activeOpacity={0.7} + onPress={handlePress} + style={styles.container}> + <SocialIcon social={label} style={styles.icon} /> + <Text style={[styles.label, {color: font_color}]}>{label}</Text> + {state.authenticated && ( + <Image + source={require('../../assets/images/link-tick.png')} + style={styles.tick} + /> + )} + </TouchableOpacity> + ); +}; + +const styles = StyleSheet.create({ + container: { + width: '28%', + height: '100%', + backgroundColor: '#4c409a', + borderRadius: 8, + marginHorizontal: '2%', + marginVertical: '2%', + alignItems: 'center', + }, + icon: { + top: '15%', + }, + label: { + fontWeight: '500', + top: '25%', + }, + tick: { + top: '30%', + }, +}); +export default SocialMediaLinker; diff --git a/src/components/onboarding/RegistrationWizard.tsx b/src/components/onboarding/RegistrationWizard.tsx index 8d747b01..437e7cfb 100644 --- a/src/components/onboarding/RegistrationWizard.tsx +++ b/src/components/onboarding/RegistrationWizard.tsx @@ -3,7 +3,7 @@ import {View, StyleSheet, ViewProps, Keyboard} from 'react-native'; import * as Animatable from 'react-native-animatable'; interface RegistrationWizardProps extends ViewProps { - step: 'one' | 'two' | 'three' | 'four' | 'five' | 'six'; + step: 'one' | 'two' | 'three' | 'four' | 'five' | 'six' | 'seven'; } const RegistrationWizard = (props: RegistrationWizardProps) => { @@ -43,6 +43,10 @@ const RegistrationWizard = (props: RegistrationWizardProps) => { <View style={props.step === 'five' ? stepActiveStyle : stepStyle} /> <View style={styles.progress} /> <View style={props.step === 'six' ? stepActiveStyle : stepStyle} /> + <View style={styles.progress} /> + <View + style={props.step === 'seven' ? stepActiveStyle : stepStyle} + /> </View> </Animatable.View> )} @@ -62,6 +66,10 @@ const RegistrationWizard = (props: RegistrationWizardProps) => { <View style={props.step === 'five' ? stepActiveStyle : stepStyle} /> <View style={styles.progress} /> <View style={props.step === 'six' ? stepActiveStyle : stepStyle} /> + <View style={styles.progress} /> + <View + style={props.step === 'seven' ? stepActiveStyle : stepStyle} + /> </View> </Animatable.View> )} @@ -86,7 +94,7 @@ const styles = StyleSheet.create({ backgroundColor: '#e1f0ff', }, progress: { - width: '13%', + width: '10%', height: 2, backgroundColor: '#e1f0ff', }, diff --git a/src/components/onboarding/index.ts b/src/components/onboarding/index.ts index 627412df..aaad7a62 100644 --- a/src/components/onboarding/index.ts +++ b/src/components/onboarding/index.ts @@ -8,3 +8,4 @@ export {default as TaggBigInput} from './TaggBigInput'; export {default as TaggDatePicker} from './TaggDatePicker'; export {default as TaggDropDown} from './TaggDropDown'; export {default as SocialMediaLinker} from './SocialMediaLinker'; +export {default as LinkSocialMedia} from './LinkSocialMedia'; |