React Socketio set online status for multiple users - node.js

How can i update online status of multiple users in React.i want that when user A is online,user B and C can also see if user A is online.Here is what i have tried using react usestate but it isnt working
function MyOffers() {
const [loading, setLoading] = useState(true);
const [cookies] = useCookies();
const { enqueueSnackbar } = useSnackbar();
const navigate = useNavigate();
const [data, setData] = useState(false);
let { id } = useParams();
const [user, setUser] = useState({
username: null,
online: false,
});
////set online status
const socket = useContext(SocketContext);
useEffect(() => {
ifvisible.on('focus', function () {
socket.emit('online', user);
console.log(user);
});
ifvisible.on('blur', function () {
socket.emit('offline', user);
console.log('offline');
});
return () => {
ifvisible.off('focus');
ifvisible.off('blur');
};
}, [user]);
useEffect(() => {
socket.on('online', (data) => {
setUser((prevState) => ({
...prevState,
...data,
}));
console.log(user);
});
socket.on('offline', (data) => {
setUser((prevState) => ({
...prevState,
...data,
}));
});
}, [socket]);
useEffect(() => {
$.ajax({
type: 'POST',
url: '/get_offer',
headers: {
'X-XSRF-TOKEN': cookies['XSRF-TOKEN'],
'Authorization': `Bearer ${localStorage.getItem('auth')}`,
},
data: {
id: id,
},
success: function (data) {
switch (data.success) {
case true:
setData(data);
setLoading(false);
break;
case false:
break;
}
},
error: function () {},
statusCode: {
403: function () {
navigate('/');
},
},
});
}, []);
return (
<React.Fragment>
<Box flexGrow={1}>
{/*seller info*/}
<Grid item xs={12} sm={4}>
{loading ? (
<Skeleton
variant="rectangular"
animation="wave"
width={'100%'}
height={200}
sx={{ borderRadius: 2, marginTop: 1 }}
/>
) : (
<Item>
<Badge
color={
data.offer &&
data.offer[0].user.username === user.username &&
user.online === true
? 'success'
: 'warning'
}
variant="dot"
overlap="circular"
anchorOrigin={{
vertical: 'bottom',
horizontal: 'right',
}}
>
<Avatar
alt="Remy Sharp"
src="/static/images/avatar/1.jpg"
sx={{ width: 56, height: 56 }}
/>
</Badge>
<Typography variant={'h5'}>
{data.offer ? data.offer[0].user.username : ''}
</Typography>
<Typography paragraph>
<Rating name="read-only" value={5} readOnly />
<Typography variant={'subtitle1'}>[5]</Typography>
</Typography>
<CardActions sx={{ display: 'flex', justifyContent: 'space-evenly' }}>
<IconButton aria-label="add to favorites">
<LockClockOutlinedIcon />
</IconButton>
<IconButton aria-label="share">
<LockClockOutlinedIcon />
</IconButton>
</CardActions>
</Item>
)}
</Grid>
</Grid>
</Box>
</React.Fragment>
);
}
export default MyOffers;
i want such when the owner of the offer is online,to update the online status badge of the user viewing the offer.Here is my server code
/**
* Listen for incoming socket connections
*/
Ws.io.on('connection', (socket) => {
socket.on('online', (data) => {
data.online = true;
socket.broadcast.emit('online', data);
});
socket.on('offline', (data) => {
data.online = false;
socket.broadcast.emit('offline', data);
});
});

Related

profile edit is not working when I change my component in profile detail

