C:\Users\Administrator\Desktop\pro\openDB.ts
import { open } from 'sqlite';
import sqlite3 from 'sqlite3';
export default async function openDB () {
return open({
filename: 'cars.sqlite',
driver: sqlite3.Database
})
}
C:\Users\Administrator\Desktop\nextjs\pages\car\[make]\[brand]\[id].tsx
import { Paper, Grid, Typography } from '@material-ui/core';
import { makeStyles, createStyles } from '@material-ui/core/styles';
import { GetServerSideProps } from 'next';
import React from 'react';
import {CarModel} from '../../../../interface/Car';
import openDB from '../../../../openDB';
const useStyles = makeStyles((theme) => createStyles({
paper: {
padding: theme.spacing(2),
margin: 'auto',
maxWidth: 888,
},
img: {
width: '100%',
},
}));
interface CarDetailsProps {
car: CarModel | null | undefined;
}
export default function CarDetails({ car }: CarDetailsProps) {
const classes = useStyles();
if (!car) {
return <h1>Sorry, car not found!</h1>;
}
return (
<div>
<Paper className={classes.paper}>
<Grid container spacing={2}>
<Grid item xs={12} sm={6} md={5}>
<img className={classes.img} src={car.photoUrl} />
</Grid>
<Grid item xs={12} sm={6} md={7} container>
<Grid item xs container direction="column" spacing={2}>
<Grid item xs>
<Typography variant="h5">
{car.make + ' ' + car.model}
</Typography>
<Typography gutterBottom variant="h4">
£{car.price}
</Typography>
<Typography gutterBottom variant="body2" color="textSecondary">
Year: {car.year}
</Typography>
<Typography gutterBottom variant="body2" color="textSecondary">
KMs: {car.kilometers}
</Typography>
<Typography gutterBottom variant="body2" color="textSecondary">
Fuel Type: {car.fuelType}
</Typography>
<Typography gutterBottom variant="body1" color="textSecondary">
Details: {car.details}
</Typography>
</Grid>
</Grid>
</Grid>
</Grid>
</Paper>
</div>
)
}
export const getServerSideProps: GetServerSideProps < CarDetailsProps > = async (ctx) => {
const {id} = ctx.query;
const db = await openDB();
const car = await db.get<CarModel | undefined>('SELECT * FROM Car where id = ?', id);
return { props: { car: car || null } };
}
Source
pages\car[make][brand][id].tsx
import { GetServerSideProps } from "next";
import { CarModel } from "../../../model/Car";
import openDB from "../../../openDB";
interface CarDetailsProps {
car: CarModel | null | undefined;
}
export default function CarDetails({ car }: CarDetailsProps) {
if (!car) {
return <h1>Sorry, car not found!</h1>;
}
return (
<div className="relative flex flex-col md:flex-row w-full my-6 bg-white shadow-sm border border-slate-200 rounded-lg">
<div className="relative p-2.5 md:w-2/5 shrink-0 overflow-hidden">
<img className="w-full" src={car.photoUrl} alt={car.make} />
</div>
<div className="p-6">
<h4 className="mb-2 text-slate-800 text-xl font-semibold">
{car.make + ' ' + car.model}
</h4>
<p className="mb-1 text-slate-600 leading-normal font-light">
<span className="font-semibold">Price: </span> ${car.price}
</p>
<p className="mb-1 text-slate-600 leading-normal font-light">
<span className="font-semibold">Year: </span> {car.year}
</p>
<p className="mb-1 text-slate-600 leading-normal font-light">
<span className="font-semibold">Kms: </span>{car.kilometers}
</p>
<p className="mb-1 text-slate-600 leading-normal font-light">
<span className="font-semibold">Type: </span>{car.fuelType}
</p>
<p className="mb-1 text-slate-600 leading-normal font-light">
<span className="font-semibold">Detail: </span>{car.details}
</p>
</div>
</div>
);
}
export const getServerSideProps: GetServerSideProps<CarDetailsProps> = async (ctx) => {
const { id } = ctx.query;
const db = await openDB();
const car = await db.get<CarModel | undefined>('SELECT * FROM Car where id = ?', id);
return {
props: {
car: car || null
}
};
}
Viết lại logic
pages\index.tsx
import Link from "next/link"
const Home: any = () => {
return (
<main className="container p-3">
<Link className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded" href="/car">Cars</Link>
</main>
)
}
export default Home
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\model\Faq.ts
export interface FaqModel {
id: number;
question: string;
answer: string;
}
pages\model\Car.ts
export interface CarModel {
id: number;
make: string;
model: string;
year: number;
fuelType: string;
kilometers: number;
details: string;
price: number;
photoUrl: string;
}
pages\car\index.tsx
import { GetServerSideProps } from "next";
import openDB from "../openDB";
import Link from "next/link";
export interface Make {
make: string;
count: number;
}
export default function CarDetails({ makes }: any) {
console.log(makes);
return (
<div className="relative flex flex-col my-6 bg-white shadow-sm border border-slate-200 rounded-lg w-full">
<div className="p-4">
<div className="divide-y divide-slate-200">
{
makes.map((make: any, index: number) => (
<div key={index} className="flex items-center justify-between pb-3 pt-3 last:pb-0">
<div className="flex items-center gap-x-3">
<img
src="/photos/cars/audi-a2-2003-8199.jpg"
alt="Maria Jimenez"
className="relative inline-block h-8 w-8 rounded-full object-cover object-center"
/>
<div>
<h6 className="text-slate-800 font-semibold">{make.make}</h6>
<p className="text-slate-600 text-sm">{make.count}</p>
</div>
</div>
<Link href={`\\car\\${make.make}`} className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded">View All</Link>
</div>
))
}
</div>
</div>
</div>
);
}
export const getServerSideProps: GetServerSideProps<any> = async (ctx) => {
const db = await openDB();
const makes = await db.all<Make[]>(`SELECT make, model, count(*) as count FROM car GROUP BY make`);
return {
props: {
makes: makes || null
}
};
}
pages\car[make]\index.tsx
import { GetServerSideProps } from "next";
import openDB from "../../openDB";
import Link from "next/link";
export interface Make {
make: string;
count: number;
}
export default function CarDetails({ makes }: any) {
console.log(makes);
return (
<div className="relative flex flex-col my-6 bg-white shadow-sm border border-slate-200 rounded-lg w-full">
<div className="p-4">
<div className="divide-y divide-slate-200">
{
makes.map((make: any, index: number) => (
<div key={index} className="flex items-center justify-between pb-3 pt-3 last:pb-0">
<div className="flex items-center gap-x-3">
<img
src={make.photoUrl}
alt="Maria Jimenez"
className="relative inline-block h-8 w-8 rounded-full object-cover object-center"
/>
<div>
<h6 className="text-slate-800 font-semibold">{make.model}</h6>
<p className="text-slate-600 text-sm">{make.year}</p>
</div>
</div>
<Link href={`\\car\\${make.make}\\${make.model}\\${make.id}`} className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded">Detail</Link>
</div>
))
}
</div>
</div>
</div>
);
}
export const getServerSideProps: GetServerSideProps<any> = async (ctx) => {
const { make } = ctx.query;
const db = await openDB();
const makes = await db.all<Make[]>('SELECT * FROM car WHERE make=?',make);
return {
props: {
makes: makes || null
}
};
}
pages\car[make][brand][id]\index.tsx
import { GetServerSideProps } from "next";
import { CarModel } from "../../../../model/Car";
import openDB from "../../../../openDB";
interface CarDetailsProps {
car: CarModel | null | undefined;
}
export default function CarDetails({ car }: CarDetailsProps) {
if (!car) {
return <h1>Sorry, car not found!</h1>;
}
return (
<div className="relative flex flex-col md:flex-row w-full my-6 bg-white shadow-sm border border-slate-200 rounded-lg">
<div className="relative p-2.5 md:w-2/5 shrink-0 overflow-hidden">
<img className="w-full" src={car.photoUrl} alt={car.make} />
</div>
<div className="p-6">
<h4 className="mb-2 text-slate-800 text-xl font-semibold">
{car.make + ' ' + car.model}
</h4>
<p className="mb-1 text-slate-600 leading-normal font-light">
<span className="font-semibold">Price: </span> ${car.price}
</p>
<p className="mb-1 text-slate-600 leading-normal font-light">
<span className="font-semibold">Year: </span> {car.year}
</p>
<p className="mb-1 text-slate-600 leading-normal font-light">
<span className="font-semibold">Kms: </span>{car.kilometers}
</p>
<p className="mb-1 text-slate-600 leading-normal font-light">
<span className="font-semibold">Type: </span>{car.fuelType}
</p>
<p className="mb-1 text-slate-600 leading-normal font-light">
<span className="font-semibold">Detail: </span>{car.details}
</p>
</div>
</div>
);
}
export const getServerSideProps: GetServerSideProps<CarDetailsProps> = async (ctx) => {
const { id } = ctx.query;
const db = await openDB();
const car = await db.get<CarModel | undefined>('SELECT * FROM Car where id = ?', id);
return {
props: {
car: car || null
}
};
}