Commit 7f525dc5 authored by Gijs Hendriksen's avatar Gijs Hendriksen

Refactor event admin screen in preparation for the pizza admin screen

parent 6fa6955b
......@@ -49,6 +49,10 @@ Object {
"Settings": "Instellingen",
"Welcome": "Welkom",
},
"ui/screens/admin/AdminScreen": Object {
"Find a member": "Zoek een lid",
"No entries found with this filter.": "Geen gegevens gevonden met dit filter.",
},
"ui/screens/events/CalendarItem": Object {
"From": "Tot",
"Until": "Van",
......@@ -65,9 +69,7 @@ Object {
"Disabled filter": "Filter uitgeschakeld",
"Filtering on payment": "Filteren op betaling",
"Filtering on presence": "Filteren op aanwezigheid",
"Find a member": "Zoek een lid",
"NOT PAID": "NIET BETAALD",
"No registrations found with this filter.": "Geen inschrijvingen gevonden met dit filter.",
"No registrations found...": "Geen inschrijvingen gevonden...",
"Present": "Aanwezig",
"Registrations": "Inschrijvingen",
......
const files = {};
files['app/ui/screens/settings/NotificationsSectionNL'] = require('./nl/app/ui/screens/settings/NotificationsSection.json');
files['app/ui/screens/welcome/EventDetailCardNL'] = require('./nl/app/ui/screens/welcome/EventDetailCard.json');
files['app/ui/screens/welcome/WelcomeScreenNL'] = require('./nl/app/ui/screens/welcome/WelcomeScreen.json');
files['app/appNL'] = require('./nl/app/app.json');
files['app/ui/components/errorScreen/ErrorScreenNL'] = require('./nl/app/ui/components/errorScreen/ErrorScreen.json');
files['app/ui/components/standardHeader/StandardHeaderNL'] = require('./nl/app/ui/components/standardHeader/StandardHeader.json');
files['app/ui/components/sidebar/SidebarNL'] = require('./nl/app/ui/components/sidebar/Sidebar.json');
files['app/ui/screens/memberList/MemberListScreenNL'] = require('./nl/app/ui/screens/memberList/MemberListScreen.json');
files['app/ui/screens/profile/ProfileScreenNL'] = require('./nl/app/ui/screens/profile/ProfileScreen.json');
files['app/ui/screens/profile/AchievementSectionNL'] = require('./nl/app/ui/screens/profile/AchievementSection.json');
files['app/ui/screens/profile/DescriptionSectionNL'] = require('./nl/app/ui/screens/profile/DescriptionSection.json');
files['app/ui/screens/profile/PersonalInfoSectionNL'] = require('./nl/app/ui/screens/profile/PersonalInfoSection.json');
files['app/ui/screens/settings/NotificationsSectionNL'] = require('./nl/app/ui/screens/settings/NotificationsSection.json');
files['app/ui/screens/events/CalendarItemNL'] = require('./nl/app/ui/screens/events/CalendarItem.json');
files['app/ui/screens/events/RegistrationScreenNL'] = require('./nl/app/ui/screens/events/RegistrationScreen.json');
files['app/ui/screens/events/EventAdminScreenNL'] = require('./nl/app/ui/screens/events/EventAdminScreen.json');
files['app/ui/screens/events/CalendarScreenNL'] = require('./nl/app/ui/screens/events/CalendarScreen.json');
files['app/ui/screens/events/EventAdminScreenNL'] = require('./nl/app/ui/screens/events/EventAdminScreen.json');
files['app/ui/screens/events/EventScreenNL'] = require('./nl/app/ui/screens/events/EventScreen.json');
files['app/ui/screens/photos/AlbumsOverviewScreenNL'] = require('./nl/app/ui/screens/photos/AlbumsOverviewScreen.json');
files['app/ui/screens/photos/AlbumDetailScreenNL'] = require('./nl/app/ui/screens/photos/AlbumDetailScreen.json');
files['app/ui/screens/admin/AdminScreenNL'] = require('./nl/app/ui/screens/admin/AdminScreen.json');
files['app/ui/screens/pizza/PizzaScreenNL'] = require('./nl/app/ui/screens/pizza/PizzaScreen.json');
files['app/ui/screens/welcome/WelcomeScreenNL'] = require('./nl/app/ui/screens/welcome/WelcomeScreen.json');
files['app/ui/screens/welcome/EventDetailCardNL'] = require('./nl/app/ui/screens/welcome/EventDetailCard.json');
files['app/ui/screens/profile/AchievementSectionNL'] = require('./nl/app/ui/screens/profile/AchievementSection.json');
files['app/ui/screens/profile/PersonalInfoSectionNL'] = require('./nl/app/ui/screens/profile/PersonalInfoSection.json');
files['app/ui/screens/profile/DescriptionSectionNL'] = require('./nl/app/ui/screens/profile/DescriptionSection.json');
files['app/ui/screens/profile/ProfileScreenNL'] = require('./nl/app/ui/screens/profile/ProfileScreen.json');
files['app/ui/screens/photos/AlbumDetailScreenNL'] = require('./nl/app/ui/screens/photos/AlbumDetailScreen.json');
files['app/ui/screens/photos/AlbumsOverviewScreenNL'] = require('./nl/app/ui/screens/photos/AlbumsOverviewScreen.json');
files['app/ui/screens/login/LoginScreenNL'] = require('./nl/app/ui/screens/login/LoginScreen.json');
files['app/ui/components/sidebar/SidebarNL'] = require('./nl/app/ui/components/sidebar/Sidebar.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/sagas/profileNL'] = require('./nl/app/sagas/profile.json');
files['app/sagas/sessionNL'] = require('./nl/app/sagas/session.json');
files['app/sagas/registrationNL'] = require('./nl/app/sagas/registration.json');
files['app/appNL'] = require('./nl/app/app.json');
files['app/sagas/profileNL'] = require('./nl/app/sagas/profile.json');
export default {
nl: {
'ui/screens/settings/NotificationsSection': files['app/ui/screens/settings/NotificationsSectionNL'],
'ui/screens/welcome/EventDetailCard': files['app/ui/screens/welcome/EventDetailCardNL'],
'ui/screens/welcome/WelcomeScreen': files['app/ui/screens/welcome/WelcomeScreenNL'],
app: files['app/appNL'],
'ui/components/errorScreen/ErrorScreen': files['app/ui/components/errorScreen/ErrorScreenNL'],
'ui/components/standardHeader/StandardHeader': files['app/ui/components/standardHeader/StandardHeaderNL'],
'ui/components/sidebar/Sidebar': files['app/ui/components/sidebar/SidebarNL'],
'ui/screens/memberList/MemberListScreen': files['app/ui/screens/memberList/MemberListScreenNL'],
'ui/screens/profile/ProfileScreen': files['app/ui/screens/profile/ProfileScreenNL'],
'ui/screens/profile/AchievementSection': files['app/ui/screens/profile/AchievementSectionNL'],
'ui/screens/profile/DescriptionSection': files['app/ui/screens/profile/DescriptionSectionNL'],
'ui/screens/profile/PersonalInfoSection': files['app/ui/screens/profile/PersonalInfoSectionNL'],
'ui/screens/settings/NotificationsSection': files['app/ui/screens/settings/NotificationsSectionNL'],
'ui/screens/events/CalendarItem': files['app/ui/screens/events/CalendarItemNL'],
'ui/screens/events/RegistrationScreen': files['app/ui/screens/events/RegistrationScreenNL'],
'ui/screens/events/EventAdminScreen': files['app/ui/screens/events/EventAdminScreenNL'],
'ui/screens/events/CalendarScreen': files['app/ui/screens/events/CalendarScreenNL'],
'ui/screens/events/EventAdminScreen': files['app/ui/screens/events/EventAdminScreenNL'],
'ui/screens/events/EventScreen': files['app/ui/screens/events/EventScreenNL'],
'ui/screens/photos/AlbumsOverviewScreen': files['app/ui/screens/photos/AlbumsOverviewScreenNL'],
'ui/screens/photos/AlbumDetailScreen': files['app/ui/screens/photos/AlbumDetailScreenNL'],
'ui/screens/admin/AdminScreen': files['app/ui/screens/admin/AdminScreenNL'],
'ui/screens/pizza/PizzaScreen': files['app/ui/screens/pizza/PizzaScreenNL'],
'ui/screens/welcome/WelcomeScreen': files['app/ui/screens/welcome/WelcomeScreenNL'],
'ui/screens/welcome/EventDetailCard': files['app/ui/screens/welcome/EventDetailCardNL'],
'ui/screens/profile/AchievementSection': files['app/ui/screens/profile/AchievementSectionNL'],
'ui/screens/profile/PersonalInfoSection': files['app/ui/screens/profile/PersonalInfoSectionNL'],
'ui/screens/profile/DescriptionSection': files['app/ui/screens/profile/DescriptionSectionNL'],
'ui/screens/profile/ProfileScreen': files['app/ui/screens/profile/ProfileScreenNL'],
'ui/screens/photos/AlbumDetailScreen': files['app/ui/screens/photos/AlbumDetailScreenNL'],
'ui/screens/photos/AlbumsOverviewScreen': files['app/ui/screens/photos/AlbumsOverviewScreenNL'],
'ui/screens/login/LoginScreen': files['app/ui/screens/login/LoginScreenNL'],
'ui/components/sidebar/Sidebar': files['app/ui/components/sidebar/SidebarNL'],
'ui/components/standardHeader/StandardHeader': files['app/ui/components/standardHeader/StandardHeaderNL'],
'ui/components/errorScreen/ErrorScreen': files['app/ui/components/errorScreen/ErrorScreenNL'],
'sagas/profile': files['app/sagas/profileNL'],
'sagas/session': files['app/sagas/sessionNL'],
'sagas/registration': files['app/sagas/registrationNL'],
app: files['app/appNL'],
'sagas/profile': files['app/sagas/profileNL'],
},
};
{
"Find a member": "Zoek een lid",
"No entries found with this filter.": "Geen gegevens gevonden met dit filter."
}
......@@ -5,8 +5,6 @@
"Present": "Aanwezig",
"No registrations found...": "Geen inschrijvingen gevonden...",
"Registrations": "Inschrijvingen",
"Find a member": "Zoek een lid",
"No registrations found with this filter.": "Geen inschrijvingen gevonden met dit filter.",
"Could not load the event...": "Kon het evenement niet laden...",
"NOT PAID": "NIET BETAALD",
"CASH": "CONTANT",
......
import React, { Component } from 'react';
import {
FlatList, RefreshControl, Switch, Text, TouchableHighlight, View,
} from 'react-native';
import { withTranslation } from 'react-i18next';
import PropTypes from 'prop-types';
import Icon from 'react-native-vector-icons/MaterialIcons';
import Snackbar from 'react-native-snackbar';
import unorm from 'unorm';
import styles from './style/AdminScreen';
import Colors from '../../style/Colors';
import SearchHeader from '../../components/searchHeader/SearchHeaderConnector';
import Button from '../../components/button/Button';
class AdminScreen extends Component {
constructor(props) {
super(props);
this.state = {
items: {},
searchKey: '',
currentFilter: 0,
};
for (let i = 0; i < this.props.items.length; i += 1) {
const {
pk, name, checkbox, select,
} = this.props.items[i];
this.state.items[pk] = {
name, checkbox, select,
};
}
}
componentDidUpdate(prevProps) {
if (!this.itemsAreEqual(this.props.items, prevProps.items)) {
const items = {};
for (let i = 0; i < this.props.items.length; i += 1) {
const {
pk, name, checkbox, select,
} = this.props.items[i];
items[pk] = {
name, checkbox, select,
};
}
this.setState({ items }); // eslint-disable-line react/no-did-update-set-state
}
}
itemsAreEqual = (a, b) => {
if (a.length !== b.length) {
return false;
}
a.sort((x, y) => x.pk - y.pk);
b.sort((x, y) => x.pk - y.pk);
for (let i = 0; i < a.length; i += 1) {
if (a[i].pk !== b[i].pk
|| a[i].checkbox !== b[i].checkbox
|| a[i].select.value !== b[i].select.value) {
return false;
}
}
return true;
};
applyFilter = (keys) => {
const { filterTypes } = this.props;
const { currentFilter } = this.state;
return keys.filter(this.containsSearchKey)
.filter(pk => filterTypes[currentFilter].checkItem(this.state.items[pk]));
};
cleanSearchTerm = term => unorm.nfd(term.toLowerCase()).replace(/[\u0300-\u036f]/g, '');
containsSearchKey = (pk) => {
const name = this.cleanSearchTerm(this.state.items[pk].name);
return name.indexOf(this.cleanSearchTerm(this.state.searchKey)) >= 0;
};
sortByName = (a, b) => {
const nameA = this.state.items[a].name.toLowerCase();
const nameB = this.state.items[b].name.toLowerCase();
if (nameA < nameB) {
return -1;
}
if (nameA > nameB) {
return 1;
}
return 0;
};
updateFilter = () => {
const { currentFilter } = this.state;
const { filterTypes } = this.props;
const newFilter = (currentFilter + 1) % filterTypes.length;
if (newFilter !== currentFilter) {
Snackbar.show({ title: filterTypes[newFilter].label });
this.setState({ currentFilter: newFilter });
}
};
updateValue = (pk, checkboxValue, selectValue) => {
const { items } = this.state;
items[pk].checkbox = checkboxValue;
items[pk].select.value = selectValue;
this.props.updateItem(pk, checkboxValue, selectValue);
this.setState({ items });
};
renderItem = ({ item, index }) => {
const {
name, checkbox, select,
} = this.state.items[item];
const { checkboxLabel } = this.props;
return (
<View key={item} style={[styles.item, index !== 0 && styles.borderTop]}>
<Text style={[styles.text, styles.name]}>
{name}
</Text>
<View style={styles.itemControls}>
{checkboxLabel && (
<View style={styles.checkboxContainer}>
<Text style={[styles.text, styles.label]}>
{checkboxLabel}
</Text>
<Switch
value={checkbox}
onValueChange={value => this.updateValue(item, value, select.value)}
trackColor={{
false: Colors.lightGray,
true: Colors.magenta,
}}
thumbColor={checkbox ? Colors.darkMagenta : Colors.grey}
/>
</View>
)}
<View style={styles.selectContainer}>
{
select.options.map(({ key, label }, buttonIndex) => (
<Button
key={`${item}_${key}`}
onPress={() => this.updateValue(item, checkbox, key)}
title={label}
color={select.value === key ? Colors.magenta : Colors.grey}
style={buttonIndex !== 0 && styles.buttonMargin}
textStyle={styles.buttonText}
containerStyle={styles.buttonTextContainer}
/>
))
}
</View>
</View>
</View>
);
};
render() {
const {
loading, t, handleRefresh, title,
} = this.props;
const keys = this.applyFilter(Object.keys(this.state.items));
const header = (
<SearchHeader
title={title}
searchText={t('Find a member')}
search={searchKey => this.setState({ searchKey })}
searchKey={this.state.searchKey}
leftIcon="arrow-back"
leftIconAction={this.props.goBack}
/>
);
const filterButton = this.props.filterTypes.length > 1 && (
<TouchableHighlight
onPress={this.updateFilter}
style={styles.filterButton}
>
<View style={styles.filterButtonWrapper}>
<Icon
name="filter-list"
size={32}
color={Colors.white}
/>
</View>
</TouchableHighlight>
);
if (keys.length === 0) {
return (
<View style={styles.rootWrapper}>
{header}
<Text
style={[styles.text, styles.noResultsMessage]}
>
{t('No entries found with this filter.')}
</Text>
{filterButton}
</View>
);
}
keys.sort(this.sortByName);
return (
<View style={styles.rootWrapper}>
{header}
<FlatList
backgroundColor={Colors.background}
contentContainerStyle={styles.container}
data={keys}
renderItem={this.renderItem}
refreshControl={(
<RefreshControl
refreshing={loading}
onRefresh={handleRefresh}
/>
)}
keyExtractor={item => item}
/>
{filterButton}
</View>
);
}
}
AdminScreen.propTypes = {
items: PropTypes.arrayOf(PropTypes.shape({
pk: PropTypes.number.isRequired,
name: PropTypes.string.isRequired,
checkbox: PropTypes.bool,
select: PropTypes.shape({
options: PropTypes.arrayOf(PropTypes.shape({
key: PropTypes.string,
label: PropTypes.string,
})),
value: PropTypes.string,
}),
})).isRequired,
checkboxLabel: PropTypes.string,
filterTypes: PropTypes.arrayOf(PropTypes.shape({
label: PropTypes.string.isRequired,
checkItem: PropTypes.func.isRequired,
})),
handleRefresh: PropTypes.func.isRequired,
title: PropTypes.string.isRequired,
loading: PropTypes.bool.isRequired,
updateItem: PropTypes.func.isRequired,
goBack: PropTypes.func.isRequired,
t: PropTypes.func.isRequired,
};
AdminScreen.defaultProps = {
checkboxLabel: '',
filterTypes: [],
};
export default withTranslation('ui/screens/admin/AdminScreen')(AdminScreen);
import { connect } from 'react-redux';
import * as navigationActions from '../../../actions/navigation';
import AdminScreen from './AdminScreen';
const mapDispatchToProps = {
goBack: navigationActions.goBack,
};
export default connect(() => ({}), mapDispatchToProps)(AdminScreen);
import Colors from '../../../style/Colors';
import StyleSheet from '../../../style/StyleSheet';
const styles = StyleSheet.create({
rootWrapper: {
flex: 1,
},
container: {
backgroundColor: Colors.background,
},
borderTop: {
borderTopColor: Colors.dividerGrey,
borderTopWidth: 1,
},
item: {
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
padding: 16,
},
text: {
color: Colors.textColour,
android: {
fontFamily: 'sans-serif-medium',
},
ios: {
fontFamily: 'System',
fontWeight: '600',
},
},
name: {
flex: 1,
},
itemControls: {
flex: 1,
flexDirection: 'row',
},
checkboxContainer: {
alignItems: 'center',
justifyContent: 'space-around',
padding: 16,
},
label: {
fontSize: 12,
},
selectContainer: {
flex: 1,
},
buttonText: {
color: Colors.white,
fontSize: 12,
},
buttonTextContainer: {
padding: 8,
ios: {
paddingLeft: 10,
paddingRight: 10,
},
},
buttonMargin: {
marginTop: 4,
},
selected: {
backgroundColor: Colors.magenta,
},
filterButton: {
position: 'absolute',
bottom: 16,
right: 16,
borderRadius: 28,
overflow: 'hidden',
backgroundColor: Colors.grey,
android: {
elevation: 4,
},
ios: {
borderColor: Colors.lightGray,
borderStyle: 'solid',
borderWidth: 0.5,
},
},
filterButtonWrapper: {
width: 56,
height: 56,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: Colors.magenta,
},
noResultsMessage: {
fontSize: 18,
padding: 16,
},
});
export default styles;
This diff is collapsed.
import Colors from '../../../style/Colors';
import StyleSheet from '../../../style/StyleSheet';
const styles = StyleSheet.create({
rootWrapper: {
flex: 1,
},
container: {
backgroundColor: Colors.background,
},
borderTop: {
borderTopColor: Colors.dividerGrey,
borderTopWidth: 1,
},
registration: {
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
padding: 16,
},
text: {
color: Colors.textColour,
android: {
fontFamily: 'sans-serif-medium',
},
ios: {
fontFamily: 'System',
fontWeight: '600',
},
},
name: {
flex: 1,
},
registrationControls: {
flex: 1,
flexDirection: 'row',
},
presenceContainer: {
alignItems: 'center',
justifyContent: 'space-around',
padding: 16,
},
label: {
fontSize: 12,
},
paymentContainer: {
flex: 1,
},
buttonText: {
color: Colors.white,
fontSize: 12,
},
buttonTextContainer: {
padding: 8,
ios: {
paddingLeft: 10,
paddingRight: 10,
},
},
buttonMargin: {
marginTop: 4,
marginBottom: 4,
},
selected: {
backgroundColor: Colors.magenta,
},
filterButton: {
position: 'absolute',
bottom: 16,
right: 16,
borderRadius: 28,
overflow: 'hidden',
backgroundColor: Colors.grey,
android: {
elevation: 4,
},
ios: {
borderColor: Colors.lightGray,
borderStyle: 'solid',
borderWidth: 0.5,
},
},
filterButtonWrapper: {
width: 56,
height: 56,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: Colors.magenta,
},
noResultsMessage: {
fontSize: 18,
padding: 16,
},
});
export default styles;
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment