Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Finish App Router Migration #615

Merged
merged 11 commits into from
Nov 11, 2024
39 changes: 39 additions & 0 deletions next/jsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
{
"compilerOptions": {
"target": "es5",
"lib": [
"dom",
"dom.iterable",
"esnext"
],
"allowJs": true,
"skipLibCheck": true,
"strict": true,
"noEmit": true,
"esModuleInterop": true,
"module": "esnext",
"moduleResolution": "bundler",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "preserve",
"incremental": true,
"plugins": [
{
"name": "next"
}
],
"paths": {
"@/*": [
"./*"
]
}
},
"include": [
"next-env.d.ts",
"**/*.js",
"**/*.jsx",
],
"exclude": [
"node_modules"
]
}
31 changes: 17 additions & 14 deletions next/lib/data.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import { sql } from "@vercel/postgres";

import { PrismaClient } from '@prisma/client';

const prisma = new PrismaClient();
Expand Down Expand Up @@ -47,20 +45,25 @@ export default async function getProducts() {
console.error("Database Error:", error)
// do sentry stuff
}
}

export async function getProduct(index) {
const i = Number(index);
try {
console.log("Fetching product...");
console.log(i);
const product = await prisma.products.findUnique({
where: { id: i }
});

async function getReview(i) {
try {
const data = await sql`SELECT * from reviews WHERE productId=${i}`;
console.log(data.rows);
return data.rows;
} catch (error) {
console.error("Db error", error);
}
const product_reviews = await prisma.reviews.findMany({
where: { id: i },
});

product.reviews = product_reviews;
return product;
} catch (error) {
console.error("Database Error:", error);
}
}

export async function getProductsPrisma() {
const products = await prisma.products.findMany();
console.log("prisma", products);
}
23 changes: 23 additions & 0 deletions next/src/app/product/[id]/page.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@

import React from 'react';
import { getProduct } from '@/lib/data';
import { Suspense } from 'react';
import ThreeDotLoader from '@/src/ui/ThreeDotLoader';
import ProductPage from '@/src/components/ProductPage';
import { notFound } from 'next/navigation';

export default async function Product({ params }) {
const product = await getProduct((await params).id);
console.log(product);

if (!product) {
notFound();
}

return (
<Suspense fallback={<ThreeDotLoader />}>
<ProductPage product={product} />
</Suspense>

);
}
59 changes: 59 additions & 0 deletions next/src/app/product/page.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
'use client'

import React, { useState, useEffect } from 'react';
import { useRouter } from 'next/router';
import { connect } from 'react-redux';
import { addProduct } from '../actions';

function Product(props) {
const [product, setProduct] = useState();

const router = useRouter();
//const location = useLocation();

useEffect(() => {
const { product } = router.query;
//const product = location.state;
setProduct(product);
}, [product]);

let averageRating;
if (product) {
averageRating = (
product.reviews.reduce((a, b) => a + (b['rating'] || 0), 0) /
product.reviews.length
).toFixed(1);
}

return product ? (
<div className="product-layout">
<div>
<img src={product.imgcropped} alt="product" />
Fixed Show fixed Hide fixed
Fixed Show fixed Hide fixed
</div>
<div className="product-info">
<h1>{product.title}</h1>
<p>{product.description}</p>
<p>{product.descriptionfull}</p>
<button
className="add-cart-btn"
onClick={() => props.addProduct(product)}
>
<span className="sentry-unmask">Add to cart —</span> ${product.price}
.00
</button>
<p>{averageRating} Rating</p>
</div>
</div>
) : (
<p>Loading…</p>
);
}

const mapStateToProps = (state, ownProps) => {
return {
cart: state.cart,
products: state.products,
};
};

export default connect(mapStateToProps, { addProduct })(Product);
4 changes: 2 additions & 2 deletions next/src/app/products-sc/page.jsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import ThreeDotLoader from '/src/ui/ThreeDotLoader';
import ProductCatalog from '/src/ui/ProductCatalog';
import ThreeDotLoader from '@/src/ui/ThreeDotLoader';
import ProductCatalog from '@/src/ui/ProductCatalog';
import { Suspense } from 'react';

export const dynamic = 'force-dynamic';
Expand Down
20 changes: 6 additions & 14 deletions next/src/components/ProductCard.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,33 +7,25 @@ import { setProducts, addProduct, setFlag } from '../actions';

function ProductCard(props) {
const router = useRouter();
const { query } = router;
const product = props.product;
const itemLink = '/product';
const stars = props.stars;

return (
<li key={product.id}>
<div
onClick={(event) => {
if (
event.target.id !== 'addToCart' &&
event.target.parentNode.id !== 'addToCart'
) {
router.push({
pathname: itemLink,
// TODO how do we push the product object to the next page using router?
query: { product: product, ...query },
});
}
}}
router.push(`/product/${product.id}`);
}}
>
<img src={product.img} alt="product" className="sentry-block" />
<div>
<h2>{product.title}</h2>
<p className="product-description">{product.description}</p>
</div>
<button id="addToCart" onClick={() => props.addProduct(product)}>
<button id="addToCart" onClick={(e) => {
props.addProduct(product);
e.stopPropagation();
}}>
<span className="sentry-unmask">Add to cart — $</span>
{product.price}.00
</button>
Expand Down
49 changes: 49 additions & 0 deletions next/src/components/ProductPage.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
'use client'

import React from 'react';
import { connect } from 'react-redux';
import { addProduct } from '../actions';

function Product(props) {
const product = props.product;

let averageRating;
if (product) {
averageRating = (
product.reviews.reduce((a, b) => a + (b['rating'] || 0), 0) /
product.reviews.length
).toFixed(1);
}

return product ? (
<div className="product-layout">
<div>
<img src={product.imgcropped} alt="product" />
</div>
<div className="product-info">
<h1>{product.title}</h1>
<p>{product.description}</p>
<p>{product.descriptionfull}</p>
<button
className="add-cart-btn"
onClick={() => props.addProduct(product)}
>
<span className="sentry-unmask">Add to cart —</span> ${product.price}
.00
</button>
<p>{averageRating} Rating</p>
</div>
</div>
) : (
<p>Loading…</p>
);
}

const mapStateToProps = (state, ownProps) => {
return {
cart: state.cart,
products: state.products,
};
};

export default connect(mapStateToProps, { addProduct })(Product);
File renamed without changes.
4 changes: 2 additions & 2 deletions next/src/ui/ProductCatalog.jsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@

import React from 'react';
import ProductCard from '/src/components/ProductCard';
import getProducts from '/lib/data.js';
import ProductCard from '@/src/components/ProductCard';
import getProducts from '@/lib/data.js';

export default async function ProductCatalog(props) {
let products = await getProducts();
Expand Down
Loading