Now that we have a concept of admin and authors, we will need to share the a lot of same code/functionalities for both user types.

So we are going to move code from pages to components. Then you can just import the entire component and use for users with the role of author.

We will create a wrapper component called <AuthorLayout> which will check if user is author, if true allow author to create and manage posts.

// components/posts/NewPostComponent
import { useState, useEffect, useContext } from "react";
import { Row, Col, Button, Modal, Input, Upload, Image } from "antd";
import Editor from "rich-markdown-editor";
import { ThemeContext } from "../../context/theme";
import axios from "axios";
import { Select, Typography } from "antd";
import { Loading3QuartersOutlined, UploadOutlined } from "@ant-design/icons";
import toast from "react-hot-toast";
import { useRouter } from "next/router";
import Media from "../media/Media";
import { MediaContext } from "../../context/media";
import { uploadImage } from "../../functions/upload";

const { Text } = Typography;

const { Option } = Select;
const NewPostComponent = () => {
  // from localstorage
  const savedTitle = () => {
    if (process.browser) {
      if (localStorage.getItem("post-title"))
        return JSON.parse(localStorage.getItem("post-title"));
    }
  };

  const savedContent = () => {
    if (process.browser) {
      if (localStorage.getItem("post-content"))
        return JSON.parse(localStorage.getItem("post-content"));
    }
  };
  // hooks
  const [theme, setTheme] = useContext(ThemeContext);
  const [media, setMedia] = useContext(MediaContext);
  const router = useRouter();
  // state
  const [title, setTitle] = useState(savedTitle());
  const [content, setContent] = useState(savedContent());
  const [categories, setCatgories] = useState([]);
  const [visible, setVisible] = useState(false);
  // const [visibleMedia, setVisibleMedia] = useState(false);
  const [loading, setLoading] = useState(false);
  const [typing, setTyping] = useState(false);
  const [loadedCatetories, setLoadedCatetories] = useState([]);

  // console.log("TITLE", title);
  // console.log("CONTENT", content);

  useEffect(() => {
    const loadCategories = async () => {
      const { data } = await axios.get("/categories");
      setLoadedCatetories(data);
    };
    loadCategories();
  }, []);

  const handleTitle = (e) => {
    setTitle(e.target.value);
    localStorage.setItem("post-title", JSON.stringify(e.target.value));
  };

  const handleContent = (value) => {
    setContent(value);
    localStorage.setItem("post-content", JSON.stringify(value));
    setTyping(true);
    setTimeout(() => {
      {
        setTyping(false);
      }
    }, 1000);
  };

  const handlePublish = async () => {
    try {
      setLoading(true);
      const { data } = await axios.post("/create-post", {
        title,
        content,
        categories,
        featuredImage: media?.selected?._id,
      });
      // console.log("POST CREATED => ", data);
      if (data?.error) {
        toast.error(data.error);
        setLoading(false);
      } else {
        toast.success("Post created successfully");
        localStorage.setItem("post-title", "");
        localStorage.setItem("post-content", "");
        setMedia({ ...media, selected: null });
        router.push("/admin/posts");
      }
    } catch (err) {
      console.log(err);
      toast.error("Post create failed. Try again.");
      setLoading(false);
    }
  };

  return (
    <Row>
      <Col sm={22} lg={14} offset={1}>
        <h4 style={{ marginBottom: "-10px" }}>Create Post</h4>
        {/* <pre>{JSON.stringify(media, null, 4)}</pre> */}
        <Input
          style={{ margin: "20px 0px 20px 0px" }}
          size="large"
          placeholder="Give it a title"
          value={title}
          onChange={handleTitle}
        />

        <Editor
          style={{ width: "100%" }}
          dark={theme === "light" ? false : true}
          placeholder="Write something..."
          defaultValue={content}
          // defaultValue="Write something..."
          uploadImage={uploadImage}
          onChange={(v) => handleContent(v())}
        />
      </Col>
      <Col sm={22} lg={6} offset={1}>
        <Button
          type="default"
          htmlType="submit"
          style={{ margin: "10px 0px 10px 0" }}
          onClick={() => setVisible(true)}
        >
          Preview
        </Button>

        {typing && (
          <>
            <Loading3QuartersOutlined spin style={{ marginLeft: 20 }} />{" "}
            <Text disabled>Saving draft...</Text>
          </>
        )}

        <h4>Categories</h4>
        <Select
          mode="multiple"
          allowClear
          style={{ width: "100%" }}
          placeholder="Please select"
          onChange={(v) => setCatgories(v)}
        >
          {loadedCatetories.map((item) => (
            <Option key={item.name}>{item.name}</Option>
          ))}
        </Select>

        {/* show selected/featured image */}
        {media.selected && (
          <>
            <div style={{ marginBottom: 15 }}></div>

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

        {/* <Upload onChange={handleFileChange} multiple={false} maxCount={1}> */}
        <Button
          // onClick={() => setVisibleMedia(true)}
          onClick={() => setMedia({ ...media, showMediaModal: true })}
          style={{ marginTop: 10 }}
          icon={<UploadOutlined />}
          block
        >
          Featured Image
        </Button>
        {/* </Upload> */}

        <Button
          onClick={handlePublish}
          type="default"
          htmlType="submit"
          style={{ margin: "10px 0px 10px 0" }}
          loading={loading}
          block
        >
          Publish
        </Button>
        {/* for post preview */}
        <Modal
          title="Preview"
          centered
          visible={visible}
          onOk={() => setVisible(false)}
          onCancel={() => setVisible(false)}
          width={720}
          footer={null}
        >
          <h1>{title}</h1>
          <img style={{ width: "100%" }} src={media.selected?.url} />
          <Editor
            dark={theme === "light" ? false : true}
            value={content}
            readOnly={true}
          />
        </Modal>
        {/* for media management */}
        <Modal
          title="Media"
          // centered
          style={{ top: 20 }}
          visible={media.showMediaModal}
          onOk={() => setMedia({ ...media, showMediaModal: false })}
          onCancel={() => setMedia({ ...media, showMediaModal: false })}
          width={720}
          footer={null}
        >
          <Media />
        </Modal>
      </Col>
    </Row>
  );
};

export default NewPostComponent;

Now import and use in /admin/posts/new

import AdminLayout from "../../../components/layout/AdminLayout";
import NewPostComponent from "../../../components/posts/NewPostComponent";

const NewPost = () => {
  return (
    <AdminLayout>
      <NewPostComponent />
    </AdminLayout>
  );
};

export default NewPost;