How to upload image with Strapi and FormData.append - reactjs

I have a problem that I can't solve with Strapi and Reactjs.
How is it possible to access the "image" field of the "Card" array ?
This work perfectly with data structure like :
const data = [{
header: "...",
content: "...",
image: "...",
price: "...",
}];
const updateImg = async value => {
try {
setisSending(!isSending);
const formData = new FormData();
formData.append('files', value[0]);
formData.append('ref', 'homepage-content');
formData.append('refId', id);
formData.append('field', 'image'); //This field name is ok.
await axios.post(`${url}/upload`, formData);
setisSending(false);
} catch (e) {
createNotification('error', 'Error message', e);
setisSending(false);
}
};
But the problem start with data structure like :
const data = [{
header: "...",
content: "...",
Card: [{
header: "...",
content: "...",
image: "...",
},
{
header: "...",
content: "...",
image: "...",
}],
price: "...",
}];
const updateImgCard = async (value, index) => {
try {
setisSending(!isSending);
const formData = new FormData();
formData.append('files', value[0]);
formData.append('ref', 'homepage-content');
formData.append('refId', id);
formData.append('field', `Card[${index}].image`); //This field name seems not to be good.
await axios.post(`${urle}/upload`, formData);
setisSending(false);
} catch (e) {
createNotification('error', 'Error message', e);
setisSending(false);
}
};

Shouldn't it be
formData.append('field', `${data[index].Card[index].image}`)

Related

Can't get collection array from mongoDB with mongoose query

