I want to add a "Download as Excel" button to my Nextj application, by using any library to simplify the development or adding a component to my project; I already tried these but had issues with both of them:
https://www.npmjs.com/package/react-html-table-to-excel
This Downloads data with '.xls' file extension so opening them with excel throws a warning. I tried to edit the source code and change file extension to '.xlsx' but this makes the output file corrupted.
https://www.npmjs.com/package/react-export-excel
this works fine with react-create-app but can't make it work in Nextjs due to it's custom webpack configuration. I can't make this part working in Nextjs
///webpack.config.js
vendor: [
.....
'xlsx',
'file-saver'
],
.....
node: {fs: 'empty'},
externals: [
{'./cptable': 'var cptable'},
{'./jszip': 'jszip'}
]
Thanks in advance for any guide!
here is my code as a a sample i hope it helps
/api/shipments/downloadManifest.js/
const fs = require("fs");
import Shipment from "../../../backend/shipmentModel";
const json2xls = require("json2xls");
import path from "path";
const handler = async (req, res) => {
if (req.method === "POST") {
const { batchStart, batchEnd } = req.body;
if (!batchStart || !batchEnd) {
return res.status(200).json({
status: "error",
error: "No start and end date defined!",
});
}
try {
const data = await Shipment.find({
createdAt: {
$gte: batchStart,
$lte: batchEnd,
},
});
const excel = json2xls(data, {
fields: [
"name",
"destination",
"weight",
"carton",
"dollar_rate",
"customs_rate",
"freight_rate",
"freight_$",
"freight",
"customs",
"amountDue",
"mobile",
"action",
],
});
await fs.writeFileSync("./public/manifest.xlsx", excel, "binary");
const filePath = path.join(process.cwd(), "/public/manifest.xlsx");
const manifestBuffer = fs.createReadStream(filePath);
await new Promise(function (resolve) {
res.setHeader(
"Content-Disposition",
"attachment; filename=manifest.xlsx"
);
res.setHeader(
"Content-Type",
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
);
res.setHeader("Content-Length", `${manifestBuffer.size}`);
manifestBuffer.pipe(res);
manifestBuffer.on("end", resolve);
manifestBuffer.on("error", function (err) {
if (err.code === "ENOENT") {
res.status(400).json({
error: "error",
error: "Sorry we could not find the file you requested!",
});
res.end();
} else {
res.status(500).json({
error: "error",
message: "Sorry, something went wrong!",
});
res.end();
}
});
});
} catch (error) {
console.log(error);
return res.status(200).json({
status: "error",
msg: error.message,
});
}
}
};
export default handler;
/pages/shipments.js
setLoading(true);
const data = await axios.post(
"/api/shipments/downloadManifest",
{
batchStart: batch.batchStart,
batchEnd:
batchIndex ===
batches?.[batches?.length - 1]?.months?.[
batches?.[batches?.length - 1]?.months?.length - 1
]?.batches?.length -
1
? new Date(Date.now())
: batch.batchEnd,
},
{
responseType: "blob",
}
);
const pdfBlob = new Blob([data.data], { type: "application/xlsx" });
setLoading(false);
return saveAs(pdfBlob, "manifest.xlsx");
do not forget to install "file-saver" and "json2xls" npm packages as a dependency
Related
When I click to delete a post, my console is saying TypeError: post.user.posts.deleteOne is not a function. It giving me this error after deleting.
const post = await Post.findByIdAndDelete(id).populate('user'); This code I am deleting the post from Post Schema
await post.user.posts.deleteOne(post)This code is to delete the post from the User Schema. I populated user and assigned it to post and then delete the user's post from this code, but I'm getting the error here.
Below is the controller code
export const deletePost = async (req, res) => {
const { id } = req.params;
try {
const post = await Post.findByIdAndDelete(id).populate('user');
await post.user.posts.deleteOne(post)
if (!post) {
return res.status(500).json({ message: "Unable To Delete" })
}
res.status(200).json({ message: "Deleted Successfully" })
} catch (error) {
console.log(error);
}
}
Client side delete request
const handleDeleteTrue = async () => {
try {
const { data } = await api.delete(`/post/${id}`)
console.log(data)
window.location.reload();
} catch (error) {
console.log(error.response.data.message);
}
};
User model schema
import mongoose from 'mongoose';
const userSchema = new mongoose.Schema({
name: {
type: String,
required: true
},
username: {
type: String,
required: true,
unique: true
},
email: {
type: String,
required: true,
unqie: true
},
password: {
type: String,
required: true,
minlength: 6
},
posts: [{ type: mongoose.Types.ObjectId, ref: "Post", required: true }]
});
export default mongoose.model('User', userSchema);
Im able to delete the post from the post model schema, but in this pic, which shows the user model schema, that same post that was deleted is not deleted here. This is the problem Im trying to solve.
What I can seem to understand in your function below is that you're trying to delete a single post and also checking if post exists first
export const deletePost = async (req, res) => {
const { id } = req.params;
try {
const post = await Post.findByIdAndDelete(id).populate('user');
await post.user.posts.deleteOne(post)
if (!post) {
return res.status(500).json({ message: "Unable To Delete" })
}
res.status(200).json({ message: "Deleted Successfully" })
catch (error) {
console.log(error);
}
}
I'd suggest you try this
export const deletePost = async (req, res) => {
const { id } = req.params;
try {
//check if document exists in mongoDB collection
if (!mongoose.Types.ObjectId.isValid(id)) {
return res.status(500).json({ message: "Unable To Delete" }) }
await Post.deleteOne(id)
res.status(200).json({ message: "Deleted Successfully" })
catch (error) {
console.log(error);
}
}
I found out the answer. My user model schema for post was an array so I had to use $pull to delete it.
This is the code that worked for me
await post.user.posts.pull(post)
await post.user.save()
You can't use findOneAndDelete on populate to delete one object from an array. it doesn't work that way. Use This Instead.
const result = await User.findOneAndUpdate(
{ _id: Id },
{ $pull: { post:PostId } },
{ new: true }
);
You can find More on Pull and Push Operations on BlogLink
It's my first time using Next Js, Mongo DB and Postman. I am building an app and when sending the information I get a 500 error in postman.
In VSC all is ok and the console does not have any errors
Can you guide me with some ideas to fix it?
I hope that the information is sent correctly and that it gives me a 201 code. As in the screenshot of the tutorial
Link to tutorial:https://www.youtube.com/watch?v=Z-hACIsjv4E&t=3115s
I'am using mongoose to...
import mongoose from "mongoose";
const MONGO_URL = process.env.MONGO_URL;
console.log(process.env.MONGO_URL);
if (!MONGO_URL) {
throw new Error(
"Please define the MONGO_URL environment variable inside .env.local"
);
}
let cached = global.mongoose;
if (!cached) {
cached = global.mongoose = { conn: null, promise: null };
}
async function dbConnect() {
if (cached.conn) {
return cached.conn;
}
if (!cached.promise) {
const opts = {
bufferCommands: false,
};
cached.promise = mongoose.connect(MONGO_URL, opts).then((mongoose) => {
return mongoose;
});
}
cached.conn = await cached.promise;
return cached.conn;
}
export default dbConnect;
import dbConnect from "../../../util/mongo";
import Product from "../../../models/Product";
export default async function handler(req, res) {
const { method } = req;
dbConnect();
if (method === "GET") {
try {
} catch (err) {}
}
if (method === "POST") {
try {
const product = await Product.create(req.body);
req.status(201).json(product);
} catch (err) {
res.status(500).json(err);
}
}
}
import mongoose from "mongoose";
const OrderSchema = new mongoose.Schema(
{
customer: {
type: String,
required: true,
maxlength: 60,
},
address: {
type: String,
required: true,
maxlength: 200,
},
total: {
type: Number,
required: true,
},
status: {
type: Number,
default: 0,
},
method: {
type: Number,
required: true,
},
},
{ timestamps: true }
);
export default mongoose.models.Order || mongoose.model("Order", OrderSchema);
so when i send a request which looks like that:
everythig in this api:
router.post('', async (req, res) => {
try {
if(!req.files || !req.body.format) {
res.send({
status: false,
message: 'No file or format'
});
} else {
let uuidv4 = () =>{
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
let r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);
return v.toString(16);
});
}
let video = req.files.video;
let video_name = uuidv4()
let video_format = req.body.format
if (allowedFormats.includes(video_format)) {
let oldVideoPath = './public/uploads/' + video_name + "." + video_format
const newVideoPath = './public/converted/' + video_name + ".mp3"
let video_path = oldVideoPath
video.mv(oldVideoPath)
let proc = new ffmpeg({source: video_path, nolog: true})
proc.setFfmpegPath("./ffmpeg/bin/ffmpeg.exe")
proc
.toFormat('mp3')
.on('end', function () {
res.send({
status: true,
message: 'File has been uploaded',
file: newVideoPath.substring(1)
});
})
.on('error', function (err) {
res.send({
status: false,
message: 'An error occurred ' + err,
});
})
.saveToFile(newVideoPath)
} else {
res.send({
status: false,
message: 'Wrong format!',
})
}
}
} catch (err) {
res.status(500).send(err);
}
});
works perfectly, but the second i send it from react
const fileHandler = (file) => {
const data = new FormData()
data.append('file', file)
data.append('format', baseFormat)
fetch(process.env.REACT_APP_API_IP+'/upload-video', {
method: 'POST',
body: data
})
.then(response => response.json())
.then(data => console.log(data))
}
it gives me an 500 (Internal Server Error).
I checked and when sent from react the file and format reach the api but it breaks somewhere after the uuidv4 function.
Any help appreciated!
You should specify that it is form data.
Add to your fetch
headers: { 'Content-Type': 'multipart/form-data' },
Other issue is that express does not handle multipart/form-data by itself. You have to use some middleware like multer - https://github.com/expressjs/multer
Express part:
const multer = require('multer');
const upload = multer({ dest: "uploads/" });
app.post("/upload-video", upload.single("video"), (req, res) => {
let video = req.file
// rest of your code
}
And in you react code remember to use video field name:
const fileHandler = (file) => {
const data = new FormData()
data.append('video', file)
// ...
My goal is to process a test payment using Stripe in a React JS web app. When I enter the test card information, I receive a 404 Error with the following message: "POST /api/payment_intents 404 (Not Found)". Why isn't the "axios.post("/api/payment_intents", method able to locate my payment intents?
[https://github.com/ChicagoJoe1991/saas-template][1]
import Stripe from "stripe";
const stripe = new Stripe(process.env.REACT_APP_SECRET_KEY);
export default async (req, res) => {
if (req.method === "POST") {
try {
const { amount } = req.body;
const paymentIntent = await stripe.paymentIntents.create({
amount,
currency: "usd",
});
res.status(200).send(paymentIntent.client_secret);
} catch (err) {
res.status(500).json({ statusCode: 500, message: err.message });
}
} else {
res.setHeader("Allow", "POST");
res.status(405).end("Method Not Allowed");
}
};
try {
const { data: clientSecret } = await axios.post("/api/payment_intents", {
amount: price * 100,
});
const paymentMethodReq = await stripe.createPaymentMethod({
type: "card",
card: cardElement,
billing_details: billingDetails,
});
if (paymentMethodReq.error) {
setCheckoutError(paymentMethodReq.error.message);
setProcessingTo(false);
return;
}
const { error } = await stripe.confirmCardPayment(clientSecret, {
payment_method: paymentMethodReq.paymentMethod.id,
});
if (error) {
setCheckoutError(error.message);
setProcessingTo(false);
return;
}
onSuccessfulCheckout();
} catch (err) {
setCheckoutError(err.message);
}
};
you are not setting baseURL.
{ axios.post("/api/payment_intents", }
You must add some server path like localhost or wherever you are hosting API.
I am using React.js as my JavaScript framework, where I have installed Jest and using pact (CDC) for unit test cases and while I run the command npm run test the spec.js file is failing and throwing an error like this
TypeError: http is not a function
This is criteria-managementcomponent.spec.js file
const path = require('path')
const pact = require('pact')
const API_PORT = process.env.API_PORT || 9123
const {
fetchProviderData, getCriteriaManagementComponent, criteriaManagementComponent
} = require('../client')
// Configure and import consumer API
// Note that we update the API endpoint to point at the Mock Service
const LOG_LEVEL = process.env.LOG_LEVEL || 'WARN'
const provider = pact({
consumer: 'Web Login',
provider: 'Web API',
port: API_PORT,
log: path.resolve(process.cwd(), 'logs', 'pact.log'),
dir: path.resolve(process.cwd(), 'pacts'),
logLevel: LOG_LEVEL,
spec: 2
})
describe('Started Testing Pact', () => {
beforeEach((done) => {
return provider.setup().then(() => done());
});
afterEach((done) => {
return provider.finalize().then(() => done())
})
describe('criteriaManagement', () => {
beforeEach(() => {
let criteriaManagement = {
uponReceiving: 'wrong criteriaManagement',
state: 'Code OK',
withRequest: {
method: 'GET',
path: '/api/criteria',
},
willRespondWith: {
status: 200,
headers: {
'Content-Type': 'application/json; charset=utf-8'
},
body: {
code: "string",
context: {},
message: "string",
payload: [
{
country: "string",
createdBy: "string",
displayOrder: 0,
id: "string",
lastModifiedBy: "string",
name: "string",
translations: {},
warehouse: "string"
}
]
}
}
};
return provider.addInteraction(criteriaManagement)
})
afterEach(() => {
return provider.verify()
})
it('Login test', done => {
criteriaManagementComponent().then((res) => {
expect(res.code).not.toBeNull();
expect(res.context).toBeDefined();
expect(res.message).not.toBeNull();
expect(res.payload.country).not.toBeNull();
expect(res.payload.createdBy).not.toBeNull();
expect(res.payload.displayOrder).toBe(0);
expect(res.payload.id).not.toBeNull();
expect(res.payload.lastModifiedBy).not.toBeNull();
expect(res.payload.translations).toBeDefined();
expect(res.payload.name).not.toBeNull();
expect(res.payload.warehouse).not.toBeNull();
});
done();
})
});
})
This is client.js file for criteria-managementcomponent.spec.js file
const request = require('superagent')
const API_HOST = process.env.API_HOST || 'http://localhost'
const API_PORT = process.env.API_PORT || 9123
const API_ENDPOINT = `${API_HOST}:${API_PORT}`
// Fetch provider data
const fetchProviderData = (submissionDate) => {
return request
.get(`${API_ENDPOINT}/provider`)
.query({ validDate: submissionDate })
.then((res) => {
console.log("Response :: ", res.body);
return {
count: 100 / res.body.count,
date: res.body.date
}
})
}
const getCriteriaManagementComponent = (accessToken, expiresIn) => {
return request
.post(`${API_ENDPOINT}/api/criteria`)
.then((res) => {
return {
code : res.body.code
}
})
}
const criteriaManagementComponent = () => {
// const request = require('request')
console.log("End Point =========> ", `${API_ENDPOINT}/api/criteria`)
return request.get(`${API_ENDPOINT}/api/criteria`).then((res) => {
return {
code : res.body.code,
context:res.body.context,
message:res.body.message,
payload:res.body.payload,
profile:res.body.payload.profile,
successful : res.body.successful
}
})
};
module.exports = {
fetchProviderData, getCriteriaManagementComponent, criteriaManagementComponent
}
It's hard to know where things are going wrong without a line number in the stack trace, however one thing is for certain - you're using a very old version of pact.
You should be using #pact-foundation/pact now.
As for the http issue, is it possible you have any mocks setup that are interfering? The issue seems unrelated to pact.
Lastly, if you could provide a reproducible github repo that others could download and run, you could probably get even better help.