Verified Commit 1ebb16b8 authored by Sébastiaan Versteeg's avatar Sébastiaan Versteeg
Browse files

Move PushNotications screen into Settings as CardSection

parent 2d7f4f66
...@@ -427,9 +427,7 @@ exports[`Sidebar component renders correctly 1`] = ` ...@@ -427,9 +427,7 @@ exports[`Sidebar component renders correctly 1`] = `
} }
> >
<Text <Text
accessible={true}
allowFontScaling={false} allowFontScaling={false}
ellipsizeMode="tail"
onPress={[Function]} onPress={[Function]}
style={ style={
Array [ Array [
...@@ -458,9 +456,6 @@ exports[`Sidebar component renders correctly 1`] = ` ...@@ -458,9 +456,6 @@ exports[`Sidebar component renders correctly 1`] = `
</Text> </Text>
<Text <Text
accessible={true}
allowFontScaling={true}
ellipsizeMode="tail"
style={ style={
Array [ Array [
Object { Object {
...@@ -478,15 +473,8 @@ exports[`Sidebar component renders correctly 1`] = ` ...@@ -478,15 +473,8 @@ exports[`Sidebar component renders correctly 1`] = `
</View> </View>
</View> </View>
<View <View
accessibilityComponentType={undefined}
accessibilityLabel={undefined}
accessibilityTraits={undefined}
accessible={true} accessible={true}
hasTVPreferredFocus={undefined}
hitSlop={undefined}
isTVSelectable={true} isTVSelectable={true}
nativeID={undefined}
onLayout={undefined}
onResponderGrant={[Function]} onResponderGrant={[Function]}
onResponderMove={[Function]} onResponderMove={[Function]}
onResponderRelease={[Function]} onResponderRelease={[Function]}
...@@ -504,8 +492,6 @@ exports[`Sidebar component renders correctly 1`] = ` ...@@ -504,8 +492,6 @@ exports[`Sidebar component renders correctly 1`] = `
}, },
] ]
} }
testID={undefined}
tvParallaxProperties={undefined}
> >
<View <View
style={ style={
......
// Group setting sections together to prepare for more submenus to be added. // Actions are grouped based on the settings sections
export const pushNotificationsSettingsActions = {
RETRIEVE: 'SETTINGS_PUSH_NOTIFICATIONS', export const settingsActions = {
LOADING: 'SETTINGS_PUSH_NOTIFICATIONS_LOADING', INIT_START: 'SETTINGS_INIT_START',
INIT_COMPLETE: 'SETTINGS_INIT_COMPLETE',
initStart: () => ({
type: settingsActions.INIT_START,
}),
initComplete: () => ({
type: settingsActions.INIT_COMPLETE,
}),
};
export const notificationsSettingsActions = {
SUCCESS: 'SETTINGS_PUSH_NOTIFICATIONS_SUCCESS', SUCCESS: 'SETTINGS_PUSH_NOTIFICATIONS_SUCCESS',
FAILURE: 'SETTINGS_PUSH_NOTIFICATIONS_FAILURE', FAILURE: 'SETTINGS_PUSH_NOTIFICATIONS_FAILURE',
SAVE_CATEGORIES: 'SETTINGS_PUSH_NOTIFICATIONS_SAVE_CATEGORIES', SAVE_CATEGORIES: 'SETTINGS_PUSH_NOTIFICATIONS_SAVE_CATEGORIES',
retrieve: () => ({
type: pushNotificationsSettingsActions.RETRIEVE,
}),
loading: () => ({
type: pushNotificationsSettingsActions.LOADING,
}),
success: categoryList => ({ success: categoryList => ({
type: pushNotificationsSettingsActions.SUCCESS, type: notificationsSettingsActions.SUCCESS,
categoryList, categoryList,
}), }),
failure: () => ({ failure: () => ({
type: pushNotificationsSettingsActions.FAILURE, type: notificationsSettingsActions.FAILURE,
}), }),
saveCategories: categories => ({ saveCategories: categories => ({
type: pushNotificationsSettingsActions.SAVE_CATEGORIES, type: notificationsSettingsActions.SAVE_CATEGORIES,
categories, categories,
}), }),
}; };
const files = {}; const files = {};
files['app/ui/screens/settings/NotificationsSectionNL'] = require('./nl/app/ui/screens/settings/NotificationsSection.json');
files['app/ui/screens/user/ProfileNL'] = require('./nl/app/ui/screens/user/Profile.json'); files['app/ui/screens/user/ProfileNL'] = require('./nl/app/ui/screens/user/Profile.json');
files['app/ui/screens/user/LoginNL'] = require('./nl/app/ui/screens/user/Login.json'); files['app/ui/screens/user/LoginNL'] = require('./nl/app/ui/screens/user/Login.json');
files['app/ui/screens/memberList/MemberListNL'] = require('./nl/app/ui/screens/memberList/MemberList.json');
files['app/ui/screens/welcome/EventDetailCardNL'] = require('./nl/app/ui/screens/welcome/EventDetailCard.json');
files['app/ui/screens/welcome/WelcomeNL'] = require('./nl/app/ui/screens/welcome/Welcome.json'); files['app/ui/screens/welcome/WelcomeNL'] = require('./nl/app/ui/screens/welcome/Welcome.json');
files['app/ui/screens/pizza/PizzaNL'] = require('./nl/app/ui/screens/pizza/Pizza.json'); files['app/ui/screens/welcome/EventDetailCardNL'] = require('./nl/app/ui/screens/welcome/EventDetailCard.json');
files['app/ui/screens/settings/SettingsNL'] = require('./nl/app/ui/screens/settings/Settings.json'); files['app/ui/screens/memberList/MemberListNL'] = require('./nl/app/ui/screens/memberList/MemberList.json');
files['app/ui/screens/settings/PushNotificationsNL'] = require('./nl/app/ui/screens/settings/PushNotifications.json');
files['app/ui/screens/events/CalendarNL'] = require('./nl/app/ui/screens/events/Calendar.json');
files['app/ui/screens/events/RegistrationNL'] = require('./nl/app/ui/screens/events/Registration.json');
files['app/ui/screens/events/CalendarItemNL'] = require('./nl/app/ui/screens/events/CalendarItem.json'); files['app/ui/screens/events/CalendarItemNL'] = require('./nl/app/ui/screens/events/CalendarItem.json');
files['app/ui/screens/events/EventNL'] = require('./nl/app/ui/screens/events/Event.json'); files['app/ui/screens/events/EventNL'] = require('./nl/app/ui/screens/events/Event.json');
files['app/ui/screens/events/RegistrationNL'] = require('./nl/app/ui/screens/events/Registration.json');
files['app/ui/screens/events/CalendarNL'] = require('./nl/app/ui/screens/events/Calendar.json');
files['app/ui/screens/pizza/PizzaNL'] = require('./nl/app/ui/screens/pizza/Pizza.json');
files['app/ui/components/standardHeader/StandardHeaderNL'] = require('./nl/app/ui/components/standardHeader/StandardHeader.json'); files['app/ui/components/standardHeader/StandardHeaderNL'] = require('./nl/app/ui/components/standardHeader/StandardHeader.json');
files['app/ui/components/errorScreen/ErrorScreenNL'] = require('./nl/app/ui/components/errorScreen/ErrorScreen.json');
files['app/ui/components/navigator/SidebarNL'] = require('./nl/app/ui/components/navigator/Sidebar.json'); files['app/ui/components/navigator/SidebarNL'] = require('./nl/app/ui/components/navigator/Sidebar.json');
files['app/ui/components/errorScreen/ErrorScreenNL'] = require('./nl/app/ui/components/errorScreen/ErrorScreen.json');
export default { export default {
nl: { nl: {
'screens/settings/NotificationsSection': files['app/ui/screens/settings/NotificationsSectionNL'],
'screens/user/Profile': files['app/ui/screens/user/ProfileNL'], 'screens/user/Profile': files['app/ui/screens/user/ProfileNL'],
'screens/user/Login': files['app/ui/screens/user/LoginNL'], 'screens/user/Login': files['app/ui/screens/user/LoginNL'],
'screens/memberList/MemberList': files['app/ui/screens/memberList/MemberListNL'],
'screens/welcome/EventDetailCard': files['app/ui/screens/welcome/EventDetailCardNL'],
'screens/welcome/Welcome': files['app/ui/screens/welcome/WelcomeNL'], 'screens/welcome/Welcome': files['app/ui/screens/welcome/WelcomeNL'],
'screens/pizza/Pizza': files['app/ui/screens/pizza/PizzaNL'], 'screens/welcome/EventDetailCard': files['app/ui/screens/welcome/EventDetailCardNL'],
'screens/settings/Settings': files['app/ui/screens/settings/SettingsNL'], 'screens/memberList/MemberList': files['app/ui/screens/memberList/MemberListNL'],
'screens/settings/PushNotifications': files['app/ui/screens/settings/PushNotificationsNL'],
'screens/events/Calendar': files['app/ui/screens/events/CalendarNL'],
'screens/events/Registration': files['app/ui/screens/events/RegistrationNL'],
'screens/events/CalendarItem': files['app/ui/screens/events/CalendarItemNL'], 'screens/events/CalendarItem': files['app/ui/screens/events/CalendarItemNL'],
'screens/events/Event': files['app/ui/screens/events/EventNL'], 'screens/events/Event': files['app/ui/screens/events/EventNL'],
'screens/events/Registration': files['app/ui/screens/events/RegistrationNL'],
'screens/events/Calendar': files['app/ui/screens/events/CalendarNL'],
'screens/pizza/Pizza': files['app/ui/screens/pizza/PizzaNL'],
'components/standardHeader/StandardHeader': files['app/ui/components/standardHeader/StandardHeaderNL'], 'components/standardHeader/StandardHeader': files['app/ui/components/standardHeader/StandardHeaderNL'],
'components/errorScreen/ErrorScreen': files['app/ui/components/errorScreen/ErrorScreenNL'],
'components/navigator/Sidebar': files['app/ui/components/navigator/SidebarNL'], 'components/navigator/Sidebar': files['app/ui/components/navigator/SidebarNL'],
'components/errorScreen/ErrorScreen': files['app/ui/components/errorScreen/ErrorScreenNL'],
}, },
}; };
{
"Notifications settings could not be loaded.": "De instellingen voor notificaties konden niet worden geladen.",
"(required)": "(verplicht)",
"Notifications": "Notificaties"
}
{
"Sorry, we couldn't load any data.": "Sorry, we konden geen gegevens laden.",
"(required)": "(verplicht)"
}
import { pushNotificationsSettingsActions } from '../actions/settings'; import pushNotifications, { initialState as initialPushNotificationsState } from './settings/pushNotifications';
import { settingsActions } from '../actions/settings';
const initialState = { const initialState = {
pushNotifications: { pushNotifications: initialPushNotificationsState,
categoryList: [], loading: true,
status: 'loading',
},
}; };
export default function settings(state = initialState, action = {}) { export default function calendar(state = initialState, action = {}) {
switch (action.type) { switch (action.type) {
case pushNotificationsSettingsActions.LOADING: { case settingsActions.INIT_START:
return { return {
...state, ...state,
pushNotifications: { loading: true,
...state.pushNotifications,
status: 'loading',
},
}; };
} case settingsActions.INIT_COMPLETE:
case pushNotificationsSettingsActions.SUCCESS: {
return { return {
...state, ...state,
pushNotifications: { loading: false,
...state.pushNotifications,
categoryList: action.categoryList,
status: 'success',
},
}; };
} default:
case pushNotificationsSettingsActions.FAILURE: {
return { return {
...state, ...state,
pushNotifications: { pushNotifications: pushNotifications(state.pushNotifications, action),
...state.pushNotifications,
status: 'failure',
},
}; };
}
default: {
return state;
}
} }
} }
import { notificationsSettingsActions as actions } from '../../actions/settings';
export const initialState = {
categoryList: [],
status: 'loading',
};
export default function pushNotifications(state = initialState, action = {}) {
switch (action.type) {
case actions.SUCCESS:
return {
categoryList: action.categoryList,
status: 'success',
};
case actions.FAILURE:
return {
...state,
status: 'failure',
};
default:
return state;
}
}
import { AsyncStorage } from 'react-native'; import { AsyncStorage } from 'react-native';
import { takeEvery, select, call, put } from 'redux-saga/effects'; import { Sentry } from 'react-native-sentry';
import {
all, call, put, select, takeEvery,
} from 'redux-saga/effects';
import { pushNotificationsSettingsActions } from '../actions/settings'; import { notificationsSettingsActions, settingsActions } from '../actions/settings';
import * as navigationActions from '../actions/navigation';
import { apiRequest, tokenSelector } from '../utils/url'; import { apiRequest, tokenSelector } from '../utils/url';
import * as pushNotifactionsActions from '../actions/pushNotifications';
const PUSHCATEGORYKEY = '@MyStore:pushCategories'; const PUSHCATEGORYKEY = '@MyStore:pushCategories';
...@@ -20,9 +23,6 @@ function* pushNotifications() { ...@@ -20,9 +23,6 @@ function* pushNotifications() {
}, },
}; };
yield put(pushNotificationsSettingsActions.loading());
yield put(navigationActions.navigate('pushNotificationsSettings'));
try { try {
const categoryList = yield call(apiRequest, 'devices/categories', data); const categoryList = yield call(apiRequest, 'devices/categories', data);
const preferencesJson = yield call(AsyncStorage.getItem, PUSHCATEGORYKEY); const preferencesJson = yield call(AsyncStorage.getItem, PUSHCATEGORYKEY);
...@@ -38,9 +38,10 @@ function* pushNotifications() { ...@@ -38,9 +38,10 @@ function* pushNotifications() {
} }
} }
yield put(pushNotificationsSettingsActions.success(categoryList)); yield put(notificationsSettingsActions.success(categoryList));
} catch (error) { } catch (error) {
yield put(pushNotificationsSettingsActions.failure()); Sentry.captureException(error);
yield put(notificationsSettingsActions.failure());
} }
} }
...@@ -49,14 +50,22 @@ function* saveCategories(action) { ...@@ -49,14 +50,22 @@ function* saveCategories(action) {
try { try {
yield call(AsyncStorage.setItem, PUSHCATEGORYKEY, JSON.stringify(categories)); yield call(AsyncStorage.setItem, PUSHCATEGORYKEY, JSON.stringify(categories));
yield put(pushNotifactionsActions.register(categories));
} catch (error) { } catch (error) {
// Swallow error Sentry.captureException(error);
} }
} }
function* init() {
yield all([
pushNotifications(),
]);
yield put(settingsActions.initComplete());
}
function* settingsSaga() { function* settingsSaga() {
yield takeEvery(pushNotificationsSettingsActions.RETRIEVE, pushNotifications); yield takeEvery(settingsActions.INIT_START, init);
yield takeEvery(pushNotificationsSettingsActions.SAVE_CATEGORIES, saveCategories); yield takeEvery(notificationsSettingsActions.SAVE_CATEGORIES, saveCategories);
} }
export default settingsSaga; export default settingsSaga;
import React from 'react'; import React from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { StyleSheet, Text, View, ViewPropTypes } from 'react-native'; import {
StyleSheet, Text, View, ViewPropTypes,
} from 'react-native';
import styles from './style/CardSection'; import styles from './style/CardSection';
const CardSection = props => ( const CardSection = props => (
<View style={[styles.section, props.style]}> <View style={[styles.section, props.style]}>
<Text style={styles.sectionHeader}>{props.sectionHeader}</Text> <Text style={styles.sectionHeader}>
{props.sectionHeader}
</Text>
<View style={[styles.card, props.contentStyle]}> <View style={[styles.card, props.contentStyle]}>
{props.children} {props.children}
</View> </View>
...@@ -28,4 +32,4 @@ CardSection.defaultProps = { ...@@ -28,4 +32,4 @@ CardSection.defaultProps = {
contentStyle: defaultStyles, contentStyle: defaultStyles,
}; };
export default CardSection; export default CardSection;
\ No newline at end of file
...@@ -35,4 +35,4 @@ const styles = StyleSheet.create({ ...@@ -35,4 +35,4 @@ const styles = StyleSheet.create({
}, },
}); });
export default styles; export default styles;
\ No newline at end of file
...@@ -16,7 +16,6 @@ import StandardHeader from '../standardHeader/StandardHeader'; ...@@ -16,7 +16,6 @@ import StandardHeader from '../standardHeader/StandardHeader';
import Registration from '../../screens/events/Registration'; import Registration from '../../screens/events/Registration';
import MemberList from '../../screens/memberList/MemberList'; import MemberList from '../../screens/memberList/MemberList';
import Settings from '../../screens/settings/Settings'; import Settings from '../../screens/settings/Settings';
import PushNotifications from '../../screens/settings/PushNotifications';
import * as actions from '../../../actions/navigation'; import * as actions from '../../../actions/navigation';
import styles from './style/ReduxNavigator'; import styles from './style/ReduxNavigator';
...@@ -40,8 +39,6 @@ const sceneToComponent = (scene) => { ...@@ -40,8 +39,6 @@ const sceneToComponent = (scene) => {
return <MemberList />; return <MemberList />;
case 'settings': case 'settings':
return <Settings />; return <Settings />;
case 'pushNotificationsSettings':
return <PushNotifications />;
default: default:
return <Welcome />; return <Welcome />;
} }
......
import React, { Component } from 'react'; import React, { Component } from 'react';
import { View, Text, Switch } from 'react-native'; import { Switch, Text, View } from 'react-native';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { translate } from 'react-i18next'; import { translate } from 'react-i18next';
import styles from './style/NotificationsSection';
import Colors from '../../style/Colors';
import LoadingScreen from '../../components/loadingScreen/LoadingScreen'; import { notificationsSettingsActions } from '../../../actions/settings';
import ErrorScreen from '../../components/errorScreen/ErrorScreen'; import CardSection from '../../components/cardSection/CardSection';
import styles from './style/PushNotifications'; const GENERAL_KEY = 'general';
import Colors from '../../style/Colors';
import { pushNotificationsSettingsActions } from '../../../actions/settings'; class NotificationsSection extends Component {
import * as pushNotificationsActions from '../../../actions/pushNotifications'; constructor(props) {
super(props);
this.state = {};
}
class PushNotifications extends Component {
static getDerivedStateFromProps = (props) => { static getDerivedStateFromProps = (props) => {
if (props.status !== 'success') { if (props.status !== 'success') {
return null; return null;
...@@ -22,63 +25,72 @@ class PushNotifications extends Component { ...@@ -22,63 +25,72 @@ class PushNotifications extends Component {
const newState = {}; const newState = {};
for (let i = 0; i < props.categoryList.length; i += 1) { for (let i = 0; i < props.categoryList.length; i += 1) {
newState[props.categoryList[i].key] = props.categoryList[i].enabled; if (props.categoryList[i].key === GENERAL_KEY) {
newState[props.categoryList[i].key] = true;
} else {
newState[props.categoryList[i].key] = props.categoryList[i].enabled;
}
} }
return newState; return newState;
}; };
constructor(props) {
super(props);
this.state = {};
}
updateField = (key, value) => { updateField = (key, value) => {
const update = {}; const update = {};
update[key] = value; update[key] = value;
this.setState(update, () => { this.setState(update, () => {
const categories = Object.keys(this.state).filter(k => this.state[k]); const categories = Object.keys(this.state).filter(k => this.state[k]);
this.props.register(categories);
this.props.saveCategories(categories); this.props.saveCategories(categories);
}); });
}; };
render() { render() {
if (this.props.status === 'loading') { const { status, categoryList, t } = this.props;
return <LoadingScreen />; let content = (
} else if (this.props.status === 'failure') { <Text style={styles.emptyText}>
return <ErrorScreen message={this.props.t('Sorry, we couldn\'t load any data.')} />; {t('Notifications settings could not be loaded.')}
</Text>
);
if (status === 'success') {
content = categoryList.map((category, i) => (
<View
style={[styles.categoryContainer, i !== 0 && styles.borderTop]}
key={category.key}
>
<Text
style={styles.label}
>
{category.name}
{' '}
{category.key === GENERAL_KEY && this.props.t('(required)')}
</Text>
<Switch
value={this.state[category.key]}
onValueChange={value => this.updateField(category.key, value)}
onTintColor={Colors.magenta}
thumbTintColor={this.state[category.key]
? Colors.darkMagenta : Colors.gray}
disabled={category.key === GENERAL_KEY}
/>
</View>
));
} }
return ( return (
<View style={styles.container}> <CardSection sectionHeader={t('Notifications')}>
{this.props.categoryList.map(category => ( {content}
<View style={styles.setting} key={category.key}> </CardSection>
<Text
style={styles.label}
key={category.key}
>{category.name} {category.key === 'general' && this.props.t('(required)')}</Text>
<Switch
value={this.state[category.key]}
onValueChange={value => this.updateField(category.key, value)}
thumbTintColor={this.state[category.key] ? Colors.darkMagenta : Colors.lightGray}
onTintColor={Colors.magenta}
disabled={category.key === 'general'}
/>
</View>
))}
</View>