I have problem with getting data from DB. I want to get "collections" Array from mongoDB and render it in table component, but query returns null because of problem "user not found". Interesting thing is that if I use {email: req.body.email} in updateOne query to search for user and then create new collection it works and user is found.
getCollections.js
const router = require("express").Router();
const User = require("../models/user");
router.get("/", (req, res) => {
var query = { email: req.body.email };
User.find(query, (err, result) => {
if (err) {
res.json({ status: "error", error: "User not found" }, err);
} else {
res.json(result);
}
});
});
module.exports = router;
frontend getCollections query
useEffect(() => {
const url = "http://localhost:5000/api/getCollections";
// const url = `https://item-collection-app-bz.herokuapp.com/api/getCollections`;
axios
.get(url, { email: localStorage.getItem("email") })
.then((response) => {
setListOfCollections(response.data);
});
});
user.js UserSchema
const jwt = require("jsonwebtoken");
const mongoose = require("mongoose");
const userSchema = new mongoose.Schema({
_id: { type: mongoose.Schema.Types.ObjectId, required: true },
username: { type: String, require: true },
password: { type: String, require: true },
email: { type: String, require: true },
admin: { type: Boolean },
blocked: { type: Boolean },
collections: [
{
_id: { type: mongoose.Schema.Types.ObjectId, required: true },
coll_name: { type: String },
type: { type: String },
coll_desc: { type: String },
coll_image: { type: String },
items: [
{
_id: { type: mongoose.Schema.Types.ObjectId, required: true },
item_name: { type: String },
item_desc: { type: String },
comments: [
{
user: { type: String },
comment: { type: String },
comment_id: { type: String },
},
],
likes: { type: Number },
item_image: { type: String },
upload_date: { type: String },
},
],
},
],
});
userSchema.methods.generateAuthToken = function () {
const appToken = jwt.sign({ _id: this._id }, process.env.JWTPRIVATEKEY, {
expiresIn: "7d",
});
return appToken;
};
const User = mongoose.model("user", userSchema);
module.exports = User;
mongoDB
mongoDB structure
Tried User.findOne(), User.find()
SOLUTION
Thank you #Varun Kaklia. The solution is changing router.get and axios.get to router.post and axios.post.
Hey #1zboro1 first check did you receive any data from frontend inside Routes like-
const router = require("express").Router();
const User = require("../models/user");
router.get("/", (req, res) => {
const email = req.body.email;
console.log("Email from frontend", email)
var query = { email: req.body.email };
if (email != null || undefined) {
try {
const user = await User.find({ email});
console.log("User Details in User Routes of Backend",user)
if (user.length > 0) {
const currentUser = {
name: user[0].name,
email1: user[0].email1,
isAdmin: user[0].isAdmin,
_id: user[0]._id,
};
// console.log("Get User in User Routes of Backend", currentUser)
res.status(200).send(currentUser);
}
} catch (error) {
res.status(404).json({
message: "Something Went wrong",
});
}
Hope this code solve your query and give you desired result. If you still facing issue lemme know.
Thanks

Why can't I push in <option> when I get the 'response.data'?

Why can't I push in my <option> when I get the response.data?
type State = {
companyManagerMap: null | Map<string, string[]>
}
useEffect(() => {
AdminListManager()
.then((response) => {
const { data } = response.data
console.log( { data });
setState((s) => ({
...s,
companyManagerMap: new Map(
Object.keys(data).map((key) => [key, data[key]])
),
}))
})
.catch(showUnexpectedError)
}, [showUnexpectedError])
data format
{"total":2,"data":[{"id":1,"name":"newspeed","contains_fields":[{"id":1,"name":"Official"}]},{"id":2,"name":"YAMAHA","contains_fields":[{"id":3,"name":"US"}]}]}
You are using your .map and Object.keys wrong
Look here at where you iterate over your Object keys properly :)
const data = {
total: 2,
data: [
{ id: 1, name: 'newspeed', contains_fields: [{ id: 1, name: 'Official' }] },
{ id: 2, name: 'YAMAHA', contains_fields: [{ id: 3, name: 'US' }] },
],
};
//now iterate over it properly
data.data.map((item) => {
Object.keys(item).map((key) => {
console.log(item[key]);
});
});
console.log will return this output
1
newspeed
[ { id: 1, name: 'Official' } ]
2
YAMAHA
[ { id: 3, name: 'US' } ]
I'm guessing you want to add the new data from your res.data to a state
So you can do something like this:
const fetchData = async () => {
try {
const res = await AdminListManager()
//do data manipulation over objects and set new state
} catch (error) {
showUnexpectedError()
}
}
useEffect(()=> {
fetchData()
}, [showUnexpectedError])

How to access smart contract functions from React JS?

I am making lottery contract , but as I try to access my method of manager I get this error in ReactJS.
[![enter image description here][1]][1]
Please help me with the solution. I have developed my contract I am having problems with connecting it to the frontend.
This is the error .
[1]: https://i.stack.imgur.com/QFc2o.png
App.js File
import detectEthereumProvider from "#metamask/detect-provider";
// import { loadContract } from "./utils/LoadContracts";
import Web3 from "web3";
import lottery from "./lottery";
import {
useEffect,
useState
} from "react";
function App() {
const [balance, setBalance] = useState("");
const [changedAccount, setChangedAccount] = useState([]);
const loader = async() => {
let provider = await detectEthereumProvider();
let web3 = new Web3(provider);
return {
provider,
web3
};
};
useEffect(async() => {
let newLoad = await loader();
let account = await newLoad.web3.eth.getAccounts();
setChangedAccount(account);
}, []);
useEffect(async() => {
let newLoad = await loader();
newLoad.provider.on("accountsChanged", function(accounts) {
let newAccount = accounts;
if (newAccount) {
setChangedAccount(newAccount);
}
});
}, []);
useEffect(async() => {
let newLoad = await loader();
let accountBal =
changedAccount.length > 0 &&
(await newLoad.web3.eth.getBalance(changedAccount[0]));
setBalance(accountBal);
}, [changedAccount]);
useEffect(async() => {
let newLoad = await loader();
let account = await newLoad.web3.eth.getAccounts();
setChangedAccount(account);
const manager = await lottery.methods.manager().call();
}, []);
return ( <
div >
<
p >
Account address {
changedAccount[0]
}, Its balance is: {
balance
} <
/p> <
/div>
);
}
export default App;
lottery.js (containing ABI and contract Address)
import Web3 from "web3";
let web3 = new Web3();
const address = "0xBEbdb8eC68A5803d0f5E93bACe9EB9E4227f5A20";
const abi = [{
inputs: [],
stateMutability: "nonpayable",
type: "constructor"
},
{
inputs: [],
name: "manager",
outputs: [{
internalType: "address",
name: "",
type: "address"
}],
stateMutability: "view",
type: "function",
},
{
inputs: [{
internalType: "uint256",
name: "",
type: "uint256"
}],
name: "players",
outputs: [{
internalType: "address",
name: "",
type: "address"
}],
stateMutability: "view",
type: "function",
},
{
inputs: [],
name: "enter",
outputs: [],
stateMutability: "payable",
type: "function",
},
{
inputs: [],
name: "getBalance",
outputs: [{
internalType: "uint256",
name: "",
type: "uint256"
}],
stateMutability: "view",
type: "function",
},
{
inputs: [],
name: "pickWinner",
outputs: [],
stateMutability: "nonpayable",
type: "function",
},
{
inputs: [],
name: "getPlayers",
outputs: [{
internalType: "address[]",
name: "",
type: "address[]"
}],
stateMutability: "view",
type: "function",
},
];
export default new web3.eth.Contract(abi, address);
You have not provided any 'provider' in lottery.js on this line
let web3 = new Web3();
which isn't giving you correct contract instance and thus you cannot access it's methods

How to ignore "req.file.path" from form data if user do not choose a file using multer

Hello I'm working on a social network project using MERN Stack and in there user can either make a post with only text or can make a post by uploading an image along with some text as a caption, but the problem is that when a user doesn't wish to upload image and just want to post only with text and leaves postImage field empty then this error occurs Cannot read property 'path' of undefined what can be the solution for this, I'm attaching the post schema, post routes and post state:
Post Schema:
const mongoose = require('mongoose');
const postSchema = mongoose.Schema({
user: {
type: mongoose.Schema.ObjectId,
ref: 'Users',
},
text: {
type: String,
required: [true, 'post cannot be empty'],
},
postImage: {
type: String,
},
name: {
type: String,
},
avatar: {
type: String,
},
likes: [
{
user: {
type: mongoose.Schema.ObjectId,
ref: 'User',
},
},
],
comments: [
{
user: {
type: mongoose.Schema.ObjectId,
ref: 'User',
},
comment: {
type: String,
required: true,
},
name: {
type: String,
},
avatar: {
type: String,
},
date: {
type: Date,
default: Date.now,
},
},
],
date: {
type: Date,
default: Date.now,
},
});
module.exports = mongoose.model('Post', postSchema);
Post Route:
const express = require('express');
const router = express.Router();
const auth = require('../middleware/auth');
const Post = require('../models/postModel');
const multer = require('multer');
const storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, './uploads');
},
filename: function (req, file, cb) {
cb(null, file.originalname);
},
});
const fileFilter = (req, file, cb) => {
if (
file.mimetype === 'image/jpeg' ||
file.mimetype === 'image/png' ||
file.mimetype === 'image/gif'
) {
cb(null, true);
} else {
cb(new Error('The supported file types are jpeg, png and gif'), false);
}
};
const upload = multer({
storage: storage,
limits: {
fileSize: 1024 * 1024 * 5,
},
fileFilter: fileFilter,
});
const { check, validationResult } = require('express-validator');
const User = require('../models/userModel');
router.post(
'/',
upload.single('postImage'),
[auth, check('text', 'Text is required').not().isEmpty()],
async (req, res) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({ errors: errors.array() });
}
try {
const user = await User.findById(req.user.id).select('-password');
const newPost = new Post({
text: req.body.text,
postImage: req.file.path,
name: user.name,
avatar: user.avatar,
user: req.user.id,
});
const post = await newPost.save();
res.json(post);
} catch (err) {
console.error(err.message);
res.status(500).send('Server Error');
}
}
);
Post State:
const createPost = async postData => {
try {
const config = {
headers: {
'Content-Type': 'multipart/form-data',
},
};
const res = await axios.post('/api/posts', postData, config);
dispatch({
type: ADD_POST,
payload: res.data,
});
} catch (err) {
dispatch({
type: POST_ERROR,
payload: err.response.msg,
});
}
};
You can simply check if req.file is defined - if yes set postImage to its path, else set it to undefined:
const newPost = new Post({
text: req.body.text,
postImage: req.file ? req.file.path : undefined,
name: user.name,
avatar: user.avatar,
user: req.user.id,
});