1.After I came to profile page that show my profile details my console log shows POST http://localhost:3000/profileEdit 500 (Internal Server error)
2.I change my activity drinks about topics and then refresh page it shows nothing like it didn't save at all except image
I debug by myself then tried to find solution in reddit, quora, stackoverflow 5 day but can't find it So please could you help me a bit
this is frontend
import React, { useState, useEffect } from "react";
import { connect } from "react-redux";
import { useCookies } from "react-cookie";
import { Link } from "react-router-dom";
import axios from "axios";
import {
ref, uploadBytesResumable, getDownloadURL, getStorage
} from "firebase/storage";
import { profileInit } from "../redux/action";
import "./profileEdit.css";
import styled from "styled-components";
const Avatar = styled.div`
width: 250px;
height: 250px;
border-radius: 50%;
background-size: cover;
background-position: center;
cursor: pointer;
`;
function ProfileEdit(props) {
const [cookies, removeCookies] = useCookies([
"userName",
"userNickname",
]);
const [activity, setActivity] = useState("");
const [drinks, setDrinks] = useState("");
const [topics, setTopics] = useState("");
const [about, setAbout] = useState("");
const [url, setUrl] = useState("./images/UploadPic.svg");
const [save, setSave] = useState("");
const id = cookies.userName;
const { profileInit, user } = props;
const [image, setImage] = useState(null);
function patchData(event) {
event.preventDefault();
axios
.patch("/users/profile", {
activity,
drinks,
topics,
about,
id,
})
.then(({ data }) => {
if (data.success) {
setSave("Changes were saved");
} else {
setSave(data.err);
}
});
const storage = getStorage();
const storageRef = ref(storage, `images/${cookies.userName || "./images/infoUser.svg"}`);
const uploadTask = uploadBytesResumable(storageRef, image);
uploadTask.on("state_changed", undefined, undefined, () => {
getDownloadURL(storageRef).then((url) => {
setUrl(url);
});
});
if (setUrl !== null || setUrl == null) {
axios
.patch("/users/profile", {
activity,
drinks,
topics,
about,
id,
avatar: url,
})
.then(({ data }) => {
if (data.success) {
setSave("Saved");
} else {
setSave(data.err);
}
});
}
}
function handleChangeAbout(event) {
event.preventDefault();
setAbout(event.target.value);
}
function handleChangeDrinks(event) {
event.preventDefault();
setDrinks(event.target.value);
}
function handleChangeTopics(event) {
event.preventDefault();
setTopics(event.target.value);
}
function handleChangeActivity(event) {
event.preventDefault();
setActivity(event.target.value);
}
function LogOut() {
user.id = null;
removeCookies("userName");
removeCookies("userNickname");
}
useEffect(() => {
const storage = getStorage();
getDownloadURL(ref(storage, `images/${cookies.userName}`))
.then((url) => {
setUrl(url);
});
axios
.post('/users/profileEdit', {
id,
})
.then(({ data }) => {
setActivity(data.profileId.activity);
setDrinks(data.profileId.drinks);
setAbout(data.profileId.about);
setTopics(data.profileId.topics);
profileInit(data.profileId);
});
}, [profileInit, id]);
function photoDownload(e) {
if (e.target.files[0]) {
setImage(e.target.files[0]);
const storage = getStorage();
const storageRef = ref(storage, `images/${cookies.userName}`);
const uploadTask = uploadBytesResumable(storageRef, image);
uploadTask.on(
"state_changed",
() => {
setUrl("./loading.gif");
},
(error) => {
console.log(error);
},
() => {
getDownloadURL(storageRef)
.then((url) => {
setUrl(url);
});
},
);
}
}
return (
<>
<div className="profile-container">
<div style={{ alignSelf: "center" }}>
<label htmlFor="file-input">
<Avatar style={{ backgroundImage: `url(${url})` }} />
</label>
<input id="file-input" type="file" onChange={photoDownload} />
</div>
<form onSubmit={patchData} className="edit">
<span
style={{ textShadow: "none", marginBottom: "8px", color: "#fff" }}
>
Activity:
</span>
<label>
<input
value={activity}
onChange={handleChangeActivity}
type="text"
name="activity"
className="profileInput"
required
/>
</label>
<span
style={{ textShadow: "none", marginBottom: "8px", color: "#fff" }}
>
Topics:
</span>
<label>
<input
value={topics}
onChange={handleChangeTopics}
type="text"
name="topics"
className="profileInput"
required
/>
</label>
<span
style={{ textShadow: "none", marginBottom: "8px", color: "#fff" }}
>
About:
</span>
<label>
<input
value={about}
onChange={handleChangeAbout}
type="text"
name="about"
className="profileInput"
required
/>
</label>
<span
style={{ textShadow: "none", marginBottom: "8px", color: "#fff" }}
>
Drinks:
</span>
<label>
<input
value={drinks}
onChange={handleChangeDrinks}
type="text"
name="drinks"
className="profileInput"
required
/>
</label>
<button
style={{ margin: "0 auto" }}
className="chatButton"
>
{" "}
Save changes
{" "}
</button>
<div style={{ marginTop: "15px", color: "#fff" }}>
{" "}
{save}
</div>
</form>
<div className="quitEdit" style={{ margin: "0 auto" }}>
<Link to="/listUsers" style={{ position: "relative" }}>
<img src="./images/back.svg" width="100" height="100" alt="BackToListPage" title="BackToListPage" />
</Link>
</div>
<div className="exit" style={{ margin: "0 auto" }}>
<Link to="/login" onClick={LogOut} style={{ position: "relative" }}>
<img src="./images/exit.svg" width="100" height="100" alt="Logout" title="Logout" />
</Link>
</div>
</div>
</>
);
}
const mapStateToProps = (state) => ({
profileId: state.user.profileId,
user: state.user,
err: state.error,
});
const mapDispatchToProps = (dispatch) => ({
profileInit: (profileId) => dispatch(profileInit(profileId)),
});
export default connect(mapStateToProps, mapDispatchToProps)(ProfileEdit);
my backend code for /users/profile and /users/profileEdit
router.patch('/profile', async (req, res) => {
const {
activity,
topics,
about,
drinks,
avatar,
id,
} = req.body;
const response = await Profile.updateOne({ person: id }, {
activity, topics, about, drinks, avatar
});
if (response) {
res.send({ success: true });
} else {
res.send({ success: false, err: 'Try again' });
}
});
router.post('/profileEdit', async (req, res) => {
const { id } = req.body;
const response = await Profile.findOne({ person: id });
if (response) {
res.send({ profileId: response });
} else {
res.status(500).send({ err: 'Something went wrong' });
}
});
Edit post here -> modelProfile.js
const mongoose = require('mongoose');
const profileSchema = new mongoose.Schema({
person: {
type: mongoose.Schema.Types.ObjectId,
ref: 'Person',
},
name: {
type: String,
required: true,
minlength: 1,
},
DoB: {
type: Date,
required: true,
},
activity: {
type: String,
required: true,
minlength: 1,
},
about: {
type: String,
minlength: 1,
},
topics: String,
drinks: String,
avatar: String,
latitude: Number,
longitude: Number,
},
{
versionKey: false,
});
module.exports = mongoose.model('Profile', profileSchema);
here is process page
import React, { useState } from "react";
import axios from "axios";
import { LogIn } from "../redux/action";
import { connect } from "react-redux";
import ImageUpload from "./PhotoUpload";
import { useNavigate } from "react-router-dom";
import { FromProcess, FromProcessContainer, ButtonCreate } from "./CreatingElements";
function CreatingAccount (props) {
const navigate = useNavigate();
const [state,setState] = useState({
currentStep: 1,
name: "",
DoB: "",
activity: "",
topics: "",
drinks: "",
about: ""
});
const handleChange = e => {
const { name, value } = e.target;
setState(state => ({
...state, // <-- copy previous state
[name]: value, // <-- update property
}));
};
const handleSubmit = async e => {
e.preventDefault();
const { user } = props;
let { name, DoB, activity, topics, drinks, about } = state;
await axios.post("/users/profile", {
name,
DoB,
activity,
topics,
drinks,
about,
id: user.id
});
const profileId = {
person: user.id,
name,
DoB,
activity,
about,
topics,
drinks
};
props.LogIn(user.id, user.nickname, profileId);
navigate("/listUsers");
};
const _next = () => {
let currentStep = state.currentStep;
currentStep = currentStep >= 2 ? 3 : currentStep + 1;
setState(state => ({
...state, // <-- copy previous state
currentStep: currentStep// <-- update property
}));
};
const _prev = () => {
let currentStep = state.currentStep;
currentStep = currentStep <= 1 ? 1 : currentStep - 1;
setState(state => ({
...state, // <-- copy previous state
currentStep: currentStep// <-- update property
}));
};
function previousButton() {
let currentStep = state.currentStep;
if (currentStep !== 1) {
return (
<>
<ButtonCreate
style={{ color: "#3103ff" }}
className="btn"
type="button"
onClick={_prev}
>
Previous
</ButtonCreate>
<br />
</>
);
}
return null;
}
function nextButton() {
let currentStep = state.currentStep;
if (currentStep < 3) {
return (
<ButtonCreate
className="btn"
type="button"
onClick={_next}
data-cy="next-process"
style={{
marginBottom: "25px",
color: "#FFF",
backgroundColor: "#3103ff"
}}
>
Next
</ButtonCreate>
);
}
return null;
}
return (
<>
<FromProcessContainer>
<FromProcess onSubmit={handleSubmit} >
<p>Step {state.currentStep}</p>
<br/>
<Step1
currentStep={state.currentStep}
handleChange={handleChange}
name={state.name}
DoB={state.DoB}
activity={state.activity}
/>
<Step2
currentStep={state.currentStep}
handleChange={handleChange}
topics={state.topics}
drinks={state.drinks}
/>
<Step3
currentStep={state.currentStep}
handleChange={handleChange}
about={state.about}
/>
{previousButton()}
{nextButton()}
</FromProcess>
</FromProcessContainer>
</>
);
}
function Step1(props) {
if (props.currentStep !== 1) {
return null;
}
return (
<div className="form-group">
<label>
<input
value={props.name}
onChange={props.handleChange}
type="text"
name="name"
placeholder="Your name"
required
data-cy="input-name-process"
/>
</label>
<label>
<input
value={props.DoB}
onChange={props.handleChange}
type="date"
name="DoB"
placeholder="Date of Birth"
max="2010-01-01"
min="1930-12-31"
required
data-cy="input-Dob-process"
/>
</label>
<label>
<input
value={props.activity}
onChange={props.handleChange}
type="text"
name="activity"
required
placeholder="Place of work or study (required)"
data-cy="input-activity-process"
/>
</label>
</div>
);
}
function Step2(props) {
if (props.currentStep !== 2) {
return null;
}
return (
<div className="form-group">
<label>
<input
value={props.topics}
onChange={props.handleChange}
type="text"
name="topics"
placeholder="Favorite topics: (Optional)"
/>
</label>
<label>
<input
type="text"
value={props.drinks}
onChange={props.handleChange}
name="drinks"
placeholder="Favorite drink: (Optional)"
/>
</label>
</div>
);
}
function Step3(props) {
if (props.currentStep !== 3) {
return null;
}
return (
<>
<ImageUpload/>
<div className="form-group">
<label>
<input
value={props.about}
onChange={props.handleChange}
className="form-control"
type="text"
name="about"
placeholder="Caption (Optional)"
/>
</label>
</div>
<button
type="submit"
className="btn"
data-cy="submit-process"
style={{
backgroundColor: "#3103ff",
marginBottom: "25px",
color: "#FFF"
}}
>
Save it
</button>
</>
);
}
const mapStateToProps = state => ({
user: state.user
});
const mapDispatchToProps = dispatch => ({
LogIn: (id, nickname, profileId) => dispatch(LogIn(id, nickname, profileId))
});
export default connect(mapStateToProps, mapDispatchToProps)(CreatingAccount);
backend for /process
router.post('/profile', async (req, res) => {
const {
name,
DoB,
activity,
topics,
about,
drinks,
avatar,
id,
} = req.body;
const user = await Person.findOne({ _id: id }).exec();
if (!user.profileId) {
const newProfile = await Profile.create({
person: id,
name,
DoB,
activity,
topics,
about,
drinks,
avatar,
});
await Person.updateOne(user, { $set: { profileId: newProfile._id } });
return res.send({
success: true,
});
}
await Person.updateOne({ _id: user.profileId }, {
$set: {
activity,
topics,
about,
drinks,
avatar,
},
});
});
In your axios post, add a .then and a .catch, console.log() the result of the post whether its a success or a failure, also, not sure if u have the favourite variable defined globally but that might also be a source of the error
Issue
In the case of backend errors the API is returning a valid response that is missing a profileId property.
router.post('/profileEdit', async (req, res) => {
const { id } = req.body;
const response = await Profile.findOne({ person: id });
if (response) {
res.send({ success: true, profileId: response });
} else {
res.send({ success: false, err: 'Something went wrong' }); // <-- here, no profileId
}
});
This doesn't cause axios to return a Promise rejection and the frontend code assumes the response object has certain properties.
The error object returned is { success: false, err: 'Something went wrong' } but the code is attempting to access into an undefined profileId property.
axios
.post("/users/profileEdit", { id })
.then(({ data }) => {
setPlace(data.profileId.place); // <-- here, data.profileId undefined
setAge(data.profileId.age);
setFavorite(data.profileId.favorite);
setCaption(data.profileId.cation);
profileInit(data.profileId);
});
data.profileId is undefined, and alone isn't an issue, it's later when trying to access the place property of an undefined object that an error is thrown.
Solution
You can keep the backend code and do a check in the frontend for a successful POST request.
axios
.post("/users/profileEdit", { id })
.then(({ data }) => {
if (data.success) {
// POST success
setPlace(data.profileId.place);
setAge(data.profileId.age);
setFavorite(data.profileId.favorite);
setCaption(data.profileId.cation);
profileInit(data.profileId);
} else {
// POST failure, check error
// access data.err
}
});
It would be better to return a non-200 status code so axios can throw/handle a rejected Promise. You can read more about HTTP status codes here. Below I'm returning a super general Status 500 error, but you will want to be a specific as you need to be, i.e. a 404 if the specific person object isn't found.
Example:
router.post('/profileEdit', async (req, res) => {
const { id } = req.body;
const response = await Profile.findOne({ person: id });
if (response) {
res.send({ profileId: response });
} else {
res.status(500).send({ err: 'Something went wrong' });
}
});
...
axios
.post("/users/profileEdit", { id })
.then(({ data }) => {
// 200 responses
const {
profileId,
profileId: { age, cation, favorite, place },
} = data;
setPlace(place);
setAge(age);
setFavorite(favorite);
setCaption(cation);
profileInit(profileId);
})
.catch(error => {
// non-200 responses
});

