iT邦幫忙

2023 iThome 鐵人賽

DAY 12
0
Modern Web

由前向後,從前端邁向全端系列 第 12

12.【從前端到全端,Nextjs+Nestjs】創建商店頁面-實現頁面和元件區塊

  • 分享至 

  • xImage
  •  

文章重點

  • 創建修改product頁面
  • 創建修改user頁面

本文

今天我們要完成的部分,是我們的product相關頁面以及user相關頁面。

我們先來完成product相關頁面

我們先來修改我們的libs\iron-components\src\lib\ProductCard\ProductCard.tsx:

import { Box, Card, Text } from "@radix-ui/themes";

import React from "react";

interface ProductCardProps {
	title?: string;
	description?: string;
	price?: string;
	imageUrl?: string;
	width?: string;
}

const ProductCard: React.FC<ProductCardProps> = (props) => {
	const {title, description, price, imageUrl, width = 'auto'} = props;
	return (
		<Card className={`w:${width}`}>
			<Box>
				<picture>
					<img src={imageUrl} aria-hidden alt="Sample Image" width="100%" />
				</picture>
				<Text as="div" size="2" weight="bold">
					{title}
				</Text>
				{
					price && (
						<Text as="div" size="2" color="gray">
							{price}
						</Text>
					)
				}
				{
					description && (
						<Text as="div" size="2" color="gray">
							{description}
						</Text>
					)
				}
			</Box>
		</Card>
	);
};

export default ProductCard;


通過修改卡片後,該卡片可以顯示產品的圖片、標題、價格和描述。接著修改我們的page,我們要創建了一個包含多個產品卡片的產品展示頁面。

打開apps\iron-ecommerce-next\app\products\products.client.tsx:

"use client";
import { Flex } from "@radix-ui/themes";

import ProductCard from "libs/iron-components/src/lib/ProductCard";

// eslint-disable-next-line @typescript-eslint/no-empty-interface
interface ProductsProps {}

// eslint-disable-next-line no-empty-pattern
const ProductsClient = ({}: ProductsProps) => {
	const sampleData = {
		title: "Sample Product",
		price: "$100.00",
		description: "This is a description for the sample product.",
		imageUrl: "https://www.w3schools.com/tags/img_girl.jpg"
	};

	return (
		<Flex align="center" justify="center">
			<section className="w:60% p:1rem flex flex:wrap flex-direction:row gap:1rem jc:center">
				{Array.from({ length: 30 }).map((_, i) => (
					<ProductCard
						key={i}
						title={sampleData.title + ` ${i+1}`}
						price={sampleData.price}
						description={sampleData.description}
						width="30%"
						imageUrl={sampleData.imageUrl}
					/>
				))}
			</section>
		</Flex>
	);
};

export default ProductsClient;

https://ithelp.ithome.com.tw/upload/images/20230927/20108931hQP3brM2Lm.png

接著,修正單一產品page,打開apps\iron-ecommerce-next\app\products\[id]\productId.client.tsx:

"use client";
import { Box, Button, Flex, Heading, Text } from "@radix-ui/themes";

import ProductCard from "libs/iron-components/src/lib/ProductCard";

interface ProductIdProps {
	productId?: string;
}

// eslint-disable-next-line no-empty-pattern
const ProductIdClient = ({ productId }: ProductIdProps) => {
	const sampleData = {
		title: "Sample Product",
		price: "$100.00",
		description: "This is a description for the sample product.",
		imageUrl: "https://www.w3schools.com/tags/img_girl.jpg"
	};

	return (
		<Flex align="center" justify="center">
			<section className="w:60% p:1rem flex flex:wrap gap:1 jc:center">
				<ProductCard
					title={sampleData.title}
					width="40%"
					imageUrl={sampleData.imageUrl}
				/>
				<Box className="w:40% p:1rem flex flex-direction:column jc:space-between">
					<Box>
						<Heading as="h1" size="8">
							{sampleData.title}
						</Heading>

						<Text as="p" size="2">
							{sampleData.description}
						</Text>
					</Box>
					<Box className="p:1rem">
						<Heading as="h1" size="8">
							{sampleData.price}
						</Heading>
						<Button className="w:100% p:1rem">Add to Cart</Button>
					</Box>
				</Box>
			</section>
		</Flex>
	);
};

