<|start_filename|>src/services/user.js<|end_filename|>
import firebase from 'firebase';
import { omit } from 'lodash';
import { Alert } from '@/components';
import { showFirebaseError, cloneDeepWithout } from './utils';

/**
 * Sends a GET request to firebase to load the current user's information.
 * @param {Function} update Redux callback
 */

export const loadCurrentUser = update => {
	const { currentUser } = firebase.auth();

	firebase.database().ref(`/users/${currentUser.uid}/`).on('value', userSnapshot => {
		firebase.database().ref(`/privileges/${currentUser.uid}/`).on('value', privilegeSnapshot => {
			update({ ...userSnapshot.val(), privilege: privilegeSnapshot.val() });
		});
	});
};

/**
 * @typedef {Object} User
 * @prop {string}  id              User's ID assigned by Firebase
 * @prop {string}  firstName       User's first name
 * @prop {string}  lastName        User's last name
 * @prop {string}  email           User's knights email
 * @prop {string}  flag            User's flag of preference
 * @prop {string}  color           User's color of preference
 * @prop {string}  picture         User's profile picture
 * @prop {number}  points          Total points for current semester
 * @prop {Object}  privilege       User privilege (user, board, e-board)
 * @prop {Object}  userCommittees  Committee(s) user belongs to
 * @prop {string}  major           User's major
 * @prop {string}  country         User's country of origin
 * @prop {string}  gender          User's gender
 * @prop {string}  birthday        User's birthday
 * @prop {boolean} paidMember      Paid member status for current year
 * @prop {boolean} applied         Applied status for current election
 * @prop {boolean} voted           Voted status for current election
 */

/**
 * Creates a user on Firebase using their knights email as the username with their
 * desired password. If it succeeds, it calls createUserSuccess.
 *
 * @param {Pick<User, 'firstName' | 'lastName' | 'email' | 'password' |
 *                    'gender' | 'major' | 'country' | 'birthday'}       user      User object
 * @param {Function?}                                                    setError  Callback to update error state on calling component.
 */

export const createUser = user => new Promise((_, reject) =>
	firebase.auth().createUserWithEmailAndPassword(user.email, user.password)
		.then(({ user: { uid } }) => createUserSuccess({ ...omit(user, 'password'), id: uid }))
		.catch(error => reject(showFirebaseError(error)))
);

/**
 * Creates a user on Firebase database with the desired fields. Then displays
 * an alert to the user letting them know to check their email.
 *
 * @param {Object} user User object
 */

const createUserSuccess = user => {
	const { firstName, lastName, email, id } = user;
	const USER_STATUS = {
		gender: 'Do not wish to disclose',
		major: 'Do not wish to disclose',
		country: 'Do not wish to disclose',
		birthday: '0000-00-00',
		points: 0,
		privilege: {},
		userCommittees: {}
	};

	firebase.database().ref(`/users/${id}/`).set({ ...USER_STATUS, ...user })
		.then(() => firebase.database().ref(`/points/${id}/`).set({ firstName, lastName, id, points: 0 }))
		.then(() => firebase.database().ref(`/privileges/${id}/`).set({ firstName, lastName, id, user: true }))
		.then(() => firebase.auth().currentUser.sendEmailVerification()
			.then(() => Alert.alert(`We sent a verification to: ${email}. Please open your email and verify your account`, { type: 'success' }))
			.catch(() => Alert.alert('We were not able to send an email. Please contact the Tech Director for assistance', { type: 'error' }))
		)
		.then(() => firebase.auth().signOut())
		.catch(error => Alert.alert(error, { type: 'error' }));
};

/**
 * Sends an UPDATE request and updates the user on the database.
 *
 * @param {Omit<User, 'firstName' | 'lastName' | 'points' | 'voted' | 'privileges' | 'paidMember'>} user User object
 */

export const editUser = user => {
	const invalid = ['firstName', 'lastName', 'points', 'voted', 'privileges', 'paidMember'];
	const { currentUser } = firebase.auth();

	firebase.database().ref(`/users/${currentUser.uid}/`).update(cloneDeepWithout(user, invalid))
		.then(() => Alert.alert('Profile edited!', { type: 'success' }))
		.catch(error => Alert.alert(error.message, { type: 'error' }));
};

/**
 * Sends a request to firebase to reset the password using the email. Then displays an alert
 * to the user that an email to reset their password was sent to them.
 *
 * @param {string} email User's knights email.
 */

