Skip to content

Instantly share code, notes, and snippets.

@chamellion
Created August 24, 2022 20:29
Show Gist options
  • Save chamellion/5d424f89c6bf51ea61c01e4a5561f6d5 to your computer and use it in GitHub Desktop.
Save chamellion/5d424f89c6bf51ea61c01e4a5561f6d5 to your computer and use it in GitHub Desktop.
Chat on booklist
import React, {useEffect, useState} from 'react';
import SafeAreaContainer from "../../components/SafeAreaContainer";
import {
Alert,
FlatList, KeyboardAvoidingView, LayoutAnimation,
StyleSheet,
Text,
TextInput,
ToastAndroid,
TouchableOpacity,
View
} from "react-native";
import Utils from "../Utils";
import DefaultPreferences from "react-native-default-preference";
import CustomSpinner from "../../components/CustomSpinner";
import Ionicons from "react-native-vector-icons/Ionicons";
const globalStyle = require('../GlobalStyleSheet')
const caretUp = <Ionicons name={'caret-up-sharp'} color={'black'} size={18}/>
const caretDown = <Ionicons name={'caret-down-sharp'} color={'black'} size={18}/>
const Chat = (props) => {
const resourceId = props.resourceId.id
const [chatResource, setChatResource] = useState([])
const [loading, setLoading] = useState(true)
const [showReply, setShowReply] = useState(false)
const [showComment, setShowComment] = useState(false)
const [shouldReplyComment, setShouldReplyComment] = useState(false)
const [activeIndex, setActiveIndex] = useState(0)
const [userComment, setUserComment] = useState("")
const [replyComment, setReplyComment] = useState("")
const getAllBookChats = async () => {
try {
setLoading(true)
let token = await DefaultPreferences.get("TOKEN_PREF")
let BASE_URL = Utils.baseUrl
let bookList = "book list"
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
const rData = restructureData(chatData)
setChatResource(rData)
} 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 () => {
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": "book list",
"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();
if (response.status === 201) {
ToastAndroid.show("Post successful", ToastAndroid.SHORT)
await getAllBookChats()
}
}
} catch (e) {
console.log(e);
} finally {
setLoading(false)
}
}
const saveAReply = async (replyId) => {
try {
setLoading(true)
if (replyComment.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": "book list",
"resourceId": resourceId,
"discussion": replyComment,
"reply": replyId,
"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();
if (response.status === 201) {
ToastAndroid.show("Post successful", ToastAndroid.SHORT)
await getAllBookChats()
}
}
} catch (e) {
console.log(e);
} finally {
setLoading(false)
}
}
useEffect(() => {
getAllBookChats().catch(e => console.log(e))
}, [])
return (
<SafeAreaContainer>
<View>
<View>
<CustomSpinner setVisibility={loading} spinnerStyle={Style.spinnerStyle}/>
<TouchableOpacity style={Style.buttonContainer} onPress={() => setShowComment(!showComment)}>
<Text style={Style.buttonText}>{showComment ? "Close Comment" : "Write Comment"}</Text>
</TouchableOpacity>
{
showComment && <View>
<TextInput style={[globalStyle.textInputStyle, {alignSelf: "center", marginTop: 12}]}
placeholder={"Type your comment"}
multiline={true}
onChangeText={setUserComment}
value={userComment}
/>
<TouchableOpacity style={Style.sendButtonContainer} onPress={async () => {
if (userComment.length <= 0) {
Alert.alert("Error", "Empty text, enter a valid message to continue")
} else {
await saveAComment()
setUserComment("")
}
}}>
<Text style={Style.sendButtonText}>Send</Text>
</TouchableOpacity>
</View>
}
</View>
<FlatList
data={chatResource}
initialNumToRender={10}
keyExtractor={(item, index) => index}
showsVerticalScrollIndicator={false}
renderItem={({item, index}) => {
const data = item.cleanData ? item.cleanData : item;
let discussion = data.discussion
let fullName = data.profile_info.surname + " " + data.profile_info.firstname
if (data.replies.length > 0) {
return (
<KeyboardAvoidingView>
<TouchableOpacity onPress={() => {
LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut)
setShowReply(!showReply)
setActiveIndex(index)
setReplyComment("")
}}>
<View style={Style.chatContainer}>
<Text style={Style.chatName}>{fullName}</Text>
<Text style={Style.chatMessage}>{discussion}</Text>
<View style={{
flexDirection: "row",
alignSelf: 'flex-end',
marginEnd: 12,
justifyContent: 'center'
}}>
<Text
style={Style.replyNumber}>{data.replies.length} {data.replies.length > 1 ? "Replies" : "Reply"}</Text>
<Text>{showReply ? caretDown : caretUp}</Text>
</View>
</View>
</TouchableOpacity>
{
(activeIndex === index) && showReply && data.replies.map((item, index) => (
<View style={Style.replyContainer} key={index}>
<Text
style={Style.chatName}>{item.profile_info.surname + " " + item.profile_info.firstname}</Text>
<Text style={Style.chatMessage}>{item.discussion}</Text>
</View>
))
}
{
(activeIndex === index) && showReply &&
<View>
<TextInput style={[globalStyle.textInputStyle, {
alignSelf: "flex-end",
marginTop: 4,
padding: 8,
width: '80%'
}]}
placeholder={"Reply Comment"}
multiline={true}
onChangeText={setReplyComment}
value={replyComment}
/>
<TouchableOpacity style={[Style.sendButtonContainer, {padding: 2}]}
onPress={async () => {
if (replyComment.length <= 0) {
Alert.alert("Error", "Empty text, enter a valid message to continue")
} else {
await saveAReply(data.id)
setReplyComment("")
}
}}>
<Text style={Style.sendButtonText}>Reply</Text>
</TouchableOpacity>
</View>
}
</KeyboardAvoidingView>
)
} else {
return (
<KeyboardAvoidingView>
<TouchableOpacity onPress={() => {
LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut)
setShouldReplyComment(!shouldReplyComment)
setActiveIndex(index)
setReplyComment("")
}}>
<View>
<View style={Style.chatContainer}>
<Text style={Style.chatName}>{fullName}</Text>
<Text style={Style.chatMessage}>{discussion}</Text>
</View>
{
(activeIndex === index) && shouldReplyComment && <View>
<TextInput style={[globalStyle.textInputStyle, {
alignSelf: "flex-end",
marginTop: 4,
padding: 8,
width: '80%'
}]}
placeholder={"Reply Comment"}
multiline={true}
onChangeText={setReplyComment}
value={replyComment}
/>
<TouchableOpacity style={[Style.sendButtonContainer, {padding: 2}]}
onPress={async () => {
if (replyComment.length <= 0) {
Alert.alert("Error", "Empty text, enter a valid message to continue")
} else {
await saveAReply(data.id)
setReplyComment("")
}
}}>
<Text style={Style.sendButtonText}>Reply</Text>
</TouchableOpacity>
</View>
}
</View>
</TouchableOpacity>
</KeyboardAvoidingView>
)
}
}}
/>
</View>
</SafeAreaContainer>
);
};
const Style = StyleSheet.create({
container: {
margin: 16,
},
buttonContainer: {
backgroundColor: Utils.buttonColor,
paddingVertical: 12,
paddingHorizontal: 10,
borderRadius: 5,
alignSelf: 'flex-end',
marginTop: 6,
},
buttonText: {
color: 'white',
fontFamily: 'NunitoSans-ExtraBold',
fontSize: 12,
textAlign: 'center',
textTransform: 'uppercase',
}
,
headerContainer: {
flexDirection: 'row',
alignItems: 'center',
margin: 8,
justifyContent: 'space-between'
}
,
vRatingText: {
fontFamily: 'NunitoSans-SemiBold',
fontSize: 16
}
,
ratingNumber: {
fontFamily: 'NunitoSans-ExtraBold',
textAlign: 'center',
color: 'black'
}
,
chatName: {
fontFamily: 'NunitoSans-ExtraBold',
color: 'black'
}
,
chatMessage: {
fontFamily: 'NunitoSans-SemiBoldItalic',
}
,
chatContainer: {
backgroundColor: '#F2F3F7',
padding: 12,
marginTop: 16,
marginStart: 8,
borderRadius: 12,
},
replyContainer: {
backgroundColor: '#F2F3F7',
padding: 12,
marginTop: 4,
marginStart: 50,
borderRadius: 12,
},
createChatBox: {
borderWidth: 1
},
sendButtonContainer: {
paddingHorizontal: 16,
alignSelf: 'flex-end',
backgroundColor:
Utils.buttonColor,
borderRadius: 5,
paddingVertical: 6,
marginEnd: 24,
marginTop: 4,
marginBottom: 8,
justifyContent: 'flex-end'
},
sendButtonText: {
textTransform: 'uppercase',
color: 'white',
fontFamily: 'NunitoSans-ExtraBold'
},
spinnerStyle: {
position: "absolute",
alignSelf: "center",
top: 100,
zIndex: 3,
elevation: 3
},
replyNumber: {
fontFamily: 'NunitoSans-BoldItalic',
textAlign: 'right',
marginEnd: 16,
fontSize: 13
}
}
)
export function restructureData(itemArray) {
let sanitizedData = []
const messages = itemArray.filter(item => item.reply === null)
const replies = itemArray.filter(item => item.reply !== null)
for (const message of messages) {
let messageId = message.id
const replyArray = replies.filter(item => item.reply === messageId)
Object.assign(message, {"replies": replyArray})
sanitizedData.push(message)
}
console.log("Sanitized array is ")
console.log(sanitizedData)
return sanitizedData
}
export default Chat;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment