|
1 |
| -/*eslint complexity: ["error", 20]*/ |
2 | 1 | // Imports
|
3 | 2 | import { useState, useEffect } from 'react';
|
4 | 3 |
|
@@ -43,109 +42,112 @@ const SingleProduct = ({ product }: IProductRootObject) => {
|
43 | 42 | if (process.browser) {
|
44 | 43 | DESCRIPTION_WITHOUT_HTML = new DOMParser().parseFromString(
|
45 | 44 | description,
|
46 |
| - 'text/html', |
| 45 | + 'text/html' |
47 | 46 | ).body.textContent;
|
48 | 47 | }
|
49 | 48 |
|
50 | 49 | return (
|
51 | 50 | <section className="bg-white mb-[8rem] md:mb-12">
|
52 |
| - {/* Show loading spinner while loading, and hide content while loading */} |
53 | 51 | {isLoading ? (
|
54 | 52 | <div className="h-56 mt-20">
|
55 | 53 | <p className="text-2xl font-bold text-center">Laster produkt ...</p>
|
56 | 54 | <br />
|
57 | 55 | <LoadingSpinner />
|
58 | 56 | </div>
|
59 | 57 | ) : (
|
60 |
| - <div className="container flex flex-wrap items-center pt-4 pb-12 mx-auto"> |
61 |
| - <div className="grid grid-cols-1 gap-4 md: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 && ( |
| 58 | + <div className="container mx-auto px-4 py-8"> |
| 59 | + <div className="flex flex-col md:grid md:grid-cols-2 md:gap-8"> |
| 60 | + {/* Image Container */} |
| 61 | + <div className="mb-6 md:mb-0"> |
71 | 62 | <img
|
72 | 63 | id="product-image"
|
73 | 64 | src={
|
74 |
| - process.env.NEXT_PUBLIC_PLACEHOLDER_LARGE_IMAGE_URL ?? |
| 65 | + image?.sourceUrl || |
| 66 | + process.env.NEXT_PUBLIC_PLACEHOLDER_LARGE_IMAGE_URL || |
75 | 67 | placeholderFallBack
|
76 | 68 | }
|
77 | 69 | 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" |
| 70 | + className="w-full h-auto object-cover transition duration-500 ease-in-out transform md:hover:scale-105" |
79 | 71 | />
|
80 |
| - )} |
81 |
| - <div className="px-4 md:ml-8"> |
| 72 | + </div> |
| 73 | + |
| 74 | + {/* Product Details Container */} |
| 75 | + <div className="flex flex-col"> |
82 | 76 | <h1 className="text-2xl font-bold text-center md:text-left mb-4">
|
83 | 77 | {name}
|
84 | 78 | </h1>
|
85 |
| - {/* Display sale price when on sale */} |
86 |
| - {onSale && ( |
87 |
| - <div className="flex flex-col md:flex-row items-center md:items-start mb-4"> |
88 |
| - <p className="text-2xl font-bold text-gray-900"> |
89 |
| - {product.variations && filteredVariantPrice(price, '')} |
90 |
| - {!product.variations && salePrice} |
91 |
| - </p> |
92 |
| - <p className="text-xl text-gray-500 line-through md:ml-4"> |
93 |
| - {product.variations && filteredVariantPrice(price, 'right')} |
94 |
| - {!product.variations && regularPrice} |
95 |
| - </p> |
96 |
| - </div> |
97 |
| - )} |
98 |
| - {/* Display regular price when not on sale */} |
99 |
| - {!onSale && <p className="text-2xl font-bold mb-4">{price}</p>} |
100 |
| - <p className="text-lg mb-4 text-center md:text-left"> |
| 79 | + |
| 80 | + {/* Price Display */} |
| 81 | + <div className="text-center md:text-left mb-6"> |
| 82 | + {onSale ? ( |
| 83 | + <div className="flex flex-col md:flex-row items-center md:items-start gap-2"> |
| 84 | + <p className="text-2xl font-bold text-gray-900"> |
| 85 | + {product.variations |
| 86 | + ? filteredVariantPrice(price, '') |
| 87 | + : salePrice} |
| 88 | + </p> |
| 89 | + <p className="text-xl text-gray-500 line-through"> |
| 90 | + {product.variations |
| 91 | + ? filteredVariantPrice(price, 'right') |
| 92 | + : regularPrice} |
| 93 | + </p> |
| 94 | + </div> |
| 95 | + ) : ( |
| 96 | + <p className="text-2xl font-bold">{price}</p> |
| 97 | + )} |
| 98 | + </div> |
| 99 | + |
| 100 | + {/* Description */} |
| 101 | + <p className="text-lg mb-6 text-center md:text-left"> |
101 | 102 | {DESCRIPTION_WITHOUT_HTML}
|
102 | 103 | </p>
|
| 104 | + |
| 105 | + {/* Stock Status */} |
103 | 106 | {Boolean(product.stockQuantity) && (
|
104 |
| - <div className="mb-4 p-2 bg-green-100 border border-green-400 rounded-lg mx-auto md:mx-0 max-w-[14.375rem]"> |
105 |
| - <p className="text-lg text-green-700 font-semibold text-center md:text-left"> |
106 |
| - {product.stockQuantity} på lager |
107 |
| - </p> |
| 107 | + <div className="mb-6 mx-auto md:mx-0"> |
| 108 | + <div className="p-2 bg-green-100 border border-green-400 rounded-lg max-w-[14.375rem]"> |
| 109 | + <p className="text-lg text-green-700 font-semibold text-center md:text-left"> |
| 110 | + {product.stockQuantity} på lager |
| 111 | + </p> |
| 112 | + </div> |
108 | 113 | </div>
|
109 | 114 | )}
|
| 115 | + |
| 116 | + {/* Variations Select */} |
110 | 117 | {product.variations && (
|
111 |
| - <div className="mb-4"> |
| 118 | + <div className="mb-6 mx-auto md:mx-0 w-full max-w-[14.375rem]"> |
112 | 119 | <label
|
113 | 120 | htmlFor="variant"
|
114 |
| - className="block text-lg font-medium mb-2" |
| 121 | + className="block text-lg font-medium mb-2 text-center md:text-left" |
115 | 122 | >
|
116 | 123 | Varianter
|
117 | 124 | </label>
|
118 | 125 | <select
|
119 | 126 | id="variant"
|
120 | 127 | name="variant"
|
121 |
| - className="max-w-[14.375rem] block w-full px-4 py-2 bg-white border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500" |
122 |
| - onChange={(e) => { |
123 |
| - setSelectedVariation(Number(e.target.value)); |
124 |
| - }} |
| 128 | + className="w-full px-4 py-2 bg-white border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500" |
| 129 | + onChange={(e) => setSelectedVariation(Number(e.target.value))} |
125 | 130 | >
|
126 | 131 | {product.variations.nodes.map(
|
127 |
| - ({ id, name, databaseId, stockQuantity }) => { |
128 |
| - // Remove product name from variation name |
129 |
| - const filteredName = name.split('- ').pop(); |
130 |
| - return ( |
131 |
| - <option key={id} value={databaseId}> |
132 |
| - {filteredName} - ({stockQuantity} på lager) |
133 |
| - </option> |
134 |
| - ); |
135 |
| - }, |
| 132 | + ({ id, name, databaseId, stockQuantity }) => ( |
| 133 | + <option key={id} value={databaseId}> |
| 134 | + {name.split('- ').pop()} - ({stockQuantity} på lager) |
| 135 | + </option> |
| 136 | + ) |
136 | 137 | )}
|
137 | 138 | </select>
|
138 | 139 | </div>
|
139 | 140 | )}
|
140 |
| - <div className="w-full p-4 md:p-0"> |
141 |
| - {product.variations && ( |
| 141 | + |
| 142 | + {/* Add to Cart Button */} |
| 143 | + <div className="w-full mx-auto md:mx-0 max-w-[14.375rem]"> |
| 144 | + {product.variations ? ( |
142 | 145 | <AddToCart
|
143 | 146 | product={product}
|
144 | 147 | variationId={selectedVariation}
|
145 | 148 | fullWidth={true}
|
146 | 149 | />
|
147 |
| - )} |
148 |
| - {!product.variations && ( |
| 150 | + ) : ( |
149 | 151 | <AddToCart product={product} fullWidth={true} />
|
150 | 152 | )}
|
151 | 153 | </div>
|
|
0 commit comments