So, i am making this request from my frontend to get all conversations of a user.
When the request made to the node server, it checks for "express-jwt" and says access denied.
When i console.log the jwt, it shows that the jwt is undefiend
(i think the bearer is ok, since it shows in the req.headers.authorization)
My react code:
import React, { useState, useEffect, useRef } from "react";
import styled from "styled-components";
import apiCalls from "../../backend/apiCalls";
import Conversion from "../../Components/Shared/Conversion";
import Message from "../../Components/Shared/Message";
import ToastSuccess from "../../Components/Shared/ToastSuccess";
import Toast from "../../Components/Shared/ToastSuccess";
import { io } from "socket.io-client";
function ChiefNotification({ id }) {
const [list, setList] = useState([]);
const socket = useRef();
useEffect(() => {
socket.current = io("ws://localhost:8900");
socket.current.on("getMessage", (data) => {
setRecievedMessages({
sender: data.senderId,
text: data.text,
createdAt: Date.now(),
});
});
}, []);
const [showConversations, setShowConversations] = useState([]);
const [conversations, setConversations] = useState([]);
const [currentChat, setCurrentChat] = useState(null);
const [messages, setMessages] = useState([]);
const [newMessage, setNewMessage] = useState("");
const [recievedMessages, setRecievedMessages] = useState("");
const scrollRef = useRef();
useEffect(() => {
recievedMessages &&
currentChat?.members.includes(recievedMessages.sender) &&
setMessages((prev) => [...prev, recievedMessages]);
}, [recievedMessages, currentChat]);
const getConversation = async () => {
await apiCalls
.getConversation(id)
.then((data) => {
setConversations(data?.data);
setShowConversations(data?.data);
})
.catch((err) => {
Toast.ToastFailure(err.response.data);
});
};
const handleSubmit = async (e) => {
e.preventDefault();
const message = {
sender: id,
text: newMessage,
conversationId: currentChat._id,
};
const recieverId = currentChat.members[1];
socket.current.emit("sendMessaage", {
senderId: id,
recieverId: recieverId,
text: newMessage,
});
await apiCalls
.sendMessage(message)
.then((data) => {
setMessages([...messages, data?.data]);
setNewMessage("");
})
.catch((err) => {
Toast.ToastFailure(err.response.data);
});
};
//handling sockets
const getSocketInfo = () => {
socket.current.emit("addUser", id);
socket.current.on("getUsers", (users) => {
console.log(users);
});
};
const getAllUsers = async () => {
await apiCalls
.getAllConvo()
.then((res) => {
setList(res?.data);
})
.catch((err) => {
ToastSuccess.ToastFailure(err?.response.data);
});
};
const NewConversation = (keyword) => {
if (keyword.length > 2) {
setShowConversations(
list.filter(
(listItem) =>
listItem.firstName.toLowerCase().includes(keyword.toLowerCase()) ||
listItem.lastName.toLowerCase().includes(keyword.toLowerCase())
)
);
} else {
setShowConversations(conversations);
}
};
useEffect(() => {
Promise.all([getConversation(), getSocketInfo(), getAllUsers()]);
}, []);
useEffect(() => {
const getMessages = async () => {
await apiCalls
.getMessages(currentChat?._id)
.then((data) => {
setMessages(data?.data);
})
.catch((err) => {
ToastSuccess.ToastFailure(err.response.data);
});
};
if (currentChat) getMessages();
}, [currentChat]);
useEffect(() => {
scrollRef.current?.scrollIntoView({ behavior: "smooth" });
}, [messages]);
return (
<>
<Breadcrum>Dashboard / Notifications</Breadcrum>
<Messenger>
<CheckMenu>
<CheckMenuWrapper>
<ChatMenuInp
placeholder="Search for Friends"
onChange={(e) => NewConversation(e.target.value)}
/>
{showConversations.map((c, index) => (
<div onClick={() => setCurrentChat(c)} key={index}>
<Conversion conversation={c} />
</div>
))}
</CheckMenuWrapper>
</CheckMenu>
<ChatBox>
<CheckBoxWrapper>
{currentChat ? (
<>
<CheckBoxTop>
{messages.map((m, index) => {
return (
<div ref={scrollRef} key={index}>
<Message message={m} own={m.sender === id} />
</div>
);
})}
</CheckBoxTop>
<CheckBoxBottom>
<ChatMessageArea
placeholder="write something...."
onChange={(e) => setNewMessage(e.target.value)}
value={newMessage}
/>
<ChatSendButton onClick={handleSubmit}>Send</ChatSendButton>
</CheckBoxBottom>
</>
) : (
<NoConversation>Open a Conversation to Start Chat</NoConversation>
)}
</CheckBoxWrapper>
</ChatBox>
</Messenger>
</>
);
}
export default ChiefNotification;
const Messenger = styled.div`
display: flex;
margin: 0% 5% 1% 5%;
border: 1px solid #e0e0e0;
border-radius: 5px;
max-height: 80vh;
min-height: 70vh;
`;
const CheckMenu = styled.div`
flex: 3;
`;
const CheckMenuWrapper = styled.div`
padding: 10px;
border-right: 1px solid #e0e0e0;
height: 100%;
`;
const ChatMenuInp = styled.input`
width: 90%;
padding: 10px;
border: none;
border-bottom: 1px solid #e0e0e0;
`;
const ChatMessageArea = styled.textarea`
width: 80%;
height: 90px;
padding: 10px;
`;
const CheckBoxBottom = styled.div`
margin-top: 5px;
display: flex;
align-items: center;
justify-content: space-between;
background-color: #f5f5f5;
padding: 2%;
`;
const ChatBox = styled.div`
flex: 7;
padding: 5px 15px;
`;
const CheckBoxWrapper = styled.div`
display: flex;
flex-direction: column;
justify-content: space-between;
position: relative;
height: 100%;
position: relative;
`;
const CheckBoxTop = styled.div`
height: 100%;
overflow-y: scroll;
padding-right: 10px;
`;
const ChatSendButton = styled.button`
width: 100px;
height: 40px;
border: none;
color: white;
border-radius: 1px;
background-color: #5f9ab4;
cursor: pointer;
`;
const Breadcrum = styled.h6`
color: #003951;
padding: 1% 5%;
display: flex;
`;
const NoConversation = styled.div`
position: absolute;
top: 10%;
font-size: 50px;
color: lightgray;
cursor: default;
width: 100%;
text-align: center;
`;
The Axios Setup Code:
import axios from "axios";
import { getCookie } from "../Auth/auth";
const authToken = getCookie("token");
axios.defaults.baseURL = "http://localhost:5000";
axios.defaults.headers.common["Authorization"] = `Bearer ${authToken}`;
axios.interceptors.response.use(null, (error) => {
const expectedError =
error.response &&
error.response.status >= 400 &&
error.response.status < 500;
if (!expectedError) {
console.log("Logging error", error);
alert("An unexpected Error occurred");
}
return Promise.reject(error);
});
// eslint-disable-next-line import/no-anonymous-default-export
export default {
get: axios.get,
post: axios.post,
put: axios.put,
delete: axios.delete,
};
The code for the API call and the jwt file
//get list of people that you can have conversation with
router.get("/allConversations", [chief], async (req, res) => {
const getUsers = await User.find({ accountStatus: true }).select(
"id firstName lastName"
);
if (getUsers) {
return res.status(200).json(getUsers);
} else return res.status(400).json("Error Occured while getting users");
});
The code for JWT
const expressJwt = require("express-jwt");
function authJwt() {
const secret = process.env.SECRET;
return expressJwt({
secret,
algorithms: ["HS256"],
isRevoked: isRevoked,
}).unless({
path: [
{ url: /\/issues(.*)/, methods: ["GET", "OPTIONS"] },
{ url: /\journal\/download(.*)/, methods: ["GET", "OPTIONS"] },
{ url: /\user\/activate(.*)/, methods: ["GET", "POST", "OPTIONS"] },
{
url: /\user\/auth\/password\/reset(.*)/,
methods: ["GET", "POST", "OPTIONS"],
},
{ url: /\/public\/uploads(.*)/, methods: ["GET", "OPTIONS"] },
{ url: /\/journal\/search(.*)/, methods: ["GET", "OPTIONS"] },
{ url: /\/journal\/currentIssues(.*)/, methods: ["GET", "OPTIONS"] },
{ url: /\journal/, methods: ["POST", "OPTIONS"] },
{ url: /\user\/chief(.*)/, methods: ["GET", "DELETE", "OPTIONS"] },
{ url: /\messages(.*)/, methods: ["GET", "OPTIONS"] },
"/user/login",
"/user/signup",
"/journal/latest",
"/user/forget",
"/user/reset",
"/user/chief/all",
],
});
}
async function isRevoked(req, payload, done) {
if (!payload.userType) {
done(null, true);
}
done();
}
module.exports = authJwt;
Related
My project is a youtube clone site and I'm trying to return video data from Back-End using Node.js, Axios and Redux-Toolkit
But the response value is always null and when I don't use dispatch, I can return the data from the backend and I don't know why. I tried a lot, but I can't find a solution
I need your help
thanks
Store.js
import { configureStore, combineReducers } from '#reduxjs/toolkit'
import userReducer from '../redux/userSlice.js'
import videoReducer from '../redux/videoSlice.js'
import storage from 'redux-persist/lib/storage'
import { PersistGate } from 'redux-persist/integration/react'
import { persistStore, persistReducer, FLUSH, REHYDRATE, PAUSE, PERSIST, PURGE, REGISTER, } from 'redux-persist'
const persistConfig = {
key: 'root',
version: 1,
storage,
}
const rootReducer = combineReducers({ user: userReducer, video: videoReducer })
const persistedReducer = persistReducer(persistConfig, rootReducer)
export const store = configureStore({
reducer: persistedReducer,
middleware: (getDefaultMiddleware) =>
getDefaultMiddleware({
serializableCheck: {
ignoredActions: [FLUSH, REHYDRATE, PAUSE, PERSIST, PURGE, REGISTER],
},
}),
})
export const persistor = persistStore(store)
videoSlice.js
import { createSlice } from "#reduxjs/toolkit";
const initialState = {
currentVideo: null,
loading: false,
error: false,
};
export const videoSlice = createSlice({
name: "video",
initialState,
reducers: {
fetchStart: (state) => {
state.loading = true;
},
fetchSuccess: (state, action) => {
state.loading = false;
state.currentVideo = action.payload;
},
fetchFailure: (state) => {
state.loading = false;
state.error = true;
},
},
})
export const { fetchStart, fetchSuccess, fetchFailure } = videoSlice.actions
export default videoSlice.reducer
Video.jsx
import React, { useEffect, useState } from 'react'
import styled from 'styled-components'
import ThumbUpAltOutlinedIcon from '#mui/icons-material/ThumbUpAltOutlined';
import ThumbDownAltOutlinedIcon from '#mui/icons-material/ThumbDownAltOutlined';
import ReplayOutlinedIcon from '#mui/icons-material/ReplayOutlined';
import AddTaskOutlinedIcon from '#mui/icons-material/AddTaskOutlined';
import Comments from '../components/Comments'
import Card from '../components/Card'
import { useDispatch, useSelector } from "react-redux";
import { useLocation } from "react-router-dom";
import axios from 'axios';
import { fetchStart, fetchSuccess, fetchFailure } from '../redux/videoSlice'
import { format } from 'timeago.js';
const Container = styled.div`
display: flex;
gap: 1.5rem;
`
const Content = styled.div`
flex: 5;
`
const Recommendation = styled.div`
flex: 2;
`
const VideoWrapper = styled.div`
`
const Details = styled.div`
display: flex;
align-items: center;
justify-content: space-between;
`
const Info = styled.span`
color: ${({ theme }) => theme.textSoft};
`
const Hr = styled.hr`
border: 0.5px solid ${({ theme }) => theme.soft};
`
const Title = styled.h1`
font-size: 18px;
font-weight: 400;
margin-top: 20px;
margin-bottom: 10px;
color: ${({ theme }) => theme.text};
`
const Buttons = styled.div`
display:flex;
gap: 20px;
color: ${({ theme }) => theme.text};
`
const Button = styled.div`
display: flex;
align-items: center;
gap:5px;
cursor: pointer;
`
const Chanel = styled.div`
display:flex;
justify-content:space-between;
`
const ChanelInfo = styled.div`
display:flex;
gap: 20px;
`
const Image = styled.img`
width: 50px;
height:50px;
border-radius: 50%;
`
const ChanelDetails = styled.div`
display:flex;
flex-direction:column;
color: ${({ theme }) => theme.text};
`
const ChanelName = styled.span`
font-weight: 500;`
const ChanelCounter = styled.span`
margin-top: 5px;
margin-bottom:20px;
color: ${({ theme }) => theme.textSoft};
font-size:12px ;
`
const Description = styled.p`
font-size:12px ;
`
const Subscripe = styled.button`
background-color: red;
font-weight: 500;
color: white;
border: none;
border-radius: 3px;
height: max-content;
cursor: pointer;
padding: 10px 20px;
`
const Video = () => {
const { currentVideo } = useSelector((state) => state.video);
const dispatch = useDispatch();
console.log('currentVideo',currentVideo);
const path = useLocation().pathname.split("/")[2];
const [channel, setChannel] = useState({});
// const [video, setVideo] = useState({});
useEffect(()=> {
const fetchData = async () => {
try {
dispatch(fetchStart())
const videoRes = await axios.get(`/videos/find/${path}`);
const channelRes = await axios.get(`/users/find/${videoRes.data.userId}`);
setChannel(channelRes.data);
dispatch(fetchSuccess(videoRes.data))
} catch (err) {
dispatch(fetchFailure())
}
};
fetchData();
}, [path, dispatch]);
return (
<Container>
<Content>
<VideoWrapper>
<iframe width="100%" height="720" src="https://www.youtube.com/embed/vkc99WHcDTk" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
</VideoWrapper>
<Title>{currentVideo.title}</Title>
<Details>
<Info>{currentVideo.views} views {format(currentVideo.createdAt)} </Info>
<Buttons>
<Button>
<ThumbUpAltOutlinedIcon /> {currentVideo.likes?.length}
</Button>
<Button>
<ThumbDownAltOutlinedIcon /> Dislike
</Button>
<Button>
<ReplayOutlinedIcon /> Share
</Button>
<Button>
<AddTaskOutlinedIcon /> Save
</Button>
</Buttons>
</Details>
<Hr />
<Chanel>
<ChanelInfo>
<Image src={channel.img} />
<ChanelDetails>
<ChanelName>{channel.name}</ChanelName>
<ChanelCounter>{channel.subscribers} subscriper</ChanelCounter>
<Description>{currentVideo.description}</Description>
</ChanelDetails>
</ChanelInfo>
<Subscripe>Subscripe</Subscripe>
</Chanel>
<Hr />
<Comments />
</Content>
{/* <Recommendation>
<Card type="sm"/>
<Card type="sm"/>
<Card type="sm"/>
<Card type="sm"/>
<Card type="sm"/>
<Card type="sm"/>
<Card type="sm"/>
<Card type="sm"/>
<Card type="sm"/>
<Card type="sm"/>
<Card type="sm"/>
</Recommendation> */}
</Container>
)
}
export default Video
Hello im working in application that i want to create PDF files using puppeteer and handlbars but it create only blank PDF
Here is my code
File : functions.js
createPDF = async (templateName, data, file_name) => {
const pdfPath = `${process.cwd()}/public/tickets/${file_name}.pdf`;
const filePath = path.join(process.cwd(), "templates", `${templateName}.hbs`);
const html = fs.readFileSync(filePath, "utf-8");
const content = hbs.compile(html);
const htmlContent = content(data);
const options = {
format: "A4",
headerTemplate: "<p></p>",
footerTemplate: "<p></p>",
displayHeaderFooter: false,
margin: {
top: "10px",
bottom: "30px",
},
printBackground: true,
path: pdfPath,
};
const browser = await puppeteer.launch({
args: ["--no-sandbox"],
headless: true,
});
const page = await browser.newPage();
await page.goto(`data:text/html;charset=UTF-8,${htmlContent}`, {
waitUntil: "networkidle0",
});
console.log(await page.content());
await page.pdf(options);
await browser.close();
};
fileContoller.js
exports.myfile = async (req, res, next) => {
const { approved } = req.body;
const getData = await MyTable.findAll({
attributes: [
"id",
"first_name",
"last_name",
"birthday",
"gender",
"address",
"img",
],
where: { approved},
raw: true,
});
for (let i = 0; i < getData.length; i++) {
const createPDFforuser = await functions.createPDF(
"myhbsmockuptemplate",
getData[i],
`${getData[i].id}+${i}`
);
}
}
when i console.log htmlContent it get the html complete and correctly done as i write it
But when i console log awit page.content()
Here i dont get the html as expected it get only few line
<html><head>
<meta charset="utf-8">
<style type="text/css">
.tmp-mockup { font-family: "Staatliches", cursive; color: black;
font-size: 14px; letter-spacing: 0.1em; margin: 25px 0; } .ticket-box {
margin: auto; display: flex; background: </style></head><body></body></html>
Wait for some element in htmlContent after page is loaded.
await page.goto(`data:text/html;charset=UTF-8,${htmlContent}`, {
waitUntil: "networkidle0",
});
await page.waitForSelector('#visible-element')
I have a form that accepts a file to pass on to Dropbox using the session upload. I've wrapped the code in a Fastify server but always end up with an error in append:
{"error_summary": "closed/..", "error": {".tag": "closed"}}.
Here's the Fastify server:
require("dotenv").config()
const https = require("https")
const JSONbig = require("json-bigint")
const TOKEN = process.env.DROPBOX_ACCESS_TOKEN
const fastify = require("fastify")({
logger: {
level: "info"
}
})
fastify.addContentTypeParser("*", function (req, done) {
done()
})
// Promisify https request
const httpRequest = (url, options, data) => {
return new Promise((resolve, reject) => {
const req = https.request(url, options, (res) => {
let body = ""
res.on("data", (chunk) => {
console.log("SDSDSDSDASDASDSAD")
body += chunk.toString()
})
res.on("error", reject)
res.on("end", () => {
if (res.statusCode >= 200 && res.statusCode <= 299) {
resolve({ statusCode: res.statusCode, headers: res.headers, body: JSON.parse(body) })
} else {
reject("Request failed. status: " + res.statusCode + ", body: " + body)
}
})
})
req.on("error", reject)
if (data) req.write(data)
req.end()
})
}
fastify.register(require("fastify-cors"))
fastify.post("/", async (req, reply) => {
const stream = req.raw
const initResponse = await httpRequest(
"https://content.dropboxapi.com/2/files/upload_session/start",
{
method: "post",
headers: {
Authorization: `Bearer ${TOKEN}`,
"Dropbox-API-Arg": JSON.stringify({
close: false
}),
"Content-Type": "application/octet-stream"
}
}
)
const sessionId = initResponse.body.session_id
req.log.info(`Initiating session ${sessionId}`)
let offset = 0
stream.on("data", async (chunk) => {
req.log.info("Sending chunk")
stream.pause()
const appendResponse = await httpRequest(
`https://content.dropboxapi.com/2/files/upload_session/append_v2`,
{
method: "post",
headers: {
Authorization: `Bearer ${TOKEN}`,
"Dropbox-API-Arg": JSONbig.stringify({
cursor: {
session_id: sessionId,
offset
},
close: false
}),
"Content-Type": "application/octet-stream"
}
},
chunk
)
stream.resume()
offset += chunk.length
})
stream.on("end", async () => {
const terminateResponse = await httpRequest(
`https://content.dropboxapi.com/2/files/upload_session/finish`,
{
method: "post",
headers: {
Authorization: `Bearer ${TOKEN}`,
"Dropbox-API-Arg": JSONbig.stringify({
cursor: {
session_id: sessionId,
offset: offset
},
commit: {
path: "/Upload/test-large.txt",
mode: "add",
autorename: true,
mute: false,
strict_conflict: false
}
}),
"Content-Type": "application/octet-stream"
}
}
)
req.log.info("upload session finished")
reply.code(204).send()
})
})
fastify.listen(3000, (err) => {
if (err) {
fastify.log.fatal(err)
process.exit(1)
}
console.log(`server listening on ${fastify.server.address().port}`)
})
And here's the form:
<!DOCTYPE html>
<!-- Coding By CodingNepal - youtube.com/codingnepal -->
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>File Upload with Progress Bar | CodingNepal</title>
<link
rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.3/css/all.min.css"
/>
<style>
/* Import Google font - Poppins */
#import url("https://fonts.googleapis.com/css2?family=Poppins:wght#400;500;600&display=swap");
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: "Poppins", sans-serif;
}
body {
display: flex;
align-items: center;
justify-content: center;
min-height: 100vh;
background: #6990f2;
}
::selection {
color: #fff;
background: #6990f2;
}
.wrapper {
width: 430px;
background: #fff;
border-radius: 5px;
padding: 30px;
box-shadow: 7px 7px 12px rgba(0, 0, 0, 0.05);
}
.wrapper header {
color: #6990f2;
font-size: 27px;
font-weight: 600;
text-align: center;
}
.wrapper form {
height: 167px;
display: flex;
cursor: pointer;
margin: 30px 0;
align-items: center;
justify-content: center;
flex-direction: column;
border-radius: 5px;
border: 2px dashed #6990f2;
}
form :where(i, p) {
color: #6990f2;
}
form i {
font-size: 50px;
}
form p {
margin-top: 15px;
font-size: 16px;
}
section .row {
margin-bottom: 10px;
background: #e9f0ff;
list-style: none;
padding: 15px 20px;
border-radius: 5px;
display: flex;
align-items: center;
justify-content: space-between;
}
section .row i {
color: #6990f2;
font-size: 30px;
}
section .details span {
font-size: 14px;
}
.progress-area .row .content {
width: 100%;
margin-left: 15px;
}
.progress-area .details {
display: flex;
align-items: center;
margin-bottom: 7px;
justify-content: space-between;
}
.progress-area .content .progress-bar {
height: 6px;
width: 100%;
margin-bottom: 4px;
background: #fff;
border-radius: 30px;
}
.content .progress-bar .progress {
height: 100%;
width: 0%;
background: #6990f2;
border-radius: inherit;
}
.uploaded-area {
max-height: 232px;
overflow-y: scroll;
}
.uploaded-area.onprogress {
max-height: 150px;
}
.uploaded-area::-webkit-scrollbar {
width: 0px;
}
.uploaded-area .row .content {
display: flex;
align-items: center;
}
.uploaded-area .row .details {
display: flex;
margin-left: 15px;
flex-direction: column;
}
.uploaded-area .row .details .size {
color: #404040;
font-size: 11px;
}
.uploaded-area i.fa-check {
font-size: 16px;
}
</style>
</head>
<body>
<div class="wrapper">
<header>File Uploader JavaScript</header>
<form action="#">
<input class="file-input" type="file" name="file" hidden />
<i class="fas fa-cloud-upload-alt"></i>
<p>Browse File to Upload</p>
</form>
<section class="progress-area"></section>
<section class="uploaded-area"></section>
</div>
<script>
const form = document.querySelector("form"),
fileInput = document.querySelector(".file-input"),
progressArea = document.querySelector(".progress-area"),
uploadedArea = document.querySelector(".uploaded-area")
// form click event
form.addEventListener("click", () => {
fileInput.click()
})
fileInput.onchange = ({ target }) => {
let file = target.files[0] //getting file [0] this means if user has selected multiple files then get first one only
if (file) {
let fileName = file.name //getting file name
if (fileName.length >= 12) {
//if file name length is greater than 12 then split it and add ...
let splitName = fileName.split(".")
fileName = splitName[0].substring(0, 13) + "... ." + splitName[1]
}
uploadFile(fileName) //calling uploadFile with passing file name as an argument
}
}
// file upload function
function uploadFile(name) {
let xhr = new XMLHttpRequest() //creating new xhr object (AJAX)
xhr.open("POST", "http://localhost:3000") //sending post request to the specified URL
xhr.upload.addEventListener("progress", ({ loaded, total }) => {
//file uploading progress event
let fileLoaded = Math.floor((loaded / total) * 100) //getting percentage of loaded file size
let fileTotal = Math.floor(total / 1000) //gettting total file size in KB from bytes
let fileSize
// if file size is less than 1024 then add only KB else convert this KB into MB
fileTotal < 1024
? (fileSize = fileTotal + " KB")
: (fileSize = (loaded / (1024 * 1024)).toFixed(2) + " MB")
let progressHTML = `<li class="row">
<i class="fas fa-file-alt"></i>
<div class="content">
<div class="details">
<span class="name">${name} • Uploading</span>
<span class="percent">${fileLoaded}%</span>
</div>
<div class="progress-bar">
<div class="progress" style="width: ${fileLoaded}%"></div>
</div>
</div>
</li>`
// uploadedArea.innerHTML = ""; //uncomment this line if you don't want to show upload history
uploadedArea.classList.add("onprogress")
progressArea.innerHTML = progressHTML
if (loaded == total) {
progressArea.innerHTML = ""
let uploadedHTML = `<li class="row">
<div class="content upload">
<i class="fas fa-file-alt"></i>
<div class="details">
<span class="name">${name} • Uploaded</span>
<span class="size">${fileSize}</span>
</div>
</div>
<i class="fas fa-check"></i>
</li>`
uploadedArea.classList.remove("onprogress")
// uploadedArea.innerHTML = uploadedHTML; //uncomment this line if you don't want to show upload history
uploadedArea.insertAdjacentHTML("afterbegin", uploadedHTML) //remove this line if you don't want to show upload history
}
})
let data = new FormData(form) //FormData is an object to easily send form data
xhr.send(data) //sending form data
}
</script>
</body>
</html>
Does need an app created on DB to get oauth token to run example.
Anyone see the issue here? I've worked from a number of examples online but all of them assume I am using some dummy static file rather than incoming uploaded file.
Ok figured it out. Basically in my example I am terminating the session on end but it turns out the end event is fired at the same time as the last data event so I am effectively closing the session in the midst of the last chunk append. I refactored things to have a flag isEnd that gets set in the end event handler and moved the terminate session and resolve code inside of the data handler to be fired from there once isEnd is set.
I'm developing a login form with react-native. My back-end definitely works, but I have included it below for reference (I've tested this by using a curl command). Anyway, I'm trying to figure out why this react-native login form doesn't POST on form submission. Whenever I attempt to debug by simply adding an alert("test") it seems to call _handleSubmit() whenever there is a detected change in either of the FormInputs. Below is the react-native code:
import React from 'react';
import { FormInput } from 'react-native-elements';
import {Animated, View, TouchableOpacity} from 'react-native';
import cssta from "cssta/native";
import Config from 'react-native-config';
const LoginButtonContainer = cssta(Animated.View)`
--primary: white;
--foreground: var(--primary);
--background: #1b2535;
padding: 10px;
background-color: var(--background);
`;
const LoginButtonText = cssta(Animated.Text)`
color: var(--foreground);
text-align: center;
`;
const RegisterButtonContainer = cssta(Animated.View)`
--primary: #1b2535;
--foreground: var(--primary);
--background: white;
padding: 10px;
border: 1px solid var(--primary);
background-color: var(--background);
`;
const RegisterButtonText = cssta(Animated.Text)`
color: var(--foreground);
text-align: center;
`;
export default class Login extends React.Component {
constructor() {
super();
this.state = {
username: '',
password: ''
};
}
_handleSubmit() {
let username = this.state.username;
let password = this.state.password;
fetch('http://localhost:4200/login', {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify({username: username, password: password})
}).then((response) => JSON.stringify(response.json()))
.then((responseData) => { console.log("response: " + responseData); })
.catch((err) => { console.log(err); });
}
_onRegisterClick() {
}
render() {
return(
<View style={{justifyContent: 'space-between'}}>
<FormInput
placeholder='Username'
onChangeText={(username) => this.setState({username})}
value={this.state.username}
/>
<FormInput
placeholder='Password'
onChangeText={(password) => this.setState({password})}
value={this.state.password}
/>
<TouchableOpacity onPress={this._handleSubmit()}>
<LoginButtonContainer>
<LoginButtonText>Login</LoginButtonText>
</LoginButtonContainer>
</TouchableOpacity>
<TouchableOpacity onPress={this._onRegisterClick()}>
<RegisterButtonContainer>
<RegisterButtonText>Register</RegisterButtonText>
</RegisterButtonContainer>
</TouchableOpacity>
</View>
)
}
};
The next bit of code is a snippet of my back-end code
import models from './models';
import mongoose from 'mongoose';
const express = require('express');
import bodyParser from 'body-parser';
const app = express();
app.use('/', express.Router());
app.use(bodyParser.urlencoded({
extended: true
}));
app.use(bodyParser.json());
app.set('view engine', 'ejs');
const PORT = 4200;
app.post('/login', (req, res) => {
console.log(req.body.username);
});
app.listen(PORT, () => {
console.log(`Server is running at PORT ${PORT}`);
});
On Press Function accepts a function as an arguments. But in your code rahter then passing a function you are invoking the funtion.
<TouchableOpacity onPress={this._handleSubmit()}>
Change To
<TouchableOpacity onPress={()=> this._handleSubmit()}>
Try This code
let _username = this.state.username;
let _password = this.state.password;
let params = {
username: _username,
password: _password
};
var formBody = [];
for (var property in params) {
var encodedKey = encodeURIComponent(property);
var encodedValue = encodeURIComponent(params[property]);
formBody.push(encodedKey + "=" + encodedValue);
}
formBody = formBody.join("&");
let fetchData = {
method: "POST",
headers: {
"Content-Type": "application/x-www-form-urlencoded;charset=UTF-8"
},
body: formBody
};
fetch("http://localhost:4200/login", fetchData)
.then(response => JSON.stringify(response.json()))
.then(responseData => {
console.log("response: " + responseData);
})
.catch(err => {
console.log(err);
});
<template>
<div class="counter-warp">
<p>make</p>
<div class="statusCon">
<p class="card">
last: {{completed.length > 0 ? completed[completed.length - 1].text : ''}}
</p>
<p>completed: {{completed.length}} </p>
<button #click="showAllSentences">showall</button>
</div>
<input v-model="currentText"/>
<p>remain: {{wordsRemain}}</p>
<button #click="addSentence">Next</button>
home
</div>
</template>
<script>
// Use Vuex
import { mapGetters } from 'vuex';
import wxapi from '#/lib/wxapi';
export default {
components: {
},
computed: {
...mapGetters(['wordsRemain', 'completed']),
currentText: {
get() {
return this.$store.state.make.current.text;
},
set(val) {
this.$store.commit('setText', val);
},
},
},
methods: {
addSentence() {
this.$store.commit('addSentence', this.$store.state.make.current);
},
complete() {
this.$store.dispatch('complete').then((workId) => {
wxapi.navigateTo({ url: `/pages/index/main?id=${workId}` });
});
},
},
};
</script>
<style>
.counter-warp {
text-align: center;
margin-top: 100px;
}
.home {
display: inline-block;
margin: 100px auto;
padding: 5px 10px;
color: blue;
border: 1px solid blue;
}
</style>
// store.js
// https://vuex.vuejs.org/zh-cn/intro.html
// make sure to call Vue.use(Vuex) if using a module system
import Sentence from '#/lib/Sentence';
import Constants from '#/lib/Constants';
import { Work, User } from '#/lib';
//
const ROW_LENGTH = {
portrait: Constants.WINDOW_WIDTH,
landscape: Constants.WINDOW_HEIGHT,
};
const store = {
state: {
orientation: 'portrait',
current: new Sentence(),
sentences: [],
},
getters: {
completed: state => state.sentences,
sentencesLength: state => state.sentences.length,
wordsRemain: (state) => {
const fontSize = state.current.fontSize;
const marginTextLength = Constants.MARGIN * fontSize;
const remainPx = ROW_LENGTH[state.orientation] - marginTextLength;
const textLimit = Math.floor(remainPx / fontSize);
return textLimit - state.current.text.length;
},
//
lastSentence: (state, getters) => {
const obj = state;
return obj.sentences[getters.sentencesLength - 1];
},
},
mutations: {
addSentence: (state, sentence) => {
state.sentences.push(sentence);
state.current = new Sentence();
console.log(state);
},
setText: (state, text) => {
state.current.text = text;
},
},
actions: {
complete: ({ state, commit }) => {
// commit('setText',)
// commit('addSentence', state.current);
const config = Object.assign({}, state);
commit('setConfig', config);
const work = new Work();
work.set('author', User.current);
work.set('config', config);
return work.save().then(obj => Promise.resolve(obj.id), (err) => {
console.log(err);
});
},
},
};
export default store;
When I click the 'next' button,the 'addSentence' mutation handler should be called,but vue prompt me that'[vuex] Do not mutate vuex store state outside mutation handlers.
Error: [vuex] Do not mutate vuex store state outside mutation handlers.'
Sentence is a simple class like { text:'' ,sth: {}};.
I think the problem is within the component method:
methods: {
addSentence() {
this.$store.commit('addSentence', this.$store.state.make.current);
},
complete() {
this.$store.dispatch('complete').then((workId) => {
wxapi.navigateTo({ url: `/pages/index/main?id=${workId}` });
});
} ,
},
When you call this.$store.state.make.current, this is modifying the store directly. Rather than adding a payload to addSentence(), all you need to do is get the store to create the current Sentence directly within the mutation.
By the way, you should not call commit directly from the component. You need to call a dispatch action on the store and then commit the mutation via that.
The pattern would be:
COMPONENT:
methods: {
addSentence () {
this.$store.dispatch('attemptAddSentence');
},
STORE:
actions: {
attemptAddSentence (({state, commit}) => {
return new Promise((resolve, reject) => {
commit(‘addSentence’)
resolve()
})
}),
mutations: {
addSentence (state) => {
// Build sentence here...
}),
Hope that helps.