Skip to content

Commit fcaca39

Browse files
committed
Merge branch 'master' into 1302-responsive-checkout
2 parents 952fcf8 + 524db2b commit fcaca39

File tree

1 file changed

+112
-101
lines changed

1 file changed

+112
-101
lines changed

src/components/Product/SingleProduct.component.tsx

Lines changed: 112 additions & 101 deletions
Original file line numberDiff line numberDiff line change
@@ -1,143 +1,154 @@
1-
import React, { useState, useEffect } from 'react';
1+
/*eslint complexity: ["error", 20]*/
2+
// Imports
3+
import { useState, useEffect } from 'react';
4+
5+
// Utils
26
import { filteredVariantPrice, paddedPrice } from '@/utils/functions/functions';
7+
8+
// Components
39
import AddToCart, { IProductRootObject } from './AddToCart.component';
410
import LoadingSpinner from '@/components/LoadingSpinner/LoadingSpinner.component';
511

6-
const SingleProduct: React.FC<IProductRootObject> = ({
7-
product,
8-
variationId: initialVariationId,
9-
}) => {
12+
const SingleProduct = ({ product }: IProductRootObject) => {
1013
const [isLoading, setIsLoading] = useState<boolean>(true);
11-
const [selectedVariation, setSelectedVariation] = useState<
12-
number | undefined
13-
>(initialVariationId);
14+
const [selectedVariation, setSelectedVariation] = useState<number>();
1415

1516
const placeholderFallBack = 'https://via.placeholder.com/600';
1617

17-
let DESCRIPTION_WITHOUT_HTML: string | null = null;
18+
let DESCRIPTION_WITHOUT_HTML;
1819

1920
useEffect(() => {
2021
setIsLoading(false);
21-
if (product.variations && !selectedVariation) {
22+
if (product.variations) {
2223
const firstVariant = product.variations.nodes[0].databaseId;
2324
setSelectedVariation(firstVariant);
2425
}
25-
}, [product.variations, selectedVariation]);
26+
}, [product.variations]);
2627

2728
let { description, image, name, onSale, price, regularPrice, salePrice } =
2829
product;
2930

30-
if (price) price = paddedPrice(price, 'kr');
31-
if (regularPrice) regularPrice = paddedPrice(regularPrice, 'kr');
32-
if (salePrice) salePrice = paddedPrice(salePrice, 'kr');
31+
// Add padding/empty character after currency symbol here
32+
if (price) {
33+
price = paddedPrice(price, 'kr');
34+
}
35+
if (regularPrice) {
36+
regularPrice = paddedPrice(regularPrice, 'kr');
37+
}
38+
if (salePrice) {
39+
salePrice = paddedPrice(salePrice, 'kr');
40+
}
3341

34-
if (typeof window !== 'undefined' && description) {
35-
DESCRIPTION_WITHOUT_HTML =
36-
new DOMParser().parseFromString(description, 'text/html').body
37-
.textContent || '';
42+
// Strip out HTML from description
43+
if (process.browser) {
44+
DESCRIPTION_WITHOUT_HTML = new DOMParser().parseFromString(
45+
description,
46+
'text/html',
47+
).body.textContent;
3848
}
3949

4050
return (
41-
<section className="bg-white mb-16 sm:mb-24">
51+
<section className="bg-white mb-[10rem] md:mb-12">
52+
{/* Show loading spinner while loading, and hide content while loading */}
4253
{isLoading ? (
4354
<div className="h-56 mt-20">
4455
<p className="text-2xl font-bold text-center">Laster produkt ...</p>
4556
<br />
4657
<LoadingSpinner />
4758
</div>
4859
) : (
49-
<div className="container mx-auto px-4 py-8 sm:px-6 lg:px-8">
50-
<div className="flex flex-col space-y-8">
51-
{/* First row: Product info, price, and purchase options */}
52-
<div className="flex flex-col md:flex-row gap-8">
53-
<div className="w-full md:w-1/2">
54-
{image ? (
55-
<img
56-
id="product-image"
57-
src={image.sourceUrl}
58-
alt={name}
59-
className="w-full h-auto object-cover rounded-lg shadow-md"
60-
/>
61-
) : (
62-
<img
63-
id="product-image"
64-
src={
65-
process.env.NEXT_PUBLIC_PLACEHOLDER_LARGE_IMAGE_URL ??
66-
placeholderFallBack
67-
}
68-
alt={name}
69-
className="w-full h-auto object-cover rounded-lg shadow-md"
70-
/>
71-
)}
72-
</div>
73-
<div className="w-full md:w-1/2 flex flex-col space-y-6">
74-
<h1 className="text-3xl font-bold">{name}</h1>
75-
<div className="flex flex-col space-y-2">
76-
{onSale && <p className="text-sm">Før {regularPrice}</p>}
77-
<p className="text-4xl font-bold">
78-
{product.variations
79-
? filteredVariantPrice(price, '')
80-
: onSale
81-
? salePrice
82-
: price}
60+
<div className="container flex flex-wrap items-center pt-4 pb-12 mx-auto ">
61+
<div className="grid grid-cols-1 gap-4 mt-16 lg:grid-cols-2 xl:grid-cols-2 md:grid-cols-2 sm:grid-cols-2">
62+
{image && (
63+
<img
64+
id="product-image"
65+
src={image.sourceUrl}
66+
alt={name}
67+
className="h-auto p-8 transition duration-500 ease-in-out transform xl:p-2 md:p-2 lg:p-2 md:hover:grow md:hover:scale-105"
68+
/>
69+
)}
70+
{!image && (
71+
<img
72+
id="product-image"
73+
src={
74+
process.env.NEXT_PUBLIC_PLACEHOLDER_LARGE_IMAGE_URL ??
75+
placeholderFallBack
76+
}
77+
alt={name}
78+
className="h-auto p-8 transition duration-500 ease-in-out transform xl:p-2 md:p-2 lg:p-2 md:hover:grow md:hover:shadow-lg md:hover:scale-105"
79+
/>
80+
)}
81+
<div className="ml-8">
82+
<p className="text-3xl font-bold text-left">{name}</p>
83+
<br />
84+
{/* Display sale price when on sale */}
85+
{onSale && (
86+
<div className="flex">
87+
<p className="pt-1 mt-4 text-3xl text-gray-900">
88+
{product.variations && filteredVariantPrice(price, '')}
89+
{!product.variations && salePrice}
8390
</p>
84-
<p className="text-sm">
85-
Tilbudet gjelder til 19/09 eller så lenge lageret rekker.
91+
<p className="pt-1 pl-8 mt-4 text-2xl text-gray-900 line-through">
92+
{product.variations && filteredVariantPrice(price, 'right')}
93+
{!product.variations && regularPrice}
8694
</p>
8795
</div>
88-
<div className="space-y-4">
96+
)}
97+
{/* Display regular price when not on sale */}
98+
{!onSale && (
99+
<p className="pt-1 mt-4 text-2xl text-gray-900"> {price}</p>
100+
)}
101+
<br />
102+
<p className="pt-1 mt-4 text-2xl text-gray-900">
103+
{DESCRIPTION_WITHOUT_HTML}
104+
</p>
105+
{Boolean(product.stockQuantity) && (
106+
<p
107+
v-if="data.product.stockQuantity"
108+
className="pt-1 mt-4 mb-4 text-2xl text-gray-900"
109+
>
110+
{product.stockQuantity} på lager
111+
</p>
112+
)}
113+
{product.variations && (
114+
<p className="pt-1 mt-4 text-xl text-gray-900">
115+
<span className="py-2">Varianter</span>
116+
<select
117+
id="variant"
118+
name="variant"
119+
className="block w-80 px-6 py-2 bg-white border border-gray-500 rounded-lg focus:outline-none focus:shadow-outline"
120+
onChange={(e) => {
121+
setSelectedVariation(Number(e.target.value));
122+
}}
123+
>
124+
{product.variations.nodes.map(
125+
({ id, name, databaseId, stockQuantity }) => {
126+
// Remove product name from variation name
127+
const filteredName = name.split('- ').pop();
128+
return (
129+
<option key={id} value={databaseId}>
130+
{filteredName} - ({stockQuantity} på lager)
131+
</option>
132+
);
133+
},
134+
)}
135+
</select>
136+
</p>
137+
)}
138+
<div className="pt-1 mt-2">
139+
{
140+
// Display default AddToCart button if we do not have variations.
141+
// If we do, send the variationId to AddToCart button
142+
}
143+
{product.variations && (
89144
<AddToCart
90145
product={product}
91146
variationId={selectedVariation}
92147
/>
93-
94-
{product.variations && (
95-
<div className="w-full">
96-
<label
97-
htmlFor="variant"
98-
className="block text-sm font-medium mb-2"
99-
>
100-
Varianter
101-
</label>
102-
<select
103-
id="variant"
104-
name="variant"
105-
className="w-full px-4 py-2 border border-gray-300 rounded-md focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
106-
onChange={(e) =>
107-
setSelectedVariation(Number(e.target.value))
108-
}
109-
value={selectedVariation}
110-
>
111-
{product.variations.nodes.map(
112-
({ id, name, databaseId, stockQuantity }) => {
113-
const filteredName = name.split('- ').pop();
114-
return (
115-
<option key={id} value={databaseId}>
116-
{filteredName} - ({stockQuantity} på lager)
117-
</option>
118-
);
119-
},
120-
)}
121-
</select>
122-
</div>
123-
)}
124-
</div>
125-
{Boolean(product.stockQuantity) && (
126-
<p className="text-sm font-semibold">
127-
<span className="inline-block w-3 h-3 bg-green-500 rounded-full mr-2"></span>
128-
{product.stockQuantity}+ stk. på lager
129-
</p>
130148
)}
149+
{!product.variations && <AddToCart product={product} />}
131150
</div>
132151
</div>
133-
134-
{/* Second row: Product description */}
135-
<div className="mt-8">
136-
<h2 className="text-2xl font-semibold mb-4">
137-
Produktbeskrivelse
138-
</h2>
139-
<p className="text-gray-600">{DESCRIPTION_WITHOUT_HTML}</p>
140-
</div>
141152
</div>
142153
</div>
143154
)}

0 commit comments

Comments
 (0)