This commit is contained in:
2019-08-05 21:23:17 -04:00
parent a9f4324f29
commit 1e464de7e8
42 changed files with 837 additions and 165 deletions

View File

@@ -0,0 +1,23 @@
import React from 'react';
import PropTypes from 'prop-types';
import { Header } from 'react-native-elements';
import HeaderTitle from './HeaderTitle.container.js';
import HeaderContentLeft from './HeaderContentLeft.container.js';
import HeaderContentRight from './HeaderContentRight.container.js';
import styles from './AppHeader.styles.js';
export default function AppHeader({ navigation }) (
<Header
placement="left"
leftComponent={<HeaderContentRight navigation={navigation} />}
centerComponent={<HeaderTitle navigation={navigation} />}
rightComponent={<HeaderContentLeft navigation={navigation} />}
/>
)
AppHeader.propTypes = {
navigation: PropTypes.func.isRequired,
};

View File

@@ -0,0 +1,16 @@
import { connect } from 'react-redux';
import { hasMultipleEvents } from '../selectors/events.js';
import HeaderContentLeft from './HeaderContentLeft.js';
const matchStateToProps = (state, ownProps) => {
const { routeName } = ownProps.navigation.state;
return {
activeRoute: routeName,
hasMultipleEvents: hasMultipleEvents(state),
};
};
export default connect(matchStateToProps, null)(HeaderContentLeft);

View File

@@ -0,0 +1,53 @@
import React from 'react';
import PropTypes from 'prop-types';
import {
Text,
TouchableOpacity,
View,
} from 'react-native';
import BackIcon from './IconButtons/BackIcon.js';
import EventsIcon from './IconButtons/EventsIcon.js';
export default function HeaderContentLeft({
activeRoute,
hasMultipleEvents,
navigation,
}) {
const _goBack = () => {
if (hasActiveEvent) {
navigation.goBack();
return false;
}
console.log('nowhere to go...');
};
const _showEvents = () => {
navigation.navigate('Events');
return false;
};
if (activeRoute === 'Events') {
return <EventsIcon action={_goBack} />;
}
if (activeRoute === 'Profile') {
return <BackIcon action={_goBack} />;
}
return <EventsIcon action={hasMultipleEvents ? _showEvents : null} />
}
HeaderContentLeft.propTypes = {
activeRoute: PropTypes.string.isRequired,
hasActiveEvent: PropTypes.bool,
navigation: PropTypes.func.isRequired,
};
HeaderContentLeft.defaultProps = {
hasActiveEvent: false,
};

View File

@@ -0,0 +1,12 @@
import { connect } from 'react-redux';
import { getProfileAvatarUrl } from '../selectors/profile.js';
import HeaderContentRight from './HeaderContentRight.js';
const matchStateToProps = (state, ownProps) => ({
avatarUrl: getProfileAvatarUrl(state),
hideUserProfileButton: ownProps.navigation.state.routeName === 'Profile',
});
export default connect(matchStateToProps, null)(HeaderContentRight);

View File

@@ -0,0 +1,17 @@
import React from 'react';
import PropTypes from 'prop-types';
import UserProfileButton from './UserProfileButton/UserProfileButton.container.js';
export default function HeaderContentRight({ hideUserProfileButton, navigation }) {
if (hideUserProfileButton) {
return null;
}
return <UserProfileButton />;
}
HeaderContentRight.propTypes = {
hideUserProfileButton: PropTypes.bool.isRequired,
};

View File

@@ -0,0 +1,18 @@
import { connect } from 'react-redux';
import { getActiveEvent, getDefaultEvent } from '../selectors/events.js';
import EventTitle from './EventTitle.js';
const matchStateToProps = (state) => {
const event = hasActiveEvent(state) ? getActiveEvent(state) : getDefaultEvent(state);
return {
date: event.get('date'),
end: event.get('end'),
name: event.get('name'),
start: event.get('start'),
};
};
export default connect(matchStateToProps, null)(EventTitle);

