Commit 75376c15 authored by Adrian's avatar Adrian

Final touches

parent d4dc9897
......@@ -2,8 +2,8 @@
"devToolsPort": 19002,
"expoServerPort": 19000,
"packagerPort": 19001,
"packagerPid": 12416,
"expoServerNgrokUrl": "https://sk-rhp.anonymous.p4.exp.direct",
"packagerNgrokUrl": "https://packager.sk-rhp.anonymous.p4.exp.direct",
"ngrokPid": 14204
"packagerPid": 15292,
"expoServerNgrokUrl": "https://93-ggc.anonymous.p4.exp.direct",
"packagerNgrokUrl": "https://packager.93-ggc.anonymous.p4.exp.direct",
"ngrokPid": 16696
}
{
"hostType": "lan",
"hostType": "tunnel",
"lanType": "ip",
"dev": true,
"minify": false,
"urlRandomness": "sk-rhp",
"urlRandomness": "93-ggc",
"https": false
}
import React, { Component } from 'react';
import { Platform, StyleSheet, Text, View } from 'react-native';
import Body from './src/components/Body'
import Top from './src/components/Top'
import React, { Component } from "react";
import { View } from "react-native";
import Body from "./src/components/Body";
import Top from "./src/components/Top";
import { createStore } from "redux";
import allReducer from "./src/reducers";
import { Provider } from "react-redux";
import ApolloClient from 'apollo-boost';
import { ApolloProvider } from '@apollo/react-hooks'
import SideMenu from './src/components/SideMenu';
import ApolloClient from "apollo-boost";
import { ApolloProvider } from "@apollo/react-hooks";
import SideMenu from "./src/components/SideMenu";
const client = new ApolloClient({
uri: 'http://it2810-26.idi.ntnu.no:4000'
})
uri: "http://it2810-26.idi.ntnu.no:4000"
});
const store = createStore(
allReducer,
window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()
);
const instructions = Platform.select({
ios: 'Press Cmd+R to reload,\n' + 'Cmd+D or shake for dev menu',
android: 'Double tap R on your keyboard to reload,\n' + 'Shake or press menu button for dev menu',
});
console.disableYellowBox = true;
export default class App extends Component {
render() {
return (
<View>
{/*<Text style={styles.instructions}>{instructions}</Text>*/}
<Provider store={ store }>
<ApolloProvider client={ client }>
<Top/>
<SideMenu/>
<Body/>
<Provider store={store}>
<ApolloProvider client={client}>
<Top />
<SideMenu />
<Body />
</ApolloProvider>
</Provider>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#F5FCFF',
},
welcome: {
fontSize: 20,
textAlign: 'center',
margin: 10,
},
instructions: {
textAlign: 'center',
color: '#333333',
marginBottom: 5,
},
});
......@@ -2,6 +2,4 @@ import { AppRegistry } from 'react-native';
import App from './App';
import { name as Drinks } from './app.json';
AppRegistry.registerComponent(Drinks, () => App);
......@@ -1189,6 +1189,11 @@
"@types/yargs": "^13.0.0"
}
},
"@react-native-community/async-storage": {
"version": "1.6.3",
"resolved": "https://registry.npmjs.org/@react-native-community/async-storage/-/async-storage-1.6.3.tgz",
"integrity": "sha512-67K2akX90uc252zKMYJt1wISvaEH6ARtdTI9bUkwmOFXVPyVk1DfPnaRmyUzcVdeCBOO1n0xv9YO2GSppIormQ=="
},
"@react-native-community/cli": {
"version": "1.11.2",
"resolved": "https://registry.npmjs.org/@react-native-community/cli/-/cli-1.11.2.tgz",
......
......@@ -9,6 +9,7 @@
},
"dependencies": {
"@apollo/react-hooks": "^3.1.3",
"@react-native-community/async-storage": "^1.6.3",
"apollo-boost": "^0.4.4",
"expo": "^35.0.0",
"graphql": "^14.5.8",
......
export const increment = () => {
return {
type : 'INCREMENT'
};
export const search = base => {
return {
type: "SEARCH",
payload: base
};
};
export const decrement = () => {
return {
type : 'DECREMENT'
};
export const filter = q => {
return {
type: "FILTER",
payload: q
};
};
export const search = (base) => {
return {
type : 'SEARCH',
payload : base
};
export const details = a => {
return {
type: "DETAILS",
payload: a
};
};
export const albums = (a) => {
return {
type : 'ALLALBUMS',
payload : a
};
};
export const filter = (q) => {
return{
type : 'FILTER',
payload : q
}
}
export const details = (a) => {
return{
type : 'DETAILS',
payload : a
}
}
export const nextPage = () => {
return{
type : 'NEXT'
}
}
return {
type: "NEXT"
};
};
export const prevPage = () => {
return{
type : 'PREVIOUS'
}
}
return {
type: "PREVIOUS"
};
};
export const defaultPage = () => {
return{
type : 'DEFAULT'
}
}
return {
type: "DEFAULT"
};
};
export const isOverlayVisible = () => {
return{
type : 'VISIBLE'
}
}
return {
type: "VISIBLE"
};
};
export const toggleSideMenu = () => {
return{
type : 'SIDEMENU'
}
}
return {
type: "SIDEMENU"
};
};
export const sortingCategory = a => {
return {
type: "SORT",
payload: a
};
};
export const dataRetriever = a => {
return {
type: "RETRIEVE",
payload: a
};
};
export const data = a => {
return {
type: "DATA",
payload: a
};
};
export const sortingCategory = (a) => {
return {
type : 'SORT',
payload : a
}
}
\ No newline at end of file
export const dataOverlay = () => {
return {
type: "DATAOVERLAY"
};
};
import React from 'react';
//import './Body.css';
import { Text, StyleSheet, ScrollView, Image } from 'react-native';
import Search from './Search';
import Content from './Content'
import Sorting from './Sorting';
//import Content from '../Content/Content.js';
//import Wordcloud from '../Wordcloud/Wordcloud.js';
import React from "react";
import { ScrollView } from "react-native";
import Search from "./Search";
import Content from "./Content";
import Sorting from "./Sorting";
import Favorites from "./Favorites";
const Body = () => {
return(
<ScrollView style={{height:"90%"}}>
<Search/>
<Sorting/>
<Content/>
</ScrollView>
);
}
return (
<ScrollView style={{ height: "90%" }}>
<Search />
<Sorting />
<Content />
<Favorites />
</ScrollView>
);
};
export default Body;
import React from "react";
import {
Text,
StyleSheet,
ScrollView,
Image,
View,
Button
} from "react-native";
import Search from "./Search";
import { Text, View, Button } from "react-native";
import { ListItem } from "react-native-elements";
import { useSelector } from "react-redux";
import { useDispatch } from "react-redux";
import { details, nextPage, prevPage } from "../actions";
import { details, nextPage } from "../actions";
import Details from "./Details";
import { isOverlayVisible } from "../actions";
import { gql } from "apollo-boost";
import { useQuery } from "@apollo/react-hooks";
import Elements from "./Elements";
import { FlatList } from "react-native-gesture-handler";
const GET_PRODUCTS = gql`
query Products(
......@@ -62,6 +53,7 @@ const Content = () => {
return isStateTypeEmpty ? {} : { filterType: stateType };
}
// This is the constant which fetches from the database. useQuery with apollo-hooks.
const { loading, error, data, fetchMore } = useQuery(GET_PRODUCTS, {
variables: {
limit: 15,
......@@ -74,6 +66,7 @@ const Content = () => {
if (error) return <Text>{error}</Text>;
const { products } = data.products;
// Function for loading more from the database. Is called when Load more button is pressed.
const handleLoadMore = () => {
dispatch(nextPage());
fetchMore({
......@@ -96,13 +89,14 @@ const Content = () => {
});
};
// Rendering of list elements.
const productElements = products.map(product => (
<View key={product.id} style={{ display: "flex" }}>
<ListItem
key={product.id}
leftAvatar={{ source: { uri: product.img } }}
title={product.name}
subtitle={product.price + " kr"}
subtitle={"Kr " + product.price}
bottomDivider
chevron
onPress={() => setOverlayState(product)}
......@@ -115,6 +109,7 @@ const Content = () => {
dispatch(details(d));
}
// Show more button is only visible when needed.
function showMoreButton() {
if (products.length === 15 + 15 * statePage) {
return (
......
import React from 'react';
import { Overlay } from 'react-native-elements';
import { useSelector } from "react-redux";
import { useDispatch } from "react-redux";
import { isOverlayVisible } from "../actions";
import {Text, View, Image, StyleSheet} from 'react-native'
import React, { useState } from "react";
import { useSelector, useDispatch } from "react-redux";
import { isOverlayVisible, dataRetriever } from "../actions";
import { Text, View, Image, StyleSheet, AsyncStorage } from "react-native";
import { Button, Overlay } from "react-native-elements";
import Icon from "react-native-vector-icons/FontAwesome";
const Details = () => {
const stateOverlay = useSelector(state => state.overlay);
const details = useSelector(state => state.details)
const dispatch = useDispatch();
return(
const stateOverlay = useSelector(state => state.overlay);
const details = useSelector(state => state.details);
const dispatch = useDispatch();
const [color, setColor] = useState("red");
// Function for setting liked product in AsyncStorage. First used as color-changer - later only used to set the favorite.
function like() {
AsyncStorage.getItem(details.id).then(result =>
dispatch(dataRetriever(result))
);
if (dataRetriever === details.name) {
AsyncStorage.removeItem(details.name);
_retrieveData();
setColor("gray");
} else {
_storeData();
setColor("red");
}
}
_storeData = async () => {
try {
await AsyncStorage.setItem(details.name, JSON.stringify(details.name));
} catch (error) {
// Error saving data
}
};
return (
<Overlay
isVisible={stateOverlay}
onBackdropPress={() => dispatch(isOverlayVisible())}
>
<View style={styles.container}>
<Text style={styles.name}>{details.name}</Text>
<Image style={styles.image} source={{uri: details.img}}/>
<Text style={styles.price}>Kr. {details.price}</Text>
<Text style={styles.type}>{details.type}</Text>
<View style={styles.info}>
<Text style={styles.alcohol}>Alcohol:<Text style={styles.elements}> {details.alcohol}% </Text></Text>
<Text style={styles.volume}>Volume:<Text style={styles.elements}> {details.volume}</Text></Text>
</View>
<View style={styles.info}>
<Text style={styles.country}>Country:<Text style={styles.elements}> {details.country}</Text></Text>
<Text style={styles.district}>District:<Text style={styles.elements}> {details.district}</Text></Text>
</View>
<Text style={styles.pricePL}>Price per liter:<Text style={styles.elements}> Kr.{details.pricePerLiter} </Text></Text>
height="auto"
isVisible={stateOverlay}
onBackdropPress={() => dispatch(isOverlayVisible())}
>
<View style={styles.container}>
<Text style={styles.name}>{details.name}</Text>
<Image style={styles.image} source={{ uri: details.img }} />
<Text style={styles.price}>Kr. {details.price}</Text>
<Text style={styles.type}>{details.type}</Text>
<View style={styles.info}>
<Text style={styles.alcohol}>
Alcohol:<Text style={styles.elements}> {details.alcohol}% </Text>
</Text>
<Text style={styles.volume}>
Volume:<Text style={styles.elements}> {details.volume}</Text>
</Text>
</View>
<Text style={styles.country}>
Country:<Text style={styles.elements}> {details.country}</Text>
</Text>
<Button
icon={<Icon name="heart" size={40} color={color} />}
type="clear"
iconRight
onPress={() => like()}
/>
</View>
</Overlay>
);
}
);
};
// Styling needed for detailview
const styles = StyleSheet.create({
container: {
margin:10,
marginTop: 10,
alignItems: 'center',
flexWrap: 'wrap',
flexDirection: 'column',
},
name: {
fontSize: 20,
textAlign: 'center',
margin: 10,
},
price: {
marginTop:5,
fontWeight: 'bold',
fontSize: 17,
},
info: {
padding: 10,
flexDirection: 'row', flexWrap: 'wrap'
},
alcohol: {
width:"60%",
paddingLeft: 5
},
volume: {
width:"40%",
paddingRight: 5
},
country: {
width:"60%",
paddingLeft: 5
},
district: {
width:"40%",
paddingRight: 5
},
type: {
borderBottomWidth:1,
borderBottomColor:'black',
width:"90%",
textAlign: "center",
paddingBottom:15,
paddingTop: 5,
marginBottom:20
},
image: {
resizeMode: "contain", height: 200, width:100, justifyContent:'center'
},
elements: {
fontWeight:'bold'
},
pricePL: {
padding:5
}
});
container: {
margin: 10,
marginTop: 10,
alignItems: "center",
flexWrap: "wrap",
flexDirection: "column"
},
name: {
fontSize: 20,
textAlign: "center",
margin: 10
},
price: {
marginTop: 5,
fontWeight: "bold",
fontSize: 17
},
info: {
padding: 10,
flexDirection: "row",
flexWrap: "wrap"
},
alcohol: {
width: "60%",
paddingLeft: 5
},
volume: {
width: "40%",
paddingRight: 5
},
type: {
borderBottomWidth: 1,
borderBottomColor: "black",
width: "90%",
textAlign: "center",
paddingBottom: 15,
paddingTop: 5,
marginBottom: 20
},
image: {
resizeMode: "contain",
height: 200,
width: 100,
justifyContent: "center"
},
elements: {
fontWeight: "bold"
},
country: {
paddingBottom: 10
}
});
export default Details;
import React from 'react'
import {Text, View, Image} from 'react-native'
export default function Elements({name, img, price, alcohol, volume, type}) {
return (
<View style={{borderWidth:1, borderColor:'black', margin:10, alignItems:'center'}}>
<Image style={{resizeMode: "contain", height: 200, width:100, justifyContent:'center'}} source={{uri: img}}/>
<Text>Name: {name}</Text>
<Text>Price: {price},-</Text>
<Text>Alcohol: {alcohol}%.</Text>
<Text>Volume: {volume}</Text>
<Text>Type: {type}</Text>
</View>
)
}
\ No newline at end of file
import React from "react";
import { useSelector, useDispatch } from "react-redux";
import { data, dataOverlay } from "../actions";
import { Text, ScrollView, Button, AsyncStorage } from "react-native";
import { Overlay } from "react-native-elements";
const Favorites = () => {
const dispatch = useDispatch();
const stateData = useSelector(state => state.data);
const stateDataOverlay = useSelector(state => state.dataOverlay);
// Retrieved all keys in Asyncstorage.
_retrieveData = async () => {
try {
const value = await AsyncStorage.getAllKeys();
if (value !== null) {
// We have data!!
dispatch(data(value));
}
} catch (error) {
// Error retrieving data
console.log("error");
}
};
// Displays info in Asyncstorage for the user.
function showData() {
return stateData.map(f => <Text>{f}</Text>);
}
_retrieveData();
return (
<Overlay
height="auto"
isVisible={stateDataOverlay}
onBackdropPress={() => dispatch(dataOverlay())}
>
<Text style={{ fontSize: 20, textAlign:'center' }}>Favorites</Text>
<ScrollView style={{ textAlign: "center", margin: 5 }}>
{showData()}
</ScrollView>
<Button
title="Clear"
onPress={() => AsyncStorage.clear()}
color="#31708e"
/>
</Overlay>
);
};
export default Favorites;
import React from "react";
import { View, Text, StyleSheet } from "react-native";
import RadioForm, {
RadioButton,
RadioButtonInput,
RadioButtonLabel
} from "react-native-simple-radio-button";
import { useDispatch } from "react-redux";
import { filter } from "../actions";
import { useSelector } from "react-redux";
import { toggleSideMenu } from "../actions";
import RadioForm from "react-native-simple-radio-button";
import { useDispatch, useSelector } from "react-redux";
import { toggleSideMenu, filter } from "../actions";
const genres = [
{ label: "All", value: "" },
......@@ -28,13 +22,12 @@ const Filtering = () => {
const stateType = useSelector(state => state.filter);
const dispatch = useDispatch();
const styles = StyleSheet.create({
headerText:{
fontSize:20,
fontWeight:'bold',
textAlign:'center',
paddingBottom:30,
headerText: {
fontSize: 20,
fontWeight: "bold",
textAlign: "center",
paddingBottom: 30
}
});
function updateFilter(e) {
......@@ -43,27 +36,33 @@ const Filtering = () => {
function onButtonPress(v) {