Group Video call using React-Native and Node js

I want to implement conference video call in React-native and node js using without any paid library
I was Implement single Person Video call using react-native-webrtc and node js Socket using Peer-to-Peer
My React-Native files below
My Privider Files
import React, { useState } from "react";
import { Alert } from "react-native";
import {
mediaDevices,
MediaStream,
MediaStreamConstraints,
} from "react-native-webrtc";
import socketio from "socket.io-client";
import ReactNativeForegroundService from "#supersami/rn-foreground-service";
import { MainContext as MainContextType, User } from "../interfaces";
import {
SERVER_URL,
PEER_SERVER_HOST,
PEER_SERVER_PORT,
PEER_SERVER_PATH,
} from "../server";
// #ts-ignore
import Peer from "react-native-peerjs";
import { navigate } from "../helpers/RootNavigation";
import InCallManager from "react-native-incall-manager";
const initialValues: MainContextType = {
username: "",
peerId: "",
users: [],
localStream: null,
remoteStream: null,
remoteUser: null,
initialize: () => {},
setUsername: () => {},
call: () => {},
switchCamera: () => {},
toggleMute: () => {},
isMuted: false,
isShareScreen: false,
toggleSpeacker: () => {},
isSpeaker: true,
swipeWindow: false,
closeCall: () => {},
reset: () => {},
localStreamSet: () => {},
activeCall: null,
};
export const MainContext = React.createContext(initialValues);
interface Props {}
const MainContextProvider: React.FC<Props> = ({ children }) => {
const [username, setUsername] = useState(initialValues.username);
const [peerId, setPeerId] = useState(initialValues.peerId);
const [users, setUsers] = useState<User[]>(initialValues.users);
const [localStream, setLocalStream] = useState<MediaStream | null>(
initialValues.localStream
);
const [remoteStream, setRemoteStream] = useState<MediaStream | null>(
initialValues.remoteStream
);
const [remoteUser, setRemoteUser] = useState<User | null>(null);
const [socket, setSocket] = useState<SocketIOClient.Socket | null>(null);
const [peerServer, setPeerServer] = useState<any>(null);
const [isMuted, setIsMuted] = useState(initialValues.isMuted);
const [swipeWindow, setSwipeWindow] = useState(initialValues.swipeWindow);
const [isShareScreen, setIsShareScreen] = useState(
initialValues.isShareScreen
);
// const localStreamSet=(newstream)=>{
// setLocalStream(null)
// }
const [isSpeaker, setIsSpeaker] = useState(initialValues.isSpeaker);
const [activeCall, setActiveCall] = useState<any>(null);
const initialize = async () => {
const isFrontCamera = true;
const devices = await mediaDevices.enumerateDevices();
const facing = isFrontCamera ? "front" : "environment";
const videoSourceId = devices.find(
(device: any) => device.kind === "videoinput" && device.facing === facing
);
const facingMode = isFrontCamera ? "user" : "environment";
const constraints: MediaStreamConstraints = {
audio: true,
video: {
mandatory: {
minWidth: 1280,
minHeight: 720,
minFrameRate: 30,
},
facingMode,
optional: videoSourceId ? [{ sourceId: videoSourceId }] : [],
},
};
const newStream = await mediaDevices.getUserMedia(constraints);
setLocalStream(newStream as MediaStream);
const io = socketio.connect(SERVER_URL, {
reconnection: true,
autoConnect: true,
});
io.on("connect", () => {
setSocket(io);
io.emit("register", username);
});
io.on("users-change", (users: User[]) => {
setUsers(users);
});
io.on("accepted-call", (user: User) => {
InCallManager.start("video");
setRemoteUser(user);
});
io.on("rejected-call", (user: User) => {
InCallManager.stop();
InCallManager.start();
setRemoteUser(null);
setActiveCall(null);
Alert.alert("Your call request rejected by " + user?.username);
navigate("Users");
});
io.on("not-available", (username: string) => {
setRemoteUser(null);
setActiveCall(null);
Alert.alert(username + " is not available right now");
navigate("Users");
});
const peerServer = new Peer(undefined, {
host: PEER_SERVER_HOST,
path: PEER_SERVER_PATH,
secure: true,
port: PEER_SERVER_PORT,
config: {
iceServers: [
{
urls: [
"stun:stun1.l.google.com:19302",
"stun:stun2.l.google.com:19302",
],
},
],
},
});
peerServer.on("error", (err: Error) =>
);
peerServer.on("open", (peerId: string) => {
setPeerServer(peerServer);
setPeerId(peerId);
io.emit("set-peer-id", peerId);
});
io.on("call", (user: User) => {
peerServer.on("call", (call: any) => {
InCallManager.startRingtone("_BUNDLE_");
setRemoteUser(user);
Alert.alert(
"New Call",
"You have a new call from " + user?.username,
[
{
text: "Reject",
onPress: () => {
InCallManager.stopRingtone();
InCallManager.stop();
io.emit("reject-call", user?.username);
setRemoteUser(null);
setActiveCall(null);
},
style: "cancel",
},
{
text: "Accept",
onPress: () => {
InCallManager.stopRingtone();
InCallManager.start();
InCallManager.setSpeakerphoneOn(true);
io.emit("accept-call", user?.username);
call.answer(newStream);
setActiveCall(call);
navigate("Call");
},
},
],
{ cancelable: false }
);
call.on("stream", (stream: MediaStream) => {
setRemoteStream(stream);
});
call.on("close", () => {
closeCall();
});
call.on("error", () => {});
});
});
};
const call = (user: User) => {
if (!peerServer || !socket) {
Alert.alert("Peer server or socket connection not found");
return;
}
if (!user.peerId) {
Alert.alert("User not connected to peer server");
return;
}
socket.emit("call", user.username);
setRemoteUser(user);
try {
const call = peerServer.call(user.peerId, localStream);
call.on(
"stream",
(stream: MediaStream) => {
setActiveCall(call);
setRemoteStream(stream);
},
(err: Error) => {
console.error("Failed to get call stream", err);
}
);
} catch (error) {
}
};
const switchCamera = () => {
if (localStream) {
// #ts-ignore
localStream.getVideoTracks().forEach((track) => track._switchCamera());
}
};
const toggleMute = () => {
if (localStream)
localStream.getAudioTracks().forEach((track) => {
track.enabled = !track.enabled;
setIsMuted(!track.enabled);
});
};
const toggleswipeWindow = () => {
var templocalstream = localStream;
var tempremotestream = remoteStream;
if (swipeWindow == false) {
setLocalStream(tempremotestream);
setRemoteStream(templocalstream);
setSwipeWindow(!swipeWindow);
} else {
setLocalStream(tempremotestream);
setRemoteStream(templocalstream);
setSwipeWindow(!swipeWindow);
}
};
const toggleScreenShare = async () => {
if (localStream)
if (isShareScreen == false) {
mediaDevices
.getDisplayMedia({ video: true, audio: true })
.then(handleSuccess, handleError);
InCallManager.setKeepScreenOn(true);
setIsShareScreen(true);
} else {
// localStream.getVideoTracks().forEach((track) => {track.stop()}
ReactNativeForegroundService.stop();
InCallManager.setKeepScreenOn(false);
setIsShareScreen(false);
}
};
const toggleSpeacker = () => {
if (localStream) InCallManager.start();
InCallManager.setSpeakerphoneOn(!isSpeaker);
setIsSpeaker(!isSpeaker);
};
const closeCall = () => {
activeCall?.close();
setActiveCall(null);
setRemoteUser(null);
navigate("Users");
Alert.alert("Call is ended");
};
const reset = async () => {
peerServer?.destroy();
socket?.disconnect();
setActiveCall(null);
setRemoteUser(null);
setLocalStream(null);
setRemoteStream(null);
setUsername("");
setPeerId("");
};
const handleError = async (error) => {
};
const handleSuccess = async (stream) => {
localStream.getVideoTracks().forEach((track) => {
localStream.removeTrack(track);
});
localStream.addTrack(stream.getTracks()[0]);
if (swipeWindow == true) {
setRemoteStream(stream);
} else {
setLocalStream(stream);
}
stream.getVideoTracks()[0].addEventListener("ended", () => {
});
};
return (
<MainContext.Provider
value={{
username,
setUsername,
peerId,
setPeerId,
users,
setUsers,
localStream,
setLocalStream,
remoteStream,
setRemoteStream,
initialize,
call,
switchCamera,
toggleMute,
isMuted,
isSpeaker,
toggleSpeacker,
closeCall,
reset,
remoteUser,
activeCall,
toggleScreenShare,
isShareScreen,
toggleswipeWindow,
swipeWindow,
// localStreamSet
}}
>
{children}
</MainContext.Provider>
);
};
export default MainContextProvider;
Callscreen.js File
import React, {useContext} from 'react';
import {
ActivityIndicator,
Dimensions,
StyleSheet,
Text,
View,
TouchableWithoutFeedback,
TouchableHighlight
} from 'react-native';
import {SafeAreaView} from 'react-native-safe-area-context';
import {RTCView} from 'react-native-webrtc';
import IconButton from '../components/IconButton';
import icons from '../constants/icons';
import {CallScreenNavigationProp} from '../interfaces/navigation';
import {MainContext} from '../store/MainProvider';
import InCallManager from 'react-native-incall-manager';
const {width, height} = Dimensions.get('window');
import RecordScreen from 'react-native-record-screen';
import Video from 'react-native-video';
interface Props {
navigation: CallScreenNavigationProp;
}
const Call = ({}: Props) => {
const {
localStream,
remoteStream,
activeCall,
remoteUser,
isMuted,
isSpeaker,
toggleSpeacker,
toggleScreenShare,
isShareScreen,
closeCall,
toggleMute,
switchCamera,
swipeWindow,
toggleswipeWindow
} = useContext(MainContext);
React.useEffect(() => {
if (InCallManager.recordPermission !== 'granted') {
InCallManager.requestRecordPermission()
.then((requestedRecordPermissionResult) => {
})
.catch((err) => {
});
}
});
const [recordscreen,setRecordScreen]=React.useState(false)
const btnStyle = React.useMemo(() => {
return recordscreen ? styles.btnActive : styles.btnDefault;
}, [recordscreen]);
const [uri, setUri] = React.useState('');
const _handleOnRecording = async () => {
if (recordscreen) {
setRecordScreen(false);
const res = await RecordScreen.stopRecording().catch((error) =>
console.warn(error)
);
if (res) {
setUri(res.result.outputURL);
}
} else {
setUri('');
setRecordScreen(true);
await RecordScreen.startRecording().catch((error) => {
console.warn(error);
setRecordScreen(false);
setUri('');
});
}
};
return (
<SafeAreaView style={styles.container}>
{uri ? (
<View style={styles.preview}>
<Video
source={{
uri,
}}
style={styles.video}
/>
</View>
) : null}
{remoteStream && (
<RTCView
key={2}
mirror={true}
style={styles.remoteStream}
streamURL={remoteStream.toURL()}
objectFit="cover"
/>
)}
{localStream && (
<View style={styles.myStreamWrapper}>
<TouchableWithoutFeedback onPress={toggleswipeWindow}>
<RTCView
style={styles.myStream}
objectFit="cover"
streamURL={localStream.toURL()}
zOrder={1}
/>
</TouchableWithoutFeedback>
</View>
)}
{!activeCall && (
<View style={styles.spinnerWrapper}>
<ActivityIndicator color="#341EFF" size={120} />
<Text style={styles.callingText}>Calling {remoteUser?.username}</Text>
</View>
)}
<View style={styles.iconsWrapper}>
<IconButton
icon={icons.CHANGE_CAMERA}
onPress={switchCamera}
iconColor={'#341EFF'}
backgroundColor="#fff"
/>
{isMuted ? (
<IconButton
icon={icons.UNMUTE}
onPress={toggleMute}
iconColor={'#fff'}
backgroundColor="red"
/>
) : (
<IconButton
icon={icons.MUTE}
onPress={toggleMute}
iconColor={'#341EFF'}
backgroundColor="#fff"
/>
)}
{isSpeaker ? (
<IconButton
icon={icons.SPEAKERON}
onPress={toggleSpeacker}
iconColor={'#341EFF'}
backgroundColor="#fff"
/>
) : (
<IconButton
icon={icons.SPEAKEROFF}
onPress={toggleSpeacker}
iconColor={'#341EFF'}
backgroundColor="#fff"
/>
)}
{recordscreen ? (
<IconButton
icon={icons.RECORDING}
onPress={_handleOnRecording}
iconColor={'#fff'}
backgroundColor="red"
/>
) : (
<IconButton
icon={icons.RECORDING}
onPress={_handleOnRecording}
iconColor={'#341EFF'}
backgroundColor="#fff"
/>
)}
{isShareScreen ? (
<IconButton
icon={icons.SCREENSHARE}
onPress={toggleScreenShare}
iconColor={'#fff'}
backgroundColor="red"
/>
) : (
<IconButton
icon={icons.SCREENSHARE}
onPress={toggleScreenShare}
iconColor={'#341EFF'}
backgroundColor="#fff"
/>
)}
<IconButton
icon={icons.END_CALL}
onPress={closeCall}
iconColor={'#fff'}
backgroundColor="red"
/>
</View>
</SafeAreaView>
);
};
export default Call;
const styles = StyleSheet.create({
preview: {
position: 'absolute',
right: 12,
bottom: 116,
width: Dimensions.get('window').width / 2,
height: Dimensions.get('window').height / 3,
zIndex: 1,
padding: 8,
backgroundColor: '#aaa',
},
video: {
flex: 1,
},
container: {
backgroundColor: '#0f0f0f',
flex: 1,
position: 'relative',
},
btnDefault: {
width: 48,
height: 48,
backgroundColor: '#fff',
borderRadius: 24,
borderWidth: 4,
borderStyle: 'solid',
borderColor: '#212121',
},
btnActive: {
width: 36,
height: 36,
backgroundColor: 'red',
borderRadius: 8,
},
myStream: {
height: width * 0.6,
width: width * 0.4,
},
myStreamWrapper: {
position: 'absolute',
bottom: 20,
right: 20,
height: width * 0.6 + 8,
width: width * 0.4 + 8,
backgroundColor: '#333',
borderRadius: 12,
overflow: 'hidden',
justifyContent: 'center',
alignItems: 'center',
},
remoteStreamWrapper: {},
remoteStream: {
width: '100%',
height: '100%',
},
spinnerWrapper: {
top: height * 0.3,
width: '100%',
justifyContent: 'center',
alignItems: 'center',
},
callingText: {
fontSize: 26,
color: '#fff',
},
iconsWrapper: {
position: 'absolute',
bottom: 20,
left: 20,
},
});
Socket Server.js
//socketio
const socketio = require("socket.io");
class SocketService {
io;
constructor() {
this.io = null;
}
listen = (server) => {
this.io = socketio(server);
this.io.users = {};
this.io.on("connection", (socket) => {
socket.on("register", (username) => this.onRegister(socket, username));
socket.on("set-peer-id", (peerId) => this.onSetPeerId(socket, peerId));
socket.on("call", (username) => this.onCall(socket, username));
socket.on("reject-call", (username) =>
this.onRejectCall(socket, username)
);
socket.on("accept-call", (username) =>
this.onAcceptCall(socket, username)
);
console.log(`${Date(Date.now()).toLocaleString()}: new user connected`);
socket.on("disconnect", () => this.onDisconnect(socket));
});
};
onAcceptCall = (socket, username) => {
if (this.io.users[username])
this.io
.to(this.io.users[username].socketId)
.emit("accepted-call", this.io.users[socket.username]);
};
onRejectCall = (socket, username) => {
if (this.io.users[username]) {
this.io
.to(this.io.users[username].socketId)
.emit("rejected-call", this.io.users[socket.username]);
}
};
onCall = (socket, username) => {
if (this.io.users[username]) {
this.io
.to(this.io.users[username].socketId)
.emit("call", this.io.users[socket.username]);
} else {
socket.emit("not-available", username);
}
};
onRegister = (socket, username) => {
console.log("Registered", username);
socket.username = username;
this.io.users[username] = {
username,
peerId: "",
socketId: socket.id,
};
this.onUsersChange(socket);
};
getUsers = () => {
const users = [];
Object.keys(this.io.users).forEach((key) => {
users.push(this.io.users[key]);
});
return users;
};
onUsersChange = (socket) => {
this.io.emit("users-change", this.getUsers());
};
onSetPeerId = (socket, peerId) => {
console.log("Set Peer Id user:", socket.username, " peerId: ", peerId);
this.io.users[socket.username] = {
peerId,
socketId: socket.id,
username: socket.username,
};
this.onUsersChange();
};
onDisconnect = (socket) => {
delete this.io.users[socket.username];
console.log(
`${Date(Date.now()).toLocaleString()} ID:${
socket.username
} user disconnected`
);
this.onUsersChange();
};
emit = (event, userId, data) => {
if (this.io.users[userId]) {
this.io.to(this.io.users[userId]).emit(event, data);
}
};
}
module.exports = new SocketService();
Peer Server.js (2nd API server in Node js)
require('dotenv').config()
const express = require("express");
const { ExpressPeerServer } = require("peer");
const app = express();
app.get("/", (req, res, next) => res.send("Hello world!"));
const http = require("http");
const server = http.createServer(app);
const peerServer = ExpressPeerServer(server, {
debug: true,
path: "/",
});
app.use("/peerjs", peerServer);
server.listen(process.env.PORT || 9000);

