mirror of https://gitlab.com/ceda_ei/sonzai.git
232 lines
5.1 KiB
JavaScript
232 lines
5.1 KiB
JavaScript
import React, { useState } from "react";
|
|
import PropTypes from "prop-types";
|
|
import {
|
|
Card,
|
|
FAB,
|
|
IconButton,
|
|
List,
|
|
Menu,
|
|
Portal,
|
|
Snackbar,
|
|
TextInput,
|
|
ToggleButton,
|
|
} from "react-native-paper";
|
|
import {
|
|
StyleSheet,
|
|
View
|
|
} from "react-native";
|
|
import DateTimePicker from "@react-native-community/datetimepicker";
|
|
import { format } from "date-fns";
|
|
|
|
function AddEntry({addTimetableEntry, days, subjects, navigation }) {
|
|
const [ subject, setSubject ] = useState({ id: null, name: null });
|
|
const [ showSubjectMenu, setShowSubjectMenu ] = useState(false);
|
|
const [ showTimePicker, setShowTimePicker ] = useState(false);
|
|
// Set to true if date time picker should set start or not
|
|
const [ mode, setMode ] = useState("start");
|
|
const [ start, setStart ] = useState(null);
|
|
const [ end, setEnd ] = useState(null);
|
|
const [ count, setCount ] = useState(0);
|
|
const [ snackbar, setSnackbar ] = useState({ visible: false, message: "" });
|
|
const [ dayStates, setDayStates ] = useState([ true, false, false, false, false, false, false ]);
|
|
function parseCount(text) {
|
|
const num = parseInt(text);
|
|
if (isNaN(num))
|
|
setCount(0);
|
|
else
|
|
setCount(num);
|
|
}
|
|
|
|
function onChange(_, selectedDate) {
|
|
setShowTimePicker(false);
|
|
if (selectedDate) {
|
|
switch (mode) {
|
|
case "start":
|
|
setStart(selectedDate);
|
|
return;
|
|
case "end":
|
|
setEnd(selectedDate);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
function submit() {
|
|
let message = "";
|
|
if (subject.id === null)
|
|
message = "Missing Subject";
|
|
else if (start === null)
|
|
message = "Missing start time.";
|
|
else if (end === null)
|
|
message = "Missing end time.";
|
|
else if (count === 0)
|
|
message = "Missing count.";
|
|
if (! dayStates.filter(i => i).length)
|
|
message = "No day selected.";
|
|
|
|
if (message !== "") {
|
|
setSnackbar({visible: true, message: message});
|
|
setTimeout(() => setSnackbar({ visible: false, message: null }), 2000);
|
|
return;
|
|
}
|
|
|
|
|
|
dayStates.forEach((i, idx) => {
|
|
if (i) {
|
|
addTimetableEntry(idx, {
|
|
sub_id: subject.id,
|
|
count,
|
|
start,
|
|
end
|
|
});
|
|
}
|
|
});
|
|
navigation.pop();
|
|
}
|
|
|
|
const defTime = (mode == "start" ? start : end) || (new Date);
|
|
return (<>
|
|
<IconButton icon="arrow-left" onPress={() => navigation.pop()}/>
|
|
<Card style={style.card}>
|
|
<Card.Title title="Add Class" />
|
|
<Card.Content>
|
|
<List.Section>
|
|
<Menu
|
|
visible={showSubjectMenu}
|
|
onDismiss={() => setShowSubjectMenu(false)}
|
|
anchor={
|
|
<List.Item
|
|
title="Subject"
|
|
description={subject.name}
|
|
onPress={() => setShowSubjectMenu(true)}
|
|
right={props => <List.Icon {...props} icon="chevron-down" />}
|
|
/>
|
|
}
|
|
>
|
|
{subjects.map(subject => (
|
|
<Menu.Item
|
|
title={subject.name}
|
|
description={subject.id}
|
|
onPress={() => {
|
|
setSubject(subject);
|
|
setShowSubjectMenu(false);
|
|
}}
|
|
key={subject.id}
|
|
/>
|
|
))}
|
|
</Menu>
|
|
<List.Item
|
|
title="Start"
|
|
description={start && format(start, "HH:mm")}
|
|
onPress={() => {
|
|
setShowTimePicker(true);
|
|
setMode("start");
|
|
}}
|
|
/>
|
|
<List.Item
|
|
title="End"
|
|
description={end && format(end, "HH:mm")}
|
|
onPress={() => {
|
|
setShowTimePicker(true);
|
|
setMode("end");
|
|
}}
|
|
/>
|
|
<TextInput
|
|
keyboardType="numeric"
|
|
label="Count"
|
|
placeholder="How Many Classes does this count for?"
|
|
mode="outlined"
|
|
value={count === 0 ? "" : count.toString()}
|
|
onChangeText={parseCount}
|
|
/>
|
|
<View
|
|
style={style.daysContainer}
|
|
>
|
|
{dayStates.map( (i, idx) => (
|
|
<ToggleButton
|
|
key={idx}
|
|
icon={`alpha-${days[idx][0].toLowerCase()}`}
|
|
status={i ? "checked": "unchecked"}
|
|
onPress={
|
|
() =>
|
|
setDayStates([
|
|
...dayStates.slice(0, idx),
|
|
!i,
|
|
...dayStates.slice(idx + 1)
|
|
])
|
|
}
|
|
/>
|
|
)
|
|
)}
|
|
</View>
|
|
</List.Section>
|
|
</Card.Content>
|
|
</Card>
|
|
<Portal>
|
|
<FAB
|
|
visible={!snackbar.visible}
|
|
large
|
|
icon="check"
|
|
onPress={submit}
|
|
style={{
|
|
position: "absolute",
|
|
margin: 16,
|
|
right: 0,
|
|
bottom: 0,
|
|
}}
|
|
/>
|
|
</Portal>
|
|
{showTimePicker && (
|
|
<DateTimePicker
|
|
testID="dateTimePicker"
|
|
timeZoneOffsetInMinutes={0}
|
|
value={defTime}
|
|
mode="time"
|
|
is24Hour={true}
|
|
display="default"
|
|
onChange={onChange}
|
|
/>
|
|
)}
|
|
<Snackbar
|
|
visible={snackbar.visible}
|
|
onDismiss={() => setSnackbar({ ...snackbar, visible: false })}
|
|
action={{
|
|
label: "Dismiss",
|
|
onPress: () => setSnackbar({ ...snackbar, visible: false }),
|
|
}}
|
|
>
|
|
{snackbar.message}
|
|
</Snackbar>
|
|
</>);
|
|
}
|
|
|
|
AddEntry.propTypes = {
|
|
addTimetableEntry: PropTypes.func,
|
|
subjects: PropTypes.array,
|
|
days: PropTypes.array,
|
|
navigation: PropTypes.object,
|
|
};
|
|
|
|
const style = StyleSheet.create({
|
|
card: {
|
|
marginTop: 12,
|
|
marginLeft: 10,
|
|
marginRight: 10,
|
|
},
|
|
text: {
|
|
marginTop: 12,
|
|
textAlign: "center",
|
|
},
|
|
class: {
|
|
flexDirection: "row",
|
|
justifyContent: "space-between"
|
|
},
|
|
daysContainer: {
|
|
flexDirection: "row",
|
|
justifyContent: "space-evenly",
|
|
marginTop: 10
|
|
},
|
|
});
|
|
|
|
export default AddEntry;
|