View File

@@ -0,0 +1,43 @@
import React from 'react';
import PropTypes from 'prop-types';
import {
Text,
TouchableOpacity,
View,
} from 'react-native';
import styles from './EventTitle.styles.js';
export default function EventTitle({
action,
date,
end,
name,
start,
}) {
const _generateEventTitle = () => (
<View style={styles.eventInfo}>
<Text style={styles.eventName}>{name}</Text>
<Text style={styles.eventDate}>{`${date} | ${start} - ${end}`}</Text>
</View>
);
if (action) {
return <TouchableOpacity onPress={action}>{_generateEventTitle()}</TouchableOpacity>;
}
return _generateEventTitle();
}
EventTitle.propTypes = {
action: PropTypes.func,
date: PropTypes.string.isRequired,
end: PropTypes.string.isRequired,
name: PropTypes.string.isRequired,
start: PropTypes.string.isRequired,
};
EventTitle.defaultProps = {
action: null,
};

View File

@@ -0,0 +1,15 @@
import { StyleSheet } from 'react-native';
export default const styles = StyleSheet.create({
eventInfo: {
flexDirection: 'row',
},
eventName: {
flex: 1,
fontWeight: 'bold',
},
eventDate: {
flex: 1,
},
});

View File

@@ -0,0 +1,18 @@
import { connect } from 'react-redux';
import { hasActiveEvent } from '../selectors/activeEvent.js';
import { hasMultipleEvents } from '../selectors/events.js';
import HeaderTitle from './HeaderTitle.js';
const matchStateToProps = (state, ownProps) => {
const { routeName } = ownProps.navigation.state;
return {
activeRoute: routeName,
hasActiveEvent: hasActiveEvent(state),
hasMultipleEvents: hasMultipleEvents(state),
};
};
export default connect(matchStateToProps, null)(HeaderTitle);

View File

@@ -0,0 +1,60 @@
import React from 'react';
import PropTypes from 'prop-types';
import {
Text,
TouchableOpacity,
View,
} from 'react-native';
import EventTitle from './EventTitle/EventTitle.container.js';
import styles from './TitleBar.styles.js';
export default function HeaderTitle({
activeRoute,
hasActiveEvent,
hasMultipleEvents,
navigation,
}) {
const _goBack = () => {
if (hasActiveEvent) {
navigation.goBack();
return false;
}
console.log('nowhere to go...');
};
const _showEvents = () => {
navigation.navigate('Events');
return false;
};
if (activeRoute === 'Events') {
return (
<TouchableOpacity onPress={_goBack}>
<Text style={styles.screenHeader}>Profile</Text>
</TouchableOpacity>
);
}
if (activeRoute === 'Profile') {
return <Text style={styles.screenHeader}>Profile</Text>;
}
return <EventTitle action={hasMultipleEvents ? _showEvents : null} />
}
HeaderTitle.propTypes = {
activeRoute: PropTypes.string.isRequired,
hasActiveEvent: PropTypes.bool,
hasMultipleEvents: PropTypes.bool.isRequired,
navigation: PropTypes.func.isRequired,
};
HeaderTitle.defaultProps = {
hasActiveEvent: false,
};

View File

@@ -0,0 +1,15 @@
import { StyleSheet } from 'react-native';
export default const styles = StyleSheet.create({
filterBar: {
backgroundColor: '#0F0',
flexDirection: 'row',
},
filter: {
flex: 2,
},
view: {
flex: 2,
},
});

View File

@@ -0,0 +1,15 @@
import React from 'react';
import PropTypes from 'prop-types';
import { TouchableOpacity } from 'react-native';
import { Icon } from 'react-native-elements';
export default function BackIcon({ action }) (
<TouchableOpacity onPress={action}>
<Icon name="ei-chevron-left" type="evilicons" size={28} />;
</TouchableOpacity>
)
BackIcon.propTypes = {
action: PropTypes.func.isRequired,
};

View File

