Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
129 changes: 129 additions & 0 deletions packages/event-app/src/components/ScheduleModal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
import {Ionicons} from '@expo/vector-icons';
import Fuse from 'fuse.js';
import React, {useState, useContext, useEffect, useRef} from 'react';
import {
Modal,
StyleSheet,
View,
Platform,
ScrollView,
TouchableOpacity,
} from 'react-native';
import {Searchbar, List} from 'react-native-paper';

import DataContext from '../context/DataContext';
import {ScheduleDay, Schedule} from '../typings/data';
type ScheduleModalProps = {
modalVisible: boolean;
setModalVisible: (visible: boolean) => void;
};

export default function ScheduleModal(props: ScheduleModalProps) {
/* Fuse.js config */
const options = {
keys: ['slots.searchableInfos'],
threshold: 0.4,
includeMatches: true,
};
const [searchQuery, setSearchQuery] = useState('');
const {event} = useContext(DataContext);
const originalSchedule = useRef<any>();
const [schedule, setSchedule] = useState<ScheduleDay[]>([]);
const fuse = useRef<any>();

function updateSlots() {
if (!originalSchedule.current) return;
if (searchQuery.length === 0) {
setSchedule(originalSchedule.current as ScheduleDay[]);
} else {
const result: any = fuse.current.search(searchQuery);
let ScheduleCpy = JSON.parse(JSON.stringify(result));
ScheduleCpy = ScheduleCpy.map((match: any) => {
const selectedValues = match.matches.map((match: any) => match.value);
console.log(match.matches);
const selected = match.item.slots.filter((slot: Schedule) => {
for (const i in selectedValues) {
if (slot.searchableInfos.includes(selectedValues[i])) return true;
}
return false;
});
match.item.slots = selected;
return match.item;
});
setSchedule(ScheduleCpy);
}
}

useEffect(() => {
updateSlots();
}, [searchQuery]);

useEffect(() => {
if (event?.groupedSchedule) {
const schedule = event.groupedSchedule.map((day) => {
const slots = day?.slots.map((slot) => {
const speakersInfos = slot?.speakers.map((speaker) => {
return [speaker?.github, speaker?.twitter, speaker?.name];
});
let searchableInfos = [slot?.description, slot?.title];
if (speakersInfos) {
searchableInfos = [...searchableInfos, ...speakersInfos?.flat()];
}
return {...slot, searchableInfos};
});
return {...day, slots};
});
originalSchedule.current = schedule;
fuse.current = new Fuse(schedule, options);
updateSlots();
}
}, [event]);

return (
<Modal animationType="slide" transparent visible={props.modalVisible}>
<View style={styles.modalView}>
<TouchableOpacity
onPress={() => {
props.setModalVisible(!props.modalVisible);
}}>
<Ionicons
name={Platform.OS === 'ios' ? 'ios-close' : 'md-close'}
size={24}
color="black"
style={{margin: 10}}
/>
</TouchableOpacity>

<Searchbar
placeholder="Search"
onChangeText={(text) => setSearchQuery(text)}
value={searchQuery}
/>
<ScrollView>
<List.AccordionGroup>
{schedule?.map((day, index) => {
const date = new Date(day?.date);
return (
<List.Accordion
key={index}
title={`${day?.title} - ${date.getDate()}`}
id={day?.date}>
{day?.slots?.map((slot, index) => {
return <List.Item key={index} title={slot?.title} />;
})}
</List.Accordion>
);
})}
</List.AccordionGroup>
</ScrollView>
</View>
</Modal>
);
}

const styles = StyleSheet.create({
modalView: {
backgroundColor: 'white',
flex: 1,
},
});
98 changes: 66 additions & 32 deletions packages/event-app/src/navigation/DynamicScheduleNavigation.tsx
Original file line number Diff line number Diff line change
@@ -1,50 +1,84 @@
import {Ionicons} from '@expo/vector-icons';
import {createMaterialTopTabNavigator} from '@react-navigation/material-top-tabs';
import React, {useContext} from 'react';
import React, {useContext, useState} from 'react';
import {Platform, TouchableOpacity} from 'react-native';
import {View} from 'react-native-animatable';

import ScheduleModal from '../components/ScheduleModal';
import DataContext from '../context/DataContext';
import Screens from '../screens';
import {ScheduleDay} from '../typings/data';
import {ScheduleDayTabParamList} from '../typings/navigation';
import {
ScheduleDayTabParamList,
ScheduleNavigationProp,
} from '../typings/navigation';
import {occurence} from '../utils/array';

const Tab = createMaterialTopTabNavigator<ScheduleDayTabParamList>();

export default function DynamicScheduleNavigation() {
export default function DynamicScheduleNavigation({
navigation,
}: {
navigation: ScheduleNavigationProp;
}) {
const [modalVisible, setModalVisible] = useState(false);
if (Platform.OS !== 'web') {
navigation.setOptions({
headerRight: () => (
<TouchableOpacity onPress={() => setModalVisible(!modalVisible)}>
<Ionicons
name={Platform.OS === 'ios' ? 'ios-search' : 'md-search'}
size={24}
color="#FFF"
style={{marginRight: 10}}
/>
</TouchableOpacity>
),
});
}
const {event} = useContext(DataContext);
let fullSchedule: ScheduleDay[] = [];
if (event?.groupedSchedule) {
fullSchedule = event.groupedSchedule as ScheduleDay[];
}

return (
<Tab.Navigator
tabBarOptions={{
style: {backgroundColor: '#333'},
activeTintColor: '#fff',
scrollEnabled: true,
}}>
{fullSchedule.map((day: ScheduleDay, index: number) => {
const dayOccurence = occurence(fullSchedule, 'title', day.title);
let dayTitle: string = day?.title
? day.title.substring(0, 3).toUpperCase()
: index.toString();
if (dayOccurence > 1) {
const monthDay = new Date(day.date).getDate();
dayTitle += '-' + monthDay.toString();
}
return (
<Tab.Screen
key={index}
name={`${event?.name}-${dayTitle}`}
options={{title: dayTitle}}
component={Screens.ScheduleDay}
initialParams={{
day: day.title ? day.title : '',
date: day.date ? day.date : '',
}}
/>
);
})}
</Tab.Navigator>
<View style={{flex: 1}}>
{Platform.OS !== 'web' && (
<ScheduleModal
modalVisible={modalVisible}
setModalVisible={setModalVisible}
/>
)}
<Tab.Navigator
tabBarOptions={{
style: {backgroundColor: '#333'},
activeTintColor: '#fff',
scrollEnabled: true,
}}>
{fullSchedule.map((day: ScheduleDay, index: number) => {
const dayOccurence = occurence(fullSchedule, 'title', day.title);
let dayTitle: string = day?.title
? day.title.substring(0, 3).toUpperCase()
: index.toString();
if (dayOccurence > 1) {
const monthDay = new Date(day.date).getDate();
dayTitle += '-' + monthDay.toString();
}
return (
<Tab.Screen
key={index}
name={`${event?.name}-${dayTitle}`}
options={{title: dayTitle}}
component={Screens.ScheduleDay}
initialParams={{
day: day.title ? day.title : '',
date: day.date ? day.date : '',
}}
/>
);
})}
</Tab.Navigator>
</View>
);
}