Skip to content

Commit

Permalink
Frontend for resources worked
Browse files Browse the repository at this point in the history
  • Loading branch information
ineshbose committed Jan 23, 2022
1 parent 562330d commit b5f4775
Show file tree
Hide file tree
Showing 10 changed files with 308 additions and 54 deletions.
13 changes: 13 additions & 0 deletions src/app/api/resources.ts
@@ -0,0 +1,13 @@
import { axiosInstance } from '.';
import { FetchData, Resource } from '../types/api';

const API_PATH = '/resources/';

export const getResources = async () => {
try {
const response = await axiosInstance.get<FetchData<Resource>>(API_PATH);
return 'results' in response.data ? response.data.results : response.data;
} catch (e) {
// unable to fetch data
}
};
12 changes: 10 additions & 2 deletions src/app/contexts/AppContext.tsx
Expand Up @@ -9,21 +9,28 @@ import { getObject } from '../api/store';
import { createUser, getUser } from '../api/user';
import { ChildComponents } from '../types';
import { AuthToken, TrackItems, User } from '../types/api';
import { RootTabParamList, RouteNames } from '../types/navigation';

type AppContextType = {
authToken?: AuthToken;
user?: User;
items?: TrackItems;
loading: boolean;
headerAction?: RouteNames<RootTabParamList>;
helpers: { [name: string]: Function };
};

const AppContext = React.createContext<AppContextType>({} as AppContextType);
const AppContext = React.createContext<AppContextType>({
loading: false,
helpers: {},
});

