├── .gitignore
├── README.md
├── knexfile.js
├── libs
└── db.js
├── migrations
└── 20210127103201_create_post_table.js
├── package.json
├── pages
├── _app.js
├── api
│ ├── hello.js
│ └── posts
│ │ ├── create.js
│ │ ├── delete
│ │ └── [id].js
│ │ ├── index.js
│ │ └── update
│ │ └── [id].js
└── index.js
├── postcss.config.js
├── public
├── favicon.ico
└── vercel.svg
├── styles
├── Home.module.css
├── globals.css
└── tailwindcss.css
├── tailwind.config.js
└── yarn.lock
/.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 | # next.js
12 | /.next/
13 | /out/
14 |
15 | # production
16 | /build
17 |
18 | # misc
19 | .DS_Store
20 | *.pem
21 |
22 | # debug
23 | npm-debug.log*
24 | yarn-debug.log*
25 | yarn-error.log*
26 |
27 | # local env files
28 | .env.local
29 | .env.development.local
30 | .env.test.local
31 | .env.production.local
32 |
33 | # vercel
34 | .vercel
35 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app).
2 |
3 | ## Getting Started
4 |
5 | First, run the development server:
6 |
7 | ```bash
8 | npm run dev
9 | # or
10 | yarn dev
11 | ```
12 |
13 | Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
14 |
15 | You can start editing the page by modifying `pages/index.js`. The page auto-updates as you edit the file.
16 |
17 | [API routes](https://nextjs.org/docs/api-routes/introduction) can be accessed on [http://localhost:3000/api/hello](http://localhost:3000/api/hello). This endpoint can be edited in `pages/api/hello.js`.
18 |
19 | The `pages/api` directory is mapped to `/api/*`. Files in this directory are treated as [API routes](https://nextjs.org/docs/api-routes/introduction) instead of React pages.
20 |
21 | ## Learn More
22 |
23 | To learn more about Next.js, take a look at the following resources:
24 |
25 | - [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
26 | - [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
27 |
28 | You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome!
29 |
30 | ## Deploy on Vercel
31 |
32 | The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/import?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
33 |
34 | Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details.
35 |
--------------------------------------------------------------------------------
/knexfile.js:
--------------------------------------------------------------------------------
1 | // Update with your config settings.
2 |
3 | module.exports = {
4 |
5 | development: {
6 | client: 'mysql',
7 | connection: {
8 | host: '127.0.0.1',
9 | user: 'root',
10 | password: '',
11 | database: 'nextjs'
12 | }
13 | },
14 |
15 | staging: {
16 | client: 'postgresql',
17 | connection: {
18 | database: 'my_db',
19 | user: 'username',
20 | password: 'password'
21 | },
22 | pool: {
23 | min: 2,
24 | max: 10
25 | },
26 | migrations: {
27 | tableName: 'knex_migrations'
28 | }
29 | },
30 |
31 | production: {
32 | client: 'postgresql',
33 | connection: {
34 | database: 'my_db',
35 | user: 'username',
36 | password: 'password'
37 | },
38 | pool: {
39 | min: 2,
40 | max: 10
41 | },
42 | migrations: {
43 | tableName: 'knex_migrations'
44 | }
45 | }
46 |
47 | };
48 |
--------------------------------------------------------------------------------
/libs/db.js:
--------------------------------------------------------------------------------
1 | const knex = require('knex')({
2 | client: 'mysql',
3 | connection: {
4 | host : '127.0.0.1',
5 | user : 'root',
6 | password : '',
7 | database : 'nextjs'
8 | }
9 | });
10 |
11 |
12 | export default knex
--------------------------------------------------------------------------------
/migrations/20210127103201_create_post_table.js:
--------------------------------------------------------------------------------
1 |
2 | exports.up = function(knex) {
3 | return knex.schema.createTable('posts', function (table) {
4 | table.increments();
5 | table.string('title');
6 | table.text('content');
7 | table.timestamps(true, true);
8 | })
9 | };
10 |
11 | exports.down = function(knex) {
12 | return knex.schema.dropTable('posts')
13 | };
14 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "nextjs",
3 | "version": "0.1.0",
4 | "private": true,
5 | "scripts": {
6 | "dev": "next dev",
7 | "build": "next build",
8 | "start": "next start",
9 | "knex": "knex"
10 | },
11 | "dependencies": {
12 | "autoprefixer": "^10.2.3",
13 | "knex": "^0.21.16",
14 | "mysql": "^2.18.1",
15 | "next": "10.0.5",
16 | "postcss": "^8.2.4",
17 | "react": "17.0.1",
18 | "react-dom": "17.0.1",
19 | "sass": "^1.32.5",
20 | "tailwindcss": "^2.0.2"
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/pages/_app.js:
--------------------------------------------------------------------------------
1 | import '../styles/globals.css'
2 | import '../styles/tailwindcss.css'
3 |
4 | function MyApp({ Component, pageProps }) {
5 | return
6 | }
7 |
8 | export default MyApp
9 |
--------------------------------------------------------------------------------
/pages/api/hello.js:
--------------------------------------------------------------------------------
1 | // Next.js API route support: https://nextjs.org/docs/api-routes/introduction
2 |
3 | export default (req, res) => {
4 | res.statusCode = 200
5 | res.json({
6 | name: 'Cecep Gans',
7 | kelas: 'XII RPL 2',
8 | istri : 4,
9 | anak : 12,
10 | message : 'makanlan disaat kamu lapar'
11 | })
12 | }
13 |
--------------------------------------------------------------------------------
/pages/api/posts/create.js:
--------------------------------------------------------------------------------
1 | import db from '../../../libs/db'
2 |
3 | async function handler(req, res) {
4 | if (req.method !== 'POST')
5 | return res.status(405).json({message: 'method not post'});
6 |
7 | const {title, content} = req.body;
8 |
9 | const create = await db('posts').insert({title, content});
10 |
11 |
12 | res.status(200);
13 | res.json({message: 'Post create successfully'})
14 |
15 | }
16 |
17 | export default handler
--------------------------------------------------------------------------------
/pages/api/posts/delete/[id].js:
--------------------------------------------------------------------------------
1 | import db from '../../../../libs/db'
2 |
3 | export default async function handler(req, res) {
4 | if (req.method !== 'DELETE')
5 | return res.status(405).json({message: 'method not delete'});
6 |
7 | const {id} = req.query;
8 |
9 | const data = await db('posts')
10 | .where({id})
11 | .del()
12 |
13 | res.status(200);
14 | res.json({message: 'post deleted successfully'})
15 |
16 | }
--------------------------------------------------------------------------------
/pages/api/posts/index.js:
--------------------------------------------------------------------------------
1 | import db from '../../../libs/db'
2 |
3 | async function handler(req,res) {
4 | if (req.method !== 'GET')
5 | return res.status(405).json({message: 'method not get'});
6 |
7 | const data = await db('posts');
8 |
9 | res.status(200);
10 | res.json({
11 | message : 'success',
12 | data
13 | })
14 |
15 |
16 | }
17 |
18 | export default handler
--------------------------------------------------------------------------------
/pages/api/posts/update/[id].js:
--------------------------------------------------------------------------------
1 | import db from '../../../../libs/db'
2 |
3 | export default async function handler(req, res) {
4 | if (req.method !== 'PUT')
5 | return res.status(405).json({message: 'method not put'});
6 |
7 | const {id} = req.query;
8 | const {title, content} = req.body;
9 |
10 | const data = await db('posts')
11 | .where({id})
12 | .update({title, content})
13 |
14 | res.status(200);
15 | res.json({message: 'post updated successfully'})
16 |
17 | }
--------------------------------------------------------------------------------
/pages/index.js:
--------------------------------------------------------------------------------
1 | import {useState, useEffect} from 'react'
2 |
3 | export default function Home() {
4 |
5 | const [idPost,
6 | setIdPost] = useState('');
7 | const [title,
8 | setTitle] = useState('');
9 | const [content,
10 | setContent] = useState('');
11 |
12 | const [post,
13 | setPost] = useState(null);
14 |
15 | const [prefetch,
16 | setPrefetch] = useState(false);
17 |
18 | const [loadSubmit,
19 | setLoadSubmit] = useState(false);
20 |
21 | const [btnUpdate,
22 | setBtnUpdate] = useState(false)
23 |
24 | useEffect(() => {
25 | getDataApi();
26 | }, [prefetch]);
27 |
28 | async function getDataApi() {
29 | const getData = await fetch('http://localhost:3000/api/posts');
30 | const resultPost = await getData.json();
31 | setPost(resultPost)
32 | }
33 |
34 | const submitValue = async() => {
35 | if (content.length < 1 || title.length < 1) {
36 | alert('data tidak boleh kosong')
37 | } else {
38 | setLoadSubmit(true)
39 | const postData = {
40 | title,
41 | content
42 | }
43 |
44 | await fetch('http://localhost:3000/api/posts/create', {
45 | method: 'POST',
46 | headers: {
47 | 'Accept': 'application/json',
48 | 'Content-Type': 'application/json'
49 | },
50 | body: JSON.stringify(postData)
51 | })
52 |
53 | setTitle('')
54 | setContent('')
55 | setPrefetch(!prefetch)
56 | setLoadSubmit(false)
57 |
58 | }
59 |
60 | }
61 |
62 | const handleDelete = async(id) => {
63 | const ask = confirm('Yakin ingin menghapus data?')
64 |
65 | if (ask) {
66 | await fetch('http://localhost:3000/api/posts/delete/' + id, {method: 'DELETE'}).then(response => response.json().then(result => console.log(result)))
67 | setPrefetch(!prefetch)
68 | }
69 |
70 | }
71 |
72 | const handleUpdate = e => {
73 | setBtnUpdate(true)
74 | setIdPost(e.id);
75 | setTitle(e.title);
76 | setContent(e.content);
77 |
78 | }
79 |
80 | const submitUpdate = async() => {
81 | if (content.length < 1 || title.length < 1 || idPost.length < 1) {
82 | alert('data tidak boleh kosong')
83 | } else {
84 | setLoadSubmit(true)
85 | const postData = {
86 | title,
87 | content
88 | }
89 |
90 | await fetch('http://localhost:3000/api/posts/update/' + idPost, {
91 | method: 'PUT',
92 | headers: {
93 | 'Accept': 'application/json',
94 | 'Content-Type': 'application/json'
95 | },
96 | body: JSON.stringify(postData)
97 | })
98 | .then(response => response.json())
99 | .then(result => console.log(result))
100 |
101 | setTitle('')
102 | setContent('')
103 | setPrefetch(!prefetch)
104 | setLoadSubmit(false)
105 | setBtnUpdate(false)
106 |
107 | }
108 | }
109 |
110 | let contentPost = null
111 | if (post === null) {
112 | contentPost =
113 | Loading...
114 |
115 | } else {
116 | if (post.data.length < 1) {
117 | contentPost =
118 | Tidak ada data
119 |
120 | }
121 | contentPost =
122 |
123 |
124 |
125 | Id |
127 | Title |
129 | Content |
131 | Actions |
133 |
134 |
135 |
136 | {post
137 | .data
138 | .map((i, index) => {
139 | // let id = 0
140 | return
143 |
145 | Id
147 | {index + 1}
148 | |
149 |
151 | Title
153 | {i.title}
154 | |
155 |
157 | Content
159 | {i.content}
160 | |
161 |
163 | Actions
165 |
166 | |
169 |
172 | |
173 |
174 | })}
175 |
176 |
177 |
178 |
179 |
180 | }
181 |
182 | return (
183 |
184 |
240 |
241 | {contentPost}
242 |
243 |
244 | )
245 | }
246 |
--------------------------------------------------------------------------------
/postcss.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | plugins: {
3 | tailwindcss: {},
4 | autoprefixer: {},
5 | },
6 | }
7 |
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cecepns/crudnextjs/a7e6f50dc9dc2e1cd7be78c5a12b4fe7dee4118f/public/favicon.ico
--------------------------------------------------------------------------------
/public/vercel.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/styles/Home.module.css:
--------------------------------------------------------------------------------
1 | .container {
2 | min-height: 100vh;
3 | padding: 0 0.5rem;
4 | display: flex;
5 | flex-direction: column;
6 | justify-content: center;
7 | align-items: center;
8 | }
9 |
10 | .main {
11 | padding: 5rem 0;
12 | flex: 1;
13 | display: flex;
14 | flex-direction: column;
15 | justify-content: center;
16 | align-items: center;
17 | }
18 |
19 | .footer {
20 | width: 100%;
21 | height: 100px;
22 | border-top: 1px solid #eaeaea;
23 | display: flex;
24 | justify-content: center;
25 | align-items: center;
26 | }
27 |
28 | .footer img {
29 | margin-left: 0.5rem;
30 | }
31 |
32 | .footer a {
33 | display: flex;
34 | justify-content: center;
35 | align-items: center;
36 | }
37 |
38 | .title a {
39 | color: #0070f3;
40 | text-decoration: none;
41 | }
42 |
43 | .title a:hover,
44 | .title a:focus,
45 | .title a:active {
46 | text-decoration: underline;
47 | }
48 |
49 | .title {
50 | margin: 0;
51 | line-height: 1.15;
52 | font-size: 4rem;
53 | }
54 |
55 | .title,
56 | .description {
57 | text-align: center;
58 | }
59 |
60 | .description {
61 | line-height: 1.5;
62 | font-size: 1.5rem;
63 | }
64 |
65 | .code {
66 | background: #fafafa;
67 | border-radius: 5px;
68 | padding: 0.75rem;
69 | font-size: 1.1rem;
70 | font-family: Menlo, Monaco, Lucida Console, Liberation Mono, DejaVu Sans Mono,
71 | Bitstream Vera Sans Mono, Courier New, monospace;
72 | }
73 |
74 | .grid {
75 | display: flex;
76 | align-items: center;
77 | justify-content: center;
78 | flex-wrap: wrap;
79 | max-width: 800px;
80 | margin-top: 3rem;
81 | }
82 |
83 | .card {
84 | margin: 1rem;
85 | flex-basis: 45%;
86 | padding: 1.5rem;
87 | text-align: left;
88 | color: inherit;
89 | text-decoration: none;
90 | border: 1px solid #eaeaea;
91 | border-radius: 10px;
92 | transition: color 0.15s ease, border-color 0.15s ease;
93 | }
94 |
95 | .card:hover,
96 | .card:focus,
97 | .card:active {
98 | color: #0070f3;
99 | border-color: #0070f3;
100 | }
101 |
102 | .card h3 {
103 | margin: 0 0 1rem 0;
104 | font-size: 1.5rem;
105 | }
106 |
107 | .card p {
108 | margin: 0;
109 | font-size: 1.25rem;
110 | line-height: 1.5;
111 | }
112 |
113 | .logo {
114 | height: 1em;
115 | }
116 |
117 | @media (max-width: 600px) {
118 | .grid {
119 | width: 100%;
120 | flex-direction: column;
121 | }
122 | }
123 |
--------------------------------------------------------------------------------
/styles/globals.css:
--------------------------------------------------------------------------------
1 | html,
2 | body {
3 | padding: 0;
4 | margin: 0;
5 | font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen,
6 | Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif;
7 | }
8 |
9 | a {
10 | color: inherit;
11 | text-decoration: none;
12 | }
13 |
14 | * {
15 | box-sizing: border-box;
16 | }
17 |
--------------------------------------------------------------------------------
/styles/tailwindcss.css:
--------------------------------------------------------------------------------
1 | @tailwind base;
2 | @tailwind components;
3 | @tailwind utilities;
--------------------------------------------------------------------------------
/tailwind.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | purge: ['./pages/**/*.{js,ts,jsx,tsx}', './components/**/*.{js,ts,jsx,tsx}'],
3 | darkMode: false, // or 'media' or 'class'
4 | theme: {
5 | extend: {},
6 | },
7 | variants: {
8 | extend: {},
9 | },
10 | plugins: [],
11 | }
12 |
--------------------------------------------------------------------------------