React Dropzone Uploader S3 - reactjs

we are using react dropzone uploader to upload video to s3 uisng presigned URL.
Below is the code:-
const MyUploader = () => {
const [snackBarOpen, setSnackBarOpen] = React.useState(false);
const [snackbarTitle, setSnackbarTitle] = React.useState("");
const handleClose = (event, reason) => {
if (reason === "onclick") {
return;
}
setSnackBarOpen(false);
}
const getUploadParams = async ({ meta: { name } }) => {
const { fields, uploadUrl, fileUrl } = await getPresignedUploadParams(name)
console.log(fields, uploadUrl, fileUrl)
return { fields, meta: { fileUrl }, url: uploadUrl }
}
// called every time a file's `status` changes
const handleChangeStatus = ({ meta, file }, status) =>
{
console.log(status)
if(status == "done") {
setSnackbarTitle("File uploaded Successfuly")
setSnackBarOpen(true)
window.location.reload(false);
}
else if (status == "error_upload") {
setSnackbarTitle("error!!Please check")
setSnackBarOpen(true)
}
else if (status == "uploading") {
setSnackbarTitle("Uploading..Please wait don't close or refresh")
setSnackBarOpen(true)
}
else {
setSnackbarTitle(status)
setSnackBarOpen(true)
}
}
return (
<div>
<Dropzone
getUploadParams={getUploadParams}
onChangeStatus={handleChangeStatus}
accept="video/*"
/>
<SnackBar
open={snackBarOpen}
close={handleClose}
snackbarTitle={snackbarTitle}
/>
</div>
)
}
we are getting below error
we try to find to find similar question in SO and found The authorization mechanism you have provided is not supported. Please use AWS4-HMAC-SHA256
As per above post have set signature version and region_name in backend.
<Error
>
<Code
>
InvalidRequest
</Code
>
<Message
>
The authorization mechanism you have provided is not supported. Please use AWS4-HMAC-SHA256.
</Message
>
<RequestId
>
5AZHFFW9Y080TTV5
</RequestId
>
<HostId
>
DzzSjYtIP73RoKN/UrNX5hgCOxJIMfwfE9HAuRlZrLKmK82n+ssBdf6jMUfbNXp4znfOX3LfrMU=
</HostId
>
</Error>
we have set signature version in backend.
client = boto3.client(
's3',
aws_access_key_id=Settings().AWSAccessKeyId,
aws_secret_access_key=Settings().AWSSecretKey,
config=Config(signature_version='s3v4'),
region_name="ap-south-1"
)
It could be great if we can get help to resolve this.

Related

Handle upload multiple files in Dragger ant design component react js

i'm trying upload multiple file with Dragger of ant design, but when I upload multiple files the onChange event is also called multiple times, it causes duplicate files
const handleChange = ({ fileList }) => {
console.log(fileList);
setFileList(fileList.filter(file => file.status !== "error"));
var notUploadYet = fileList.reduce((accumulator, file) => {
if (!fileUploaded.find(x => x.name === file.name)) {
accumulator.push(file);
}
return accumulator;
}, [])
const handleUpload = async () => {
try {
for await (const file of notUploadYet) {
const typeMedia = file.type.split('/')[0]
var nameOnCloud = typeMedia === "video" ? `videos/${file.name + v4()}` : `images/${file.name + v4()}`
const storageRef = ref(storage, nameOnCloud);
await uploadBytes(storageRef, file.originFileObj)
console.log('upload success')
try {
const link = await getDownloadURL(storageRef)
setFileUploaded([...fileUploaded,
{
name: file.name,
link: link,
nameOnCloud: nameOnCloud,
type: typeMedia
}
])
} catch (error) {
console.log(error)
}
}
} catch (error) {
console.log(error)
}
}
handleUpload()
}
<Dragger
listType="picture-card"
fileList={fileList}
beforeUpload={beforeUpload}
onPreview={handlePreview}
onChange={handleChange}
onRemove={handleOnRemove}
multiple={true}
>
<AiOutlineUpload style={{ 'fontSize': 30 }} />
<div className="uploadText">
<p>Kéo và thả ở đây hoặc click để chọn</p>
</div>
</Dragger>
I want the onChange event to be called only once when I upload multiple files