export const resetPassword = email => new Promise((_, reject) =>
	firebase.auth().sendPasswordResetEmail(email)
		.then(() => Alert.alert(`If an account with email ${email} exists, \
a reset password email will be sent. Please check your email.`)
		)
		.catch(error => reject(showFirebaseError(error)))
);

<|start_filename|>src/services/members.js<|end_filename|>
import firebase from 'firebase';
import { Alert } from '@/components';
import _ from 'lodash';

export const editMember = user => {
	const { firstName, lastName, points, id } = user;

	firebase.database().ref(`/users/${id}/`).update(user)
		.then(() => firebase.database().ref(`/points/${id}/`).update({
			firstName,
			lastName,
			points
		}))
		.then(() => firebase.database().ref(`/privileges/${id}/`).update({
			firstName,
			lastName,
			user: true,
			board: false,
			eboard: false,
			president: false
		}))
		.then(() => Alert.alert('Account Updated'));
};

export const assignPosition = (title, types, id, oldChair) => {
	if (oldChair) {
		firebase.database().ref(`/users/${oldChair.id}/${types}`).remove()
			.then(() => firebase.database().ref(`/privileges/${oldChair.id}/`).update({ [types]: false }));
	}

	firebase.database().ref(`/users/${id}/`).update({ [types]: title })
		.then(() => firebase.database().ref(`/privileges/${id}/`).update({ [types]: true }));
};

/*
 *members: should have list of IDs -> Array<String>
 *privilegeChanged: should have the privilege type that should be changed -> string
 *value: Value that privilege should be changed to -> boolean
 */

export const changePrivilegeOfMembers = (members, privilegeChanged, value) => {
	firebase.database().ref('/privileges/').once('value', snapshot => {
		let updates = snapshot.val();

		members.forEach(memberId => {
			if (!updates[memberId]) updates[memberId] = {};
			updates[memberId][privilegeChanged] = value;
		});

		firebase.database().ref('/privileges/').update(updates)
			.then(() =>Alert.alert('Changes successful', { type: 'success' }))
			.catch(() =>Alert.alert('Changes were not successful', { type: 'error' }));
	});

	if (privilegeChanged === 'paidMember') {
		firebase.database().ref('/users/').once('value', snapshot => {
			let updates = snapshot.val();

			members.forEach(memberId => {
				updates[memberId][privilegeChanged] = value;
			});

			firebase.database().ref('/users/').update(updates)
				.catch(() =>Alert.alert('Changes were not successful', { type: 'error' }));
		});
	}
};

export const getAllMemberAccountsAndRankings = (listener, update) =>
	firebase.database().ref('/users/')[listener ? 'on' : 'once']('value', snapshot => {
		const allMemberAccounts = _.orderBy(snapshot.val(), ['lastName', 'firstName'], ['asc', 'asc'])
			.reduce((allMembers, member) => ({ ...allMembers, [member.id]: member }), {});
		const rankedIDs = _.orderBy(allMemberAccounts, ['points'], ['desc']).map(({ id }) => id);
		let pastPoints = 0;
		let pastRank = 1;

		rankedIDs.forEach((id, index) => {
			const member = allMemberAccounts[id];

			member.rank = member.points !== 0 ? index + 1 : rankedIDs.length;
			if (member.points === pastPoints) member.rank = pastRank;

			pastRank = member.rank;
			pastPoints = member.points;
		});

		update({ allMemberAccounts, rankedIDs });
	});

export const getAllMemberPoints = (listener, update) =>
	firebase.database().ref('/points')[listener ? 'on' : 'once']('value', snapshot => update(snapshot.val()));

<|start_filename|>src/services/utils.js<|end_filename|>
import _ from 'lodash';

/**
 * Updates error state in calling component.
 *
 * @param {Object} error
 * @param {string} error.code     Firebase error code.
 * @param {string} error.message  Firebase error message.
 */

export const showFirebaseError = ({ code, message }) => {
	switch (code) {
		case 'auth/user-not-found':
			return 'There is no user record corresponding to this identifier';
		case 'auth/invalid-email':
			return 'Enter a valid email';
		case 'auth/wrong-password':
			return 'Incorrect credentials';
		default:
			return message;
	}
};

/**
 * Clones object recursively, omitting `invalid` keys.
 * Sets objects with a single null child to false.
 *
 * @param {Object}   obj      Object to be cloned
 * @param {string[]} invalid  Array of possible invalid keys inside `obj`
 */