Mongoose saving dynamic array of subdocuments in one shot

I have searched high and low but haven't found a solution.
I am trying to save an array of subdocuments (that is dynamic).
Here's my schema:
const EventSchema = new Schema({
user: {
type: mongoose.Schema.Types.ObjectId,
ref: 'users'
},
title: {
type: String,
required: true
},
attendee:[
{
email: {
type: String,
required: true
},
name: {
type: String,
required: true
},
status: {
type: String
}
}]
});
Here's the route:
router.post('/', auth, async (req, res) => {
const {title, attendee: [{ email, name, status }] } = req.body
try{
const newEvent = new Event({
title,
user: req.user.id,
attendee: [{ email, name, status }]
});
const event = await newEvent.save();
if (!event) throw Error('Something went wrong saving the event');
res.status(200).json(event);
catch (e) {
res.status(400).json({ msg: e.message });
}
});
Currently I am only getting 1 element in the array to save.
The items in the array will always be different.
I don't have the option of creating the "event" first and then adding "attendees".
Example of input:
{
"title": "Something",
"attendee": [
{
"email": "email#gmail.com",
"name": "Bob"
},
{
"email": "sandwich#gmail.com",
"name": "Martha"
}
]
}
Output:
{
"_id": "5ef1521f06a67811f74ba905",
"title": "Something",
"user": "5ecdaf3601cd345ddb73748b",
"attendee": [
{
"_id": "5ef1521f06a67811f74ba906",
"email": "email#gmail.com",
"name": "Bob"
}
],
"__v": 0
}
Instead of destructuring for the one object of the array, you can get the whole array of attendee from the request body and save it as it is.
router.post('/', auth, async (req, res) => {
const eventObj = {
user: req.user.id,
title : req.body.title,
// get the whole array of attendee objects from the request
attendee: req.body.attendee
}
try{
const newEvent = new Event(eventObj);
const event = await newEvent.save();
if (!event) throw Error('Something went wrong saving the event');
res.status(200).json(event);
catch (e) {
res.status(400).json({ msg: e.message });
}
});
If I understand you correctly, you should not destructure attendee and insert into your new Event every attendee (choosing which key to insert in database).
const {
title,
attendee,
} = req.body;
const newEvent = new Event({
title,
user: req.user.id,
attendee: attendee.map(x => ({
email: x.email,
name: x.name,
status: x.status,
})),
});

Resources