export const ContextProvider = ({ children }: ChildComponents) => {
const [authToken, setAuthToken] = React.useState<AuthToken>();
const [items, setItems] = React.useState<TrackItems>([]);
const [user, setUser] = React.useState<User>();
const [headerAction, setHeaderAction] =
React.useState<RouteNames<RootTabParamList>>();
const [loading, setLoading] = React.useState<boolean>(true);

React.useEffect(() => {
Expand Down Expand Up @@ -86,8 +93,9 @@ export const ContextProvider = ({ children }: ChildComponents) => {
authToken,
user,
items,
headerAction,
loading,
helpers: { signIn, signUp, signOut, setItems },
helpers: { signIn, signUp, signOut, setItems, setHeaderAction },
}}
>
{children}
Expand Down
37 changes: 21 additions & 16 deletions src/app/navigation/BottomTabNavigator.tsx
Expand Up @@ -8,6 +8,7 @@ import { Image, ImageProps } from 'react-native';
import {
RootTabParamList,
RouteActionIcon,
RouteNames,
TabConfig,
} from '../types/navigation';
import {
Expand Down Expand Up @@ -67,14 +68,17 @@ export default function BottomTabNavigator() {
const {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
user,
helpers: { signOut },
headerAction,
helpers: { signOut, setHeaderAction },
} = useAppContext();
const { ThemeToggle } = useThemeContext();
const [action, setAction] = React.useState<string>('');
const [modalVisible, setModalVisible] = React.useState<boolean>(false);

const navigationLeftAccessory = (props: {} | undefined) => (
<Text {...props}>
<Text
{...props}
style={{ justifyContent: 'center', alignItems: 'center', flex: 1 }}
>
<Image
style={{
height: 30,
Expand All @@ -84,7 +88,7 @@ export default function BottomTabNavigator() {
uri: 'https://portion-mate-glasgow.readthedocs.io/en/latest/assets/logo.png',
}}
/>
<Text>Portion Mate</Text>
<Text category="s2">Portion Mate</Text>
</Text>
);

Expand All @@ -94,7 +98,7 @@ export default function BottomTabNavigator() {
) => (
<Icon
key="action"
name={headerButtonIcons[route.name as keyof RootTabParamList]}
name={headerButtonIcons[route.name as RouteNames<RootTabParamList>]}
size={30}
{...props}
/>
Expand All @@ -111,7 +115,9 @@ export default function BottomTabNavigator() {
<ButtonGroup appearance="ghost" {...props}>
<Button
accessoryLeft={(p) => navRightAccessoryActionIcon(p, route)}
onPress={() => setAction(action === route.name ? '' : route.name)}
onPress={() =>
setHeaderAction(headerAction === route.name ? '' : route.name)
}
/>
<Button
accessoryLeft={userAvatar}
Expand Down Expand Up @@ -148,7 +154,12 @@ export default function BottomTabNavigator() {
size: number;
}
| Partial<ImageProps>
) => <Icon name={tab.icon} {...props} />;
) => {
if (props) {
// props.styles.tintColor = '#fff';
}
return <Icon name={tab.icon} {...props} />;
};

const TabBar = (props: BottomTabBarProps) => (
<BottomNavigation
Expand All @@ -157,6 +168,8 @@ export default function BottomTabNavigator() {
props.navigation.navigate(props.state.routeNames[index])
}
appearance="noIndicator"
// style={{ backgroundColor: Colors.primary }}
{...props}
>
{tabs.map((tab) => (
<BottomNavigationTab
Expand All @@ -179,15 +192,7 @@ export default function BottomTabNavigator() {
}}
>
{tabs.map((tab) => (
<BottomTab.Screen key={tab.name} name={tab.name}>
{/* https://github.com/react-navigation/react-navigation/issues/8517 */}
{(props) =>
tab.component({
isAction: action === tab.name,
...props,
})
}
</BottomTab.Screen>
<BottomTab.Screen key={tab.name} {...tab} />
))}
</BottomTab.Navigator>
);
Expand Down
2 changes: 1 addition & 1 deletion src/app/screens/Auth/RegisterForm.tsx
Expand Up @@ -77,7 +77,7 @@ export default function RegisterForm({
status={error?.agreedTerms && !agreedTerms ? 'danger' : 'primary'}
style={{ marginVertical: 10 }}
>
<Text>I read and agree to the Terms {'&'} Conditions</Text>
<Text>{'I read and agree to the Terms & Conditions'}</Text>
</CheckBox>
<Button
onPress={() =>
Expand Down
16 changes: 9 additions & 7 deletions src/app/screens/HomePage.tsx
@@ -1,6 +1,7 @@
import * as React from 'react';
import {
ImageProps,
ListRenderItemInfo,
SafeAreaView,
StyleSheet,
TextProps,
Expand All @@ -16,7 +17,6 @@ import {
Icon,
Text,
} from '@ui-kitten/components';
import { ComponentTabArguments } from '../types/navigation';
import { deleteTrackItem, getTrackItems, updateTrackItem } from '../api/items';
import {
PortionItem,
Expand Down Expand Up @@ -49,13 +49,15 @@ const getFrequencyDisplay = (frequency: number) => {
);
};

export default function HomePage(pageProps: ComponentTabArguments<'Home'>) {
const { isAction } = pageProps;
export default function HomePage() {
const {
items,
headerAction,
helpers: { setItems },
} = useAppContext();

const isAction = headerAction === 'Home';

React.useEffect(() => {
const getItems = async () => {
if (!(items && items.length > 0)) {
Expand Down Expand Up @@ -211,11 +213,11 @@ export default function HomePage(pageProps: ComponentTabArguments<'Home'>) {
</>
);

const renderItem = ({ item }: { item: TrackItem }) => (
const renderItem = (info: ListRenderItemInfo<TrackItem>) => (
<ListItem
title={(item.item as PortionItem).name}
description={(props) => renderItemDescription(props, item)}
accessoryRight={(props) => renderItemAccessory(props, item)}
title={(info.item.item as PortionItem).name}
description={(props) => renderItemDescription(props, info.item)}
accessoryRight={(props) => renderItemAccessory(props, info.item)}
/>
);

Expand Down
167 changes: 157 additions & 10 deletions src/app/screens/ResourcesPage.tsx
@@ -1,28 +1,175 @@
import * as React from 'react';
import { Layout } from '@ui-kitten/components';
import { SafeAreaView, StyleSheet } from 'react-native';
import {
ImageProps,
Linking,
ListRenderItemInfo,
SafeAreaView,
ScrollView,
StyleSheet,
View,
ViewProps,
} from 'react-native';
import {
Button,
ButtonGroup,
Card,
Icon,
Layout,
List,
Text,
TopNavigation,
TopNavigationAction,
} from '@ui-kitten/components';
import Markdown from 'react-native-markdown-display';
import { Resource, Resources } from '../types/api';
import { getResources } from '../api/resources';
import { IconOptions } from '../types';
import { ComponentTabArguments } from '../types/navigation';

export default function ResourcesPage(
pageProps: ComponentTabArguments<'Resources'>
) {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const { isAction } = pageProps;
const [resources, setResources] = React.useState<Resources>([]);
const [selectedResource, setSelectedResource] = React.useState<Resource>();

React.useEffect(() => {
const getItems = async () => {
if (!(resources && resources.length > 0)) {
setResources((await getResources()) as Resources);
}
};

getItems();
}, [resources, setResources]);

const renderActionIcon = (
props: Partial<ImageProps> | undefined,
name: IconOptions
) => <Icon key={name} name={name} {...props} />;

const renderMoreAction = (props: {} | undefined) => (
<ButtonGroup {...props} appearance="ghost" status="basic">
<Button accessoryLeft={(p) => renderActionIcon(p, 'star')} />
<Button
accessoryLeft={(p) => renderActionIcon(p, 'open-in-new')}
onPress={() =>
Linking.openURL(selectedResource ? selectedResource.link : '')
}
/>
</ButtonGroup>
);

const renderBackAction = (props: {} | undefined) => (
<TopNavigationAction
icon={(p) => renderActionIcon(p, 'arrow-back')}
onPress={() => setSelectedResource(undefined)}
{...props}
/>
);

const renderItemFooter = (
props: ViewProps | undefined,
info: ListRenderItemInfo<Resource>
) => (
<View {...props} style={styles.itemFooter}>
<View style={styles.itemAuthoringContainer}>
<Text category="s2">{info.item.author}</Text>
<Text appearance="hint" category="c1">
{info.item.date_published}
</Text>
</View>
<Button
appearance="ghost"
status="basic"
accessoryLeft={(p) => renderActionIcon(p, 'star')}
/>
</View>
);

const renderItem = (info: ListRenderItemInfo<Resource>) => (
<Card
style={styles.item}
footer={(p) => renderItemFooter(p, info)}
onPress={() => setSelectedResource(info.item)}
>
<Text category="h2">{info.item.title}</Text>
<Text>
<Markdown>{`${info.item.content.substring(0, 82)}...`}</Markdown>
</Text>
</Card>
);

export default function ResourcesPage() {
return (
<SafeAreaView style={{ flex: 1 }}>
<Layout style={styles.container}></Layout>
<SafeAreaView style={styles.container}>
<Layout style={styles.container}>
{selectedResource ? (
<>
<TopNavigation
alignment="center"
title={selectedResource.title}
subtitle={`${selectedResource.author} | ${selectedResource.date_published}`}
accessoryLeft={renderBackAction}
accessoryRight={renderMoreAction}
/>
<ScrollView>
<Markdown style={{ body: { paddingHorizontal: 10 } }}>
{selectedResource.content}
</Markdown>
</ScrollView>
</>
) : resources.length > 0 ? (
<List data={resources} renderItem={renderItem} />
) : (
<Layout style={styles.noResourceContainer}>
<Text style={styles.noResourceTitle}>
{'No resources available'}
</Text>
</Layout>
)}
</Layout>
</SafeAreaView>
);
}

const styles = StyleSheet.create({
container: {
flex: 1,
},
noResourceContainer: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
padding: 20,
},
title: {
noResourceTitle: {
fontSize: 20,
fontWeight: 'bold',
},
separator: {
marginVertical: 30,
height: 1,
width: '80%',
list: {
flex: 1,
},
listContent: {
paddingHorizontal: 16,
paddingVertical: 8,
},
item: {
marginVertical: 8,
},
itemHeader: {
height: 220,
},
itemContent: {
marginVertical: 8,
},
itemFooter: {
flexDirection: 'row',
marginHorizontal: -8,
},
itemAuthoringContainer: {
flex: 1,
justifyContent: 'center',
marginHorizontal: 16,
},
});

0 comments on commit b5f4775

Please sign in to comment.