Skip to content

Commit

Permalink
Merge pull request #5 from TiveCS/detail-product
Browse files Browse the repository at this point in the history
  • Loading branch information
TiveCS authored Dec 30, 2022
2 parents 037f196 + 2a78406 commit 6dbe4aa
Show file tree
Hide file tree
Showing 5 changed files with 174 additions and 2 deletions.
18 changes: 18 additions & 0 deletions components/pages/DetailProduct/BodyProduct.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { ProductWithAuthor } from '../../../pages/api/products/[id]';

interface BodyProductProps {
product: ProductWithAuthor;
}

const BodyProduct: React.FC<BodyProductProps> = ({
product,
}: BodyProductProps) => {
return (
<div>
<h4 className="mb-2 text-lg font-medium">Description</h4>
<p className="text-base leading-loose">{product.description}</p>
</div>
);
};

export default BodyProduct;
51 changes: 51 additions & 0 deletions components/pages/DetailProduct/HeroProduct.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { Product } from '@prisma/client';
import { ProductWithAuthor } from '../../../pages/api/products/[id]';
import Button from '../../Button';

interface HeroProductProps {
product: ProductWithAuthor;
}

const HeroProduct: React.FC<HeroProductProps> = ({ product }) => {
const price = product.price > 0 ? '$' + product.price.toString() : 'FREE';

// format date of updated_at to: 1 day ago, 2 days ago or in format of dd/mm/yyyy
const updatedAt = new Date(product.updated_at);
const today = new Date();
const diffTime = Math.abs(today.getTime() - updatedAt.getTime());
const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24));
const readableUpdatedAt =
diffDays <= 14
? diffDays > 1
? `${diffDays} days ago`
: 'Today'
: `${updatedAt.getDate()}/${
updatedAt.getMonth() + 1
}/${updatedAt.getFullYear()}`;

return (
<div className="grid justify-between grid-flow-col pb-4 mb-8 border-b">
<div className="flex flex-col gap-4">
<div>
<h2 className="text-2xl font-medium">{product.title}</h2>
<h4 className="text-base text-recandy-blue-600">
{product.author.name}
</h4>
</div>

<div>
<p className="text-sm text-recandy-gray-800">
Last Update <span>{readableUpdatedAt}</span>
</p>
</div>
</div>
<div>
<Button type="primary" size="md" textSize="sm">
Buy for {price}
</Button>
</div>
</div>
);
};

export default HeroProduct;
40 changes: 40 additions & 0 deletions pages/api/products/[id].tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { Product } from '@prisma/client';
import { NextApiHandler, NextApiRequest, NextApiResponse } from 'next';
import prisma from '../../../lib/prisma';

export type ProductWithAuthor = Product & { author: { name: string | null } };

const handler: NextApiHandler = async (
req: NextApiRequest,
res: NextApiResponse,
) => {
const { id } = req.query;
const { method } = req;

switch (method) {
case 'GET':
// Get data from your database
const product: ProductWithAuthor | null = await prisma.product.findUnique(
{
where: {
id: Number(id),
},
include: {
author: {
select: {
name: true,
},
},
},
},
);

res.status(200).json({ product });
break;
default:
res.setHeader('Allow', ['GET']);
res.status(405).end(`Method ${method} Not Allowed`);
}
};

export default handler;
54 changes: 54 additions & 0 deletions pages/products/[id].tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { Product } from '@prisma/client';
import axios from 'axios';
import { GetServerSideProps } from 'next';
import Head from 'next/head';
import { useRouter } from 'next/router';
import BodyProduct from '../../components/pages/DetailProduct/BodyProduct';
import HeroProduct from '../../components/pages/DetailProduct/HeroProduct';
import { ProductWithAuthor } from '../api/products/[id]';

interface DetailProductProps {
product: ProductWithAuthor;
}

const DetailProduct = (props: DetailProductProps) => {
const router = useRouter();

const { product } = props;

const title: string = product.title;

return (
<>
<Head>
<title>{product.title} | Product</title>
</Head>
<div className="px-8 py-12 mx-24 my-16 rounded-sm shadow-md">
<HeroProduct product={product} />

<BodyProduct product={product} />
</div>
</>
);
};

export default DetailProduct;

export const getServerSideProps: GetServerSideProps = async (context) => {
const { id } = context.query;
const host = process.env.NEXTAUTH_URL;

const { data } = await axios.get(`${host}/api/products/${id}`);
const { product } = data;

if (!product)
return {
notFound: true,
};

return {
props: {
product,
},
};
};
13 changes: 11 additions & 2 deletions pages/products/sell.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -209,12 +209,21 @@ export default function SellPage() {
<FormInput
id="description"
type={'text'}
onChange={(e) => setDescription(e.target.value)}
onChangeTextArea={(e) => setDescription(e.target.value)}
isTextArea
/>
</label>

<Button width="fit" type="primary" onClick={handleSubmit} textSize="sm">
<Button
style={{
opacity: isSubmitting ? '.5' : '1',
cursor: isSubmitting ? 'not-allowed' : 'pointer',
}}
width="fit"
type="primary"
onClick={handleSubmit}
textSize="sm"
>
{isSubmitting ? 'Submitting...' : 'Submit'}
</Button>
</div>
Expand Down

1 comment on commit 6dbe4aa

@vercel
Copy link

@vercel vercel bot commented on 6dbe4aa Dec 30, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

codemart-next – ./

codemart-next-tivecs.vercel.app
codemart-next.vercel.app
codemart-next-git-main-tivecs.vercel.app

Please sign in to comment.