@@ -0,0 +1,24 @@
import React from 'react';
import PropTypes from 'prop-types';
import { TouchableOpacity } from 'react-native';
import { Icon } from 'react-native-elements';
export default function EventsIcon({ action }) {
const renderEventsIcon = () => <Icon name="ei-calendar" type="evilicons" size={28} />;
if (action) {
return <TouchableOpacity onPress={action}>{renderEventsIcon()}</TouchableOpacity>;
}
return renderEventsIcon();
}
EventsIcon.propTypes = {
action: PropTypes.func,
};
EventsIcon.defaultProps = {
action: null,
};

View File

@@ -0,0 +1,11 @@
import { connect } from 'react-redux';
import { getProfileAvatarUrl } from '../selectors/profile.js';
import HeaderContentRight from './HeaderContentRight.js';
const matchStateToProps = (state) => ({
avatarUrl: getProfileAvatarUrl(state),
});
export default connect(matchStateToProps, null)(HeaderContentRight);

View File

@@ -0,0 +1,35 @@
import React from 'react';
import PropTypes from 'prop-types';
import { Image, TouchableOpacity, View } from 'react-native';
import { Icon } from 'react-native-elements';
import styles from './UserProfileButton.styles.js';
export default function UserProfileButton({ avatarUrl, navigation }) {
const _goToProfile = () => {
navigation.navigate('Profile');
return false;
};
return (
<TouchableOpacity onPress={_goToProfile}>
{avatarUrl !== null ? (
<View style={styles.avatarWrap}>
<Image source={{ uri: avatarUrl }} />
</View>
) : (
<Icon name="ei-user" type="evilicons" size={28} />;
)}
</TouchableOpacity>
);
}
HeaderContentRight.propTypes = {
avatarUrl: PropTypes.string,
};
HeaderContentRight.propTypes = {
avatarUrl: null,
};

View File

@@ -17,7 +17,7 @@ import BidStatus from '../../containers/Auction/BidStatus.js';
import { ITEM_TYPES } from '../../constants/constants.js';
import { formatPrice, getAuctionTime } from '../../library/helpers.js';
export default class ItemRow extends Component {
export default class AuctionListItem extends Component {
static get propTypes() {
return {
description: PropTypes.string,

View File

@@ -0,0 +1,84 @@
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import {
StyleSheet,
TouchableOpacity,
Text,
Image,
View
} from 'react-native';
export default class EventListItem extends Component {
static get propTypes() {
return {
description: PropTypes.string.isRequired,
endTime: PropTypes.string.isRequired,
id: PropTypes.string.isRequired,
images: PropTypes.arrayOf(
PropTypes.shape({
url: PropTypes.string,
}),
),
isTicketed: PropTypes.bool,
postCount: PropTypes.number,
setActiveEvent: PropTypes.func.isRequired,
showFrom: PropTypes.string.isRequired,
showUntil: PropTypes.string.isRequired,
startTime: PropTypes.string.isRequired,
tagline: PropTypes.string,
title: PropTypes.string.isRequired,
};
}
static get defaultProps() {
return {
images: null,
isTicketed: false,
postCount: 0,
tagline: null,
};
}
constructor(props) {
super(props);
}
_viewEventDetail = () => {
const { id } = this.props.details;
this.props.setActiveEvent(id);
this.props.navigation.navigate('Event');
}
render() {
const {
} = this.props;
return(
<TouchableOpacity onPress={this._viewEventDetail}>
<View style={styles.rowContainer}>
</View>
</TouchableOpacity>
);
}
}
const styles = StyleSheet.create({
rowContainer: {
backgroundColor: '#FFF',
borderRadius: 4,
flex: 1,
flexDirection: 'column',
marginRight: 10,
marginLeft: 10,
marginTop: 10,
padding: 10,
shadowColor: '#CCC',
shadowOffset: {
width: 1,
height: 1
},
shadowOpacity: 1.0,
shadowRadius: 1,
},
});