|
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