Remove object from array with specific index (MongoDB, NodeJS, React)

I have app with devices-array which have objects
with device_name and device_id. I'd like to remove specific device depending which device user want's to remove from devices array.
I've already tryied to findIndex and indexOf -methods, but it return's undefined for request. How to access device depending which device user want's to remove?
deviceController.js
'use strict'
import Users from '../models/userModel.js'
deleteDevice: async (req, res) => {
try {
const { device } = req.body.device.device_id
const dev = await Users.findOne({ _id: req.user.id }).populate('device')
const devs = dev.device //devices
const index = devs.findIndex(req.body.device)
const devic = devs.slice(index, 1)
await Users.findOneAndUpdate({ _id: req.user.id }, { device: devic })
res.json({ msg: 'Deleted success' })
} catch (err) {
return res.status(500).json({ msg: err.message })
}
}
export { deviceControl }
import React, { useState, useEffect } from 'react'
import { Link } from 'react-router-dom'
import axios from 'axios'
import { useSelector, useDispatch } from 'react-redux'
import { FontAwesomeIcon } from '#fortawesome/react-fontawesome'
import { faEdit, faTrash } from '#fortawesome/free-solid-svg-icons'
import { Container, Table } from 'react-bootstrap'
import { showErr, showSuccess } from '../utils/notifications/Notification'
import {
fetchAllUsers,
dispatchGetAllUsers
} from '../../redux/actions/usersAction'
import '../../index.css'
//initialize device
const initialState = {
device: { device_name: '', _id: '', device_id: '' },
err: '',
success: ''
}
function AllDevices() {
//authentication
const auth = useSelector((state) => state.auth)
//token
const token = useSelector((state) => state.token)
//set data
const [data, setData] = useState(initialState)
//users
const users = useSelector((state) => state.users)
const { device_name, device_id, err, success } = data
//loading
const [loading, setLoading] = useState(false)
//authentication
const { user, isAdmin } = auth
const dispatch = useDispatch()
const handleChange = (e) => {
const { name, value } = e.target
setData({ ...data, [name]: value, err: '', success: '' })
}
useEffect(() => {
if (isAdmin) {
fetchAllUsers(token).then((res) => {
dispatch(dispatchGetAllUsers(res))
})
}
if (isAdmin || user) {
setData(initialState)
}
}, [token, user, isAdmin, dispatch, loading])
const updateDeviceName = async () => {
try {
if (window.confirm('Are you sure you want to rename this device?')) {
await axios.patch(
`/device/edit/${data.device._id}/${data.device.device_name}`,
{
device: { device_name, device_id }
},
{
headers: { Authorization: token }
}
)
}
setData({ ...data, err: '', success: 'Updated Success!' })
} catch (err) {
setData({ ...data, err: err.response.data.msg, success: '' })
}
}
const handleUpdate = () => {
if (device_name) updateDeviceName(device_name)
}
const handleDelete = async () => {
try {
if (window.confirm('Are you sure you want to delete this device?')) {
setLoading(true)
await axios.patch(
`/device/delete/${data.device}`,
{ device: data.device },
{
headers: { Authorization: token }
}
)
}
setData({ ...data, err: '', success: 'Updated Success!' })
} catch (err) {
setData({ ...data, err: err.response.data.msg, success: '' })
}
}
return (
<>
<h5 className='m-5'>
{' '}
<Link to='/'>
<i className='fas fa-undo-alt'></i>Takaisin
</Link>
</h5>
<Container fluid='sm'>
<div>
{err && showErr(err)}
{success && showSuccess(success)}
{loading && <h3>Loading.....</h3>}
</div>
<Table bordered hover variant='light' responsive>
<tbody>
<tr>
<th>Nimi</th>
<th>Laite</th>
</tr>
{/* Loop through user details */}
{users.map((p) => (
<tr>
<td>
{p.name}
<br />
{p.email}
</td>
<td>
{p.device.map((d) => (
<div>
<div
className='d-flex-inline'
style={{
position: 'relative',
width: '170px'
}}
>
{' '}
<input
type='text'
style={{
fontSize: '16px',
width: '100px'
}}
defaultValue={d.device_name}
name='device_name'
onChange={handleChange}
/>{' '}
<FontAwesomeIcon
style={{
position: 'absolute',
top: '3px',
right: '70px',
zIndex: '2'
}}
icon={faEdit}
title='Edit'
onClick={() => handleUpdate(d.device_name)}
/>{' '}
</div>
<div
className='d-flex'
style={{
position: 'relative',
width: '100px'
}}
>
<input
type='text'
style={{
fontSize: '14px',
width: '200px',
color: '#333'
}}
defaultValue={d.device_id}
disabled
name='device_id'
/>{' '}
<FontAwesomeIcon
style={{
position: 'absolute',
top: '3px',
right: '3px',
zIndex: '2'
}}
icon={faTrash}
title='Trash'
onClick={() => handleDelete(d.device)}
/>{' '}
</div>
</div>
))}
</td>
</tr>
))}
</tbody>
</Table>
</Container>
</>
)
}
export default AllDevices
const deviceSchema = mongoose.Schema({
device_id: { type: Number, required: true },
device_name: { type: String, required: true }
})
const userSchema = new mongoose.Schema(
{
name: {
type: String,
required: [true, 'Please enter your name!']
},
email: {
type: String,
required: [true, 'Please enter your email!']
},
device: [deviceSchema, { type: mongoose.Schema.Types.ObjectId }],
password: {
type: String,
required: [true, 'Please enter your password!']
},
days: { type: Date },
role: {
type: Number,
default: 0 // 0 = user 1= admin 3=visitor
}
},
{
timestamps: true
}
)
const Users = mongoose.model('User', userSchema)
export default Users
import { deviceControl } from '../controllers/deviceController.js'
import express from 'express'
import auth from '../middleware/auth.js'
import authAdmin from '../middleware/authAdmin.js'
const router = express.Router()
router.get('/device', auth, authAdmin, deviceControl.getUsersAllDevices)
router.post('/device', auth, authAdmin, deviceControl.getUsersAllDevices)
router.patch('/device/delete/:id', auth, authAdmin, deviceControl.deleteDevice)
router.put('/add_device', auth, deviceControl.addDevice)
router.patch('/device/edit', auth, deviceControl.updateDeviceName)
export default router
try using JS filter function.
const removeDevice(devices, id) => {
return devices.filter(device => device.id !== id)
}

