Skip to content

Commit

Permalink
Merge branch 'main' into emily/storyStyling
Browse files Browse the repository at this point in the history
  • Loading branch information
adityapawar1 authored Apr 24, 2024
2 parents ca3fd58 + e04494e commit 85b33d5
Show file tree
Hide file tree
Showing 11 changed files with 188 additions and 18 deletions.
1 change: 0 additions & 1 deletion assets/icons.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,6 @@ const IconSvgs: Record<IconType, React.ReactElement> = {
</svg>`}
/>
),

home_inactive: (
<SvgXml
xml={`<svg
Expand Down
Binary file removed assets/save_story.png
Binary file not shown.
Binary file removed assets/saved_story.png
Binary file not shown.
22 changes: 22 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
"expo": "~49.0.11",
"expo-constants": "~14.4.2",
"expo-font": "~11.4.0",
"expo-image": "~1.3.5",
"expo-linking": "~5.0.2",
"expo-router": "^2.0.0",
"expo-status-bar": "~1.6.0",
Expand Down Expand Up @@ -72,11 +73,11 @@
"react-native-vector-icons": "^10.0.2",
"react-scroll-to-top": "^3.0.0",
"use-debounce": "^10.0.0",
"validator": "^13.11.0",
"expo-image": "~1.3.5"
"validator": "^13.11.0"
},
"devDependencies": {
"@babel/core": "^7.20.0",
"@iconify/react": "^4.1.1",
"@types/react": "~18.2.14",
"@types/react-native": "^0.72.3",
"@types/react-native-htmlview": "^0.16.1",
Expand Down
21 changes: 18 additions & 3 deletions src/app/(tabs)/library/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import {
fetchUserStoriesReadingList,
} from '../../../queries/savedStories';
import { FlatList } from 'react-native-gesture-handler';
import { usePubSub } from '../../../utils/PubSubContext';
import { Channel, usePubSub } from '../../../utils/PubSubContext';

function LibraryScreen() {
const { user } = useSession();
Expand All @@ -25,6 +25,7 @@ function LibraryScreen() {
);
const { channels } = usePubSub();
let updateReadingListTimeout: NodeJS.Timeout | null = null;
let updateFavoritesListTimeout: NodeJS.Timeout | null = null;

const favoritesPressed = () => {
setFavoritesSelected(true);
Expand Down Expand Up @@ -60,6 +61,20 @@ function LibraryScreen() {
);
};

useEffect(() => {
if (updateFavoritesListTimeout) {
clearTimeout(updateFavoritesListTimeout);
}

updateFavoritesListTimeout = setTimeout(
() =>
fetchUserStoriesFavorites(user?.id).then(favoriteStories => {
setFavoriteStories(favoriteStories);
}),
4000,
);
}, [channels[Channel.FAVORITES]]);

useEffect(() => {
if (updateReadingListTimeout) {
clearTimeout(updateReadingListTimeout);
Expand All @@ -70,9 +85,9 @@ function LibraryScreen() {
fetchUserStoriesReadingList(user?.id).then(readingList => {
setReadingListStories(readingList);
}),
5000,
4000,
);
}, [channels]);
}, [channels[Channel.SAVED_STORIES]]);

useEffect(() => {
(async () => {
Expand Down
20 changes: 19 additions & 1 deletion src/app/(tabs)/story/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ import { SafeAreaView } from 'react-native-safe-area-context';
import styles from './styles';
import Icon from '../../../../assets/icons';
import AuthorImage from '../../../components/AuthorImage/AuthorImage';
import FavoriteStoryButton from '../../../components/FavoriteStoryButton/FavoriteStoryButton';
import SaveStoryButton from '../../../components/SaveStoryButton/SaveStoryButton';
import ReactionPicker from '../../../components/ReactionPicker/ReactionPicker';
import { fetchStory } from '../../../queries/stories';
import { Story } from '../../../queries/types';
Expand Down Expand Up @@ -165,7 +167,23 @@ function StoryScreen() {
By {story.author_name}
</Text>
</View>

<View style={styles.options}>
<SaveStoryButton storyId={parseInt(storyId as string, 10)} />
<FavoriteStoryButton storyId={parseInt(storyId as string, 10)} />
<Button
textColor="black"
buttonColor={colors.gwnOrange}
icon="share"
onPress={onShare}
style={{ width: 125, marginBottom: 16, borderRadius: 10 }}
>
<Text
style={[globalStyles.bodyUnderline, styles.shareButtonText]}
>
Share Story
</Text>
</Button>
</View>
<Button
textColor="black"
icon="arrow-up"
Expand Down
5 changes: 5 additions & 0 deletions src/app/(tabs)/story/styles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,11 @@ const styles = StyleSheet.create({
color: 'black',
marginBottom: 16,
},
options: {
flex: 1,
flexDirection: 'row',
justifyContent: 'flex-end',
},
backToTopButtonText: {
fontFamily: 'Manrope-Regular',
fontSize: 15,
Expand Down
76 changes: 76 additions & 0 deletions src/components/FavoriteStoryButton/FavoriteStoryButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import { useEffect, useState } from 'react';
import { TouchableOpacity } from 'react-native-gesture-handler';
import Svg, { Path } from 'react-native-svg';

import {
addUserStoryToFavorites,
deleteUserStoryToFavorites,
isStoryInFavorites,
} from '../../queries/savedStories';
import { useSession } from '../../utils/AuthContext';
import { Channel, usePubSub } from '../../utils/PubSubContext';

type FavoriteStoryButtonProps = {
storyId: number;
};

export default function FavoriteStoryButton({
storyId,
}: FavoriteStoryButtonProps) {
const { user } = useSession();
const { publish } = usePubSub();
const [storyIsFavorited, setStoryIsFavorited] = useState(false);

useEffect(() => {
isStoryInFavorites(storyId, user?.id).then(storyInReadingList => {
setStoryIsFavorited(storyInReadingList);
});
}, [storyId]);

useEffect(() => {
isStoryInFavorites(storyId, user?.id).then(storyInFavorites => {
setStoryIsFavorited(storyInFavorites);
publish(Channel.FAVORITES, storyId, storyInFavorites);
});
}, [storyId]);

const favoriteStory = async (favorited: boolean) => {
setStoryIsFavorited(favorited);

if (favorited) {
publish(Channel.FAVORITES, storyId, true);
await addUserStoryToFavorites(user?.id, storyId);
} else {
publish(Channel.FAVORITES, storyId, false);
await deleteUserStoryToFavorites(user?.id, storyId);
}
};

const renderFavoritedIcon = () => {
return (
<Svg width="30" height="30" viewBox="0 0 30 30" fill="none">
<Path
d="M15 24.5675L14.0525 23.7113C12.0125 21.8479 10.325 20.2525 8.99 18.925C7.655 17.5983 6.60125 16.4283 5.82875 15.415C5.05708 14.4008 4.5175 13.4837 4.21 12.6637C3.90333 11.8429 3.75 11.0175 3.75 10.1875C3.75 8.5975 4.29 7.2625 5.37 6.1825C6.45 5.1025 7.785 4.5625 9.375 4.5625C10.475 4.5625 11.5063 4.84375 12.4688 5.40625C13.4313 5.96875 14.275 6.78667 15 7.86C15.725 6.78667 16.5687 5.96875 17.5312 5.40625C18.4937 4.84375 19.525 4.5625 20.625 4.5625C22.215 4.5625 23.55 5.1025 24.63 6.1825C25.71 7.2625 26.25 8.5975 26.25 10.1875C26.25 11.0175 26.0967 11.8425 25.79 12.6625C25.4825 13.4833 24.9429 14.4008 24.1712 15.415C23.3987 16.4283 22.3487 17.5983 21.0212 18.925C19.6946 20.2525 18.0029 21.8483 15.9462 23.7125L15 24.5675Z"
fill="#EB563B"
/>
</Svg>
);
};

const renderNotFavoritedIcon = () => {
return (
<Svg width="30" height="30" viewBox="0 0 30 30" fill="none">
<Path
d="M15 24.5675L14.0525 23.7113C12.0125 21.8479 10.325 20.2525 8.99 18.925C7.655 17.5983 6.60125 16.4283 5.82875 15.415C5.05708 14.4008 4.5175 13.4837 4.21 12.6637C3.90333 11.8429 3.75 11.0175 3.75 10.1875C3.75 8.5975 4.29 7.2625 5.37 6.1825C6.45 5.1025 7.785 4.5625 9.375 4.5625C10.475 4.5625 11.5063 4.84375 12.4688 5.40625C13.4313 5.96875 14.275 6.78667 15 7.86C15.725 6.78667 16.5687 5.96875 17.5312 5.40625C18.4937 4.84375 19.525 4.5625 20.625 4.5625C22.215 4.5625 23.55 5.1025 24.63 6.1825C25.71 7.2625 26.25 8.5975 26.25 10.1875C26.25 11.0175 26.0967 11.8425 25.79 12.6625C25.4825 13.4833 24.9429 14.4008 24.1712 15.415C23.3987 16.4283 22.3487 17.5983 21.0212 18.925C19.6946 20.2525 18.0029 21.8483 15.9462 23.7125L15 24.5675ZM15 22.875C17 21.0667 18.6458 19.5183 19.9375 18.23C21.2292 16.9408 22.25 15.8221 23 14.8738C23.75 13.9254 24.2708 13.0858 24.5625 12.355C24.8542 11.6233 25 10.9008 25 10.1875C25 8.9375 24.5833 7.89583 23.75 7.0625C22.9167 6.22917 21.875 5.8125 20.625 5.8125C19.63 5.8125 18.7117 6.09667 17.87 6.665C17.0283 7.2325 16.275 8.08792 15.61 9.23125H14.39C13.7083 8.07292 12.9508 7.21333 12.1175 6.6525C11.2842 6.0925 10.37 5.8125 9.375 5.8125C8.14167 5.8125 7.10417 6.22917 6.2625 7.0625C5.42083 7.89583 5 8.9375 5 10.1875C5 10.9008 5.14583 11.6233 5.4375 12.355C5.72917 13.0867 6.25 13.9263 7 14.8738C7.75 15.8213 8.77083 16.9358 10.0625 18.2175C11.3542 19.4992 13 21.0517 15 22.875Z"
fill="black"
/>
</Svg>
);
};

return (
<TouchableOpacity onPress={() => favoriteStory(!storyIsFavorited)}>
{storyIsFavorited ? renderFavoritedIcon() : renderNotFavoritedIcon()}
</TouchableOpacity>
);
}
36 changes: 26 additions & 10 deletions src/components/SaveStoryButton/SaveStoryButton.tsx
Original file line number Diff line number Diff line change
@@ -1,22 +1,20 @@
import { useEffect, useState } from 'react';
import { TouchableOpacity } from 'react-native-gesture-handler';
import Svg, { Path } from 'react-native-svg';

import {
addUserStoryToReadingList,
deleteUserStoryToReadingList,
isStoryInReadingList,
} from '../../queries/savedStories';
import { Channel, usePubSub } from '../../utils/PubSubContext';
import { useSession } from '../../utils/AuthContext';
import { Image } from 'expo-image';
import { TouchableOpacity } from 'react-native-gesture-handler';

type SaveStoryButtonProps = {
storyId: number;
defaultState?: boolean | null;
};

const saveStoryImage = require('../../../assets/save_story.png');
const savedStoryImage = require('../../../assets/saved_story.png');

export default function SaveStoryButton({
storyId,
defaultState = null,
Expand Down Expand Up @@ -54,13 +52,31 @@ export default function SaveStoryButton({
}
};

const renderSavedStoryImage = () => {
return (
<Svg width="30" height="30" viewBox="0 0 30 30" fill="none">
<Path
d="M4.375 19.375V18.125H13.125V19.375H4.375ZM4.375 14.375V13.125H18.125V14.375H4.375ZM4.375 9.375V8.125H18.125V9.375H4.375ZM20.4375 22.885L16.865 19.3125L17.75 18.4275L20.4375 21.1013L25.75 15.7887L26.635 16.6875L20.4375 22.885Z"
fill="#703929"
/>
</Svg>
);
};

const renderSaveStoryImage = () => {
return (
<Svg width="30" height="30" viewBox="0 0 30 30" fill="none">
<Path
d="M4.375 19.375V18.125H13.125V19.375H4.375ZM4.375 14.375V13.125H18.125V14.375H4.375ZM4.375 9.375V8.125H18.125V9.375H4.375ZM20.625 24.375V19.375H15.625V18.125H20.625V13.125H21.875V18.125H26.875V19.375H21.875V24.375H20.625Z"
fill="black"
/>
</Svg>
);
};

return (
<TouchableOpacity onPress={() => saveStory(!storyIsSaved)}>
{storyIsSaved ? (
<Image style={{ width: 30, height: 30 }} source={savedStoryImage} />
) : (
<Image style={{ width: 30, height: 30 }} source={saveStoryImage} />
)}
{storyIsSaved ? renderSavedStoryImage() : renderSaveStoryImage()}
</TouchableOpacity>
);
}
20 changes: 19 additions & 1 deletion src/queries/savedStories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ async function addUserStory(
) {
const { error } = await supabase
.from('saved_stories')
.upsert([{ user_id: user_id, story_id: story_id, name: name }])
.upsert([{ user_id, story_id, name }])
.select();

if (error) {
Expand Down Expand Up @@ -128,3 +128,21 @@ export async function isStoryInReadingList(

return data;
}

export async function isStoryInFavorites(
storyId: number,
userId: string | undefined,
): Promise<boolean> {
const { data, error } = await supabase.rpc('is_story_saved_for_user', {
list_name: 'favorites',
story_db_id: storyId,
user_uuid: userId,
});

if (error) {
console.error(error);
return false;
}

return data;
}

0 comments on commit 85b33d5

Please sign in to comment.