1.2 Next.js Building a Car Trader App #1- Introduction and FAQ Page (ok)
https://www.npmjs.com/package/better-sqlite3
C:\Users\Administrator\Desktop\nextjs\package.json
{
"name": "nextjs",
"version": "0.1.0",
"private": true,
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start"
},
"dependencies": {
"@material-ui/core": "^4.11.3",
"@material-ui/icons": "^4.11.2",
"@material-ui/lab": "^4.0.0-alpha.57",
"axios": "^0.21.1",
"formik": "^2.2.6",
"next": "10.0.8",
"react": "17.0.1",
"react-dom": "17.0.1",
"sqlite": "^4.0.19",
"sqlite3": "^5.0.2",
"swr": "^0.5.2"
},
"devDependencies": {
"@types/node": "^14.14.33",
"@types/react": "^17.0.3",
"typescript": "^4.2.3"
}
}
C:\Users\Administrator\Desktop\pro\database-test.js
const sqlite = require('sqlite');
const sqlite3 = require('sqlite3');
async function setup() {
const db = await sqlite.open({
filename: 'cars.sqlite',
driver: sqlite3.Database,
});
await db.migrate({ force: 'last' });
const faq = await db.all('SELECT * FROM FAQ ORDER BY createDate DESC');
console.log('ALL faq', JSON.stringify(faq, null, 2));
const cars = await db.all('SELECT * FROM Car');
console.log('ALL CARS', JSON.stringify(cars, null, 2));
}
setup();
Hoặc viết theo lối hiện đại hơn
const sqlite = require('sqlite');
const sqlite3 = require('sqlite3');
(async () => {
const db = await sqlite.open({
filename: 'cars.sqlite',
driver: sqlite3.Database,
});
await db.migrate({ force: 'last' });
const faq = await db.all('SELECT * FROM FAQ ORDER BY createDate DESC');
console.log('ALL faq', JSON.stringify(faq, null, 2));
const cars = await db.all('SELECT * FROM Car');
console.log('ALL CARS', JSON.stringify(cars, null, 2));
})()
1. Create FAQ
C:\Users\Administrator\Desktop\nextjs\pages\index.tsx
export default function Home() {
return <h1>Hello Youtube</h1>;
}
C:\Users\Administrator\Desktop\nextjs\pages\faq.tsx
import { Accordion, AccordionDetails, AccordionSummary, Typography } from '@material-ui/core';
import ExpandMoreIcon from '@material-ui/icons/ExpandMore';
import { GetStaticProps } from 'next';
import FaqModel from '../api/Faq';
import openDB from '../openDB';
interface FaqProps {
faq: FaqModel[];
}
export default function Faq({ faq }: FaqProps) {
return (
<div>
{faq.map((f) => (
<Accordion key={f.id}>
<AccordionSummary
expandIcon={<ExpandMoreIcon />}
aria-controls="panel1a-content"
id="panel1a-header"
>
<Typography>
{f.question}
</Typography>
</AccordionSummary>
<AccordionDetails>
<Typography>
{f.answer}
</Typography>
</AccordionDetails>
</Accordion>
))}
</div>
);
}
export const getStaticProps: GetStaticProps = async () => {
const db = await openDB();
const faq = await db.all('SELECT * FROM FAQ ORDER BY createDate DESC');
return { props: { faq } };
};
C:\Users\Administrator\Desktop\nextjs\interface\Car.ts
export interface CarModel {
id: number;
make: string;
model: string;
year: number;
fuelType: string;
kilometers: number;
details: string;
price: number;
photoUrl: string;
}
C:\Users\Administrator\Desktop\nextjs\api\Faq.ts
export interface FaqModel {
id: number;
question: string;
answer: string;
}
C:\Users\Administrator\Desktop\nextjs\components\Nav.tsx
import { AppBar, Button, makeStyles, Toolbar, Typography } from '@material-ui/core';
import Link from 'next/link';
import React from 'react';
const useStyles = makeStyles(theme => ({
root: {
flexGrow: 1
},
menuButton: {
marginRight: theme.spacing(2)
},
title: {
flexGrow: 1
}
}));
export function Nav() {
const classes = useStyles();
return (
<AppBar position="static">
<Toolbar variant="dense">
<Typography variant="h6" className={classes.title}>
Car Trader
</Typography>
<Button color="inherit">
<Link href="/">
<a style={{ color: 'white' }}>
<Typography color="inherit">
Home
</Typography>
</a>
</Link>
</Button>
<Button color="inherit">
<Link href="/faq">
<a style={{ color: 'white' }}>
<Typography color="inherit">
FAQ
</Typography>
</a>
</Link>
</Button>
</Toolbar>
</AppBar>
);
}
Source
Viết theo cách mới
pages\faq.tsx
import { GetStaticProps } from 'next';
import openDB from './openDB';
function toggleAccordion(index: any) {
const content = document.getElementById(`content-${index}`);
const icon = document.getElementById(`icon-${index}`);
const minusSVG = `
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="currentColor" class="w-4 h-4">
<path d="M3.75 7.25a.75.75 0 0 0 0 1.5h8.5a.75.75 0 0 0 0-1.5h-8.5Z" />
</svg>
`;
const plusSVG = `
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="currentColor" class="w-4 h-4">
<path d="M8.75 3.75a.75.75 0 0 0-1.5 0v3.5h-3.5a.75.75 0 0 0 0 1.5h3.5v3.5a.75.75 0 0 0 1.5 0v-3.5h3.5a.75.75 0 0 0 0-1.5h-3.5v-3.5Z" />
</svg>
`;
if (content!.style.maxHeight && content!.style.maxHeight !== '0px') {
content!.style.maxHeight = '0';
icon!.innerHTML = plusSVG;
} else {
content!.style.maxHeight = content?.scrollHeight + 'px';
icon!.innerHTML = minusSVG;
}
}
export default function Faq({ faq }: any) {
return (
<div className="w-screen p-3">
{faq.map((f: any) => (
<div key={f.id} className="border-b border-slate-200" onClick={() => toggleAccordion(f.id)}>
<button className="w-full flex justify-between items-center py-5 text-slate-800">
<span>{f.question}</span>
<span id={`icon-${f.id}`} className="text-slate-800 transition-transform duration-300">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="currentColor" className="w-4 h-4">
<path fillRule="evenodd" d="M11.78 9.78a.75.75 0 0 1-1.06 0L8 7.06 5.28 9.78a.75.75 0 0 1-1.06-1.06l3.25-3.25a.75.75 0 0 1 1.06 0l3.25 3.25a.75.75 0 0 1 0 1.06Z" clipRule="evenodd" />
</svg>
</span>
</button>
<div id={`content-${f.id}`} className="max-h-0 overflow-hidden transition-all duration-300 ease-in-out">
<div className="pb-5 text-sm text-slate-500">
{f.answer}
</div>
</div>
</div>
))}
</div>
);
}
export const getStaticProps: GetStaticProps = async () => {
const db = await openDB();
const faq = await db.all('SELECT * FROM FAQ ORDER BY createDate DESC');
return { props: { faq } };
};
pages\openDB.ts
import { open } from 'sqlite'
import sqlite3 from 'sqlite3'
// you would have to import / invoke this in another file
export default async function openDB () {
return open({
filename: './pages/data/helloworld.sql',
driver: sqlite3.Database
})
}
Previous1. 1 Next.js Building a Car Trader App #1- Introduction and FAQ PageNext2.0 Next.js Building a Car Trader App #2: Car Details Page using getServerSideProps
Last updated
Was this helpful?