aboutsummaryrefslogtreecommitdiff
path: root/src/screens/profile
diff options
context:
space:
mode:
authorIvan Chen <ivan@tagg.id>2021-04-21 13:57:09 -0400
committerGitHub <noreply@github.com>2021-04-21 13:57:09 -0400
commit4e8e1c0d58424e6b63cfb8470fc0a73c0e6b102b (patch)
tree5b2dcc2daffc5b6f4fa2ae2b55c5548a12b6210c /src/screens/profile
parentb556f97a7eae3f9d9fce2d9c5c25f419ba77fa14 (diff)
parentf902c4938344dd25d82d7d01035476f488db2b24 (diff)
Merge pull request #370 from IvanIFChen/tma795-move-create-button
[TMA-795/796] Move create button
Diffstat (limited to 'src/screens/profile')
-rw-r--r--src/screens/profile/AccountType.tsx3
-rw-r--r--src/screens/profile/CaptionScreen.tsx5
-rw-r--r--src/screens/profile/CategorySelection.tsx273
-rw-r--r--src/screens/profile/CreateCustomCategory.tsx121
-rw-r--r--src/screens/profile/IndividualMoment.tsx4
-rw-r--r--src/screens/profile/index.ts2
6 files changed, 401 insertions, 7 deletions
diff --git a/src/screens/profile/AccountType.tsx b/src/screens/profile/AccountType.tsx
index 60ed0668..8a3f7775 100644
--- a/src/screens/profile/AccountType.tsx
+++ b/src/screens/profile/AccountType.tsx
@@ -10,6 +10,7 @@ import {
import {SafeAreaView} from 'react-native-safe-area-context';
import {useDispatch, useSelector} from 'react-redux';
import {Background} from '../../components';
+import {TAGG_LIGHT_BLUE_2} from '../../constants';
import {updateProfileVisibility} from '../../services';
import {NO_PROFILE} from '../../store/initialStates';
import {RootState} from '../../store/rootReducer';
@@ -60,7 +61,7 @@ const AccountType: React.FC = () => {
/>
{!isLoading && (
<Switch
- trackColor={{false: 'red', true: '#6EE7E7'}}
+ trackColor={{false: 'red', true: TAGG_LIGHT_BLUE_2}}
thumbColor={'white'}
ios_backgroundColor="transparent"
style={styles.switchStyles}
diff --git a/src/screens/profile/CaptionScreen.tsx b/src/screens/profile/CaptionScreen.tsx
index 998897e2..282857d6 100644
--- a/src/screens/profile/CaptionScreen.tsx
+++ b/src/screens/profile/CaptionScreen.tsx
@@ -13,11 +13,12 @@ import {
} from 'react-native';
import {Button} from 'react-native-elements';
import {useDispatch, useSelector} from 'react-redux';
-import {MainStackParams} from '../../routes';
import {SearchBackground, TaggBigInput} from '../../components';
import {CaptionScreenHeader} from '../../components/';
import TaggLoadingIndicator from '../../components/common/TaggLoadingIndicator';
+import {TAGG_LIGHT_BLUE_2} from '../../constants';
import {ERROR_UPLOAD, SUCCESS_PIC_UPLOAD} from '../../constants/strings';
+import {MainStackParams} from '../../routes';
import {postMoment} from '../../services';
import {
loadUserMoments,
@@ -137,7 +138,7 @@ const styles = StyleSheet.create({
},
shareButtonTitle: {
fontWeight: 'bold',
- color: '#6EE7E7',
+ color: TAGG_LIGHT_BLUE_2,
},
header: {
marginVertical: 20,
diff --git a/src/screens/profile/CategorySelection.tsx b/src/screens/profile/CategorySelection.tsx
new file mode 100644
index 00000000..c02eef0d
--- /dev/null
+++ b/src/screens/profile/CategorySelection.tsx
@@ -0,0 +1,273 @@
+import {RouteProp} from '@react-navigation/native';
+import {StackNavigationProp} from '@react-navigation/stack';
+import React, {useEffect, useState} from 'react';
+import {
+ Alert,
+ StatusBar,
+ StyleSheet,
+ Text,
+ TouchableOpacity,
+ View,
+} from 'react-native';
+import {ScrollView} from 'react-native-gesture-handler';
+import {useDispatch, useSelector} from 'react-redux';
+import PlusIcon from '../../assets/icons/plus_icon-01.svg';
+import {Background, MomentCategory} from '../../components';
+import {MOMENT_CATEGORIES, TAGG_LIGHT_BLUE_2} from '../../constants';
+import {ERROR_SOMETHING_WENT_WRONG} from '../../constants/strings';
+import {MainStackParams} from '../../routes';
+import {updateMomentCategories} from '../../store/actions';
+import {RootState} from '../../store/rootReducer';
+import {BackgroundGradientType} from '../../types';
+import {normalize, SCREEN_WIDTH} from '../../utils';
+
+type CategorySelectionRouteProps = RouteProp<
+ MainStackParams,
+ 'CategorySelection'
+>;
+
+type CategorySelectionNavigationProps = StackNavigationProp<
+ MainStackParams,
+ 'CategorySelection'
+>;
+
+interface CategorySelectionProps {
+ route: CategorySelectionRouteProps;
+ navigation: CategorySelectionNavigationProps;
+}
+
+const CategorySelection: React.FC<CategorySelectionProps> = ({
+ route,
+ navigation,
+}) => {
+ const dispatch = useDispatch();
+ const {newCustomCategory} = route.params;
+ const {momentCategories = []} = useSelector(
+ (state: RootState) => state.momentCategories,
+ );
+
+ // Stores all the categories that will be saved to the store
+ const [selectedCategories, setSelectedCategories] = useState<string[]>([]);
+
+ /**
+ * Stores all the custom categories for the UI, allow easier logic for
+ * unchecking a custom category.
+ *
+ * Each uncommited custom category should also have a copy in selectedCategories
+ * since that's the final value that will be stored in the store.
+ */
+ const [uncommitedCustomCategories, setUncommitedCustomCategories] = useState<
+ string[]
+ >([]);
+
+ const customCategories = momentCategories.filter(
+ (mc) => !MOMENT_CATEGORIES.includes(mc),
+ );
+
+ navigation.setOptions({
+ headerRight: () => (
+ <TouchableOpacity onPress={handleButtonPress}>
+ <Text style={styles.createLabel}>Create</Text>
+ </TouchableOpacity>
+ ),
+ });
+
+ useEffect(() => {
+ if (newCustomCategory) {
+ setUncommitedCustomCategories([
+ ...uncommitedCustomCategories,
+ newCustomCategory,
+ ]);
+ selectedCategories.push(newCustomCategory);
+ }
+ }, [newCustomCategory]);
+
+ /**
+ * Handle selection of a new category
+ * case isAdded:
+ * Return without doing anything
+ * case isSelected:
+ * Add to the selected categories
+ * case not isSelected:
+ * Remove from the selected categories
+ */
+ const onSelect = (
+ category: string,
+ isSelected: boolean,
+ isAdded: boolean,
+ ) => {
+ if (isAdded) {
+ return;
+ }
+ if (isSelected) {
+ setSelectedCategories((prev) => [...prev, category]);
+ } else {
+ setSelectedCategories(
+ selectedCategories.filter((item) => item !== category),
+ );
+ }
+ };
+
+ /**
+ * Handle deselection of custom category.
+ *
+ * Custom categories is "added" and "selected" by CreateCustomCategory screen.
+ * User can only "deselect" an uncommited custom category.
+ *
+ * case isAdded || isSelected:
+ * Return without doing anything
+ * default:
+ * Remove from selected categories AND uncommitedCustomCategories
+ */
+ const onDeselectCustomCategory = (
+ category: string,
+ isSelected: boolean,
+ isAdded: boolean,
+ ) => {
+ if (isAdded || isSelected) {
+ return;
+ }
+ setSelectedCategories(
+ selectedCategories.filter((item) => item !== category),
+ );
+ setUncommitedCustomCategories(
+ uncommitedCustomCategories.filter((item) => item !== category),
+ );
+ };
+
+ const handleButtonPress = async () => {
+ if (momentCategories.length + selectedCategories.length === 0) {
+ Alert.alert('Please select at least 1 category');
+ return;
+ }
+ try {
+ dispatch(
+ updateMomentCategories(
+ momentCategories.concat(selectedCategories),
+ true,
+ ),
+ );
+ navigation.goBack();
+ } catch (error) {
+ console.log(error);
+ Alert.alert(ERROR_SOMETHING_WENT_WRONG);
+ }
+ };
+
+ /**
+ * Using a scroll view to accomodate dynamic category creation later on
+ */
+ return (
+ <ScrollView bounces={false}>
+ <Background
+ style={styles.container}
+ gradientType={BackgroundGradientType.Dark}>
+ <StatusBar barStyle="light-content" />
+ <Text style={styles.subtext}>Create Categories</Text>
+ <View style={styles.container}>
+ <TouchableOpacity
+ style={styles.createCategory}
+ onPress={() => {
+ navigation.push('CreateCustomCategory', {
+ existingCategories: momentCategories.concat(selectedCategories),
+ });
+ }}>
+ <PlusIcon width={30} height={30} color="white" />
+ <Text style={styles.createCategoryLabel}>
+ Create your own category
+ </Text>
+ </TouchableOpacity>
+ <View style={styles.linkerContainer}>
+ {/* commited custom categories */}
+ {customCategories.map((category, index) => (
+ <MomentCategory
+ key={index}
+ categoryType={category}
+ isSelected={false}
+ isAdded={true}
+ onSelect={onDeselectCustomCategory}
+ />
+ ))}
+ {/* uncommited custom categroies */}
+ {uncommitedCustomCategories.map((category, index) => (
+ <MomentCategory
+ key={index}
+ categoryType={category}
+ isSelected={selectedCategories.includes(category)}
+ isAdded={false}
+ onSelect={onDeselectCustomCategory}
+ />
+ ))}
+ {customCategories.length + uncommitedCustomCategories.length !==
+ 0 && <View style={styles.divider} />}
+ {MOMENT_CATEGORIES.map((category, index) => (
+ <MomentCategory
+ key={index}
+ categoryType={category}
+ isSelected={selectedCategories.includes(category)}
+ isAdded={momentCategories.includes(category)}
+ onSelect={onSelect}
+ />
+ ))}
+ </View>
+ </View>
+ </Background>
+ </ScrollView>
+ );
+};
+
+const styles = StyleSheet.create({
+ container: {
+ flex: 1,
+ alignItems: 'center',
+ justifyContent: 'space-around',
+ marginBottom: '10%',
+ },
+ linkerContainer: {
+ flex: 1,
+ flexDirection: 'row',
+ flexWrap: 'wrap',
+ justifyContent: 'center',
+ alignContent: 'center',
+ marginBottom: '10%',
+ },
+ subtext: {
+ color: '#fff',
+ fontSize: 20,
+ fontWeight: '600',
+ textAlign: 'center',
+ marginVertical: '8%',
+ marginHorizontal: '10%',
+ marginTop: '15%',
+ },
+ createCategory: {
+ backgroundColor: '#53329B',
+ width: SCREEN_WIDTH * 0.9,
+ height: 70,
+ alignItems: 'center',
+ justifyContent: 'center',
+ borderRadius: 10,
+ flexDirection: 'row',
+ marginBottom: '5%',
+ },
+ createCategoryLabel: {
+ color: 'white',
+ marginLeft: '3%',
+ fontSize: 18,
+ fontWeight: '500',
+ },
+ divider: {
+ borderColor: 'white',
+ borderBottomWidth: 1,
+ width: SCREEN_WIDTH * 0.9,
+ marginVertical: '2%',
+ },
+ createLabel: {
+ color: TAGG_LIGHT_BLUE_2,
+ marginRight: 20,
+ fontSize: normalize(15),
+ fontWeight: '800',
+ },
+});
+
+export default CategorySelection;
diff --git a/src/screens/profile/CreateCustomCategory.tsx b/src/screens/profile/CreateCustomCategory.tsx
new file mode 100644
index 00000000..c4b17b1e
--- /dev/null
+++ b/src/screens/profile/CreateCustomCategory.tsx
@@ -0,0 +1,121 @@
+import {RouteProp} from '@react-navigation/native';
+import {StackNavigationProp} from '@react-navigation/stack';
+import React, {useState} from 'react';
+import {
+ Alert,
+ KeyboardAvoidingView,
+ StatusBar,
+ StyleSheet,
+ Text,
+ TextInput,
+ TouchableOpacity,
+} from 'react-native';
+import {Background} from '../../components';
+import {MainStackParams} from '../../routes';
+import {BackgroundGradientType} from '../../types';
+import {SCREEN_HEIGHT, SCREEN_WIDTH} from '../../utils';
+
+type CreateCustomCategoryRouteProps = RouteProp<
+ MainStackParams,
+ 'CreateCustomCategory'
+>;
+
+type CreateCustomCategoryNavigationProps = StackNavigationProp<
+ MainStackParams,
+ 'CreateCustomCategory'
+>;
+
+interface CreateCustomCategoryProps {
+ route: CreateCustomCategoryRouteProps;
+ navigation: CreateCustomCategoryNavigationProps;
+}
+
+const CreateCustomCategory: React.FC<CreateCustomCategoryProps> = ({
+ route,
+ navigation,
+}) => {
+ /**
+ * Same component to be used for category selection while onboarding and while on profile
+ */
+ const {existingCategories} = route.params;
+ const [newCategory, setNewCategory] = useState('');
+
+ const handleButtonPress = () => {
+ if (existingCategories.includes(newCategory)) {
+ Alert.alert('Looks like you already have that one created!');
+ } else {
+ navigation.navigate('CategorySelection', {
+ newCustomCategory: newCategory,
+ });
+ }
+ };
+
+ return (
+ <>
+ <StatusBar barStyle="light-content" />
+ <Background
+ style={styles.container}
+ gradientType={BackgroundGradientType.Dark}>
+ <KeyboardAvoidingView
+ style={styles.innerContainer}
+ behavior={'padding'}>
+ <Text style={styles.title}>Give your category a name</Text>
+ <TextInput
+ style={styles.input}
+ selectionColor={'white'}
+ onChangeText={setNewCategory}
+ autoFocus={true}
+ />
+ <TouchableOpacity
+ onPress={handleButtonPress}
+ style={styles.finalAction}>
+ <Text style={styles.finalActionLabel}>{'Create'}</Text>
+ </TouchableOpacity>
+ </KeyboardAvoidingView>
+ </Background>
+ </>
+ );
+};
+
+const styles = StyleSheet.create({
+ container: {
+ alignItems: 'center',
+ minHeight: SCREEN_HEIGHT,
+ },
+ innerContainer: {
+ height: '40%',
+ top: '20%',
+ justifyContent: 'space-around',
+ alignItems: 'center',
+ },
+ title: {
+ color: 'white',
+ fontSize: 20,
+ fontWeight: '600',
+ },
+ input: {
+ width: SCREEN_WIDTH * 0.75,
+ fontSize: 30,
+ color: 'white',
+ textAlign: 'center',
+ borderBottomWidth: 1,
+ borderBottomColor: 'white',
+ },
+ finalAction: {
+ backgroundColor: 'white',
+ justifyContent: 'center',
+ alignItems: 'center',
+ width: 150,
+ height: 40,
+ borderRadius: 5,
+ borderWidth: 1,
+ borderColor: '#8F01FF',
+ },
+ finalActionLabel: {
+ fontSize: 16,
+ fontWeight: '500',
+ color: 'black',
+ },
+});
+
+export default CreateCustomCategory;
diff --git a/src/screens/profile/IndividualMoment.tsx b/src/screens/profile/IndividualMoment.tsx
index 871d62bf..515cbacf 100644
--- a/src/screens/profile/IndividualMoment.tsx
+++ b/src/screens/profile/IndividualMoment.tsx
@@ -114,10 +114,6 @@ const styles = StyleSheet.create({
flex: 1,
paddingBottom: 0,
},
- shareButtonTitle: {
- fontWeight: 'bold',
- color: '#6EE7E7',
- },
content: {
flex: 9,
},
diff --git a/src/screens/profile/index.ts b/src/screens/profile/index.ts
index b7efdd3b..d5377494 100644
--- a/src/screens/profile/index.ts
+++ b/src/screens/profile/index.ts
@@ -10,3 +10,5 @@ export {default as InviteFriendsScreen} from './InviteFriendsScreen';
export {default as SettingsScreen} from './SettingsScreen';
export {default as PrivacyScreen} from './PrivacyScreen';
export {default as AccountType} from './AccountType';
+export {default as CategorySelection} from './CategorySelection';
+export {default as CreateCustomCategory} from './CreateCustomCategory';