export default ProductIdClient;

https://ithelp.ithome.com.tw/upload/images/20230927/20108931Mcms2h4xsz.png

接著完成user page相關的頁面。

我們先修改用戶頁面,我們設計一個展示user profile的頁面,該頁面包含用戶的頭像、名稱、電子郵件和自我介紹。

打開apps\iron-ecommerce-next\app\user\[id]\userId.client.tsx並修改:

"use client";
import { Avatar, Box, Card, Flex, Heading, Text } from "@radix-ui/themes";

interface UserIdProps {
	userId?: string;
}

// eslint-disable-next-line no-empty-pattern
const UserIdClient = ({ userId }: UserIdProps) => {

	const userData = {
		name: "John Doe",
		email: "john.doe@example.com",
		avatar: "https://via.placeholder.com/150",
		bio: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque sed suscipit lorem."
	};

	return (
		<Flex align="center" justify="center">
			<section className="flex flex:wrap flex-direction:row flex-basis:xs flex-basis:full@<xs gap:1rem jc:center">
				<Card mt="2">
					<Box className="w:100% m:1rem">
						<Flex align="center">
							<Avatar
								src="https://images.unsplash.com/photo-1502823403499-6ccfcf4fb453?&w=64&h=64&dpr=2&q=70&crop=focalpoint&fp-x=0.5&fp-y=0.3&fp-z=1&fit=crop"
								fallback="S"
								className="pr:1rem"
							/>
							<Box>
								<Heading as="h1" size="7">{userData.name}</Heading>
								<Text as="p" size="1" color="gray">{userData.email}</Text>
							</Box>
						</Flex>
						<Text as="p" size="4">{userData.bio}</Text>
					</Box>
				</Card>
			</section>
		</Flex>
	);
};

export default UserIdClient;

https://ithelp.ithome.com.tw/upload/images/20230927/20108931GdT5oC71NF.png

最後,我們修改個用戶認證頁面,該頁面允許用戶輸入他們的電子郵件和密碼進行登錄。

打開apps\iron-ecommerce-next\app\user\auth\userAuth.client.tsx:

"use client";
import { Box, Button, Card, Flex, Text, TextField } from "@radix-ui/themes";
import { FormEventHandler } from "react";

// eslint-disable-next-line @typescript-eslint/no-empty-interface
interface UserAuthProps {}

// eslint-disable-next-line no-empty-pattern
const UserAuthClient = ({}: UserAuthProps) => {

	const handleSubmit: FormEventHandler = (event) => {
		event.preventDefault();
		console.log('Form submitted');
	};

	return (
		<Flex align="center" justify="center">
			<section className="flex flex:wrap flex-direction:row flex-basis:xs flex-basis:full@<xs gap:1rem jc:center">
				<Box className="w:100% mt:1rem">
					<Card>
						<h1 className="text:2xl font:bold text:center mb:4">Login</h1>

						<form onSubmit={handleSubmit} className="flex flex-direction:column gap:2">
							<div className="flex flex-direction:column gap:1rem">
								<TextField.Root >
									<TextField.Slot>
										<Text as="label">Email</Text>
									</TextField.Slot>
									<TextField.Input />
								</TextField.Root>

								<TextField.Root >
									<TextField.Slot>
										<Text as="label">Password</Text>
									</TextField.Slot>
									<TextField.Input />
								</TextField.Root>
								<Button type="submit">Login</Button>
							</div>
						</form>
					</Card>
				</Box>
			</section>
		</Flex>
	);
};

export default UserAuthClient;

https://ithelp.ithome.com.tw/upload/images/20230927/20108931dDHNDe37mm.png


總結

在這篇文章中,我們將所有頁面基本的顯示都完成實現,簡易的展示了介面。但目前由於沒有狀態,明天會繼續完善網路商店的基本功能。


上一篇
11.【從前端到全端,Nextjs+Nestjs】使用Nx創建component generator
下一篇
13.【從前端到全端,Nextjs+Nestjs】創建商店頁面-建立表單
系列文
由前向後,從前端邁向全端30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言