Commit e59a41de authored by Hedda Mathilde Sæther Langvik's avatar Hedda Mathilde Sæther Langvik
Browse files

Merge branch 'detailed-card' into 'master'

#13 backend woring and started on detailed card

See merge request !12
parents 78b3a06a 716c4b7b
......@@ -15,23 +15,12 @@ router.post('/updateData', (req, res) => {
// this is our get method to get data by id for destination page
router.get('/search/:id', (req, res, next) => {
var destinatoinID = req.params.id;
Destinations.findById(destinatoinID, (err, data) => {
if (err) return res.json({ success: false, error: err });
return res.json({ success: true, data: data });
});
});
// get all data
router.get('/getData', (req, res) => {
Destinations.find((err, data) => {
if (err) return res.json({ success: false, error: err });
else{
var sorted = sortData(data, req)
return res.json({ success: true, data: sorted });
}
});
router.get('/getFrom/:id', (req, res, next) => {
const destinatoinID = req.params.id;
Destinations.findById(destinatoinID, (err, data) => {
if (err) return res.json({ success: false, error: err });
return res.json({ success: true, data: data });
});
});
......@@ -43,31 +32,44 @@ Destinations.find().sort({popularity: -1}).limit(5).exec(function(err, data){
})
})
router.get('/search/:word', (req, res, next) => {
const word = req.params.word.toLowerCase()
console.log("API: ", word)
Destinations.find({$or: [{'name': word}, {'country': word}, {'continent': word}]}, function (err, data){
if (err) return res.json({ success: false, error: err });
else{
var sorted = sortData(data, req)
return res.json({ success: true, data: sorted });
}
// get all data
router.get('/getData/:sorting', (req, res) => {
const sorting = req.params.sorting
Destinations.find((err, data) => {
if (err) return res.json({ success: false, error: err });
else{
var sorted = sortData(data, sorting)
return res.json({ success: true, data: sorted });
}
});
});
router.get('/search/:word/:sorting', (req, res, next) => {
const sorting = req.params.sorting
const word = req.params.word.toLowerCase()
Destinations.find({$or: [{'name': word}, {'country': word}, {'continent': word}]}, function (err, data){
if (err) return res.json({ success: false, error: err });
else{
var sorted = sortData(data, sorting)
return res.json({ success: true, data: sorted });
}
})})
router.get('/search/:continent/:word', (req, res) => {
router.get('/search/:continent/:word/:sorting', (req, res) => {
const sorting = req.params.sorting
const continent = req.params.continent.toLowerCase()
const word = req.params.word.toLowerCase()
Destinations.find({ $and: [ {$or: [{'name': word}, {'country': word}]}, {'continent': continent} ]} , function (err, data){
if (err) return res.json({ success: false, error: err })
else{
var sorted = this.sortData(data)
var sorted = this.sortData(data, sorting)
return res.json({ success: true, data: sorted });
}
})})
sortData = (data, req) => {
const sorting = req.params.sort;
sortData = (data, sorting) => {
if(sorting === "A-Z"){
const sorted = data.sort((a,b) => (a.name > b.name) ? 1:-1)
return sorted
......
export const showDestination = (destinationID) => {
export const showDestination = (destinationID, visible) => {
return (dispatch, getState) => {
dispatch({
type: 'SHOW_DESTINATION',
......
......@@ -2,15 +2,13 @@ import axios from "axios"
// Checks what the input is, and returns the correct fetch-URL
// based on the input.
const createURL = (input) => {
const createURL = (input, sorting) => {
const API_URL = "http://it2810-10.idi.ntnu.no:3001/api/"
console.log("INPUT: ", input)
if(input == ""){
console.log(API_URL)
return API_URL +"getData"
return API_URL +"getData/" + sorting
}
if(typeof input == 'string'){
return API_URL + "search/" + input
return API_URL + "search/" + input + "/" + sorting
}
if(typeof input == 'number'){
return API_URL + "fiveMostPopular"
......@@ -21,9 +19,9 @@ const createURL = (input) => {
// The only method that fetches data from database.
// Creates proper URL and fetches the data with axios
export const GetData = async (input) => {
const url = createURL(input)
console.log("URL: ", url)
export const GetData = async (input, sorting) => {
var url = createURL(input, sorting)
console.log(url)
return await axios.get(url).catch((err) => {console.log("Error from axios: ", err)})
}
......
......@@ -3,11 +3,15 @@ import { StyleSheet, Text, View, Alert, TouchableHighlight, Image, FlatList } fr
import { connect } from 'react-redux';
import { GetData, UpdatePopulatiry } from '../api/fetchers'
import { ScrollView } from 'react-native-gesture-handler';
import { showDestination } from '../actions/DestinationAction';
import MaterialDialog from './DetailedCard';
class Card extends Component {
state ={
data: [],
currentSerachWord: "all"
currentSerachWord: "all",
dataElement: [],
visible: false
}
componentWillMount(){
......@@ -15,7 +19,7 @@ class Card extends Component {
}
setData(input) {
GetData(input).then((res) => this.setState({data: res.data.data}))
GetData(input, this.props.sort).then((res) => this.setState({data: res.data.data}))
}
checkPage(){
......@@ -37,6 +41,16 @@ class Card extends Component {
openDetailedCard(destinationID, popularity){
GetData(destinationID).then((res) => this.setState({dataElement: res.data.data, visible: true}))
this.props.showDestination(destinationID);
newPop = popularity + 1
UpdatePopulatiry(destinationID, newPop);
}
render(){
......@@ -70,7 +84,7 @@ class Card extends Component {
const { data } = this.state
const { dataElement } = this.state
if (this.state.currentSerachWord.toLowerCase() !== this.props.word.toLowerCase()){
this.setState({ currentSerachWord: this.props.word })
this.checkPage()
......@@ -96,7 +110,15 @@ class Card extends Component {
windowSize = {5}
//updateCellsBatchingPeriod = {10}
/>
)}
/*<MaterialDialog
title={dataElement.name}
visible={this.state.visible}
onOk={() => console.log("OK was pressed")}
onCancel={() => console.log("Cancel was pressed")}>
>
<Text>heiheiehi</Text>
</MaterialDialog> */
)}
}
......@@ -105,8 +127,17 @@ const mapStateToProps = (state) => { //give us accsess to the data in store
return {
page: state.page.page,
word: state.filter.searchWord,
continent: state.filter.continent
continent: state.filter.continent,
destinationID: state.destination.destinationID,
sort: state.sort.sortType
}
};
};
const mapDispatchToProps = (dispatch) => {
return {
showDestination: (destinationID) => dispatch(showDestination(destinationID)),
}
};
export default connect(mapStateToProps)(Card);
export default connect(mapStateToProps, mapDispatchToProps)(Card);
import React from 'react';
import PropTypes from 'prop-types';
import {
StyleSheet,
Modal,
Text,
Platform,
TouchableHighlight,
KeyboardAvoidingView,
TouchableWithoutFeedback,
View,
Dimensions,
} from 'react-native';
import colors from './colors';
import { material } from 'react-native-typography';
const { height } = Dimensions.get('window');
// TODO: Don't rely on Dimensions for the actions footer layout
// TODO: Support custom actions
// TODO: Stacked full-width buttons
const ActionButton = ({ testID, onPress, colorAccent, label }) => (
<TouchableHighlight
testID={testID}
style={styles.actionContainer}
underlayColor={colors.androidPressedUnderlay}
onPress={onPress}
>
<Text style={[material.button, { color: colorAccent }]}>{label}</Text>
</TouchableHighlight>
);
const MaterialDialog = ({
visible,
scrolled,
title,
titleColor,
colorAccent,
backgroundColor,
addPadding,
onOk,
onCancel,
okLabel,
cancelLabel,
children,
}) => (
<Modal
animationType={'fade'}
transparent
hardwareAccelerated
visible={visible}
onRequestClose={onCancel}
supportedOrientations={['portrait', 'landscape']}
>
<TouchableWithoutFeedback onPress={onCancel}>
<View style={styles.backgroundOverlay}>
<KeyboardAvoidingView behavior={Platform.OS === 'ios' ? 'padding' : null}>
<View
style={[
styles.modalContainer,
(title != null || (addPadding && title == null)) && styles.modalContainerPadding,
{ backgroundColor },
]}
>
<TouchableWithoutFeedback>
<View>
{title != null ? (
<View style={scrolled ? styles.titleContainerScrolled : styles.titleContainer}>
<Text style={[material.title, { color: titleColor }]}>{title}</Text>
</View>
) : null}
<View
style={
scrolled
? [
styles.contentContainerScrolled,
addPadding && styles.contentContainerScrolledPadding,
]
: [styles.contentContainer, addPadding && styles.contentContainerPadding]
}
>
{children}
</View>
{onOk != null && onCancel != null ? (
<View
style={scrolled ? styles.actionsContainerScrolled : styles.actionsContainer}
>
<ActionButton
testID="dialog-cancel-button"
colorAccent={colorAccent}
onPress={onCancel}
label={cancelLabel}
/>
<ActionButton
testID="dialog-ok-button"
colorAccent={colorAccent}
onPress={onOk}
label={okLabel}
/>
</View>
) : null}
</View>
</TouchableWithoutFeedback>
</View>
</KeyboardAvoidingView>
</View>
</TouchableWithoutFeedback>
</Modal>
);
const styles = StyleSheet.create({
backgroundOverlay: {
flex: 1,
flexDirection: 'row',
justifyContent: 'center',
alignItems: 'center',
backgroundColor: colors.backgroundOverlay,
},
modalContainer: {
marginHorizontal: 16,
marginVertical: 106,
minWidth: 280,
borderRadius: 2,
elevation: 24,
overflow: 'hidden',
},
modalContainerPadding: {
paddingTop: 24,
},
titleContainer: {
paddingHorizontal: 24,
paddingBottom: 20,
flexDirection: 'row',
justifyContent: 'flex-start',
alignItems: 'center',
},
titleContainerScrolled: {
paddingHorizontal: 24,
paddingBottom: 20,
flexDirection: 'row',
justifyContent: 'flex-start',
alignItems: 'center',
borderBottomWidth: StyleSheet.hairlineWidth,
borderColor: colors.androidBorderColor,
},
contentContainer: {
flex: -1,
},
contentContainerPadding: {
paddingHorizontal: 24,
paddingBottom: 24,
},
contentContainerScrolled: {
flex: -1,
maxHeight: height - 264, // (106px vertical margin * 2) + 52px
},
contentContainerScrolledPadding: {
paddingHorizontal: 24,
},
actionsContainer: {
height: 52,
flexDirection: 'row',
justifyContent: 'flex-end',
alignItems: 'center',
paddingLeft: 8,
},
actionsContainerScrolled: {
height: 52,
flexDirection: 'row',
justifyContent: 'flex-end',
alignItems: 'center',
paddingLeft: 8,
borderTopWidth: StyleSheet.hairlineWidth,
borderColor: colors.androidBorderColor,
},
actionContainer: {
marginRight: 8,
paddingHorizontal: 8,
paddingVertical: 8,
minWidth: 64,
flexDirection: 'row',
justifyContent: 'center',
alignItems: 'center',
},
});
MaterialDialog.propTypes = {
visible: PropTypes.bool.isRequired,
children: PropTypes.element.isRequired,
onCancel: PropTypes.func.isRequired,
onOk: PropTypes.func,
cancelLabel: PropTypes.string,
okLabel: PropTypes.string,
title: PropTypes.string,
titleColor: PropTypes.string,
backgroundColor: PropTypes.string,
colorAccent: PropTypes.string,
scrolled: PropTypes.bool,
addPadding: PropTypes.bool,
};
MaterialDialog.defaultProps = {
okLabel: 'OK',
cancelLabel: 'CANCEL',
title: undefined,
titleColor: colors.androidPrimaryTextColor,
backgroundColor: colors.background,
colorAccent: colors.androidColorAccent,
scrolled: false,
addPadding: true,
onOk: undefined,
onCancel: undefined,
};
ActionButton.propTypes = {
testID: PropTypes.string.isRequired,
colorAccent: PropTypes.string.isRequired,
label: PropTypes.string.isRequired,
onPress: PropTypes.func.isRequired,
};
export default MaterialDialog;
\ No newline at end of file
import React, { Component } from 'react';
import { GetAllData } from '../api/fetchers';
import {View, Text} from 'react-native';
import { connect } from 'react-redux';
class Test extends Component {
state = {
data: []
}
componentDidMount() {
var dataen = GetAllData()
dataen.then((data) => this.setState({data: data}))
}
state = { }
render() {
return (
<View>
{console.log(this.state.data, "\n tjohei")}
</View>
);
}
}
const mapStateToProps = (state) => { //give us accsess to the data in store
return {
data: state.data.data
}
}
export default connect(mapStateToProps)(Test);
\ No newline at end of file
export default {
background: '#FFFFFF',
backgroundOverlay: 'rgba(0, 0, 0, 0.6)',
androidColorPrimaryDark: '#5AD185',
androidColorAccent: '#51BC78',
androidPressedUnderlay: '#F0F0F0',
androidBorderColor: '#DCDCDC',
androidPrimaryTextColor: 'rgba(0, 0, 0, 0.87)',
};
\ No newline at end of file
......@@ -6478,6 +6478,16 @@
"resolved": "https://registry.npmjs.org/react-native-material-design-styles/-/react-native-material-design-styles-0.2.7.tgz",
"integrity": "sha512-dEtVROG1zqso3fiElJulOU+8/HwWh2TVIyDICrddlyAuDt5dpowelLpmamkRW1CV8VHRdHY5ZhxGWUOiPvROgw=="
},
"react-native-material-dialog": {
"version": "0.7.6",
"resolved": "https://registry.npmjs.org/react-native-material-dialog/-/react-native-material-dialog-0.7.6.tgz",
"integrity": "sha512-K5lExew1rl6orpuDaXGV92aVXTahdWTv6RsD5OEuMf3h3iH7Sxgocb3tbRdqqZlw2cVrPl7DemwyT/lZS9jOHg==",
"requires": {
"prop-types": "^15.5.10",
"react-native-typography": "^1.0.3",
"react-native-vector-icons": "^4.2.0"
}
},
"react-native-material-ui": {
"version": "1.30.1",
"resolved": "https://registry.npmjs.org/react-native-material-ui/-/react-native-material-ui-1.30.1.tgz",
......@@ -6553,6 +6563,56 @@
"resolved": "https://registry.npmjs.org/react-native-tab-view/-/react-native-tab-view-2.10.0.tgz",
"integrity": "sha512-qgexVz5eO4yaFjdkmn/sURXgVvaBo6pZD/q1eoca96SbPVbaH3WzVhF3bRUfeTHwZkXwznFTpS3JURqIFU8vQA=="
},
"react-native-typography": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/react-native-typography/-/react-native-typography-1.4.1.tgz",
"integrity": "sha512-dc9Zfs4jUdq4ygx4/KwO6jKTERBu6cRrfPJGntw/pA+D6BMjlWfMNuhZ/69vf4Zpsnt9s4AGe+Z/V1QFYaCXAA=="
},
"react-native-vector-icons": {
"version": "4.6.0",
"resolved": "https://registry.npmjs.org/react-native-vector-icons/-/react-native-vector-icons-4.6.0.tgz",
"integrity": "sha512-rpfhfPiXCK2PX1nrNhdxSMrEGB/Gw/SvKoPM0G2wAkSoqynnes19K0VYI+Up7DqR1rFIpE4hP2erpT1tNx2tfg==",
"requires": {
"lodash": "^4.0.0",
"prop-types": "^15.5.10",
"yargs": "^8.0.2"
},
"dependencies": {
"y18n": {
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz",
"integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE="
},
"yargs": {
"version": "8.0.2",
"resolved": "https://registry.npmjs.org/yargs/-/yargs-8.0.2.tgz",
"integrity": "sha1-YpmpBVsc78lp/355wdkY3Osiw2A=",
"requires": {
"camelcase": "^4.1.0",
"cliui": "^3.2.0",
"decamelize": "^1.1.1",
"get-caller-file": "^1.0.1",
"os-locale": "^2.0.0",
"read-pkg-up": "^2.0.0",
"require-directory": "^2.1.1",
"require-main-filename": "^1.0.1",
"set-blocking": "^2.0.0",
"string-width": "^2.0.0",
"which-module": "^2.0.0",
"y18n": "^3.2.1",
"yargs-parser": "^7.0.0"
}
},
"yargs-parser": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-7.0.0.tgz",
"integrity": "sha1-jQrELxbqVd69MyyvTEA4s+P139k=",
"requires": {
"camelcase": "^4.1.0"
}
}
}
},
"react-native-view-shot": {
"version": "2.6.0",
"resolved": "https://registry.npmjs.org/react-native-view-shot/-/react-native-view-shot-2.6.0.tgz",
......
......@@ -21,8 +21,10 @@
"react-native": "https://github.com/expo/react-native/archive/sdk-35.0.0.tar.gz",
"react-native-elements": "^1.2.7",
"react-native-gesture-handler": "~1.3.0",
"react-native-material-dialog": "^0.7.6",
"react-native-material-ui": "^1.30.1",
"react-native-reanimated": "^1.4.0",
"react-native-typography": "^1.4.1",
"react-native-web": "^0.11.7",
"react-navigation": "^4.0.10",
"react-navigation-tabs": "^2.5.6",
......
......@@ -3,11 +3,11 @@ import { Text, View, ScrollView } from 'react-native';
import Card from '../components/Card'
import { createStore, applyMiddleware } from 'redux';
import rootReducer from '../reducers/';
import { Provider } from 'react-redux'
import thunk from 'redux-thunk'
import { connect } from 'react-redux';
import { setPage } from '../actions/SetPageAction';
const store = createStore(rootReducer, applyMiddleware(thunk))
class HomePage extends Component {
......
const initState = {
destinationID: ""
destinationID: "",
}
const destinationReducer = (state =