How to Sort comments to show the newest comments on top and old ones at the bottom in Express or React

I am working on a Mern-stack Application, in my Application, I have an Event model and the event has many comments. how do I sort the comments to show the newest comments on top while the old ones will be at the bottom?
And where should I make this logic? in the API (backend) or frontend (React)? The comment have an attribute called createdAt a new date gets inserted into createdAt attribute anytime a comment is created.
This is how I fetch an Event with comments in my Express backend
router.get("/:id/eventcomments", async (req, res) => {
const event = await Event.findById({ _id: req.params.id }).populate(
"eventcomments"
);
res.json(event);
});
and Here is the Schema Model for comment.
const eventcommentSchema = new mongoose.Schema({
description: {
type: String,
required: true
},
name: {
type: String,
required: true
},
createdAt: {
type: Date,
required: true,
default: Date.now
},
event: { type: Schema.Types.ObjectId, ref: 'Event'}
})
Here is my Component
export default function EventAndComments(props) {
const EventComment = (props) => (
<CardContent>
<Typography variant="body2" color="textSecondary" component="p">
{props.comment.name}
</Typography>
<Typography variant="body2" color="textSecondary" component="p">
{props.comment.description}
</Typography>
</CardContent>
);
const theme = useTheme();
const [events, setEventData] = useState([]);
const [comments, setCommentData] = useState([]);
const useStyles = makeStyles((theme) => ({
root: {
maxWidth: 550,
},
media: {
height: 0,
paddingTop: "86%", // 16:9
display: "flex",
flexDirection: "column",
alignItems: "center",
},
expand: {
transform: "rotate(0deg)",
marginLeft: "auto",
transition: theme.transitions.create("transform", {
duration: theme.transitions.duration.shortest,
}),
},
expandOpen: {
transform: "rotate(180deg)",
},
avatar: {
backgroundColor: red[500],
},
}));
const classes = useStyles();
const [expanded, setExpanded] = React.useState(false);
const handleExpandClick = () => {
setExpanded(!expanded);
};
useEffect(() => {
axios
.get(
"http://localhost:9000/events/" +
props.match.params.id +
"/eventcomments"
)
.then((response) => {
setEventData(response.data);
})
.catch(function (error) {
console.log(error);
});
}, []);
const onPageLoad = () => {
axios
.get(
"http://localhost:9000/events/" +
props.match.params.id +
"/eventcomments"
)
.then((response) => {
setCommentData(response.data.eventcomments);
})
.catch(function (error) {
console.log(error);
});
};
useEffect(() => {
onPageLoad();
}, []);
const nowIso = new Date();
const getTitle = (startDateTs, endDateTs) => {
const now = Date.parse(nowIso);
if (endDateTs <= now) {
return "Started:" + " " + moment(startDateTs).format("LLLL");
}
if (startDateTs < now && endDateTs > now) {
return "Live:" + " " + moment(startDateTs).format("LLLL");
}
return "Starting:" + " " + moment(startDateTs).format("LLLL");
};
const getEnded = (startDateTs, endDateTs) => {
const now = Date.parse(nowIso);
if (endDateTs <= now) {
return "Ended:" + " " + moment(startDateTs).format("LLLL");
}
if (startDateTs < now && endDateTs > now) {
return "Will End:" + " " + moment(startDateTs).format("LLLL");
}
return "Ends:" + " " + moment(startDateTs).format("LLLL");
};
const [eventDescription, setEventComment] = React.useState("");
const [name, setName] = React.useState("");
const handleChange = (parameter) => (event) => {
if (parameter === "name") {
setName(event.target.value);
}
if (parameter === "description") {
setEventComment(event.target.value);
}
};
const onSubmit = useCallback(
(e) => {
e.preventDefault();
axios
.post(
"http://localhost:9000/events/" +
props.match.params.id +
"/eventcomment",
{ name: name, description: eventDescription }
)
.then(function (response) {
onPageLoad();
})
.catch(function (error) {
console.log(error);
});
},
[props.match.params.id, name, eventDescription]
);
let eventCommentList = comments.map((comment, k) => (
<EventComment comment={comment} key={k} />
));
return (
<Grid
container
spacing={0}
direction="column"
alignItems="center"
justify="center"
style={{ minHeight: "100vh" }}
>
<Card className={classes.root}>
<h3
style={{
background: " #800000",
color: "white",
textAlign: "center",
}}
className={classes.cardheader}
>
{events.title}
</h3>
<CardHeader
avatar={
<Avatar aria-label="recipe" className={classes.avatar}>
CB
</Avatar>
}
action={
<IconButton aria-label="settings">
<MoreVertIcon />
</IconButton>
}
title={getTitle(
Date.parse(events.startingDate),
Date.parse(events.closingDate)
)}
subheader={getEnded(
Date.parse(events.startingDate),
Date.parse(events.closingDate)
)}
style={{ background: "#DCDCDC" }}
/>
<CardMedia
className={classes.media}
image={events.eventImage}
title="Paella dish"
/>
<CardContent>
<Typography variant="body2" color="textSecondary" component="p">
{events.description}
</Typography>
</CardContent>
</Card>
<form
className={classes.root}
noValidate
autoComplete="off"
onSubmit={onSubmit}
>
<FormControl>
<InputLabel htmlFor="component-simple">Name</InputLabel>
<Input
id="component-simple"
value={name}
onChange={handleChange("name")}
label="Name"
/>
</FormControl>
<FormControl variant="outlined">
<InputLabel htmlFor="component-outlined">Description</InputLabel>
<OutlinedInput
id="component-outlined"
value={eventDescription}
onChange={handleChange("description")}
label="Description"
/>
</FormControl>
<Button type="submit" fullWidth variant="contained" color="primary">
Create Comment
</Button>
</form>
<CardContent>{eventCommentList}</CardContent>
</Grid>
);
}
}
I have added all my codes.
You can sort functionality in mongoose like this
const event = await Event.findById({ _id: req.params.id }).populate("eventcomments").sort({createdAt:-1});
You can read more about it here
Update
Try passing it as an option
const event = await Event.findById({ _id: req.params.id },null,{sort:{createdAt:-1}}).populate("eventcomments")
Strictly speaking, you don't really need the createdAt field. MongoDB ObjectIds encode the time of object creation. From the MongoDB docs:
sorting on an _id field that stores ObjectId values is roughly equivalent to sorting by creation time.
See: https://docs.mongodb.com/v3.0/reference/bson-types/#objectid
You can also extract the timestamp from an objectId by using ObjectId.getTimestamp().
However, if you're trying to sort sub-documents, then you can't do it in a query on the parent. You're going to have to use an aggregation pipeline, since the sort command is going to sort your Events, not your comments.
In your use case though, you would be better off storing the whole comment document on the event document. Every time someone posts a comment it should get pushed into the array of comments on the event, where it will live already sorted. This will prevent your server from having to do a TON of lookups and document modifications every time someone requests an event. The way you have things set up now, your database will receive (1 * the number of comments) read requests every time someone looks up an event. Then it will have to insert those comments into your event document. This is fine in relational database systems; It's what they're designed to do. It doesn't work so well in NoSQL databases.
This is referred to as an embedded document pattern. And if you want to use MongoDB, then it's a very good idea to familiarize with it. Here is an in depth link where you can find more info on this pattern and its usefulness in a NoSQL system:
https://docs.mongodb.com/manual/tutorial/model-embedded-one-to-many-relationships-between-documents/
I have managed to make it work with this code.
router.get("/:id/eventcomments", async (req, res) => {
Event.findById({ _id: req.params.id })
.populate("eventcomments", "_id name description createdAt",
null, {
sort: { createdAt: -1 },
})
.exec(function (error, results) {
res.json(results);
});
});
the difference between what I have here and the example given above is that it requires that I pass in the names of my fields.