export const cloneDeepWithout = (obj, invalid) => {
	const innerClone = deepObj => _.transform(deepObj, (accumulator, value, key) => {
		if (invalid.includes(key)) return;

		accumulator[key] = _.isObject(value)
			?	_.every(value, value => value === null) ? false : innerClone(value)
			: value;
	});

	return innerClone(obj);
};

<|start_filename|>src/components/general/PickerInput.js<|end_filename|>
import React, { useState } from 'react';
import { View, Modal, FlatList, Dimensions, TouchableOpacity, Text, TextStyle, ViewStyle } from 'react-native';
import { Input } from './Input';
import { Icon } from './Icon';

const { height, width } = Dimensions.get('screen');

/**
 * Component to select an item from an array of data
 *
 * @typedef {Object} PickerInputProps
 * @prop {string}    title
 * @prop {string}    value
 * @prop {Array}     data
 * @prop {string}    placeholder
 * @prop {Object}    icon
 * @prop {number}    icon.size
 * @prop {string}    icon.color
 * @prop {TextStyle} icon.style
 * @prop {Function}  onSelect
 * @prop {TextStyle} inputBoxStyle
 * @prop {ViewStyle} style
 *
 * @param {PickerInputProps}
 */

export const PickerInput = ({ title, value, data, placeholder, icon, onSelect, inputBoxStyle, style }) => {
	const [visible, setVisibility] = useState(false);

	const renderSelections = ({ item }) => {
		const { itemStyle, itemTextStyle } = styles;

		return (
			<TouchableOpacity onPress = { () => onSelect(item) } style = { [itemStyle, style] }>
				<Text style = { itemTextStyle }>{ item }</Text>
			</TouchableOpacity>
		);
	};

	const renderModal = () => (
		<Modal transparent visible = { visible }>
			<View style = { modalBackground }>
				<View style = { modalStyle }>
					<Text style = { titleStyle }>{ title }</Text>
					<View style = { flatListStyle }>
						<FlatList
							data = { data }
							keyExtractor = { (item, index) => index }
							renderItem = { renderSelections }
						/>
					</View>
					<TouchableOpacity
						onPress = { () => setVisibility(false) }
						style = { [buttonStyle, buttonContainer] }
					>
						<Text style = { textStyle }>Cancel</Text>
					</TouchableOpacity>
				</View>
			</View>
		</Modal>
	);

	const {
		inputStyle,
		iconStyle,
		modalStyle,
		modalBackground,
		textStyle,
		buttonContainer,
		flatListStyle,
		buttonStyle,
		titleStyle
	} = styles;

	return (
		<>
			<View style = { [{ flexDirection: 'row' }, style] }>
				<Input
					value = { value }
					editable = { false }
					placeholder = { placeholder }
					style = { [inputBoxStyle, inputStyle] }
				/>
				<Icon
					onPress = { () => setVisibility(true) }
					name = 'chevron-down-circle-outline'
					style = { [icon.style, iconStyle] }
					{ ...icon }
				/>
			</View>
			{ renderModal() }
		</>
	);
};

PickerInput.defaultProps = {
	title: 'Title',
	placeholder: 'Choose an option',
	iconSize: 35,
	iconColor: 'white'
};

const styles = {
	itemStyle: {
		flex: 1,
		alignItems: 'center',
		justifyContent: 'center',
		flexDirection: 'column',
		borderBottomColor: '#0002',
		borderBottomWidth: 1
	},
	itemTextStyle: {
		paddingTop: height * 0.03,
		paddingBottom: height * 0.03,
		flex: 1,
		fontSize: 16,
		alignSelf: 'center'
	},
	titleStyle: {
		flex: 0.13,
		alignSelf: 'center',
		fontSize: 20
	},
	buttonStyle: {
		flex: 1,
		alignSelf: 'center'
	},
	flatListStyle: {
		flex: 0.8
	},
	buttonContainer: {
		flex: 0.2,
		flexDirection: 'row',
		borderTopColor: '#0001',
		borderTopWidth: 1
	},
	textStyle: {
		flex: 1,
		alignSelf: 'center',
		fontSize: 18,
		paddingTop: 5
	},
	modalBackground: {
		justifyContent: 'center',
		alignItems: 'center',
		backgroundColor: '#0003',
		margin: 0,
		height: height,
		width: width
	},
	modalStyle: {
		height: height * 0.4,
		width: width * 0.8,
		backgroundColor: '#fff',
		padding: 12,
		borderRadius: 12
	},
	inputStyle: {
		flex: 1
	},
	iconStyle: {
		flex: 0.2,
		paddingLeft: 10,
		alignSelf: 'center'
	}
};

