diff --git a/README.md b/README.md index a91c623..cec2212 100644 --- a/README.md +++ b/README.md @@ -67,7 +67,7 @@ We use for generic UI components ## TODO upgrade +- Refactor EventDetail and EventList to functional components - Make stripe work again - Fix icons - Fix colors in native base theme -- Refactor EventDetail and EventList to functional components diff --git a/src/Navigation.js b/src/Navigation.js index 57ead87..ffcf2a0 100644 --- a/src/Navigation.js +++ b/src/Navigation.js @@ -5,7 +5,7 @@ import { createNativeStackNavigator } from '@react-navigation/native-stack'; import Icon from 'react-native-vector-icons/SimpleLineIcons'; import EventListScreen from './screens/EventListScreen'; -import EventDetailScreen from './screens/EventDetailScreen'; +import EventDetail from './modules/events/EventDetail'; import Membership from './modules/membership/Membership'; import Login from './modules/login/Login'; @@ -24,8 +24,8 @@ const EventStackScreen = () => ( /> ({ title: route.params.item.title.decoded })} + component={EventDetail} + options={({ route }) => ({ title: route.params.event.title.decoded })} /> ); diff --git a/src/modules/events/EventDetail.js b/src/modules/events/EventDetail.js index 0264bd2..3c9913d 100644 --- a/src/modules/events/EventDetail.js +++ b/src/modules/events/EventDetail.js @@ -1,4 +1,4 @@ -import React, { Component } from 'react'; +import React from 'react'; import { Linking, StyleSheet, ScrollView, Text, Platform, View, Image, TouchableOpacity } from 'react-native'; import HTMLView from 'react-native-htmlview'; import moment from 'moment'; @@ -10,230 +10,192 @@ moment.locale('nb'); const CHATEAU_NEUF_ADDRESS = 'Chateau Neuf, Slemdalsveien 15, 0369 Oslo'; -export default class EventDetail extends Component { - _formatTime(time) { - return moment(time).format('HH:mm'); +const FORMAT_TIME = 'HH:mm'; +const FORMAT_MONTH = 'MMM'; +const FORMAT_DAY = 'DD.'; +const FORMAT_LOCAL_DAY = 'ddd'; +const FORMAT_YEAR = 'YYYY'; + +const formatRelative = (time) => moment(time).fromNow(); + +const format = (time, formatString = FORMAT_TIME) => moment(time).format(formatString); + +const formatTicketText = (event) => { + /* FIXME: This should be handled by API */ + let regularPrice = ''; + let memberPrice = ''; + if (event.price_regular === '0') { + event.price_regular = 'Gratis'; + } + if (event.price_member === '0') { + event.price_member = 'Gratis'; + } + if (event.price_regular !== 'Gratis') { + regularPrice = ' kr'; + } + if (event.price_member !== 'Gratis') { + memberPrice = ' kr'; } - _formatMonth(time) { - return moment(time).format('MMM'); + let text = ''; + if (event.price_regular && event.price_member) { + text = `Pris: ${event.price_regular}${regularPrice} / Medlemmer: ${event.price_member}${memberPrice}`; + } else if (event.price_regular) { + text = `Pris: ${event.price_regular}${regularPrice}`; + } else if (event.price_member) { + text = `Pris (Medlemmer): ${event.price_member}${memberPrice}`; + } else { + return ''; + } + return text; +}; + +const onFacebookUrlPress = (link) => { + const fbEventPattern = /https?:\/\/www\.facebook\.com\/events\/(\d+)\/?/i; + const matches = fbEventPattern.exec(link); + let iosURL = link; + if (matches && matches.length) { + iosURL = `fb://event/?id=${matches[1]}`; + } + const url = Platform.select({ + ios: iosURL, + android: link, + }); + Linking.canOpenURL(url) + .then((supported) => { + if (!supported) { + return Linking.openURL(link); + } + return Linking.openURL(url); + }) + .catch((err) => console.error('An error occurred', err)); +}; + +const onLocationPress = (venue) => { + if (venue !== 'Annetsteds') { + Linking.openURL(`https://www.google.com/maps/dir/?api=1&destination=${CHATEAU_NEUF_ADDRESS}`); + } +}; + +const VenueLocation = ({ venue }) => (venue !== 'Annetsteds' ? CHATEAU_NEUF_ADDRESS : 'Ukjent adresse'); + +const PriceAndTicket = ({ event }) => { + const text = formatTicketText(event); + + if (text === '') { + return null; } - _formatDay(time) { - return moment(time).format('DD.'); - } - - _formatLocalDay(time) { - return moment(time).format('ddd'); - } - - _formatYear(time) { - return moment(time).format('YYYY'); - } - - _formatRelative(time) { - return moment(time).fromNow(); - } - - _formatLocation() { - if (this.props.item.venue !== 'Annetsteds') { - return CHATEAU_NEUF_ADDRESS; - } - return 'Ukjent adresse'; - } - - _formatTicketText() { - /* FIXME: This should be handled by API */ - const { item } = this.props; - let regularPrice = ''; - let memberPrice = ''; - if (item.price_regular === '0') { - item.price_regular = 'Gratis'; - } - if (item.price_member === '0') { - item.price_member = 'Gratis'; - } - if (item.price_regular !== 'Gratis') { - regularPrice = ' kr'; - } - if (item.price_member !== 'Gratis') { - memberPrice = ' kr'; - } - - let text = ''; - if (item.price_regular && item.price_member) { - text = `Pris: ${item.price_regular}${regularPrice} / Medlemmer: ${item.price_member}${memberPrice}`; - } else if (item.price_regular) { - text = `Pris: ${item.price_regular}${regularPrice}`; - } else if (item.price_member) { - text = `Pris (Medlemmer): ${item.price_member}${memberPrice}`; - } else { - return ''; - } - return text; - } - - onTicketUrlPress(link) { - Linking.openURL(link); - } - - onFacebookUrlPress(link) { - const fbEventPattern = /https?:\/\/www\.facebook\.com\/events\/(\d+)\/?/i; - const matches = fbEventPattern.exec(link); - let iosURL = link; - if (matches && matches.length) { - iosURL = `fb://event/?id=${matches[1]}`; - } - const url = Platform.select({ - ios: iosURL, - android: link, - }); - Linking.canOpenURL(url) - .then((supported) => { - if (!supported) { - return Linking.openURL(link); - } - return Linking.openURL(url); - }) - .catch((err) => console.error('An error occurred', err)); - } - - onLocationPress(venue) { - if (venue !== 'Annetsteds') { - Linking.openURL(`https://www.google.com/maps/dir/?api=1&destination=${CHATEAU_NEUF_ADDRESS}`); - } - } - - showPriceAndTicket() { - const { item } = this.props; - const text = this._formatTicketText(); - - if (text === '') { - return null; - } - - if (item.ticket_url) { - return ( - this.onTicketUrlPress(item.ticket_url)}> - - - - - {text} - Kjøp billett - - - ); - } - + if (event.ticket_url) { return ( - + Linking.openURL(event.ticket_url)}> {text} - Billett i døra - - - ); - } - - showFacebutton() { - const { item } = this.props; - if (!item.facebook_url) { - return null; - } - - return ( - this.onFacebookUrlPress(item.facebook_url)} style={styles.metaInner}> - - - - - På Facebook + Kjøp billett ); } - showImage() { - const { item } = this.props; - - if (item.thumbnail.medium_large) { - return ; - } + return ( + + + + + + {text} + Billett i døra + + + ); +}; +const FaceButton = ({ event }) => { + if (!event.facebook_url) { return null; } - showYear() { - const { item } = this.props; - - if (moment().year() !== moment(item.start_time).year()) { - return {this._formatYear(item.start_time)}; - } + return ( + onFacebookUrlPress(event.facebook_url)} style={styles.metaInner}> + + + + + På Facebook + + + ); +}; +const Year = ({ startTime }) => { + if (moment().year() === moment(startTime).year()) { return null; } + return {format(startTime, FORMAT_YEAR)}; +}; - formatTimeFull(item) { - const endTime = item.end_time ? ` - ${this._formatTime(item.end_time)}` : ''; - const startTime = `${this._formatLocalDay(item.start_time)} kl. ${this._formatTime(item.start_time)}`; - return `${startTime}${endTime}`; - } +const formatTimeFull = (event) => { + const endTime = event.end_time ? ` - ${format(event.end_time, FORMAT_TIME)}` : ''; + const startTime = `${format(event.start_time, FORMAT_LOCAL_DAY)} kl. ${format(event.start_time, FORMAT_TIME)}`; + return `${startTime}${endTime}`; +}; - render() { - const { item } = this.props; - return ( - - {this.showImage()} - - {/* Date and title */} - - - - {this._formatDay(item.start_time)} - {this._formatMonth(item.start_time)} - {this.showYear()} - - - - - {item.title.decoded} - - +const EventDetail = ({ + route: { + params: { event }, + }, +}) => ( + + {event.thumbnail.medium_large && } + + {/* Date and title */} + + + + {format(event.start_time, FORMAT_DAY)} + {format(event.start_time, FORMAT_MONTH)} + - {/* Time and calendar */} - - - - - - {this.formatTimeFull(item)} - {this._formatRelative(item.start_time)} - - - {/* Location and maps */} - this.onLocationPress(item.venue)}> - - - - - {item.venue} - - {this._formatLocation()} - - - - {this.showPriceAndTicket()} - {this.showFacebutton()} - - - ); - } -} + + + {event.title.decoded} + + + + {/* Time and calendar */} + + + + + + {formatTimeFull(event)} + {formatRelative(event.start_time)} + + + {/* Location and maps */} + onLocationPress(event.venue)}> + + + + + {event.venue} + + + + + + + + + + +); + +export default EventDetail; const styles = StyleSheet.create({ dateAndTitle: { diff --git a/src/screens/EventDetailScreen.js b/src/screens/EventDetailScreen.js deleted file mode 100644 index 7dd81d5..0000000 --- a/src/screens/EventDetailScreen.js +++ /dev/null @@ -1,7 +0,0 @@ -import React from 'react'; - -import EventDetail from '../modules/events/EventDetail'; - -const EventDetailScreen = ({ route }) => ; - -export default EventDetailScreen; diff --git a/src/screens/EventListScreen.js b/src/screens/EventListScreen.js index 31024c7..1e3d6dd 100644 --- a/src/screens/EventListScreen.js +++ b/src/screens/EventListScreen.js @@ -7,8 +7,8 @@ const EventListScreen = () => { const { navigate } = useNavigation(); return ( { - navigate('EventDetail', { item }); + showEvent={(event) => { + navigate('EventDetail', { event }); }} /> );