Shopping page
Task
Create the same page as on the picture above

Result

React JS
import React, { useState } from "react";
import "./styles.css";
const App = () => {
const [quantity, setQuantity] = useState(1);
const [favorite, setFavorite] = useState(false);
const [zipCode, setZipCode] = useState("32163");
const rating = 4.8;
const totalReviews = 28;
const handleIncrease = () => setQuantity((prev) => prev + 1);
const handleDecrease = () => {
if (quantity > 1) setQuantity((prev) => prev - 1);
};
const handleFavoriteToggle = () => setFavorite((prev) => !prev);
const handleChangeZip = () => {
const newZip = prompt("Enter new Zip Code:", zipCode);
if (newZip) setZipCode(newZip);
};
return (
<div className="product-page">
<div className="product-image">
<img
src="https://via.placeholder.com/400x400"
alt="Parisian Leather Sofa Chair - White"
/>
<button
className={`favorite-button ${favorite ? "active" : ""}`}
onClick={handleFavoriteToggle}
>
♡
</button>
</div>
<div className="product-details">
<h1>Parisian Leather Sofa Chair - White</h1>
<p className="brand">by Best Selling Home</p>
<div className="rating">
<span className="stars">
{"★".repeat(Math.floor(rating))}
{"☆".repeat(5 - Math.floor(rating))}
</span>
<span className="rating-number">{rating.toFixed(1)}</span>
<span className="review-count">({totalReviews})</span>
</div>
<div className="price">
<span className="current-price">$298.39</span>
<span className="original-price">$359.00</span>
</div>
<div className="sale">
<span>ON SALE / Save 17%</span>
</div>
<div className="affirm">
<p>As low as $25/month or 0% APR with Affirm</p>
</div>
<div className="shipping">
<p>FREE SHIPPING</p>
<p>Arrives by Aug 16</p>
<p>
Zip Code: <input type="text" value={zipCode} readOnly />
</p>
<button onClick={handleChangeZip}>Change</button>
</div>
<div className="quantity">
<button onClick={handleDecrease}>-</button>
<input type="text" value={quantity} readOnly />
<button onClick={handleIncrease}>+</button>
</div>
<button className="add-to-cart">Add To Cart</button>
</div>
</div>
);
};
export default App;
React TS
import React, { useState } from "react";
import "./styles.css";
const App: React.FC = () => {
const [quantity, setQuantity] = useState<number>(1);
const [favorite, setFavorite] = useState<boolean>(false);
const [zipCode, setZipCode] = useState<string>("32163");
const rating: number = 4.8;
const totalReviews: number = 28;
const handleIncrease = () => setQuantity((prev) => prev + 1);
const handleDecrease = () => {
if (quantity > 1) setQuantity((prev) => prev - 1);
};
const handleFavoriteToggle = () => setFavorite((prev) => !prev);
const handleChangeZip = () => {
const newZip = prompt("Enter new Zip Code:", zipCode);
if (newZip) setZipCode(newZip);
};
return (
<div className="product-page">
<div className="product-image">
<img
src="https://via.placeholder.com/400x400"
alt="Parisian Leather Sofa Chair - White"
/>
<button
className={`favorite-button ${favorite ? "active" : ""}`}
onClick={handleFavoriteToggle}
>
♡
</button>
</div>
<div className="product-details">
<h1>Parisian Leather Sofa Chair - White</h1>
<p className="brand">by Best Selling Home</p>
<div className="rating">
<span className="stars">
{"★".repeat(Math.floor(rating))}
{"☆".repeat(5 - Math.floor(rating))}
</span>
<span className="rating-number">{rating.toFixed(1)}</span>
<span className="review-count">({totalReviews})</span>
</div>
<div className="price">
<span className="current-price">$298.39</span>
<span className="original-price">$359.00</span>
</div>
<div className="sale">
<span>ON SALE / Save 17%</span>
</div>
<div className="affirm">
<p>As low as $25/month or 0% APR with Affirm</p>
</div>
<div className="shipping">
<p>FREE SHIPPING</p>
<p>Arrives by Aug 16</p>
<p>
Zip Code: <input type="text" value={zipCode} readOnly />
</p>
<button onClick={handleChangeZip}>Change</button>
</div>
<div className="quantity">
<button onClick={handleDecrease}>-</button>
<input type="text" value={quantity} readOnly />
<button onClick={handleIncrease}>+</button>
</div>
<button className="add-to-cart">Add To Cart</button>
</div>
</div>
);
};
export default App;
React JS + Tailwind
import React, { useState } from "react";
const App = () => {
const [quantity, setQuantity] = useState(1);
const [favorite, setFavorite] = useState(false);
const [zipCode, setZipCode] = useState("32163");
const rating = 4.8;
const totalReviews = 28;
const handleIncrease = () => setQuantity((prev) => prev + 1);
const handleDecrease = () => {
if (quantity > 1) setQuantity((prev) => prev - 1);
};
const handleFavoriteToggle = () => setFavorite((prev) => !prev);
const handleChangeZip = () => {
const newZip = prompt("Enter new Zip Code:", zipCode);
if (newZip) setZipCode(newZip);
};
return (
<div className="max-w-3xl mx-auto p-6 bg-white shadow-md rounded-lg flex">
<div className="relative flex-1 flex justify-center items-center">
<img
src="https://via.placeholder.com/400x400"
alt="Parisian Leather Sofa Chair - White"
className="max-w-full rounded-lg"
/>
<button
className={`absolute top-3 right-3 text-2xl ${favorite ? "text-red-500" : "text-gray-400"}`}
onClick={handleFavoriteToggle}
>
♡
</button>
</div>
<div className="flex-1 flex flex-col ml-6">
<h1 className="text-2xl mb-2">Parisian Leather Sofa Chair - White</h1>
<p className="text-gray-500 mb-2">by Best Selling Home</p>
<div className="flex items-center mb-2">
<span className="text-2xl text-gray-400">
{"★".repeat(Math.floor(rating))}
{"☆".repeat(5 - Math.floor(rating))}
</span>
<span className="ml-2 text-lg text-gray-700">
{rating.toFixed(1)}
</span>
<span className="ml-2 text-sm text-gray-500">({totalReviews})</span>
</div>
<div className="flex items-center mb-2">
<span className="text-red-500 text-2xl font-bold">$298.39</span>
<span className="text-gray-500 line-through text-xl ml-2">
$359.00
</span>
</div>
<div className="text-red-500 text-sm mb-4">ON SALE / Save 17%</div>
<div className="mb-4">
<p className="mb-2">As low as $25/month or 0% APR with Affirm</p>
<p>FREE SHIPPING</p>
<p>Arrives by Aug 16</p>
<div className="flex items-center mt-2">
<span>Zip Code: </span>
<input
type="text"
value={zipCode}
readOnly
className="ml-2 border p-1 rounded-md"
/>
<button
onClick={handleChangeZip}
className="ml-2 bg-gray-800 text-white px-3 py-1 rounded-md"
>
Change
</button>
</div>
</div>
<div className="flex items-center mb-4">
<button
onClick={handleDecrease}
className="px-4 py-2 bg-gray-300 text-xl rounded-md"
>
-
</button>
<input
type="text"
value={quantity}
readOnly
className="mx-2 text-center border p-2 rounded-md w-12"
/>
<button
onClick={handleIncrease}
className="px-4 py-2 bg-gray-300 text-xl rounded-md"
>
+
</button>
</div>
<button className="py-3 bg-gray-800 text-white rounded-md text-lg">
Add To Cart
</button>
</div>
</div>
);
};
export default App;
React TS + Tailwind
import React, { useState } from "react";
const App: React.FC = () => {
const [quantity, setQuantity] = useState<number>(1);
const [favorite, setFavorite] = useState<boolean>(false);
const [zipCode, setZipCode] = useState<string>("32163");
const rating: number = 4.8;
const totalReviews: number = 28;
const handleIncrease = () => setQuantity((prev) => prev + 1);
const handleDecrease = () => {
if (quantity > 1) setQuantity((prev) => prev - 1);
};
const handleFavoriteToggle = () => setFavorite((prev) => !prev);
const handleChangeZip = () => {
const newZip = prompt("Enter new Zip Code:", zipCode);
if (newZip) setZipCode(newZip);
};
return (
<div className="max-w-3xl mx-auto p-6 bg-white shadow-md rounded-lg flex">
<div className="relative flex-1 flex justify-center items-center">
<img
src="https://via.placeholder.com/400x400"
alt="Parisian Leather Sofa Chair - White"
className="max-w-full rounded-lg"
/>
<button
className={`absolute top-3 right-3 text-2xl ${favorite ? "text-red-500" : "text-gray-400"}`}
onClick={handleFavoriteToggle}
>
♡
</button>
</div>
<div className="flex-1 flex flex-col ml-6">
<h1 className="text-2xl mb-2">Parisian Leather Sofa Chair - White</h1>
<p className="text-gray-500 mb-2">by Best Selling Home</p>
<div className="flex items-center mb-2">
<span className="text-2xl text-gray-400">
{"★".repeat(Math.floor(rating))}
{"☆".repeat(5 - Math.floor(rating))}
</span>
<span className="ml-2 text-lg text-gray-700">
{rating.toFixed(1)}
</span>
<span className="ml-2 text-sm text-gray-500">({totalReviews})</span>
</div>
<div className="flex items-center mb-2">
<span className="text-red-500 text-2xl font-bold">$298.39</span>
<span className="text-gray-500 line-through text-xl ml-2">
$359.00
</span>
</div>
<div className="text-red-500 text-sm mb-4">ON SALE / Save 17%</div>
<div className="mb-4">
<p className="mb-2">As low as $25/month or 0% APR with Affirm</p>
<p>FREE SHIPPING</p>
<p>Arrives by Aug 16</p>
<div className="flex items-center mt-2">
<span>Zip Code: </span>
<input
type="text"
value={zipCode}
readOnly
className="ml-2 border p-1 rounded-md"
/>
<button
onClick={handleChangeZip}
className="ml-2 bg-gray-800 text-white px-3 py-1 rounded-md"
>
Change
</button>
</div>
</div>
<div className="flex items-center mb-4">
<button
onClick={handleDecrease}
className="px-4 py-2 bg-gray-300 text-xl rounded-md"
>
-
</button>
<input
type="text"
value={quantity}
readOnly
className="mx-2 text-center border p-2 rounded-md w-12"
/>
<button
onClick={handleIncrease}
className="px-4 py-2 bg-gray-300 text-xl rounded-md"
>
+
</button>
</div>
<button className="py-3 bg-gray-800 text-white rounded-md text-lg">
Add To Cart
</button>
</div>
</div>
);
};
export default App;