<|start_filename|>src/utils/events.js<|end_filename|>
import { Alert } from '@/components';

export const shortMonths = ['Jan', 'Feb', 'Mar', 'April', 'May', 'June', 'July', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
export const fullMonths = [
	'January',
	'February',
	'March',
	'April',
	'May',
	'June',
	'July',
	'August',
	'September',
	'October',
	'November',
	'December'
];

/**
 * Convert given time to the format given, returned as an array of strings.
 *
 * @param {string}                  time    Initial time string: 'HH:MM [AM/PM]'
 * @param {'standard' | 'military'} format  Time format
 */

export const convertTimeTo = (time, format) => {
	let [hour, minute, period] = time.split(/[: ]/);

	switch (format) {
		case 'standard':
			if (!period) {
				period = (hour >= 12) ? 'PM' : 'AM';
				hour -= (hour > 12) ? 12 : 0;
			}

			return [String(hour || 12), minute, period];
		case 'military':
			if (period)
				hour = (hour == 12 ? 0 : parseInt(hour)) + (period === 'PM' ? 12 : 0);

			return [String(hour).padStart(2, '0'), minute];
	}
};

/**
 * Extract month name and day from a numerical date
 *
 * @param {String} date Format: 'Year-Month-Day'
 *
 * @returns {String} Format: 'Month(Name) Day(Number)'
 */

export const convertNumToDate = date => {
	let [, month, day] = date.split('-');

	return `${shortMonths[Number(month) - 1]} ${day}`;
};

export const formatEventListForCalendar = events => {
	let dates = {};

	events.forEach((event) => {
		if (!dates[event.date])
			dates[event.date] = [event];
		else
			dates[event.date].push(event);
	});

	return dates;
};

/**
 * Verifies whether an events times are valid.
 *
 * @param {String} startTime  Start Time
 * @param {String} endTime    End Time
 */

export const timeVerification = (startTime, endTime) => {
	let [startHour, startMinute] = startTime.split(':');
	let [endHour, endMinute] = endTime.split(':');
	let validTime = endHour >= startHour || (endHour !== startHour && endMinute > startMinute);

	if (!validTime)
		Alert.alert('Ending time must be after start time');

	return validTime;
};

/**
 * Changes an hour by a certain amount and returns the new hour.
 *
 * @param {string} time    Hour to be changed (**Must be Military Time**)
 * @param {number} amount  Amount to change the hour by
 */

export const changeHourBy = (time, amount) => {
	const [hour, minute] = time.split(':');
	let newHour = ((parseInt(hour) + amount) % 24).toString().padStart(2, '0');

	return `${newHour}:${minute}`;
};

/**
 * Filters out all events that have passed; only leaving future events.
 *
 * @param {Object[]} sortedEvents A sorted array of all the events.
 */

export const filterPastEvents = sortedEvents => sortedEvents.filter(event => {
	const today = new Date();
	const [year, month, date] = event.date.split('-');

	return !(year < today.getFullYear() || month < 	today.getMonth() + 1
		|| (month == today.getMonth() + 1 && date < today.getDate()));
});

/**
 * Filters out all events that aren't inside of the eventIds array.
 *
 * @param {Object}   eventIds      An array of the event Ids that you want to keep.
 * @param {Object[]} sortedEvents  An array of all the events that you are searching through.
 */

export const filterEvents = (eventIds, sortedEvents) => sortedEvents.filter((event) => event.id in eventIds);

<|start_filename|>src/ducks/Members.js<|end_filename|>
import { createActionTypes } from './utils';
import { getAllMemberAccountsAndRankings, getAllMemberPoints } from '@/services/members';

const ACTIONS = createActionTypes([
	'STORE_ALL_MEMBER_ACCOUNTS_AND_RANKINGS',
	'STORE_ALL_MEMBER_POINTS'
]);

const INITIAL_STATE = {
	allMemberAccounts: {},
	allMemberPoints: {},
	rankedIDs: []
};

export default (state = INITIAL_STATE, { payload, type }) => {
	switch (type) {
		case ACTIONS.STORE_ALL_MEMBER_ACCOUNTS_AND_RANKINGS:
			return { ...state, allMemberAccounts: payload.allMemberAccounts, rankedIDs: payload.rankedIDs };
		case ACTIONS.STORE_ALL_MEMBER_POINTS:
			return { ...state, allMemberPoints: payload };
		default:
			return state;
	}
};

export const storeMemberAccountsAndRankings = () => dispatch =>
	getAllMemberAccountsAndRankings(true, ({ allMemberAccounts, rankedIDs }) => dispatch({
		type: ACTIONS.STORE_ALL_MEMBER_ACCOUNTS_AND_RANKINGS,
		payload: { allMemberAccounts, rankedIDs }
	}));

export const storeAllMemberPoints = () => dispatch =>
	getAllMemberPoints(true, allMemberPoints => dispatch({
		type: ACTIONS.STORE_ALL_MEMBER_POINTS,
		payload: allMemberPoints
	}));

<|start_filename|>src/ducks/Elections.js<|end_filename|>
import { createActionTypes } from './utils';
import { getAllPositions, getAllVotes, updateElectionStatus } from '@/services/elections';

const ACTIONS = createActionTypes([
	'GET_POSITIONS',
	'GET_VOTES',
	'UPDATE_ELECTION'
]);

const INITIAL_STATE = {
	election: false,
	apply: false,
	numOfVotes: 0,
	positions: [],
	votes: []
};

export default (state = INITIAL_STATE, { type, payload }) => {
	switch (type) {
		case ACTIONS.GET_POSITIONS:
			return { ...state, positions: payload };
		case ACTIONS.GET_VOTES:
			return { ...state, votes: payload };
		case ACTIONS.UPDATE_ELECTION:
			return {
				...state, apply: payload.apply, election: payload.election, numOfVotes: payload.votes };
		default:
			return state;
	}
};

export const getPositions = () => dispatch => {
	getAllPositions(payload => dispatch({ type: ACTIONS.GET_POSITIONS, payload }));
};

export const getVotes = () => dispatch => {
	getAllVotes(payload => dispatch({ type: ACTIONS.GET_VOTES, payload }));
};

export const updateElection = () => dispatch => {
	updateElectionStatus(payload => dispatch({ type: ACTIONS.UPDATE_ELECTION, payload }));
};

<|start_filename|>src/components/general/TimePicker.js<|end_filename|>
import React, { useState, useEffect } from 'react';
import { View } from 'react-native';
import { Input } from './Input';
import { PickerInput } from './PickerInput';
import { convertTimeTo } from '@/utils/events';

/**
 * Picker to select hour, minute, and period.
 *
 * @typedef {Object} TimePickerProps
 * @prop {string}   value        Initial value of time.
 * @prop {Function} onSelect     Callback to use new time values picked.
 * @prop {string=}  placeholder  Placeholder for time picker input.
 *
 * @param {TimePickerProps}
 */

export const TimePicker = ({ value, onSelect, placeholder = 'Choose a time' }) => {
	const [initHour = '', initMinute = '', initPeriod = ''] = value && convertTimeTo(value, 'standard');
	const [hour, setHour] = useState(initHour);
	const [minute, setMinute] = useState(initMinute);
	const [period, setPeriod] = useState(initPeriod);
	const [focused, setFocused] = useState(false);

	const hourArray = Array.from(Array(12), (v, hour) => hour + 1);
	const minuteArray = [0, 15, 30, 45];
	const periodArray = ['AM', 'PM'];

	useEffect(() => {
		(hour && minute && period) && onSelect(convertTimeTo(`${hour}:${minute} ${period}`, 'military').join(':'));
	}, [hour, minute, period]);

	/**
	 * @description Sets the hour/min/period based on a given time and time type.
	 *
	 * @param {string}                       timeValue  Contains the value of hour/minute/time.
	 * @param {'hour' | 'minute' | 'period'} type       Describes which value is being changed.
	 */
	const changeStateOfType = (timeValue, type) => {
		switch (type) {
			case 'hour':
				return setHour(timeValue);
			case 'minute':
				return setMinute(timeValue);
			case 'period':
				return setPeriod(timeValue);
		}
	};

	const { style, timePickerStyle, fieldContainer, inputBoxStyle, dropDownArrowStyle } = styles;
	const defaultPickerStyle = { style, inputBoxStyle, iconSize: 32, iconColor: 'black', dropDownArrowStyle };
	const pickers = [
		{ data: hourArray, time: 'hour', value: hour, placeholder: '12' },
		{ data: minuteArray, time: 'minute', value: minute.padStart(2, '0'), placeholder: '00' },
		{ data: periodArray, time: 'AM/AP', value: period, placeholder: 'PM' }
	];

	return (
		!focused && <Input placeholder = { placeholder } value = '' onFocus = { () => setFocused(true) } />
			|| <View style = { timePickerStyle }>
				{ pickers.map(({ time, ...timeProps }) =>
					<View style = { fieldContainer }>
						<PickerInput
							title = { `Enter ${time}` }
							onSelect = { time => changeStateOfType(time, time) }
							{ ...timeProps }
							{ ...defaultPickerStyle }
						/>
					</View>
				) }
			</View>
	);
};

const styles = {
	fieldContainer: {
		flex: 1,
		flexDirection: 'row',
		alignItems: 'center'
	},
	style: {
		flex: 1,
		width: 130
	},
	inputBoxStyle: {
		flex: 0.42,
		borderRadius: 15,
		margin: 5,
		padding: 7
	},
	dropDownArrowStyle: {
		flex: 0.3,
		paddingLeft: 0
	},
	timePickerStyle: {
		flex: 1,
		color: '#000',
		fontSize: 16,
		backgroundColor: 'white',
		borderRadius: 25,
		flexDirection: 'row',
		marginVertical: 8
	}
};

<|start_filename|>src/ducks/User.js<|end_filename|>
import { createActionTypes } from './utils';
import { loadCurrentUser } from '@/services/user';

const ACTIONS = createActionTypes([
	'LOAD_USER_AND_PRIVILEGE'
]);

/**
 * @typedef {Object} UserState
 * @prop {string}  id              User's ID assigned by Firebase
 * @prop {string}  firstName       User's first name
 * @prop {string}  lastName        User's last name
 * @prop {string}  email           User's knights email
 * @prop {string}  flag            User's flag of preference
 * @prop {string}  picture         User's profile picture
 * @prop {number}  points          Total points for current semester
 * @prop {Object}  privilege       User privilege (user, board, e-board)
 * @prop {Object}  userCommittees  Committees user belongs to
 * @prop {string}  major           User's major
 * @prop {string}  country         User's country of origin
 * @prop {string}  gender          User's gender
 * @prop {string}  birthday        User's birthday
 * @prop {boolean} paidMember      Paid member status for current year
 * @prop {boolean} applied         Applied status for current election
 * @prop {boolean} voted           Voted status for current election
 */

/**
 * @type {UserState}
 */

const INITIAL_STATE = {};

export default (state = INITIAL_STATE, { payload, type }) => {
	switch (type) {
		case ACTIONS.LOAD_USER_AND_PRIVILEGE:
			return { ...state, ...payload };
		default:
			return state;
	}
};

export const loadUser = () => dispatch => {
	loadCurrentUser(payload => dispatch({ type: ACTIONS.LOAD_USER_AND_PRIVILEGE, payload }));
};

<|start_filename|>src/screens/General/Leaderboard.js<|end_filename|>
import React, { useState } from 'react';
import { Dimensions, SafeAreaView } from 'react-native';
import { useSelector } from 'react-redux';
import { NavBar, FilterList, Icon, MemberPanel } from '@/components';

const { height } = Dimensions.get('screen');

export const Leaderboard = () => {
	const [search, setSearch] = useState(false);
	const { members: { allMemberAccounts, rankedIDs } } = useSelector(state => state);
	const { screenBackground } = styles;
	const searchIcon = <Icon
		onPress = { () => setSearch(!search) }
		name = 'ios-search'
		size = { height * 0.04 }
		color = '#FECB00'
	/>;

	return (
		<SafeAreaView style = { screenBackground }>
			<NavBar title = 'Leaderboard' childComponent = { searchIcon } back />
			<FilterList
				data = { rankedIDs.map(id => allMemberAccounts[id]) }
				search = { search }
				placeholder = 'Find user'
				itemJSX = { member => <MemberPanel member = { member } variant = 'Leaderboard' /> }
				regexFunc = { ({ firstName, lastName }) => `${firstName} ${lastName}` }
				onSelect = { () => null }
				style = {{ flex: 1 }}
			/>
		</SafeAreaView>
	);
};

const styles = {
	screenBackground: {
		flex: 1,
		backgroundColor: '#0c0b0b'
	}
};