Skip to content

Instantly share code, notes, and snippets.

@chamellion
Created August 24, 2022 20:26
Show Gist options
  • Save chamellion/a5e28469b3dea88eb6eee61a4fd0b9b3 to your computer and use it in GitHub Desktop.
Save chamellion/a5e28469b3dea88eb6eee61a4fd0b9b3 to your computer and use it in GitHub Desktop.
The curriculum content
import React, {useCallback, useEffect, useMemo, useRef, useState} from "react";
import SafeAreaContainer from "../../components/SafeAreaContainer";
import {
Alert,
Dimensions,
Linking,
ScrollView,
StyleSheet,
Text,
ToastAndroid,
TouchableOpacity,
View
} from "react-native";
import DefaultPreferences from "react-native-default-preference";
import Utils from "../Utils";
import CustomSpinner from "../../components/CustomSpinner";
import CurriculumDetail from "../../components/CurriculumDetail";
import {Dropdown} from "react-native-element-dropdown/index";
import Entypo from "react-native-vector-icons/Entypo";
import BottomSheet, {
BottomSheetFlatList, BottomSheetModal,
BottomSheetModalProvider,
BottomSheetTextInput,
useBottomSheet
} from "@gorhom/bottom-sheet";
import {useNavigation} from "@react-navigation/native";
const chatIcon = <Entypo name={'chat'} color={'white'} size={24}/>
const globalStyle = require('../GlobalStyleSheet')
const CurriculumContent = ({route}) => {
const param = route.params
const volumeId = param.volumeId
const classChosen = param.classChosen
const subjectId = param.subjectId
const term = param.term
const week = param.week
const [weekState, setWeekState] = useState(Number.parseInt(week))
const [content, setContent] = useState({})
const [isLoading, setLoading] = useState(true)
const [dataExist, setDataExist] = useState(false)
const BASE_URL = Utils.baseUrl
const weekDataArray = [
{
label: "Week 1",
value: '1'
},
{
label: 'Week 2',
value: 2
},
{
label: 'Week 3',
value: 3
},
{
label: 'Week 4',
value: 4
},
{
label: 'Week 5',
value: 5
},
{
label: 'Week 6',
value: 6
},
{
label: 'Week 7',
value: 7
},
{
label: 'Week 8',
value: 8
},
{
label: 'Week 9',
value: 9
},
{
label: 'Week 10',
value: 10
},
{
label: 'Week 11',
value: 11
},
{
label: 'Week 12',
value: 12
},
{
label: 'Week 13',
value: 13
}
]
const [weekData] = useState(weekDataArray)
const [chosenWeek, setChosenWeek] = useState(null)
const getCurriculumContent = async (passedWeek) => {
try {
setLoading(true)
let token = await DefaultPreferences.get('TOKEN_PREF')
let URL = `${BASE_URL}curriculum-contents/volume/${volumeId}/class/${classChosen}/subject/${subjectId}/term/${term}/week/${passedWeek}`
console.log(URL)
let response =
await fetch(URL, {
method: 'GET',
headers: {
"Authorization": token
}
})
let responseJson = await response.json();
console.log(responseJson)
if (response.status === 200) {
let content = responseJson.data['curriculum content']
if (content.length === 0) {
setDataExist(false)
} else {
setDataExist(true)
setContent(content[0])
let chat = content.chat
setChatResource(chat)
}
} else if (response.status === 401 && responseJson.messages[0] === 'Expired access token error') {
console.log("This loop was breached")
const refreshToken = await DefaultPreferences.get('REFRESH_TOKEN');
const sessionId = await DefaultPreferences.get('SESSION_ID')
const token = await DefaultPreferences.get('TOKEN_PREF')
const mUrl = BASE_URL + 'sessions/' + sessionId
console.log("Refresh token url is " + mUrl)
let refreshResponse = await fetch(mUrl, {
method: 'PATCH',
headers: {
"Authorization": token
},
body: JSON.stringify({
"refreshToken": refreshToken
})
});
let refreshResponseJson = await refreshResponse.json();
if (refreshResponse.status === 200) {
let refreshToken = refreshResponseJson.data.refreshToken
let nAccessToken = refreshResponseJson.data.accessToken
await DefaultPreferences.set("REFRESH_TOKEN", refreshToken)
await DefaultPreferences.set("REFRESH_TOKEN", nAccessToken)
await getCurriculumContent()
} else {
Alert.alert("Error", refreshResponseJson.messages[0])
}
} else {
Alert.alert("Error", responseJson.messages[0])
}
} catch (e) {
console.log("error is " + e);
} finally {
setLoading(false)
}
}
const refHook = useRef(true)
useEffect(() => {
getCurriculumContent(weekState).catch(error => console.log(error))
}, [])
const [isNonTeachingWeek] = useState(weekState === 7 || weekState === 11 || weekState === 12 || weekState === 13)
useEffect(() => {
if (refHook.current) {
refHook.current = false
return
}
getCurriculumContent(weekState).catch(e => console.log(e))
}, [weekState])
// useEffect(() => {
// if (refHook.current) {
// refHook.current = false
// return
// }
//
// }, [openModal])
const bottomRef = useRef(null)
const [openModal, setModalOpen] = useState(true)
const snapPoint = useMemo(() => ['80%'], [])
const [chatResource, setChatResource] = useState([])
const [userComment, setUserComment] = useState("")
const getAllBookChats = async (resourceId) => {
try {
setLoading(true)
let token = await DefaultPreferences.get("TOKEN_PREF")
let BASE_URL = Utils.baseUrl
let bookList = "curriculum"
let response = await fetch(`${BASE_URL}/chat/resource/${bookList}/resourceId/${resourceId}`, {
method: 'GET',
headers: {
"Authorization": token
}
})
let responseJson = await response.json()
if (response.status === 200) {
let chatData = responseJson.data.Chats
setChatResource(chatData)
} else {
Alert.alert("Error", responseJson.messages[0])
}
} catch (e) {
console.log(e);
Alert.alert("Error", "One or more error has occurred")
} finally {
setLoading(false)
}
}
const saveAComment = async (resourceId) => {
try {
setLoading(true)
if (userComment.length <= 0) {
Alert.alert("Error", "Empty text, enter a valid message to continue")
} else {
let profileId = await DefaultPreferences.get("PROFILE_PREF")
let token = await DefaultPreferences.get("TOKEN_PREF")
const data = JSON.stringify({
"profileId": profileId,
"resource": "curriculum",
"resourceId": resourceId,
"discussion": userComment,
"reply": null,
"attachment": null
})
let BASE_URL = Utils.baseUrl
let response = await fetch(BASE_URL + "chat", {
method: 'POST',
headers: {
"Authorization": token,
'Content-type': 'application/json',
},
body: data
})
let responseJson = await response.json();
console.log(responseJson)
if (response.status === 201) {
ToastAndroid.show("Post successful", ToastAndroid.LONG)
await getAllBookChats(resourceId)
}
}
} catch (e) {
console.log(e);
} finally {
setLoading(false)
}
}
// callbacks
const handlePresentModalPress = useCallback(() => {
if (openModal){
bottomRef.current?.present();
setModalOpen(!openModal)
}else {
bottomRef.current?.dismiss();
setModalOpen(!openModal)
}
}, [openModal]);
const handleSheetChanges = useCallback((index: number) => {
console.log('handleSheetChanges', index);
}, []);
return (
<SafeAreaContainer>
<BottomSheetModalProvider>
{
!isLoading && <ScrollView showsVerticalScrollIndicator={false}
contentContainerStyle={{minHeight: '100%'}}>
<View>
<CustomSpinner setVisibility={isLoading} spinnerStyle={Style.loadingIndicators}/>
{
dataExist ? <View style={Style.topicContainer}>
<Text style={Style.topicText}>{JSON.parse(content.topic)?.heading?.content}</Text>
</View> :
<Text style={Style.topicText}>No Content Available</Text>
}
<View style={{marginEnd: 32}}>
<View style={{flexDirection: "row"}}>
<CurriculumDetail
heading={"Class"}
detail={`${(content?.levelName)?.charAt(0)}${(content?.name)?.charAt(0)}${content.class}`}
backgroundStyle={{marginStart: 16, marginTop: 16, marginEnd: 50}}/>
<CurriculumDetail
heading={"Subject"}
detail={`${content.subjectName}`}
backgroundStyle={{marginStart: 16, marginTop: 16}}/>
</View>
<View style={{flexDirection: "row"}}>
<CurriculumDetail
heading={"Term"}
detail={getTermInWords(content.term)}
backgroundStyle={{
marginTop: 8,
marginStart: 16,
marginBottom: 16,
marginEnd: 24
}}/>
<CurriculumDetail
heading={"Week"}
detail={`${content.week_no}`}
detailStyle={{textAlign: 'center'}}
backgroundStyle={{marginTop: 8, marginStart: 16, marginBottom: 16}}/>
</View>
</View>
<View style={[globalStyle.androidCardView, {backgroundColor: "#D9D9D9"}]}>
{
dataExist && (
<View style={Style.subTopicContainer}>
<Text style={Style.subTopic}>Topic</Text>
<Text
style={Style.subTopicContent}>{(content.week_no === 7 || content.week_no === 11 || content.week_no === 12 || content.week_no === 13) ?
<Text>{""}</Text> : JSON.parse(content.topic).heading.content}</Text>
{(content.week_no === 7 || content.week_no === 11 || content.week_no === 12 || content.week_no === 13) ?
<Text>{""}</Text> : JSON.parse(content.topic)?.body?.type === 'ul' ? JSON.parse(content.topic)?.body?.content?.map((element) => (
<Text
style={{color: 'black'}}>{element.value.length === 0 ? "" : `\t \u2022 ${element?.value}`}</Text>)) :
<Text>{""}</Text>}
</View>
)
}
</View>
<View style={[globalStyle.androidCardView, {backgroundColor: "#D9D9D9"}]}>
{
dataExist && (
<View style={Style.subTopicContainer}>
<Text style={Style.subTopic}>Learning Objective</Text>
{
((JSON.parse(content?.learning_objective)?.heading?.content).length > 0) &&
<Text
style={Style.subTopicContent}>{(content.week_no === 7 || content.week_no === 11 || content.week_no === 12 || content.week_no === 13) ?
<Text>{""}</Text> :
<Text>{`${JSON.parse(content?.learning_objective)?.heading?.content}`}</Text>}</Text>
}
{(content.week_no === 7 || content.week_no === 11 || content.week_no === 12 || content.week_no === 13) ?
<Text>{""}</Text> : (JSON.parse(content.learning_objective)?.body.type === 'ul' ? JSON.parse(content.learning_objective)?.body?.content?.map((element) => (
<Text
style={{color: 'black'}}>{`\t\u2022 ${element?.value}`}</Text>)) :
<Text>{""}</Text>)}
</View>
)
}
</View>
<View style={[globalStyle.androidCardView, {backgroundColor: "#D9D9D9"}]}>
{
dataExist && (
<View style={Style.subTopicContainer}>
<Text style={Style.subTopic}>Learning Activity</Text>
{
((JSON.parse(content.learning_activity)?.heading?.content).length > 0) &&
<Text
style={Style.subTopicContent}>{(content.week_no === 7 || content.week_no === 11 || content.week_no === 12 || content.week_no === 13) ?
<Text>{""}</Text> : JSON.parse(content.learning_activity)?.heading?.content}</Text>
}
{(content.week_no === 7 || content.week_no === 11 || content.week_no === 12 || content.week_no === 13) ?
<Text>{""}</Text> : JSON.parse(content.learning_activity)?.body?.type === 'ul' ? JSON.parse(content.learning_activity)?.body?.content?.map((element) => (
<Text
style={{color: 'black'}}>{element.value.length === 0 ? "" : `\t \u2022 ${element?.value}`}</Text>)) : JSON.parse(content.learning_activity)?.body?.content.map((element) => (
<Text style={{color: 'black'}}>{element.value}</Text>))}
</View>
)
}
</View>
<View style={[globalStyle.androidCardView, {backgroundColor: "#D9D9D9"}]}>
{
dataExist && (
<View style={Style.subTopicContainer}>
<Text style={Style.subTopic}>Embedded Core Skills</Text>
{
((JSON.parse(content?.embedded_core_skill)?.heading?.content).length > 0) &&
<Text
style={Style.subTopicContent}>{(content.week_no === 7 || content.week_no === 11 || content.week_no === 12 || content.week_no === 13) ?
<Text>{""}</Text> : JSON.parse(content?.embedded_core_skill)?.heading?.content}</Text>
}
{(content.week_no === 7 || content.week_no === 11 || content.week_no === 12 || content.week_no === 13) ?
<Text>{""}</Text> : JSON.parse(content.embedded_core_skill)?.body?.type === 'ul' ? JSON.parse(content?.embedded_core_skill)?.body?.content?.map((element) => (
<Text>{`\t\u2022 ${element.value}`}</Text>)) : JSON.parse(content.embedded_core_skill)?.body?.content?.map((element) => (
<Text style={{color: 'black'}}>{element?.value}</Text>))}
</View>
)
}
</View>
<View style={[globalStyle.androidCardView, {backgroundColor: "#D9D9D9"}]}>
{
dataExist && (
<View style={Style.subTopicContainer}>
<Text style={Style.subTopic}>Learning Resources</Text>
{
((JSON.parse(content.learning_resource)?.heading?.content).length > 0) &&
<Text style={Style.subTopicContent}>
{(content.week_no === 7 || content.week_no === 11 || content.week_no === 12 || content.week_no === 13) ?
<Text>{""}</Text> : JSON.parse(content.learning_resource)?.heading?.content}
</Text>
}
{(content.week_no === 7 || content.week_no === 11 || content.week_no === 12 || content.week_no === 13) ?
<Text>{""}</Text> : JSON.parse(content.learning_resource).body.content.map((element) => (
processLink(element)
))}
</View>
)
}
</View>
<View style={{flexDirection: "row", justifyContent: "space-around", marginBottom: 32}}>
<TouchableOpacity style={Style.smallButtons} onPress={() => {
if (weekState < 2) {
Alert.alert("Error", "All Curriculum begins at week one")
} else {
let newWeek = weekState - 1
setWeekState(newWeek)
}
}}>
<Text style={Style.smallButtonText}>prev</Text>
</TouchableOpacity>
<Dropdown
style={Style.dropdown}
data={weekData}
value={chosenWeek}
labelField={"label"}
valueField={"value"}
maxHeight={300}
onChange={item => {
setChosenWeek(item.value)
setWeekState(item.value)
}}/>
<TouchableOpacity style={Style.smallButtons} onPress={() => {
/*Week at 12 is being checked because update is later done in the else block
when weekState is 12, it's being updated already to 13 in else block
*/
if (weekState > 12) {
Alert.alert("Error", "You have reached the end of the week for a term")
} else {
let newWeekState = weekState + 1
setWeekState(newWeekState)
}
}}>
<Text style={Style.smallButtonText}>Next</Text>
</TouchableOpacity>
</View>
</View>
</ScrollView>
}
<TouchableOpacity style={Style.sendButtonContainer}
activeOpacity={0.4}
onPress={() => handlePresentModalPress()}>
<View style={{flexDirection: 'row', alignItems: 'center'}}>
<Text style={{marginEnd: 6}}>{chatIcon}</Text>
<Text style={Style.sendButtonText}>{openModal ? "Show Comment" : "Close Comment"}</Text>
</View>
</TouchableOpacity>
<BottomSheetModal snapPoints={snapPoint}
ref={bottomRef}
enablePanDownToClose={true}
enableDismissOnClose={true}>
<CustomSpinner setVisibility={isLoading} spinnerStyle={Style.loadingIndicators}/>
<BottomSheetFlatList
data={chatResource}
showsVerticalScrollIndicator={false}
ListHeaderComponent={
<View>
{/*<TouchableOpacity style={Style.sendChatContainer}>*/}
{/* <Text style={Style.sendChatText}>Close</Text>*/}
{/*</TouchableOpacity>*/}
<BottomSheetTextInput
style={[globalStyle.textInputStyle, {alignSelf: "center", marginTop: 12}]}
placeholder={"Type your comment"}
autoCorrect={false}
multiline={true}
onChangeText={setUserComment}
value={userComment}
/>
<TouchableOpacity style={Style.sendChatContainer} onPress={async () => {
if (userComment.length <= 0) {
Alert.alert("Error", "Empty text, enter a valid message to continue")
} else {
await saveAComment(content.id)
setUserComment("")
}
}}>
<Text style={Style.sendChatText}>Send</Text>
</TouchableOpacity>
</View>
}
renderItem={({item}) => {
const data = item.cleanData ? item.cleanData : item;
let discussion = data.discussion
let fullName = data.profile_info.surname + " " + data.profile_info.firstname
return (
<View style={Style.chatContainer}>
<Text style={Style.chatName}>{fullName}</Text>
<Text style={Style.chatMessage}>{discussion}</Text>
</View>
)
}}
/>
</BottomSheetModal>
</BottomSheetModalProvider>
</SafeAreaContainer>
)
}
const Style = StyleSheet.create({
topicText: {
textAlign: "center",
marginTop: 16,
fontSize: 24,
fontFamily: 'NunitoSans-ExtraBold',
color: 'black'
},
topicContainer: {
alignContent: "center",
marginTop: 8,
marginHorizontal: 16,
justifyContent: "center",
},
subTopic: {
fontSize: 20,
fontFamily: 'NunitoSans-SemiBold',
color: 'black'
},
subTopicContainer: {
marginHorizontal: 16,
marginTop: 12,
},
subTopicContent: {
fontFamily: 'NunitoSans-Regular',
color: 'black'
},
scrollViewStyle: {
flexGrow: 1
},
loadingIndicators: {
position: "absolute",
top: Dimensions.get("screen").height / 3,
zIndex: 3,
elevation: 3,
alignSelf: "center"
},
subHeading: {
marginStart: 16,
marginTop: 16,
marginBottom: 16
},
dropdown: {
borderWidth: 1,
borderRadius: 8,
paddingHorizontal: 12,
width: 150,
borderColor: '#E0E2EB',
backgroundColor: '#d9d9d9',
},
smallButtons: {
backgroundColor: '#005EB4',
paddingVertical: 4,
paddingHorizontal: 24,
alignItems: 'center',
justifyContent: 'center',
borderRadius: 6
},
smallButtonText: {
fontWeight: 'bold',
textAlign: 'center',
color: '#ffffff',
textTransform: 'uppercase',
fontFamily: 'Roboto-Regular',
lineHeight: 16
},
sendButtonContainer: {
paddingHorizontal: 16,
alignSelf: 'baseline',
backgroundColor:
Utils.buttonColor,
borderRadius: 5,
paddingVertical: 6,
marginBottom: 8,
position: 'absolute',
zIndex: 2,
elevation: 2,
alignItems: 'center',
justifyContent: 'center',
right: 32,
bottom: 70,
},
sendButtonText: {
textTransform: 'uppercase',
color: 'white',
fontFamily: 'NunitoSans-ExtraBold'
},
chatName: {
fontFamily: 'NunitoSans-ExtraBold',
color: 'black'
},
chatMessage: {
fontFamily: 'NunitoSans-SemiBoldItalic',
},
chatContainer: {
backgroundColor: '#F2F3F7',
padding: 12,
marginTop: 16,
marginStart: 24,
borderRadius: 12,
},
sendChatContainer:{
paddingHorizontal: 16,
alignSelf: 'flex-end',
backgroundColor:
Utils.buttonColor,
borderRadius: 5,
paddingVertical: 6,
marginEnd: 24,
marginTop: 4,
marginBottom: 8,
justifyContent: 'flex-end'
},
sendChatText: {
textTransform: 'uppercase',
color: 'white',
fontFamily: 'NunitoSans-ExtraBold'
}
})
function processLink(element) {
if (element.type === "a") {
return (
<TouchableOpacity onPress={() => handleLinkClicked(element)}>
<Text style={{color: 'black', textDecorationLine: 'underline'}}>{`\t\u2022 ${element.value}`}</Text>
</TouchableOpacity>
)
} else {
return <Text style={{color: 'black'}}>{`\t\u2022 ${element.value}`}</Text>
}
}
async function handleLinkClicked(element) {
try {
let canOpenLink = Linking.canOpenURL(element.value)
if (canOpenLink) {
let value = Linking.openURL(element.value)
console.log("Value is " + value)
}
} catch (e) {
console.log(e);
}
}
function getTermInWords(termNumber) {
switch (termNumber) {
case 1:
return "First Term"
case 2:
return "Second Term"
case 3:
return "Third Term"
}
}
export default CurriculumContent
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment