😗Next.js Tutorial Typescript, sqlite create, update Full (ok)
PreviousSự liên quan giữa jwt & base64decode (ok)Next========== Start Next.js Building a Car ============
Last updated
Was this helpful?
Last updated
Was this helpful?
tailwind.config.js
/** @type {import('tailwindcss').Config} */
module.exports = {
content: [
"./pages/*.{ts,tsx}",
"./pages/**/*.{ts,tsx}",
],
theme: {
extend: {},
},
plugins: [],
}
postcss.config.js
module.exports = {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
}
styles\globals.css
@tailwind base;
@tailwind components;
@tailwind utilities;
pages\List.tsx
import Link from 'next/link';
const people = [
{ v: 'car', name: 'bruno' },
{ v: 'bike', name: 'John' },
{ v: 'airplane', name: 'Mick' }
]
export default function List() {
return (
<div className="container">
{people.map(e => (
<Link className='block' key={e.v} as={`/${e.v}/${e.name}`} href="/[vehicle]/[person]">
Navigate to {e.name}'s {e.v}
</Link>
))}
</div>
)
}
pages\[vehicle]\[person].tsx
import { useRouter } from 'next/router';
export default function Person() {
const router = useRouter();
console.log(router.query);
return <h2>{router.query.person}'s {router.query.vehicle}</h2>
}
pages\list.tsx
import React, { useState, useEffect } from 'react';
import Link from 'next/link';
export default function List({ ownersList }: any) {
const [owners, setOwners] = useState([]);
useEffect(() => {
async function loadData() {
const response = await fetch('http://localhost:3000/api/vehicles');
const ownersList = await response.json();
setOwners(ownersList);
}
loadData();
}, []);
return (
<div className='container'>
{owners.map((e: any, index: number) => (
<Link className='block' key={index} as={`/${e.vehicle}/${e.ownerName}`} href="/[vehicle]/[person]">
Navigate to {e.ownerName}'s {e.vehicle}
</Link>
))}
</div>
);
}
pages\api\vehicles.ts
// Next.js API route support: https://nextjs.org/docs/api-routes/introduction
import type { NextApiRequest, NextApiResponse } from 'next'
import data from "../../data/db.json"
export default async function handler(req: NextApiRequest,res: NextApiResponse<any>) {
res.status(200).json(data)
}
data\db.json
[
{
"vehicle": "Car",
"ownerName": "Bruno Antunes",
"details": "some detail about Bruno's Car"
},
{
"vehicle": "Bike",
"ownerName": "Bruno Antunes",
"details": "some detail about Bruno's Bike"
},
{
"vehicle": "Bike",
"ownerName": "John Doe",
"details": "some detail bile"
},
{
"vehicle": "Airplane",
"ownerName": "Bill Gates",
"details": "some detail Bill Gates"
},
{
"vehicle": "SpaceX",
"ownerName": "Elon Musk",
"details": "some detail Elon"
}
]
pages[vehicle][person].tsx
import { useRouter } from 'next/router';
import { NextPageContext } from 'next';
import {useState, useEffect } from 'react';
export interface PersonProps {
ownersList?: any;
}
export default function Person({ ownersList }: PersonProps) {
const [owners, setOwners] = useState(ownersList);
const router = useRouter();
useEffect(() => {
async function loadData() {
const response = await fetch('http://localhost:3000/api/vehicles?ownerName=' + router.query.person + '&vehicle=' + router.query.vehicle);
const ownersList: any[] | undefined = await response.json();
setOwners(ownersList);
}
if (ownersList?.length === 0) {
loadData();
}
}, [])
return <pre>{owners[0]?.details}</pre>;
}
Person.getInitialProps = async ({query, req}: NextPageContext) => {
console.log(query);
if (!req) {
return { ownersList: [] };
}
const response = await fetch('http://localhost:3000/api/vehicles?ownerName=' + query.person + '&vehicle=' + query.vehicle);
const ownersList: any[] | undefined = await response.json();
return { ownersList };
}
pages\data\mydb.sqlite
pages\api\vehicles.ts
import { NextApiRequest, NextApiResponse } from 'next';
const sqlite = require('sqlite');
const sqlite3 = require('sqlite3');
async function openDb() {
return sqlite.open({
filename: './pages/data/mydb.sqlite',
driver: sqlite3.Database,
});
}
export default async function getAllVehicles(req: NextApiRequest, res: NextApiResponse) {
const db = await openDb();
const vehicle = await db.all('SELECT * FROM Vehicle');
res.json(vehicle);
}
pages\api\person\index.ts
import { NextApiRequest, NextApiResponse } from 'next';
const sqlite = require('sqlite');
const sqlite3 = require('sqlite3');
async function openDb() {
return sqlite.open({
filename: './pages/data/mydb.sqlite',
driver: sqlite3.Database,
});
}
export default async function getAllPerson(req: NextApiRequest, res: NextApiResponse) {
const db = await openDb();
const person = await db.all('SELECT * FROM Person');
res.json(person);
}
pages\api\signup.ts
import { NextApiRequest, NextApiResponse } from 'next';
const bcrypt = require('bcrypt');
const sqlite = require('sqlite');
const sqlite3 = require('sqlite3');
async function openDb() {
return sqlite.open({
filename: './pages/data/mydb-pass.sqlite',
driver: sqlite3.Database,
});
}
export default async function signup( req: NextApiRequest, res: NextApiResponse ) {
const db = await openDb();
if (req.method === 'POST') {
bcrypt.hash(req.body.password, 10, async function(err:any, hash:any) {
// Store hash in your password DB.
const statement = await db.prepare( 'INSERT INTO person (name, email, password) values (?, ?, ?)');
const result = await statement.run(req.body.name, req.body.email, hash);
const person = await db.all('select * from person');
res.json(person);
});
} else {
res.status(405).json({ message: 'We only support POST' });
}
}
pages\api\secret.ts
export const secret = '0e900be1-0ac5-4e6a-bf4b-38f8b21a189b';
pages\api\login.ts
import { compare, hash } from 'bcrypt';
import { NextApiRequest, NextApiResponse } from 'next';
import { secret } from '../api/secret';
import { sign } from 'jsonwebtoken';
const sqlite = require('sqlite');
const sqlite3 = require('sqlite3');
async function openDb() {
return sqlite.open({
filename: './pages/data/mydb-pass.sqlite',
driver: sqlite3.Database,
});
}
export default async function login(req: NextApiRequest, res: NextApiResponse) {
const db = await openDb();
if (req.method === 'POST') {
const person = await db.get('select * from person where email = ?', [req.body.email]);
compare(req.body.password, person?.password, function(err, result) {
if (!err && result) {
const claims = { sub: person.id, myPersonEmail: person.email };
const jwt = sign(claims, secret, { expiresIn: '1h' });
res.json({ authToken: jwt });
} else {
res.json({ message: 'Ups, something went wrong!' });
}
});
}else {
res.status(405).json({ message: 'We only support POST' });
}
}
pages\api\person[id]\index.ts
import { NextApiRequest, NextApiResponse } from 'next';
const sqlite = require('sqlite');
const sqlite3 = require('sqlite3');
async function openDb() {
return sqlite.open({
filename: './pages/data/mydb.sqlite',
driver: sqlite3.Database,
});
};
export default async function getPersonById(req: NextApiRequest, res: NextApiResponse) {
const db = await openDb();
if (req.method === 'PUT') {
const statement = await db.prepare('UPDATE person SET name= ?, email = ? where id = ?');
await statement.run(req.body.name,req.body.email,req.query.id);
}
const person = await db.get('select * from person where id = ?', req.query.id);
res.json(person);
}
pages\api\login.ts
import { compare, hash } from 'bcrypt';
import { NextApiRequest, NextApiResponse } from 'next';
import { secret } from '../api/secret';
import { sign } from 'jsonwebtoken';
const sqlite = require('sqlite');
const sqlite3 = require('sqlite3');
import * as cookie from 'cookie';
require('dotenv').config()
async function openDb() {
return sqlite.open({
filename: './pages/data/mydb-pass.sqlite',
driver: sqlite3.Database,
});
}
export default async function login(req: NextApiRequest, res: NextApiResponse) {
const db = await openDb();
if (req.method === 'POST') {
const person = await db.get('select * from person where email = ?', [req.body.email]);
compare(req.body.password, person?.password, function(err, result) {
if (!err && result) {
const claims = { sub: person.id, myPersonEmail: person.email };
const jwt = sign(claims, secret, { expiresIn: '1h' });
res.setHeader('Set-Cookie', cookie.serialize('auth', jwt, {
httpOnly: true,
secure: process.env.TEST !== 'development',
sameSite: 'strict',
maxAge: 3600,
path: '/'
}));
res.json({message: 'Welcome back to the app!'});
} else {
res.json({ message: 'Ups, something went wrong!' });
}
});
}else {
res.status(405).json({ message: 'We only support POST' });
}
}
.env
TEST=production
pages\api\people.ts
import { verify } from 'jsonwebtoken';
import { NextApiHandler, NextApiRequest, NextApiResponse } from 'next';
const sqlite = require('sqlite');
const sqlite3 = require('sqlite3');
import { secret } from '../api/secret';
async function openDb() {
return sqlite.open({
filename: './pages/data/mydb-pass.sqlite',
driver: sqlite3.Database,
});
}
export const authenticated = (fn: NextApiHandler) => async (req: NextApiRequest, res: NextApiResponse) => {
verify(req.cookies.auth!, secret, async function(err, decoded) {
if (!err && decoded) {
return await fn(req, res);
}
res.status(401).json({ message: 'Sorry you are not authenticated' });
});
}
export default authenticated(async function getPeople(req: NextApiRequest,res: NextApiResponse) {
const db = await openDb();
const people = await db.all('select id, email, name from person');
res.json(people);
});
pages\microphone[id].tsx
import { GetStaticPaths, GetStaticProps } from 'next';
import { useRouter } from 'next/router';
import { Microphone } from '../model/Microphone';
import openDB from '../../pages/openDB';
export default function MicrophoneDetail({ id, brand, model, price, imageUrl }: Microphone) {
const router = useRouter();
if (router.isFallback) {
return <div>Loading......I'm sorry for the wait!!</div>;
}
return (
<div className="p-3 w-screen">
<div className='text-blue-600/100'>{id}</div>
<div className='text-blue-600/75'>{brand}</div>
<div className='text-blue-600/50'>{model}</div>
<div className='text-blue-600/25'>{price}</div>
<div>{imageUrl}</div>
</div>
);
}
export const getStaticProps: GetStaticProps<Microphone> = async (ctx: any) => {
const id = ctx.params.id as string;
const db = await openDB();
const microphone = await db.get('select * from microphone where id = ?', + id);
return { props: microphone };
};
export const getStaticPaths: GetStaticPaths<{ id: string }> = async () => {
const db = await openDB();
const microphones = await db.all('select * from microphone');
const paths = microphones.map((a) => {
return {
params: {
id: a.id.toString()
}
};
});
return {
paths,
fallback: false
};
};
pages\index.tsx
import type { GetStaticProps, NextPage } from 'next';
import openDB from '../pages/openDB';
import {Microphone} from './model/Microphone';
export interface IndexProps {
microphones: Microphone[]
}
import styles from '../styles/Home.module.css'
import Link from 'next/link';
const Home: any = ({microphones}: IndexProps) => {
return (
<div className={styles.container}>
<main className={styles.main}>
{
microphones?.map((microphone) => {
return (
<Link className='block' href="/microphone/[id]" as={`/microphone/${microphone.id}`} key={microphone.id}>
{microphone.brand + " " + microphone.model + " " + microphone.price}
</Link>
)
})
}
</main>
</div>
)
}
export default Home
export const getStaticProps: GetStaticProps = async (ctx) => {
const currentPage = ctx.params?.currentPage as string;
const currentPageNumber = +(currentPage || 0);
const min = currentPageNumber * 5;
const max = (currentPageNumber + 1) * 5;
const db = await openDB();
const microphones = await db.all(
'select * from microphone where id > ? and id <= ?',min,max
);
return { props: { microphones } };
};
pages\[currentPage].tsx
import { GetStaticPaths } from 'next';
import openDB from '../pages/openDB';
import Index, { getStaticProps } from './';
export default Index;
export { getStaticProps };
export const getStaticPaths: GetStaticPaths = async () => {
const db = await openDB();
const { total } = await db.get('select count(*) as total from microphone');
const numberOfPages = Math.ceil(total / 5.0);
const paths = Array(numberOfPages - 1).fill('').map((_, index) => {
return {
params: {
currentPage: (index + 1).toString()
}
}
});
return {
fallback: false,
paths: paths,
};
}
pages\index.tsx
import type { GetServerSideProps} from 'next';
import openDB from '../pages/openDB';
import {Microphone} from './model/Microphone';
export interface IndexProps {
microphones: Microphone[]
}
import styles from '../styles/Home.module.css'
import Link from 'next/link';
const Home: any = ({microphones}: IndexProps) => {
return (
<div className={styles.container}>
<main className={styles.main}>
{
microphones?.map((microphone) => {
return (
<Link className='block' href="/microphone/[id]" as={`/microphone/${microphone.id}`} key={microphone.id}>
{microphone.brand + " " + microphone.model + " " + microphone.price}
</Link>
)
})
}
</main>
</div>
)
}
export default Home
export const getServerSideProps: GetServerSideProps<IndexProps> = async (ctx:any) => {
const db = await openDB();
const microphones = await db.all<Microphone[]>('select * from microphone');
return { props: { microphones } };
};