Steps

  • Save uploaded images to server
  • Model > route > controller
  • Create media context
  • On each upload response, update media context
  • Show uploaded image as selected file with preview in new.js

Server

// models/media
import mongoose from "mongoose";
const { ObjectId } = mongoose.Schema;

const mediaSchema = new mongoose.Schema(
  {
    url: String,
    public_id: String,
    postedBy: {
      type: ObjectId,
      ref: "User",
    },
  },
  { timestamps: true }
);

export default mongoose.model("Media", mediaSchema);
// routes/media
router.post(
  "/upload-image-file",
  formidable(),
  requireSignin,
  isAdmin,
  uploadImageFile
);
// controllers/post
export const uploadImageFile = async (req, res) => {
  //   console.log(req.files); // [] of File {}
  try {
    // console.log(req.body.image);
    const result = await cloudinary.uploader.upload(req.files.file.path);
    // console.log("uploaded image url => ", result);
    // save to db
    const media = await new Media({
      url: result.secure_url,
      public_id: result.public_id,
      postedBy: req.user._id,
    }).save();
    res.json(media);
    // res.json({
    //   url: result.secure_url,
    //   public_id: result.public_id,
    // });
  } catch (err) {
    console.log(err);
  }
};

Client

import React from "react";
import { useState, createContext } from "react";

const MediaContext = createContext();

const MediaProvider = ({ children }) => {
  const [media, setMedia] = useState({
    images: [],
    selected: null,
  });

  return (
    <MediaContext.Provider value={[media, setMedia]}>
      {children}
    </MediaContext.Provider>
  );
};

export { MediaContext, MediaProvider };
// add this line of code in props={} in 
// UploadFile.js <Upload {...props} /> 
// MediaLibrary.js <Dragger {...props}>
setMedia({
    images: [...media.images, info.file.response],
    selected: info.file.response,
});

Then in new.js show uploaded/selected file preview. Also send it to server on post create.

// pages/admin/posts/new.js
{media.selected && (
  <>
    <div style={{ marginBottom: 15 }}></div>

    <Image width="100%" src={media.selected.url} />
  </>
)}

Update post create controller function

// controllers/post
export const createPost = async (req, res) => {
  try {
    const { title, content, categories } = req.body;
    // check if title is taken
    const alreadyExist = await Post.findOne({
      slug: slugify(title.toLowerCase()),
    }).exec();
    if (alreadyExist) return res.json({ error: "Title is taken" });

    // get category ids based on category name
    let ids = [];
    for (let i = 0; i < categories.length; i++) {
      Category.findOne({ name: categories[i] }).exec((err, c) => {
        if (err) {
          console.log(err);
        }
        // console.log("c", c._id);
        ids.push(c._id);
      });
    }
    // save post
    setTimeout(async () => {
      const newPost = await new Post({
        ...req.body,
        slug: slugify(title),
        categories: ids,
        postedBy: req.user._id,
      }).save();
      return res.json(newPost);
    }, 1000);
  } catch (err) {
    console.log(err);
  }
};