Strange Sockets Behavior with React - [RESOLVED]

I am new to using Web Sockets, and am trying to use the Sockets.io library to finish a chat application I am building. When a message is sent, the recipient receives the message twice, which is obviously not how the app is supposed to work.
I built a Socket context that joins the user into a room that is represented by their unique MongoDB identifier so they can be reached regardless of whichever chat they may be currently viewing. I tried to build it so that each chat the user views enters them into a new room while simultaneously causing them to leave the room for the chat they were viewing previously.
This is my code for the socket-related portion of my server:
io.on('connection', socket => {
socket.on('setup', userData => {
socket.join(userData._id);
});
socket.on('join chat', chatId => {
socket.join(chatId);
});
socket.on('new message', message => {
let chat = message.chat;
chat.users.forEach(user => {
if (user._id === message.sender._id) return;
socket.to(user._id).emit('message received', message);
});
});
socket.on('leave chat', chatId => {
socket.leave(chatId);
});
Here is the relevant code for my socket context (if a new user signs in then it should close the old socket and create a new room representing the new user):
useEffect(() => {
if (!currentUser) return;
const newSocket = io(ENDPOINT);
newSocket.emit('setup', currentUser);
setSocket(newSocket);
return () => newSocket.close();
}, [currentUser]);
And, finally, here is the code within the chat instance component:
useEffect(() => {
if (!socket) return;
socket.emit('join chat', activeChat[0]._id);
return () => socket.emit('leave chat', activeChat[0]._id);
}, [activeChat, socket]);
useEffect(() => {
if (!socket) return;
socket.on('message received', message => {
if (!activeChat[0]._id || message.chat._id !== activeChat[0]._id) {
if (!notifications) return;
setNotifications(prevState => [message, ...prevState]);
return;
} else {
setMessages(prevState => {
return [...prevState, message];
});
}
});
}, [activeChat, fetchChats, notifications, socket, setNotifications]);
Just as a side note, I had the application working previously when I kept the socket instance inside of the chat instance (and did not try importing it from the socket hook), but it inhibited my ability for the user to be contacted while viewing another chat since removed the socket instance when the chat instance unmounted by calling return () => socket.close(). Here is that code:
let socket; // Global scope
useEffect(() => {
socket = io(ENDPOINT);
socket.emit('setup', currentUser);
socket.emit('stop typing', activeChat[0]._id, currentUser);
return () => socket.close();
}, [currentUser, activeChat]);
If there is anything I can clarify, please let me know! Thanks so much for the help :)
EDIT: So I fixed my problem and it had to do with how I was handling the event listeners on the client side, which I was never unmounting. For anyone in the future who faces the same problem, please see the code below that I used to handle user messaging, typing, and handling changes to which users are online. Namaste.
Server.js (relevant portion):
global.onlineUsers = new Map();
io.on('connection', socket => {
socket.on('setup', userId => {
socket.join(userId);
global.onlineUsers.set(userId, socket.id);
for (const [
onlineUserId,
_onlineSocketId,
] of global.onlineUsers.entries()) {
if (onlineUserId === userId) {
socket.emit('logged in user change', [...global.onlineUsers]);
return;
} else {
socket
.to(onlineUserId)
.emit('logged in user change', [...global.onlineUsers]);
}
}
});
socket.on('join room', chatId => {
socket.join(chatId);
});
socket.on('leave room', chatId => {
socket.leave(chatId);
});
socket.on('send-msg', message => {
message.chat.users.forEach(user => {
if (user._id === message.sender._id) return;
socket.to(user._id).emit('msg-received', message);
});
});
socket.on('typing', (room, user) => {
socket.to(room).emit('typing', user.userName);
});
socket.on('stop typing', (room, user) =>
socket.to(room).emit('stop typing', user.userName)
);
socket.on('log out', userId => {
socket.leave(userId);
global.onlineUsers.delete(userId);
for (const [
onlineUserId,
_onlineSocketId,
] of global.onlineUsers.entries()) {
socket
.to(onlineUserId)
.emit('logged in user change', [...global.onlineUsers]);
}
});
});
Socket Context (relevant portion):
useEffect(() => {
if (!currentUser) return;
const newSocket = io(ENDPOINT);
newSocket.emit('setup', currentUser._id);
newSocket.on('logged in user change', users => {
const userIdArr = users.map(([userId, socketId]) => userId);
setOnlineUsers(userIdArr);
});
setSocket(newSocket);
return () => {
newSocket.off('logged in user change');
newSocket.emit('log out', currentUser._id);
};
}, [currentUser]);
Chat Instance (entire component):
import { useCallback, useEffect, useState } from 'react';
import { io } from 'socket.io-client';
import Lottie from 'lottie-react';
import { useChatView } from '../../contexts/chat-view-context';
import Spinner from '../spinner/spinner.component';
import './message-view.styles.scss';
import { useAuthentication } from '../../contexts/authentication-context';
import animationData from '../../animations/typing.json';
import {
defaultToast,
sameSenderAndNotCurrentUser,
TOAST_TYPE,
userSent,
getTyperString,
} from '../../utils/utils';
import { useSocket } from '../../contexts/socket-context';
// Could definitely add timestamp data to the message as well, that would be pretty clean actually
let typingTimer;
const MessageView = () => {
// Somehow we are going to have to get all of the message in a conversation potentially and then mark whether or not they are your messages or someone else's to style accordingly;
const { currentUser } = useAuthentication();
const { activeChat, notifications, setNotifications, fetchChats } =
useChatView();
const { socket } = useSocket();
// const [socketConnected, setSocketConnected] = useState(false);
const [messages, setMessages] = useState([]);
const [isLoading, setIsLoading] = useState(false);
const [isTyping, setIsTyping] = useState(false);
const [typing, setTyping] = useState(false);
const [typers, setTypers] = useState([]);
// console.log('typers from outside', typers);
// So I am thinking that I can definitely scroll into view whatever message is actually clicked within whatever chat, I don't see why that would not be possible?
// Pretty cool, when the component actually mounts, the ref for the element gets passed into the callback function, could actually do some pretyy coll things with this, like making an animation or shake the screen or bounce the message or anything when the message actually enters the screen...
const handleKeyDown = async e => {
if (!socket) return;
const newMessage = e.target.innerHTML;
if (e.key === 'Enter' && newMessage) {
e.preventDefault();
e.target.innerHTML = '';
try {
const response = await fetch(`http://localhost:4000/api/message`, {
method: 'post',
headers: {
Authorization: `Bearer ${currentUser.token}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
chatId: activeChat[0]._id,
text: newMessage,
}),
});
const message = await response.json();
socket.emit('send-msg', message);
setMessages(prevState => [...prevState, message]);
setTyping(false);
return;
} catch (error) {
defaultToast(TOAST_TYPE.error, 'Error sending');
}
} else {
if (!typing) {
setTyping(true);
socket.emit('typing', activeChat[0]._id, currentUser);
}
const lastTypingTime = new Date().getTime();
const timerLength = 3000;
if (typingTimer) clearTimeout(typingTimer);
typingTimer = setTimeout(() => {
const timeNow = new Date().getTime();
const timeDiff = timeNow - lastTypingTime;
if (timeDiff >= timerLength) {
socket.emit('stop typing', activeChat[0]._id, currentUser);
setTyping(false);
}
}, timerLength);
}
};
const fetchMessages = useCallback(async () => {
if (!socket) return;
if (!activeChat) return;
setIsLoading(true);
const response = await fetch(
`http://localhost:4000/api/message/${activeChat[0]._id}`,
{
method: 'get',
headers: { Authorization: `Bearer ${currentUser.token}` },
}
);
const messages = await response.json();
setMessages(messages);
setIsLoading(false);
}, [activeChat, currentUser.token, socket]);
useEffect(() => {
fetchMessages();
}, [fetchMessages, activeChat]);
useEffect(() => {
if (!socket) return;
socket.emit('join room', activeChat[0]._id);
socket.emit('stop typing', activeChat[0]._id, currentUser);
return () => socket.emit('leave room', activeChat[0]._id);
}, [activeChat, socket, currentUser]);
useEffect(() => {
if (!socket) return;
socket.on('msg-received', message => {
if (!activeChat[0]._id || message.chat._id !== activeChat[0]._id) {
setNotifications(prevState => [message, ...prevState]);
return;
} else {
setIsTyping(false);
setMessages(prevState => [...prevState, message]);
}
});
return () => socket.off('msg-received');
}, [socket, activeChat, setNotifications]);
useEffect(() => {
if (!socket) return;
socket.on('typing', typer => {
setIsTyping(true);
setTypers(prevState => [...new Set([typer, ...prevState])]);
});
socket.on('stop typing', userName => {
const usersStillTyping = typers.filter(typer => typer !== userName);
if (usersStillTyping.length > 0 && typers.length !== 0) {
setIsTyping(true);
setTypers(usersStillTyping);
return;
}
setIsTyping(false);
setTypers([]);
});
return () => {
socket.off('typing');
socket.off('stop typing');
};
}, [socket, typers]);
const setRef = useCallback(
node => {
if (node && isTyping && isScrolledIntoView(node)) {
node.scrollIntoView({ smooth: true });
} else if (node && !isTyping) {
node.scrollIntoView({ smooth: true });
}
},
[isTyping]
);
function isScrolledIntoView(el) {
var rect = el.getBoundingClientRect();
var elemTop = rect.top;
var elemBottom = rect.bottom;
// Only completely visible elements return true:
var isVisible = elemTop >= 0 && elemBottom <= window.innerHeight;
// Partially visible elements return true:
//isVisible = elemTop < window.innerHeight && elemBottom >= 0;
return isVisible;
}
// What is the best way to make it so that the text bubble can expland if it needs to??
return (
<div className="message-view-container">
{isLoading ? (
<Spinner type="search" />
) : (
<>
<div className="message-view-active-chat-container">
{messages.length > 0 &&
messages.map((message, i) => {
const lastMessageBool = messages.length - 1 === i + 1;
const userSentBool = userSent(currentUser, message);
const sameSenderAndNotCurrentUserBool =
sameSenderAndNotCurrentUser(i, messages, currentUser);
return (
<div
key={i}
ref={lastMessageBool ? setRef : null}
className={`message-view-message-container ${
userSentBool ? 'user-sent' : ''
}`}
>
<div
className="message-view-message-image-container"
style={
sameSenderAndNotCurrentUserBool || userSentBool
? { visibility: 'hidden' }
: { marginTop: '2px' }
}
>
<img
height="100%"
src={message.sender.picture}
alt="profile"
/>
</div>
<div className="message-view-text-container">
<div className="message-view-text">{message.text}</div>
<div
style={
sameSenderAndNotCurrentUserBool || userSentBool
? { display: 'none' }
: {}
}
className="message-view-text-info"
>
<p>
#{!userSentBool ? message.sender.userName : 'You'}
</p>
</div>
</div>
</div>
);
})}
</div>
{isTyping && (
<div className="lottie-container">
{typers.length ? getTyperString(typers) : ''}
<Lottie
animationData={animationData}
loop={true}
autoplay={true}
style={{ height: '16px', display: 'block' }}
/>
</div>
)}
<div
className="send-message-editable"
data-text={`Message `}
contentEditable
onKeyDown={handleKeyDown}
/>
</>
)}
</div>
);
};
export default MessageView;

React - autocomplete search for API - array always returns empty

I'm trying to make an autocomplete search for Alpha Vantage API, but the array which should contain the matches (suggestion) always returns empty when I type in the input field and I don't know what could be the reason, I'm stuck for a while on this and would appreciate if someone could help me with this.
The related code here is mostly in useEffect and the inputHandler:
const Search = () => {
useEffect(() => {
const getSymbols = async () => {
const searchURL = `https://www.alphavantage.co/query?function=SYMBOL_SEARCH&keywords=${textInput}&apikey=${process.env.REACT_APP_ALPHA_VANTAGE_API_KEY}`
const res = await axios.get(searchURL);
if(res) {
setSecurity(res.data.bestMatches);
if(security !== undefined && security.length > 0) {
let symbols = security.map(sec => sec['1. symbol'])
setAllSymbol(symbols);
}
}
}
getSymbols();
}, [])
console.log(allSymbol);
const inputHandler = (e) => {
setTextInput(e.target.value);
let matches = [];
if(textInput.length > 0) {
matches = allSymbol.filter(sym => {
const regex = new RegExp(`${textInput}`, "gi");
return sym.match(regex);
})
setSuggestion(matches);
}
console.log(suggestion);
setTextInput(e.target.value);
}
const showData = async (e) => {
e.preventDefault();
const searchURL = `https://www.alphavantage.co/query?function=SYMBOL_SEARCH&keywords=${textInput}&apikey=${process.env.REACT_APP_ALPHA_VANTAGE_API_KEY}`
const monthlyURL = `https://www.alphavantage.co/query?function=TIME_SERIES_MONTHLY&symbol=${textInput}&apikey=${process.env.REACT_APP_ALPHA_VANTAGE_API_KEY}`
try {
const res = await axios.get(searchURL);
const data = await axios.get(monthlyURL);
if(res) {
setTickers(res.data.bestMatches[0]);
setSymbol(res.data.bestMatches[0]['1. symbol']);
setSecurity(res.data.bestMatches);
if(data) {
const monthlyTimeSeries = Object.values(data.data['Monthly Time Series']);
const result = [monthlyTimeSeries[1]];
const resultValues = Object.keys(result[0]).map(key => {
return Math.floor(result[0][key]);
})
setPrices(resultValues);
}
}
} catch(err) {
console.log(err)
}
setDailyPrices([]);
setWeeklyPrices([]);
setIntraPrices([]);
}
return (
<StyledSearch>
<div className="wrapper">
<h1>Security Price Monitor App </h1>
<form onSubmit={showData} className="search-form">
<input type="text" value={textInput} onChange={inputHandler} placeholder='Enter Stock Symbol (GOOG, MSFT)'/>
<button type="submit">Search</button>
</form>
</div>
{prices.length > 0 && (
<>
<Table prices={prices} symbol={symbol}/>
<TimeFrames symbol={symbol} textInput={textInput} weeklyPrices={weeklyPrices} setWeeklyPrices={setWeeklyPrices} dailyPrices={dailyPrices} setDailyPrices={setDailyPrices} intraPrices={intraPrices} setIntraPrices={setIntraPrices} />
</>
)}
</StyledSearch>
)
}

Using nodemailer with heroku

i have a next.js app deployed with heroku https://new-cardenal.herokuapp.com/reserve with a contact form that has a submit button that sends an email and it works fine when i run it locally via: npm install, npm run build, npm start but when i try it on the heroku url it sends a 500 error, here is my code
server.js
const express = require('express');
const cors = require('cors')
const next = require('next');
const path = require('path');
const url = require('url');
const cluster = require('cluster');
const numCPUs = require('os').cpus().length;
const dev = process.env.NODE_ENV !== 'production';
const port = process.env.PORT || 3000;
const mailer = require('./mailer')
const bodyParser = require('body-parser')
if (!dev && cluster.isMaster) {
for (let i = 0; i < numCPUs; i++) {cluster.fork();
}
cluster.on('exit', (worker, code, signal) => {
console.error(`Node cluster worker ${worker.process.pid} exited: code ${code}, signal
${signal}`);
});
} else {
const nextApp = next({ dir: '.', dev });
const nextHandler = nextApp.getRequestHandler();
nextApp.prepare().then(() => {
const server = express();
server.use(cors());
server.use(bodyParser.json())
server.use(bodyParser.urlencoded({extended: true}));
server.post('/api/contact', (req, res) => {
const {senderMail,sendTo,rooms,date} = req.body
mailer({senderMail,sendTo,rooms,date}).then(() => {
console.log('success')
res.send('success')
}).catch((error) => {
console.log('failed', error)
res.send('badddd')
})})
if (!dev) {
server.use(function(req, res, next) {
var proto = req.headers["x-forwarded-proto"];
if (proto === "https") {
res.set({'Strict-Transport-Security': 'max-age=31557600'});
return next();
}
res.redirect("https://" + req.headers.host + req.url);
});
}
server.use('/static', express.static(path.join(__dirname, 'static'), {maxAge: dev ? '0'
: '365d'}));
server.get('*', (req, res) => {
const parsedUrl = url.parse(req.url, true);
nextHandler(req, res, parsedUrl);
});
server.listen(port, (err) => {if (err) throw err;});
});
}
contact.js
import nodemailer from "nodemailer"
const emailPass = "qbmD6Zs8Qv76b96"
const transporter = nodemailer.createTransport({
host: "smtp.gmail.com",
port: 465,
secure: true,
auth: {
user: "eitanschreiber97#gmail.com",
pass: emailPass
},
tls: {
rejectUnauthorized: false
}})
export default async (req, res) => {
const { senderMail, sendTo, rooms, date } = req.body
if (sendTo === "" || rooms === "" || date === "") {
res.status(403).send("")
return
}
const mailerRes = await mailer({ senderMail, sendTo, rooms, date })
res.send(mailerRes)
}
const mailer = ({ senderMail, sendTo, rooms, date }) => {
const message = {
senderMail,
to: `${sendTo}`,
subject: `El Cardenal Hotel`,
text: `Thank you for your reservation
you have reserved rooms: ${rooms} for ${date}
to cancel you can contact El Cardenal Hotel at (+593) 99 642 4583 or email at
elcardenalhotel#gmail.com`,
replyTo: senderMail
}
return new Promise((resolve, reject) => {
transporter.sendMail(message, (error, info) =>
error ? reject(error) : resolve(info)
)})}
reserve.js
import React, { Component } from 'react'
import dynamic from 'next/dynamic';
import Link from 'next/link'
import styled from 'styled-components'
import Header from '../components/header'
import OtherFooter from '../components/otherFooter'
import { sendContactMail } from "../components/networking/mail-api"
import Rooms from '../data/rooms'
import moment from 'moment';
import { GoArrowLeft } from 'react-icons/go';
import { GoArrowRight } from 'react-icons/go';
import { i18n, withTranslation } from '../i18n'
import { createForm, createFactory, createField } from 'micro-form'
import axios from 'axios';
const Wrapper=styled.div``
class DayNames extends Component {
render() {
return (<div className="row day-names">
<span className="day">Sun</span>
<span className="day">Mon</span>
<span className="day">Tue</span>
<span className="day">Wed</span>
<span className="day">Thu</span>
<span className="day">Fri</span>
<span className="day">Sat</span>
</div>);
}}
class Week extends Component {
render() {
let days = [];
let {
date,
} = this.props;
const {
month,
selected,
select,
} = this.props;
for (var i = 0; i < 7; i++) {
let day = {
name: date.format("dd").substring(0, 1),
number: date.date(),
isCurrentMonth: date.month() === month.month(),
isToday: date.isSame(new Date(), "day"),
date: date
};
days.push(<Day day={day}selected={selected}select={select}/>);
date = date.clone();
date.add(1, "day");
}
return <div className="row week" key={days[0]}>{days}</div>;
}}
class Day extends Component {
render() {
const {
day,
day: {
date,
isCurrentMonth,
isToday,
number
},
select,
selected
} = this.props;
return <span key={date.toString()}className={"day" + (isToday ? " today" :
"") + (isCurrentMonth ? "" : " different-month") + (date.isSame(selected) ? "
selected" : "")}onClick={()=>select(day)}>{number}</span>;
}}
const which = [201, 202, 301, 302, 303, 304];
class ReservePage extends Component {
constructor(props) {
super(props);
this.state={rooms:[false,false,false,false,false,false],
em:``,
firstMonth: moment(),secondMonth: moment(),firstSelected:
moment().startOf('day'),firstShow: false,secondSelected:
moment().startOf('day'),secondShow: false,thank_you:false}}
static async getInitialProps(ctx){
return {namespacesRequired: ['common', 'header']}
}
selectRoom = n => {
const y = n
this.setState(prev => {
const rooms = prev.rooms.map((r, ind) => {if (ind == y) {return !r
} else {return r}})
return { rooms }
})}
submitForm = async e => {
e.preventDefault();
const senderMail = `eitanschreiber97#gmail.com`
const res = await sendContactMail(senderMail, this.state.em,
which.filter((w, ind) => this.state.rooms[ind]),
[this.state.firstSelected.format("ll"),this.state.secondSelected.format("ll")])
if (res.status < 300) {
this.setState({rooms: [false,false,false,false,false,false],thank_you:
true,em: ``,firstSelected: moment().startOf('day'),firstShow: false,secondSelected:
moment().startOf('day'),secondShow: false})
}
}
firstPrevious = () => {
const {
firstMonth,
} = this.state;
this.setState({firstMonth:firstMonth.subtract(1,'month')});
}
secondPrevious = () => {
const {
secondMonth,
} = this.state;
this.setState({secondMonth:secondMonth.subtract(1,'month')});
}
firstNext = () => {
const {
firstMonth,
} = this.state;
this.setState({firstMonth:firstMonth.add(1,'month')});
}
secondNext = () => {
const {
secondMonth,
} = this.state;
this.setState({secondMonth:secondMonth.add(1,'month')});
}
firstSelect = day =>
this.setState({firstShow:true,firstSelected:day.date,firstMonth:day.date.clone()});
secondSelect = day =>
this.setState({secondShow:true,secondSelected:day.date,secondMonth:day.date.clone()});
renderFirstWeeks() {
let weeks = [];
let done = false;
let date = this.state.firstMonth.clone().startOf("month").add("w"
-1).day("Sunday");
let count = 0;
let monthIndex = date.month();
const {
firstSelected,
firstMonth,
} = this.state;
while (!done) {
weeks.push(<Week key={date}date={date.clone()}month=.
{firstMonth}select={(day)=>this.firstSelect(day)}selected={firstSelected}/>);
date.add(1, "w");
done = count++ > 2 && monthIndex !== date.month();
monthIndex = date.month();
}
return weeks;
};
renderSecondWeeks() {
let weeks = [];
let done = false;
let date = this.state.secondMonth.clone().startOf("month").add("w"
-1).day("Sunday");
let count = 0;
let monthIndex = date.month();
const {
secondSelected,
secondMonth,
} = this.state;
while (!done) {
weeks.push(<Week key={date}date={date.clone()}month=.
{secondMonth}select={(day)=>this.secondSelect(day)}selected={secondSelected}/>);
date.add(1, "w");
done = count++ > 2 && monthIndex !== date.month();
monthIndex = date.month();
}
return weeks;
};
renderFirstMonthLabel() {
const {
firstMonth,
} = this.state;
return firstMonth.format("MMMM YYYY");
}
renderSecondMonthLabel() {
const {
secondMonth,
} = this.state;
return secondMonth.format("MMMM YYYY");
}
render() {
const { rooms, date, em } = this.state
return (<Wrapper>
<Header/>
<main style={{width:`100%`, margin:0, position:`relative`, top:`7vh`, paddingTop:`90px`,
paddingBottom:`90px`, display:`flex`, flexDirection:`column`, alignItems:`center`,
zIndex:1, backgroundImage:`url(/roomsPage/background_1.png)`,
backgroundPosition:`center`, backgroundSize:`cover`, backgroundRepeat:`no-repeat`}}>
<section>
<h1>Select your room</h1>
<div className="top_list">
{Rooms.map((r,ind)=>{
return <div onClick={()=>this.selectRoom(ind)}>
<h1>{r.number}</h1>
<div style={{width:`240px`,height:`170px`,background:`center / cover no-repeat
url(/roomsPage/${r.number}.jpg)`,backgroundColor:this.state.rooms[ind] ? `grey` :
null,backgroundBlendMode:`multiply`}}></div>
</div>})}
</div>
<h1>Select the date</h1>
<div className="dates">
<div>
<p>Check in</p>
<section>
{this.state.firstShow ? <p>{this.state.firstSelected.format("ll")}</p> : null}
<section className="calendar">
<header className="header">
<div className="month-display row">.
{moment().format("MMMM YYYY") != this.renderFirstMonthLabel() ? <GoArrowLeft onClick=.
{this.firstPrevious}/> : null}<span className="month-label">.
{this.renderFirstMonthLabel()}</span><GoArrowRight onClick={this.firstNext}/></div>
<DayNames />
</header>
{this.renderFirstWeeks()}
</section>
</section>
</div>
<div>
<p>Check out</p>
<section>
{this.state.secondShow ? <p>
{this.state.secondSelected.format("ll")}</p> : null}
<section className="calendar">
<header className="header">
<div className="month-display row">.
{moment().format("MMMM YYYY") != this.renderSecondMonthLabel() ? <GoArrowLeft
onClick={this.SecondPrevious}/> : null}<span className="month-label">
{this.renderSecondMonthLabel()}</span><GoArrowRight onClick={this.secondNext}/>
</div>
<DayNames />
</header>
{this.renderSecondWeeks()}
</section>
</section>
</div>
</div>
<div className="bottom">
<div>
<p>Email</p>
<input type="text"id="em"name="em_name"value={em}onChange=
{e=>this.setState({em:e.target.value})}/>
</div>
<button type="submit" onClick={this.submitForm}>Reserve</button>
{this.state.thank_you && <p>thank you</p>}
</div>
</section>
</main>
<OtherFooter/>
</Wrapper>)}}
export default withTranslation('common')(ReservePage)
mail-api.js
import axios from "axios"
export const sendContactMail = async (senderMail, sendTo, rooms, date) => {
const data = {senderMail, sendTo, rooms, date}
try {
const res = await axios({
method: "post",
url: "/api/contact",
headers: {
"Content-Type": "application/json"
},
data
})
return res
} catch (error) {
return error
}
}
what do i need to fix
UPDATE: apparently i need to add ajax code
$.ajax({
url: 'https://new-cardenal.herokuapp.com/',
type: 'POST',
headers: {'Accept': 'application/json;'},
data: {
"subject": "the subject",
"message": "the body"
},
}).done(function (res) {
console.log(res); // it shows your email sent message.
});
i'm just not sure which file to put it code in or do i create a new file
never mind i figured it out i singed in with google accounts and kept the window open then ran: npm install, npm run build and npm start and it worked

How to get the response data from backend to React in React-dropzone-uploader

const MyUploader = () => {
const getUploadParams = ({ meta,url }) => { // specify upload params and url for your files
console.log("uploadParams",meta,url)
return { url: '/v1/file_uploads/' }
}
const handleChangeStatus = ({ meta, file }, status) => { // called every time a file's `status` changes
console.log("handleStatus",status, meta, file)
}
const handleSubmit = (files, allFiles) => { // receives array of files that are done uploading when submit button is clicked
console.log(files.map(f => f.meta))
allFiles.forEach(f => f.remove())
}
return (
<Dropzone
getUploadParams={getUploadParams}
onChangeStatus={handleChangeStatus}
onSubmit={handleSubmit}
accept="image/*"
/>
)
}
<MyUploader />
I'm able to save the uploaded file in the Database, when file is saved i am rendering some information
render json: {status: "Success", blob: blob, url: URL }
How can i console log this data which i am rendering in the React ??
The link of the package is : https://github.com/fortana-co/react-dropzone-uploader
I have solved the problem by passing xhr as a parameter to handleChangeStatus function.
const MyUploader = () => {
const getUploadParams = ({ meta }) => { // specify upload params and url for your files
return { url: '/v1/file_uploads/' }
}
const handleChangeStatus = ({ meta, file,xhr }, status) => { // called every time a file's `status` changes
console.log("handleStatus",status, meta, file)
if(status == "done") {
var json = JSON.parse(xhr.response)
var arr_blob_ids = state.documents_blob_ids.slice()
console.log("id added",json.blob.id)
if (json.blob.id){
arr_blob_ids.push(json.blob.id)
setState({...state,documents_blob_ids: arr_blob_ids})
}
}
else if(status == "removed") {
var json = JSON.parse(xhr.response)
var arr_blob_ids = state.documents_blob_ids.slice()
console.log("id removed",json.blob.id)
if (json.blob.id){
arr_blob_ids = arr_blob_ids.filter( v => v!= json.blob.id)
setState({...state,documents_blob_ids: arr_blob_ids})
}
}
}
const handleSubmit = (files, allFiles) => { // receives array of files that are done uploading when submit button is clicked
console.log(files.map(f => f.meta))
allFiles.forEach(f => f.remove())
}
return (
<Dropzone
getUploadParams={getUploadParams}
onChangeStatus={handleChangeStatus}
onSubmit={handleSubmit}
accept="image/*"
submitButtonContent = {null}
SubmitButtonComponent = {null}
/>
)
}

Resources