├── public
├── favicon.ico
├── logo192.png
├── logo512.png
├── home_page.png
├── robots.txt
├── manifest.json
└── index.html
├── src
├── App.css
├── context
│ ├── blog-context.js
│ ├── GlobalState.js
│ └── reducers.js
├── App.js
├── index.css
├── components
│ ├── PageLoader.js
│ ├── Main.js
│ ├── Home.js
│ ├── BlogFormOld.js
│ └── BlogForm.js
├── index.js
├── header.js
├── shared
│ └── Header.js
└── data
│ └── blogs.json
├── static.json
├── .gitignore
├── package.json
└── README.md
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MA-Ahmad/reactBlog/HEAD/public/favicon.ico
--------------------------------------------------------------------------------
/public/logo192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MA-Ahmad/reactBlog/HEAD/public/logo192.png
--------------------------------------------------------------------------------
/public/logo512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MA-Ahmad/reactBlog/HEAD/public/logo512.png
--------------------------------------------------------------------------------
/src/App.css:
--------------------------------------------------------------------------------
1 |
2 | .active {
3 | color: #d4de3c;
4 | border-bottom: 1px solid;
5 | }
6 |
--------------------------------------------------------------------------------
/public/home_page.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MA-Ahmad/reactBlog/HEAD/public/home_page.png
--------------------------------------------------------------------------------
/public/robots.txt:
--------------------------------------------------------------------------------
1 | # https://www.robotstxt.org/robotstxt.html
2 | User-agent: *
3 | Disallow:
4 |
--------------------------------------------------------------------------------
/static.json:
--------------------------------------------------------------------------------
1 | {
2 | "root": "build/",
3 | "clean_urls": false,
4 | "routes": {
5 | "/**": "index.html"
6 | }
7 | }
--------------------------------------------------------------------------------
/src/context/blog-context.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import blogs from "../data/blogs";
3 |
4 | export default React.createContext({
5 | blogs: blogs,
6 | createBlog: blog => {},
7 | deleteBlog: blogId => {}
8 | });
9 |
--------------------------------------------------------------------------------
/src/App.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { BrowserRouter as Router } from "react-router-dom";
3 | import Main from "./components/Main";
4 | import GlobalState from "./context/GlobalState";
5 |
6 | function App() {
7 | return (
8 |
9 |
10 |
11 |
12 |
13 | );
14 | }
15 |
16 | export default App;
17 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .pnp.js
7 |
8 | # testing
9 | /coverage
10 |
11 | # production
12 | /build
13 |
14 | # misc
15 | .DS_Store
16 | .env.local
17 | .env.development.local
18 | .env.test.local
19 | .env.production.local
20 |
21 | npm-debug.log*
22 | yarn-debug.log*
23 | yarn-error.log*
24 |
--------------------------------------------------------------------------------
/src/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
4 | 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
5 | sans-serif;
6 | -webkit-font-smoothing: antialiased;
7 | -moz-osx-font-smoothing: grayscale;
8 | }
9 |
10 | code {
11 | font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
12 | monospace;
13 | }
14 |
--------------------------------------------------------------------------------
/src/components/PageLoader.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { Flex, Spinner } from "@chakra-ui/core";
3 | const PageLoader = () => {
4 | return (
5 |
16 |
17 |
18 | );
19 | };
20 |
21 | export default PageLoader;
22 |
--------------------------------------------------------------------------------
/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "React App",
3 | "name": "Create React App Sample",
4 | "icons": [
5 | {
6 | "src": "favicon.ico",
7 | "sizes": "64x64 32x32 24x24 16x16",
8 | "type": "image/x-icon"
9 | },
10 | {
11 | "src": "logo192.png",
12 | "type": "image/png",
13 | "sizes": "192x192"
14 | },
15 | {
16 | "src": "logo512.png",
17 | "type": "image/png",
18 | "sizes": "512x512"
19 | }
20 | ],
21 | "start_url": ".",
22 | "display": "standalone",
23 | "theme_color": "#000000",
24 | "background_color": "#ffffff"
25 | }
26 |
--------------------------------------------------------------------------------
/src/components/Main.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { Switch, Route, Redirect } from "react-router-dom";
3 | import Header from "../shared/Header";
4 | import BlogForm from "./BlogForm";
5 | import Home from "./Home";
6 |
7 | const Main = () => {
8 | return (
9 |
10 |
11 |
12 |
13 | {
17 | return ;
18 | }}
19 | />
20 | {
24 | return ;
25 | }}
26 | />
27 |
28 |
29 |
30 | );
31 | };
32 |
33 | export default Main;
34 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import ReactDOM from 'react-dom'
3 | import App from './App'
4 | import { theme, ThemeProvider, CSSReset } from '@chakra-ui/core'
5 |
6 | const breakpoints = ['600px', '850px', '900px', '1440px']
7 | breakpoints.sm = breakpoints[0]
8 | breakpoints.md = breakpoints[1]
9 | breakpoints.lg = breakpoints[2]
10 | breakpoints.xl = breakpoints[3]
11 |
12 | const newTheme = {
13 | ...theme,
14 | breakpoints,
15 | }
16 |
17 | ReactDOM.render(
18 |
19 |
20 |
21 |
22 |
23 | ,
24 | document.getElementById('root')
25 | )
26 | // function App() {
27 | // return (
28 | //
29 | //
30 | //
31 | //
32 | //
33 | // );
34 | // }
35 |
36 | // const rootElement = document.getElementById("root");
37 | // ReactDOM.render(, rootElement);
38 |
--------------------------------------------------------------------------------
/src/context/GlobalState.js:
--------------------------------------------------------------------------------
1 | import React, { useReducer } from "react";
2 | import BlogContext from "./blog-context";
3 | import { blogReducer, CREATE_BLOG, EDIT_BLOG, DELETE_BLOG } from "./reducers";
4 | import blogs_data from "../data/blogs";
5 |
6 | const GlobalState = props => {
7 | const blogs = blogs_data;
8 | const [blogState, dispatch] = useReducer(blogReducer, { blogs: blogs });
9 |
10 | const createBlog = blog => {
11 | dispatch({ type: CREATE_BLOG, blog: blog });
12 | };
13 |
14 | const editBlog = blog => {
15 | dispatch({ type: EDIT_BLOG, blog: blog });
16 | };
17 |
18 | const deleteBlog = blogId => {
19 | dispatch({ type: DELETE_BLOG, blogId: blogId });
20 | };
21 |
22 | return (
23 |
31 | {props.children}
32 |
33 | );
34 | };
35 |
36 | export default GlobalState;
37 |
--------------------------------------------------------------------------------
/src/context/reducers.js:
--------------------------------------------------------------------------------
1 | export const CREATE_BLOG = "CREATE_BLOG";
2 | export const EDIT_BLOG = "EDIT_BLOG";
3 | export const DELETE_BLOG = "DELETE_BLOG";
4 |
5 | const createBlog = (blog, state) => {
6 | const state_blogs = [...state.blogs];
7 | state_blogs.push({ ...blog, id: state_blogs.length + 1 });
8 | return { ...state, blogs: state_blogs };
9 | };
10 |
11 | const editBlog = (blog, state) => {
12 | const state_blogs = [...state.blogs];
13 | const blogIndex = getBlogIndex(state, blog.id);
14 | state_blogs[blogIndex] = blog;
15 | return { ...state, blogs: state_blogs };
16 | };
17 |
18 | const getBlogIndex = (state, blogId) => {
19 | return state.blogs.findIndex(blog => blog.id === blogId);
20 | };
21 |
22 | const deleteBlog = (blogId, state) => {
23 | const state_blogs = [...state.blogs];
24 | return { ...state, blogs: state_blogs.filter(blog => blog.id !== blogId) };
25 | };
26 |
27 | export const blogReducer = (state, action) => {
28 | switch (action.type) {
29 | case CREATE_BLOG:
30 | return createBlog(action.blog, state);
31 | case EDIT_BLOG:
32 | return editBlog(action.blog, state);
33 | case DELETE_BLOG:
34 | return deleteBlog(action.blogId, state);
35 | default:
36 | return state;
37 | }
38 | };
39 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "blog",
3 | "version": "0.1.0",
4 | "private": true,
5 | "homepage": "https://ma-ahmad.github.io/reactBlog",
6 | "dependencies": {
7 | "@chakra-ui/core": "^0.8.0",
8 | "@emotion/core": "^10.0.28",
9 | "@emotion/styled": "^10.0.27",
10 | "@testing-library/jest-dom": "^4.2.4",
11 | "@testing-library/react": "^9.3.2",
12 | "@testing-library/user-event": "^7.1.2",
13 | "emotion-theming": "^10.0.27",
14 | "formik": "^2.1.5",
15 | "react": "^16.13.1",
16 | "react-animation-components": "^3.0.0",
17 | "react-dom": "^16.13.1",
18 | "react-dotdotdot": "^1.3.1",
19 | "react-icons": "^3.10.0",
20 | "react-image": "^4.0.3",
21 | "react-router-dom": "^5.2.0",
22 | "react-scripts": "3.4.1",
23 | "react-transition-group": "^4.4.1"
24 | },
25 | "scripts": {
26 | "start": "react-scripts start",
27 | "predeploy": "npm run build",
28 | "deploy": "gh-pages -d build",
29 | "build": "react-scripts build",
30 | "test": "react-scripts test",
31 | "eject": "react-scripts eject"
32 | },
33 | "eslintConfig": {
34 | "extends": "react-app"
35 | },
36 | "browserslist": {
37 | "production": [
38 | ">0.2%",
39 | "not dead",
40 | "not op_mini all"
41 | ],
42 | "development": [
43 | "last 1 chrome version",
44 | "last 1 firefox version",
45 | "last 1 safari version"
46 | ]
47 | },
48 | "devDependencies": {
49 | "gh-pages": "^3.1.0"
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
React Blogs
2 |
3 |
4 |
5 | [](https://www.linkedin.com/in/muhammad-ahmad20/)
6 | [](mailto:muhammad.ahmad8043@gmail.com)
7 |
8 | This app shows you how to create a CRUD app with react by using ChakraUI.
9 |
10 | 
11 |
12 | ## What this App does?
13 |
14 | - By this app, you will be able to:
15 |
16 | - Create a new Blog.
17 | - Edit a Blog.
18 | - Delete a Blog.
19 | - Get list of all Blogs.
20 |
21 | ## Built with
22 |
23 | - Reactjs (react hooks, react router)
24 | - ChakraUI used for styling
25 | - Formik used for validations
26 | - react-transition-group for animation
27 |
28 | ## Setup
29 |
30 | - Clone the repository
31 | - Use `cd `
32 | - Run `npm install`
33 | - Run `npm start`
34 |
35 | ## View and copy code of your favourite components
36 | [TemplatesKart website](https://templateskart.com/projects/blog-app)
37 |
38 | ## Author
39 |
40 | Muhammad Ahmad
41 |
42 | - Github: [@Ahmad](https://github.com/MA-Ahmad)
43 |
44 | - LinkedIn: [Muhammad Ahmad](https://www.linkedin.com/in/muhammad-ahmad20/)
45 |
46 | ## 🤝 Contributing
47 |
48 | Contributions, issues and feature requests are welcome! Start by:
49 |
50 | - Forking the project
51 | - Cloning the project to your local machine
52 | - `cd` into the project directory
53 | - Run `git checkout -b your-branch-name`
54 | - Make your contributions
55 | - Push your branch up to your forked repository
56 | - Open a Pull Request with a detailed description to the development branch of the original project for a review
57 |
58 | ## Show your support
59 |
60 | Give a ⭐️ if you like this project!
61 |
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
12 |
13 |
17 |
18 |
27 | React App
28 |
29 |
30 |
31 |
32 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/src/header.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { Box, Heading, Flex, Text, Button } from "@chakra-ui/core";
3 |
4 | const MenuItems = ({ children }) => (
5 |
6 | {children}
7 |
8 | );
9 |
10 | // Note: This code could be better, so I'd recommend you to understand how I solved and you could write yours better :)
11 | const Header = props => {
12 | const [show, setShow] = React.useState(false);
13 | const handleToggle = () => setShow(!show);
14 |
15 | return (
16 |
26 |
27 |
28 | Blog
29 |
30 |
31 |
32 |
33 |
42 |
43 |
44 |
50 | New
51 | List
52 |
53 |
54 |
55 |
59 |
62 |
63 |
64 | );
65 | };
66 |
67 | export default Header;
68 |
--------------------------------------------------------------------------------
/src/shared/Header.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Box, Heading, Flex, Text, Button, Link } from '@chakra-ui/core'
3 | import { NavLink } from 'react-router-dom'
4 | import { FaGithub } from 'react-icons/fa'
5 | import '../App.css'
6 |
7 | const MenuItems = ({ children }) => (
8 |
9 | {children}
10 |
11 | )
12 |
13 | // Note: This code could be better, so I'd recommend you to understand how I solved and you could write yours better :)
14 | const Header = (props) => {
15 | const [show, setShow] = React.useState(false)
16 | const handleToggle = () => setShow(!show)
17 |
18 | return (
19 |
20 |
32 |
33 |
34 | Blog
35 |
36 |
37 |
38 |
39 |
48 |
49 |
50 |
56 |
57 |
58 |
59 | New
60 |
61 |
62 |
63 |
64 |
65 |
66 | List
67 |
68 |
69 |
70 |
71 |
72 |
73 |
78 |
81 |
82 |
83 |
84 |
85 | )
86 | }
87 |
88 | export default Header
89 |
--------------------------------------------------------------------------------
/src/data/blogs.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "id": 1,
4 | "title": "Rails ActiveAdmin",
5 | "authorName": "Ali",
6 | "content": "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum."
7 | },
8 | {
9 | "id": 2,
10 | "title": "Future of ROR",
11 | "authorName": "Ahmad",
12 | "content": "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum."
13 | },
14 | {
15 | "id": 3,
16 | "title": "ReactJs with Chakra",
17 | "authorName": "Taimoor",
18 | "content": "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum."
19 | },
20 | {
21 | "id": 4,
22 | "title": "ReactJS with Rails",
23 | "authorName": "Hassan",
24 | "content": "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum."
25 | },
26 | {
27 | "id": 5,
28 | "title": "React on Rails",
29 | "authorName": "Umar",
30 | "content": "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum."
31 | }
32 | ]
--------------------------------------------------------------------------------
/src/components/Home.js:
--------------------------------------------------------------------------------
1 | import React, { useContext, useState, useEffect } from 'react'
2 | import { Box, Badge, SimpleGrid, useToast } from '@chakra-ui/core'
3 | import Dotdotdot from 'react-dotdotdot'
4 | import BlogContext from '../context/blog-context'
5 | import { Link } from 'react-router-dom'
6 | import PageLoader from './PageLoader'
7 | import { Img } from 'react-image'
8 |
9 | const Home = () => {
10 | const context = useContext(BlogContext)
11 | const [blogId, setBlogId] = useState('')
12 | const toast = useToast()
13 |
14 | useEffect(() => {
15 | context.deleteBlog(blogId)
16 | }, [blogId])
17 |
18 | const handleDelete = (id) => {
19 | toast({
20 | position: 'bottom',
21 | title: 'Notification',
22 | description: 'Blog deleted successfully',
23 | status: 'success',
24 | duration: 2000,
25 | isClosable: true,
26 | })
27 | setBlogId(id)
28 | }
29 | return (
30 |
38 |
39 | {context.blogs.map((blog) => {
40 | return (
41 |
42 |
50 | handleDelete(blog.id)}
56 | >
57 | Delete
58 |
59 |
60 |
61 |
69 |
}
73 | />
74 |
75 |
76 |
83 | {blog.title}
84 |
85 |
86 |
87 |
88 |
89 | {blog.authorName}
90 |
91 |
92 |
93 |
94 |
102 | {blog.content}
103 |
104 |
105 |
106 |
107 |
108 |
109 | )
110 | })}
111 |
112 |
113 | )
114 | }
115 |
116 | export default Home
117 |
--------------------------------------------------------------------------------
/src/components/BlogFormOld.js:
--------------------------------------------------------------------------------
1 | import React, { useState, useContext } from "react";
2 | import {
3 | Box,
4 | Flex,
5 | FormControl,
6 | FormLabel,
7 | Input,
8 | Stack,
9 | Textarea,
10 | Button,
11 | Heading,
12 | useToast,
13 | FormErrorMessage
14 | } from "@chakra-ui/core";
15 | import BlogContext from "../context/blog-context";
16 | import { Formik, Field, Form, ErrorMessage, useFormik } from "formik";
17 | import { red } from "color-name";
18 |
19 | const BlogForm = () => {
20 | const context = useContext(BlogContext);
21 | const toast = useToast();
22 |
23 | const [title, setTitle] = useState("");
24 | const [authorName, setAuthorName] = useState("");
25 | const [content, setContent] = useState("");
26 |
27 | const handleSubmit = e => {
28 | e.preventDefault();
29 | console.log(title);
30 | context.createBlog({ title: title, author: authorName, content: content });
31 | toast({
32 | position: "bottom",
33 | title: "Account created.",
34 | description: "We've created your account for you.",
35 | status: "success",
36 | duration: 5000,
37 | isClosable: true
38 | });
39 | setTitle("");
40 | setAuthorName("");
41 | setContent("");
42 | };
43 |
44 | const handleNameChange = e => {
45 | setAuthorName(e.target.value);
46 | };
47 |
48 | const handleTitleChange = e => {
49 | setTitle(e.target.value);
50 | };
51 |
52 | const handleContentChange = e => {
53 | setContent(e.target.value);
54 | };
55 |
56 | const validate = values => {
57 | const errors = {};
58 | if (!values.title) {
59 | errors.title = "Required";
60 | } else if (values.title.length < 5) {
61 | errors.title = "Must be 5 characters or more";
62 | }
63 |
64 | if (!values.authorName) {
65 | errors.authorName = "Required";
66 | } else if (values.authorName.length > 20) {
67 | errors.authorName = "Must be 20 characters or less";
68 | }
69 |
70 | return errors;
71 | };
72 |
73 | const formik = useFormik({
74 | initialValues: {
75 | title: title,
76 | authorName: authorName
77 | },
78 | validate,
79 | onSubmit: values => {
80 | alert(JSON.stringify(values, null, 2));
81 | },
82 | onChange: value => {
83 | console.log(value);
84 | setTitle(title);
85 | setAuthorName(authorName);
86 | }
87 | });
88 |
89 | return (
90 |
98 |
99 |
100 | Create a Blog
101 |
102 |
103 |
104 |
105 |
148 |
149 |
150 |
151 |
152 | );
153 | };
154 |
155 | export default BlogForm;
156 |
--------------------------------------------------------------------------------
/src/components/BlogForm.js:
--------------------------------------------------------------------------------
1 | import React, { useState, useContext, useEffect } from 'react'
2 | import {
3 | Box,
4 | Flex,
5 | FormControl,
6 | FormLabel,
7 | Input,
8 | Stack,
9 | Textarea,
10 | Button,
11 | Heading,
12 | useToast,
13 | FormErrorMessage,
14 | } from '@chakra-ui/core'
15 | import BlogContext from '../context/blog-context'
16 | import { Formik, Field } from 'formik'
17 | import { FadeTransform } from 'react-animation-components'
18 |
19 | const BlogForm = ({ match, history, editMode }) => {
20 | const [initialValues, setInitialValues] = useState({
21 | title: '',
22 | authorName: '',
23 | content: '',
24 | })
25 | const [id, setId] = useState(match.params.id)
26 | const context = useContext(BlogContext)
27 | const toast = useToast()
28 |
29 | useEffect(() => {
30 | if (editMode) {
31 | const selectedBlog = context.blogs.filter(
32 | (blog) => blog.id === Number(id)
33 | )[0]
34 | setInitialValues(selectedBlog)
35 | } else {
36 | setInitialValues({
37 | title: '',
38 | authorName: '',
39 | content: '',
40 | })
41 | }
42 | }, [editMode])
43 |
44 | function validateTitle(value) {
45 | let error
46 | if (!value) {
47 | error = 'Title is required'
48 | } else if (value.length < 5) {
49 | error = 'Must be 5 characters or more'
50 | }
51 | return error
52 | }
53 |
54 | function validateAuthorName(value) {
55 | let error
56 | if (!value) {
57 | error = 'Name is required'
58 | } else if (value.length < 5) {
59 | error = 'Must be 5 characters or more'
60 | }
61 | return error
62 | }
63 |
64 | return (
65 |
71 |
79 |
84 |
85 | {editMode ? 'Update' : 'Create'} a Blog
86 |
87 |
88 |
95 |
96 | {
100 | setTimeout(() => {
101 | if (editMode) {
102 | values['id'] = Number(id)
103 | context.editBlog(values)
104 | setInitialValues(values)
105 | } else {
106 | context.createBlog(values)
107 | actions.resetForm({})
108 | }
109 | history.push('/')
110 |
111 | actions.setSubmitting(false)
112 | const text = editMode
113 | ? 'Blog post updated successfully'
114 | : "You've successfully created a blog post."
115 | toast({
116 | position: 'bottom',
117 | title: 'Notification',
118 | description: text,
119 | status: 'success',
120 | duration: 2000,
121 | isClosable: true,
122 | })
123 | }, 200)
124 | }}
125 | >
126 | {({ values, handleChange, handleSubmit, isSubmitting }) => {
127 | return (
128 |
203 | )
204 | }}
205 |
206 |
207 |
208 |
209 |
210 |
211 | )
212 | }
213 |
214 | export default BlogForm
215 |
--------------------------------------------------------------------------------