How to clear input field after a successful Submittion in React, using useEffect function component

I am working on a Mern-stack Application, but I'm not able to clear the input field after a successful post Request. I am using a function-based component with useEffect.
I tried examples I got here on Stack Overflow but it still didn't work. After submitting successfully the input still left in the input field. How do I make this to clear?
I have tried setCommentData([]) after the submit but it didn't work.
Here is my Component
export default function EventAndComments(props) {
const EventComment = (props) => (
<CardContent>
<Typography variant="body2" color="textSecondary" component="p">
{props.comment.name}
</Typography>
<Typography variant="body2" color="textSecondary" component="p">
{props.comment.description}
</Typography>
</CardContent>
);
const theme = useTheme();
const [events, setEventData] = useState([]);
const [comments, setCommentData] = useState([]);
const useStyles = makeStyles((theme) => ({
root: {
maxWidth: 550,
},
media: {
height: 0,
paddingTop: "86%", // 16:9
display: "flex",
flexDirection: "column",
alignItems: "center",
},
expand: {
transform: "rotate(0deg)",
marginLeft: "auto",
transition: theme.transitions.create("transform", {
duration: theme.transitions.duration.shortest,
}),
},
expandOpen: {
transform: "rotate(180deg)",
},
avatar: {
backgroundColor: red[500],
},
}));
const classes = useStyles();
const [expanded, setExpanded] = React.useState(false);
const handleExpandClick = () => {
setExpanded(!expanded);
};
useEffect(() => {
axios
.get(
"http://localhost:9000/events/" +
props.match.params.id +
"/eventcomments"
)
.then((response) => {
setEventData(response.data);
})
.catch(function (error) {
console.log(error);
});
}, []);
const onPageLoad = () => {
axios
.get(
"http://localhost:9000/events/" +
props.match.params.id +
"/eventcomments"
)
.then((response) => {
setCommentData(response.data.eventcomments);
})
.catch(function (error) {
console.log(error);
});
};
useEffect(() => {
onPageLoad();
}, []);
const nowIso = new Date();
const getTitle = (startDateTs, endDateTs) => {
const now = Date.parse(nowIso);
if (endDateTs <= now) {
return "Started:" + " " + moment(startDateTs).format("LLLL");
}
if (startDateTs < now && endDateTs > now) {
return "Live:" + " " + moment(startDateTs).format("LLLL");
}
return "Starting:" + " " + moment(startDateTs).format("LLLL");
};
const getEnded = (startDateTs, endDateTs) => {
const now = Date.parse(nowIso);
if (endDateTs <= now) {
return "Ended:" + " " + moment(startDateTs).format("LLLL");
}
if (startDateTs < now && endDateTs > now) {
return "Will End:" + " " + moment(startDateTs).format("LLLL");
}
return "Ends:" + " " + moment(startDateTs).format("LLLL");
};
const [eventDescription, setEventComment] = React.useState("");
const [name, setName] = React.useState("");
const handleChange = (parameter) => (event) => {
if (parameter === "name") {
setName(event.target.value);
}
if (parameter === "description") {
setEventComment(event.target.value);
}
};
const onSubmit = useCallback(
(e) => {
e.preventDefault();
axios
.post(
"http://localhost:9000/events/" +
props.match.params.id +
"/eventcomment",
{ name: name, description: eventDescription }
)
.then(function (response) {
onPageLoad();
})
.catch(function (error) {
console.log(error);
});
},
[props.match.params.id, name, eventDescription]
);
let eventCommentList = comments.map((comment, k) => (
<EventComment comment={comment} key={k} />
));
return (
<Grid
container
spacing={0}
direction="column"
alignItems="center"
justify="center"
style={{ minHeight: "100vh" }}
>
<Card className={classes.root}>
<h3
style={{
background: " #800000",
color: "white",
textAlign: "center",
}}
className={classes.cardheader}
>
{events.title}
</h3>
<CardHeader
avatar={
<Avatar aria-label="recipe" className={classes.avatar}>
CB
</Avatar>
}
action={
<IconButton aria-label="settings">
<MoreVertIcon />
</IconButton>
}
title={getTitle(
Date.parse(events.startingDate),
Date.parse(events.closingDate)
)}
subheader={getEnded(
Date.parse(events.startingDate),
Date.parse(events.closingDate)
)}
style={{ background: "#DCDCDC" }}
/>
<CardMedia
className={classes.media}
image={events.eventImage}
title="Paella dish"
/>
<CardContent>
<Typography variant="body2" color="textSecondary" component="p">
{events.description}
</Typography>
</CardContent>
</Card>
<form
className={classes.root}
noValidate
autoComplete="off"
onSubmit={onSubmit}
>
<FormControl>
<InputLabel htmlFor="component-simple">Name</InputLabel>
<Input
id="component-simple"
value={name}
onChange={handleChange("name")}
label="Name"
/>
</FormControl>
<FormControl variant="outlined">
<InputLabel htmlFor="component-outlined">Description</InputLabel>
<OutlinedInput
id="component-outlined"
value={eventDescription}
onChange={handleChange("description")}
label="Description"
/>
</FormControl>
<Button type="submit" fullWidth variant="contained" color="primary">
Create Comment
</Button>
</form>
<CardContent>{eventCommentList}</CardContent>
</Grid>
);
}
}
I have added all my codes above.
In your onSubmit function, call setName("") and setEventComment("") to clear those values.
Also, just to follow conventions, I would rename setEventComment to setEventDescription since the state variable is named eventDescription not eventComment.

Resources