first commit

This commit is contained in:
mukesh13
2025-07-30 13:44:47 +05:30
commit 6c0c0e3d1d
494 changed files with 57695 additions and 0 deletions

View File

@ -0,0 +1,344 @@
"use client";
import { useContextElement } from "@/context/Context";
import Link from "next/link";
import DropdownSelect from "../common/DropdownSelect";
export default function Checkout() {
const {
cartProducts,
totalPrice,
} = useContextElement();
return (
<div className="checkout-product tf-spacing-40">
<div className="tf-container">
<div className="row">
<div className="col-md-8">
<div className="left">
<form
className="form-checkout"
onSubmit={(e) => e.preventDefault()}
>
<div className="mb_33">
<h6 className="mb_12">Contact information</h6>
<p className="text-body-2 mb_18">
Well use this email to send you details and updates about
your order
</p>
<fieldset>
<input
type="email"
placeholder="Email address"
id="email"
className="rounded-cycle"
required
/>
</fieldset>
</div>
<div className="mb_34">
<h6 className="mb_12">Billing address</h6>
<p className="text-body-2 mb_18">
Enter the billing address that matches your payment method
</p>
<div className="tf-select-tranform-lable mb_24">
<span className="select-label">Country/Region</span>
<select id="countrySelect" name="region-choose">
<option />
<option
value="United States"
data-provinces="[['Alabama','Alabama'],['Alaska','Alaska'],['American Samoa','American Samoa'],['Arizona','Arizona'],['Arkansas','Arkansas'],['Armed Forces Americas','Armed Forces Americas'],['Armed Forces Europe','Armed Forces Europe'],['Armed Forces Pacific','Armed Forces Pacific'],['California','California'],['Colorado','Colorado'],['Connecticut','Connecticut'],['Delaware','Delaware'],['District of Columbia','Washington DC'],['Federated States of Micronesia','Micronesia'],['Florida','Florida'],['Georgia','Georgia'],['Guam','Guam'],['Hawaii','Hawaii'],['Idaho','Idaho'],['Illinois','Illinois'],['Indiana','Indiana'],['Iowa','Iowa'],['Kansas','Kansas'],['Kentucky','Kentucky'],['Louisiana','Louisiana'],['Maine','Maine'],['Marshall Islands','Marshall Islands'],['Maryland','Maryland'],['Massachusetts','Massachusetts'],['Michigan','Michigan'],['Minnesota','Minnesota'],['Mississippi','Mississippi'],['Missouri','Missouri'],['Montana','Montana'],['Nebraska','Nebraska'],['Nevada','Nevada'],['New Hampshire','New Hampshire'],['New Jersey','New Jersey'],['New Mexico','New Mexico'],['New York','New York'],['North Carolina','North Carolina'],['North Dakota','North Dakota'],['Northern Mariana Islands','Northern Mariana Islands'],['Ohio','Ohio'],['Oklahoma','Oklahoma'],['Oregon','Oregon'],['Palau','Palau'],['Pennsylvania','Pennsylvania'],['Puerto Rico','Puerto Rico'],['Rhode Island','Rhode Island'],['South Carolina','South Carolina'],['South Dakota','South Dakota'],['Tennessee','Tennessee'],['Texas','Texas'],['Utah','Utah'],['Vermont','Vermont'],['Virgin Islands','U.S. Virgin Islands'],['Virginia','Virginia'],['Washington','Washington'],['West Virginia','West Virginia'],['Wisconsin','Wisconsin'],['Wyoming','Wyoming']]"
>
United States
</option>
<option
value="Australia"
data-provinces="[['Australian Capital Territory','Australian Capital Territory'],['New South Wales','New South Wales'],['Northern Territory','Northern Territory'],['Queensland','Queensland'],['South Australia','South Australia'],['Tasmania','Tasmania'],['Victoria','Victoria'],['Western Australia','Western Australia']]"
>
Australia
</option>
<option value="Austria" data-provinces="[]">
Austria
</option>
<option value="Belgium" data-provinces="[]">
Belgium
</option>
<option
value="Canada"
data-provinces="[['Alberta','Alberta'],['British Columbia','British Columbia'],['Manitoba','Manitoba'],['New Brunswick','New Brunswick'],['Newfoundland and Labrador','Newfoundland and Labrador'],['Northwest Territories','Northwest Territories'],['Nova Scotia','Nova Scotia'],['Nunavut','Nunavut'],['Ontario','Ontario'],['Prince Edward Island','Prince Edward Island'],['Quebec','Quebec'],['Saskatchewan','Saskatchewan'],['Yukon','Yukon']]"
>
Canada
</option>
<option value="Czech Republic" data-provinces="[]">
Czechia
</option>
<option value="Denmark" data-provinces="[]">
Denmark
</option>
<option value="Finland" data-provinces="[]">
Finland
</option>
<option value="France" data-provinces="[]">
France
</option>
<option value="Germany" data-provinces="[]">
Germany
</option>
<option
value="Hong Kong"
data-provinces="[['Hong Kong Island','Hong Kong Island'],['Kowloon','Kowloon'],['New Territories','New Territories']]"
>
Hong Kong SAR
</option>
<option
value="Ireland"
data-provinces="[['Carlow','Carlow'],['Cavan','Cavan'],['Clare','Clare'],['Cork','Cork'],['Donegal','Donegal'],['Dublin','Dublin'],['Galway','Galway'],['Kerry','Kerry'],['Kildare','Kildare'],['Kilkenny','Kilkenny'],['Laois','Laois'],['Leitrim','Leitrim'],['Limerick','Limerick'],['Longford','Longford'],['Louth','Louth'],['Mayo','Mayo'],['Meath','Meath'],['Monaghan','Monaghan'],['Offaly','Offaly'],['Roscommon','Roscommon'],['Sligo','Sligo'],['Tipperary','Tipperary'],['Waterford','Waterford'],['Westmeath','Westmeath'],['Wexford','Wexford'],['Wicklow','Wicklow']]"
>
Ireland
</option>
<option value="Israel" data-provinces="[]">
Israel
</option>
<option
value="Italy"
data-provinces="[['Agrigento','Agrigento'],['Alessandria','Alessandria'],['Ancona','Ancona'],['Aosta','Aosta Valley'],['Arezzo','Arezzo'],['Ascoli Piceno','Ascoli Piceno'],['Asti','Asti'],['Avellino','Avellino'],['Bari','Bari'],['Barletta-Andria-Trani','Barletta-Andria-Trani'],['Belluno','Belluno'],['Benevento','Benevento'],['Bergamo','Bergamo'],['Biella','Biella'],['Bologna','Bologna'],['Bolzano','South Tyrol'],['Brescia','Brescia'],['Brindisi','Brindisi'],['Cagliari','Cagliari'],['Caltanissetta','Caltanissetta'],['Campobasso','Campobasso'],['Carbonia-Iglesias','Carbonia-Iglesias'],['Caserta','Caserta'],['Catania','Catania'],['Catanzaro','Catanzaro'],['Chieti','Chieti'],['Como','Como'],['Cosenza','Cosenza'],['Cremona','Cremona'],['Crotone','Crotone'],['Cuneo','Cuneo'],['Enna','Enna'],['Fermo','Fermo'],['Ferrara','Ferrara'],['Firenze','Florence'],['Foggia','Foggia'],['Forlì-Cesena','Forlì-Cesena'],['Frosinone','Frosinone'],['Genova','Genoa'],['Gorizia','Gorizia'],['Grosseto','Grosseto'],['Imperia','Imperia'],['Isernia','Isernia'],['L'Aquila','LAquila'],['La Spezia','La Spezia'],['Latina','Latina'],['Lecce','Lecce'],['Lecco','Lecco'],['Livorno','Livorno'],['Lodi','Lodi'],['Lucca','Lucca'],['Macerata','Macerata'],['Mantova','Mantua'],['Massa-Carrara','Massa and Carrara'],['Matera','Matera'],['Medio Campidano','Medio Campidano'],['Messina','Messina'],['Milano','Milan'],['Modena','Modena'],['Monza e Brianza','Monza and Brianza'],['Napoli','Naples'],['Novara','Novara'],['Nuoro','Nuoro'],['Ogliastra','Ogliastra'],['Olbia-Tempio','Olbia-Tempio'],['Oristano','Oristano'],['Padova','Padua'],['Palermo','Palermo'],['Parma','Parma'],['Pavia','Pavia'],['Perugia','Perugia'],['Pesaro e Urbino','Pesaro and Urbino'],['Pescara','Pescara'],['Piacenza','Piacenza'],['Pisa','Pisa'],['Pistoia','Pistoia'],['Pordenone','Pordenone'],['Potenza','Potenza'],['Prato','Prato'],['Ragusa','Ragusa'],['Ravenna','Ravenna'],['Reggio Calabria','Reggio Calabria'],['Reggio Emilia','Reggio Emilia'],['Rieti','Rieti'],['Rimini','Rimini'],['Roma','Rome'],['Rovigo','Rovigo'],['Salerno','Salerno'],['Sassari','Sassari'],['Savona','Savona'],['Siena','Siena'],['Siracusa','Syracuse'],['Sondrio','Sondrio'],['Taranto','Taranto'],['Teramo','Teramo'],['Terni','Terni'],['Torino','Turin'],['Trapani','Trapani'],['Trento','Trentino'],['Treviso','Treviso'],['Trieste','Trieste'],['Udine','Udine'],['Varese','Varese'],['Venezia','Venice'],['Verbano-Cusio-Ossola','Verbano-Cusio-Ossola'],['Vercelli','Vercelli'],['Verona','Verona'],['Vibo Valentia','Vibo Valentia'],['Vicenza','Vicenza'],['Viterbo','Viterbo']]"
>
Italy
</option>
<option
value="Japan"
data-provinces="[['Aichi','Aichi'],['Akita','Akita'],['Aomori','Aomori'],['Chiba','Chiba'],['Ehime','Ehime'],['Fukui','Fukui'],['Fukuoka','Fukuoka'],['Fukushima','Fukushima'],['Gifu','Gifu'],['Gunma','Gunma'],['Hiroshima','Hiroshima'],['Hokkaidō','Hokkaido'],['Hyōgo','Hyogo'],['Ibaraki','Ibaraki'],['Ishikawa','Ishikawa'],['Iwate','Iwate'],['Kagawa','Kagawa'],['Kagoshima','Kagoshima'],['Kanagawa','Kanagawa'],['Kumamoto','Kumamoto'],['Kyōto','Kyoto'],['Kōchi','Kochi'],['Mie','Mie'],['Miyagi','Miyagi'],['Miyazaki','Miyazaki'],['Nagano','Nagano'],['Nagasaki','Nagasaki'],['Nara','Nara'],['Niigata','Niigata'],['Okayama','Okayama'],['Okinawa','Okinawa'],['Saga','Saga'],['Saitama','Saitama'],['Shiga','Shiga'],['Shimane','Shimane'],['Shizuoka','Shizuoka'],['Tochigi','Tochigi'],['Tokushima','Tokushima'],['Tottori','Tottori'],['Toyama','Toyama'],['Tōkyō','Tokyo'],['Wakayama','Wakayama'],['Yamagata','Yamagata'],['Yamaguchi','Yamaguchi'],['Yamanashi','Yamanashi'],['Ōita','Oita'],['Ōsaka','Osaka']]"
>
Japan
</option>
<option
value="Malaysia"
data-provinces="[['Johor','Johor'],['Kedah','Kedah'],['Kelantan','Kelantan'],['Kuala Lumpur','Kuala Lumpur'],['Labuan','Labuan'],['Melaka','Malacca'],['Negeri Sembilan','Negeri Sembilan'],['Pahang','Pahang'],['Penang','Penang'],['Perak','Perak'],['Perlis','Perlis'],['Putrajaya','Putrajaya'],['Sabah','Sabah'],['Sarawak','Sarawak'],['Selangor','Selangor'],['Terengganu','Terengganu']]"
>
Malaysia
</option>
<option value="Netherlands" data-provinces="[]">
Netherlands
</option>
<option
value="New Zealand"
data-provinces="[['Auckland','Auckland'],['Bay of Plenty','Bay of Plenty'],['Canterbury','Canterbury'],['Chatham Islands','Chatham Islands'],['Gisborne','Gisborne'],['Hawke's Bay','Hawkes Bay'],['Manawatu-Wanganui','Manawatū-Whanganui'],['Marlborough','Marlborough'],['Nelson','Nelson'],['Northland','Northland'],['Otago','Otago'],['Southland','Southland'],['Taranaki','Taranaki'],['Tasman','Tasman'],['Waikato','Waikato'],['Wellington','Wellington'],['West Coast','West Coast']]"
>
New Zealand
</option>
<option value="Norway" data-provinces="[]">
Norway
</option>
<option value="Poland" data-provinces="[]">
Poland
</option>
<option
value="Portugal"
data-provinces="[['Aveiro','Aveiro'],['Açores','Azores'],['Beja','Beja'],['Braga','Braga'],['Bragança','Bragança'],['Castelo Branco','Castelo Branco'],['Coimbra','Coimbra'],['Faro','Faro'],['Guarda','Guarda'],['Leiria','Leiria'],['Lisboa','Lisbon'],['Madeira','Madeira'],['Portalegre','Portalegre'],['Porto','Porto'],['Santarém','Santarém'],['Setúbal','Setúbal'],['Viana do Castelo','Viana do Castelo'],['Vila Real','Vila Real'],['Viseu','Viseu'],['Évora','Évora']]"
>
Portugal
</option>
<option value="Singapore" data-provinces="[]">
Singapore
</option>
<option
value="South Korea"
data-provinces="[['Busan','Busan'],['Chungbuk','North Chungcheong'],['Chungnam','South Chungcheong'],['Daegu','Daegu'],['Daejeon','Daejeon'],['Gangwon','Gangwon'],['Gwangju','Gwangju City'],['Gyeongbuk','North Gyeongsang'],['Gyeonggi','Gyeonggi'],['Gyeongnam','South Gyeongsang'],['Incheon','Incheon'],['Jeju','Jeju'],['Jeonbuk','North Jeolla'],['Jeonnam','South Jeolla'],['Sejong','Sejong'],['Seoul','Seoul'],['Ulsan','Ulsan']]"
>
South Korea
</option>
<option
value="Spain"
data-provinces="[['A Coruña','A Coruña'],['Albacete','Albacete'],['Alicante','Alicante'],['Almería','Almería'],['Asturias','Asturias Province'],['Badajoz','Badajoz'],['Balears','Balears Province'],['Barcelona','Barcelona'],['Burgos','Burgos'],['Cantabria','Cantabria Province'],['Castellón','Castellón'],['Ceuta','Ceuta'],['Ciudad Real','Ciudad Real'],['Cuenca','Cuenca'],['Cáceres','Cáceres'],['Cádiz','Cádiz'],['Córdoba','Córdoba'],['Girona','Girona'],['Granada','Granada'],['Guadalajara','Guadalajara'],['Guipúzcoa','Gipuzkoa'],['Huelva','Huelva'],['Huesca','Huesca'],['Jaén','Jaén'],['La Rioja','La Rioja Province'],['Las Palmas','Las Palmas'],['León','León'],['Lleida','Lleida'],['Lugo','Lugo'],['Madrid','Madrid Province'],['Melilla','Melilla'],['Murcia','Murcia'],['Málaga','Málaga'],['Navarra','Navarra'],['Ourense','Ourense'],['Palencia','Palencia'],['Pontevedra','Pontevedra'],['Salamanca','Salamanca'],['Santa Cruz de Tenerife','Santa Cruz de Tenerife'],['Segovia','Segovia'],['Sevilla','Seville'],['Soria','Soria'],['Tarragona','Tarragona'],['Teruel','Teruel'],['Toledo','Toledo'],['Valencia','Valencia'],['Valladolid','Valladolid'],['Vizcaya','Biscay'],['Zamora','Zamora'],['Zaragoza','Zaragoza'],['Álava','Álava'],['Ávila','Ávila']]"
>
Spain
</option>
<option value="Sweden" data-provinces="[]">
Sweden
</option>
<option value="Switzerland" data-provinces="[]">
Switzerland
</option>
<option
value="United Arab Emirates"
data-provinces="[['Abu Dhabi','Abu Dhabi'],['Ajman','Ajman'],['Dubai','Dubai'],['Fujairah','Fujairah'],['Ras al-Khaimah','Ras al-Khaimah'],['Sharjah','Sharjah'],['Umm al-Quwain','Umm al-Quwain']]"
>
United Arab Emirates
</option>
<option
value="United Kingdom"
data-provinces="[['British Forces','British Forces'],['England','England'],['Northern Ireland','Northern Ireland'],['Scotland','Scotland'],['Wales','Wales']]"
>
United Kingdom
</option>
<option value="Vietnam" data-provinces="[]">
Vietnam
</option>
</select>
</div>
<div className="grid-2 mb_24">
<fieldset>
<input
type="text"
placeholder="First name"
id="first-name"
className="rounded-cycle"
required
/>
</fieldset>
<fieldset>
<input
type="text"
placeholder="Last name"
id="last-name"
className="rounded-cycle"
required
/>
</fieldset>
</div>
<fieldset className="mb_22">
<input
type="text"
placeholder="Address"
id="address"
className="rounded-cycle"
required
/>
</fieldset>
<a href="#" className="link text-body-2 mb_18">
+ Add apartment, suit, etc.
</a>
<div className="grid-2 mb_24">
<fieldset>
<input
type="text"
placeholder="City"
id="city"
className="rounded-cycle"
required
/>
</fieldset>
<div className="tf-select-tranform-lable">
<span className="select-label">State</span>
<select name="region-choose" id="state">
<option />
<option value="California">California</option>
<option value="Alabama">Alabam</option>
<option value="Alaska">Alaska</option>
<option value="Arizona">Arizona</option>
<option value="Arkansas">Arkansas</option>
<option value="Florida">Florida</option>
<option value="Georgia">Georgia</option>
<option value="Hawaii">Hawaii</option>
<option value="Washington">Washington</option>
<option value="Texas">Texas</option>
<option value="Iowa">Iowa</option>
<option value="Nevada">Nevada</option>
<option value="Illinois">Illinois</option>
</select>
</div>
</div>
<div className="grid-2">
<fieldset>
<input
type="text"
placeholder="Zip Code"
id="zip-code"
className="rounded-cycle"
required
/>
</fieldset>
<fieldset>
<input
type="number"
placeholder="Phone (optional)"
id="phone"
className="rounded-cycle"
required
/>
</fieldset>
</div>
</div>
<div className="mb_33">
<h6 className="title mb_16">Payment options</h6>
<div className="notification d-flex gap_16">
<div className="icon">
<i className="icon-info-circle-solid" />
</div>
<p className="text-body-2 text_mono-gray-6">
There are no payment methods available. This may be an
error on our side. Please contact us if you need any
<br />
help placing your order.
</p>
</div>
</div>
<div className="bot">
<div className="align-items-center d-flex gap_8 mb_29">
<fieldset className="fieldset-item">
<input
type="checkbox"
name="brand"
className="tf-check"
id="add"
defaultChecked=""
/>
</fieldset>
<label className="h6" htmlFor="add">
Add a note to your order
</label>
</div>
<p className="text-body-2 mb_41">
By proceeding with your purchase you agree to our Terms and
Conditions and Privacy Policy
</p>
<div className="wrap-btn d-flex align-items-center justify-content-between">
<Link
href={`/cart`}
className="link d-flex align-items-center gap_20 text-body-1"
>
<i className="icon-long-arrow-alt-left-solid" />
Back to cart
</Link>
<a href="#" className="tf-btn btn-primary2 height-2">
<span>Place Order</span>
<span className="bg-effect" />
</a>
</div>
</div>
</form>
</div>
</div>
<div className="col-md-4">
<div className="cart-totals v2">
<h2 className="title">Cart totals</h2>
<div className="wrap-info">
{cartProducts.map((product, i) => (
<div key={i} className="info sub-heading d-flex">
<div className="name">{product.title}</div>
<span>x{product.quantity}</span>{" "}
<div className="price sub-heading">
${(product.price * product.quantity).toFixed(2)}
</div>
</div>
))}
</div>
<DropdownSelect
defaultOption={"Add a coupon"}
options={["coupon 10%", "coupon 20%"]}
addtionalParentClass="h6 text_black px-0"
/>
<div className="sub-total d-flex justify-content-between align-items-center h6">
<span>Discount</span>
<span>-{totalPrice ? "$1.796" : 0}</span>
</div>
<div className="total h4 d-flex justify-content-between align-items-center">
<span>Total</span>
<span>${totalPrice ? (totalPrice - 1.796).toFixed(2) : 0}</span>
</div>
</div>
</div>
</div>
</div>
</div>
);
}

View File

@ -0,0 +1,65 @@
"use client";
export default function CommentBox() {
return (
<form className="form-leave-comment" onSubmit={(e) => e.preventDefault()}>
<div className="wrap">
<fieldset className="">
<textarea
className=""
rows={4}
placeholder="Comment*"
tabIndex={2}
aria-required="true"
required
defaultValue={""}
/>
</fieldset>
<div className="tf-grid-layout md-col-3">
<fieldset className="">
<input
className=""
type="text"
placeholder="Name*"
name="text"
tabIndex={2}
defaultValue=""
aria-required="true"
required
/>
</fieldset>
<fieldset className="">
<input
className=""
type="email"
placeholder="Email*"
name="email"
tabIndex={2}
defaultValue=""
aria-required="true"
required
/>
</fieldset>
<fieldset className="">
<input
className=""
type="text"
placeholder="Website*"
name="website"
tabIndex={2}
defaultValue=""
aria-required="true"
required
/>
</fieldset>
</div>
</div>
<div className="button-submit mt_32">
<button className="tf-btn btn-primary2" type="submit">
<span> Post Comment</span>
<span className="bg-effect" />
</button>
</div>
</form>
);
}

View File

@ -0,0 +1,137 @@
"use client";
import Slider from "rc-slider";
const brands = ["apple", "samsung", "xiaomi", "nokia", "sony", "oppo"];
export default function FilteringOptions({ allProps }) {
return (
<>
{" "}
<form className="form-search mb_30" onSubmit={(e) => e.preventDefault()}>
<fieldset className="text">
<input
type="text"
placeholder="Search..."
className="rounded-cycle"
name="search"
tabIndex={0}
defaultValue=""
aria-required="true"
required
/>
</fieldset>
<button className="" type="submit">
<svg
width={20}
height={20}
viewBox="0 0 20 20"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M11.875 1.875C8.43018 1.875 5.625 4.68018 5.625 8.125C5.625 9.62158 6.1499 10.9937 7.03125 12.0703L2.05078 17.0508L2.94922 17.9492L7.92969 12.9688C9.00635 13.8501 10.3784 14.375 11.875 14.375C15.3198 14.375 18.125 11.5698 18.125 8.125C18.125 4.68018 15.3198 1.875 11.875 1.875ZM11.875 3.125C14.6436 3.125 16.875 5.35645 16.875 8.125C16.875 10.8936 14.6436 13.125 11.875 13.125C9.10645 13.125 6.875 10.8936 6.875 8.125C6.875 5.35645 9.10645 3.125 11.875 3.125Z"
fill="#5F697C"
/>
</svg>
</button>
</form>
<div className="categories">
<h6 className="title mb_26">Categories</h6>
<ul className="list d-grid gap_9">
<li className="active">
<a href="#" className="link text-body-1">
Phone, Tablet
</a>
</li>
<li>
<a href="#" className="link text-body-1">
Sound
</a>
</li>
<li>
<a href="#" className="link text-body-1">
Clock, Camera
</a>
</li>
<li>
<a href="#" className="link text-body-1">
Household appliances
</a>
</li>
<li>
<a href="#" className="link text-body-1">
Accessory
</a>
</li>
</ul>
</div>
<div className="filter mb_42">
<div className="heading d-flex align-items-center justify-content-between mb_50">
<h6 className="">Fillters</h6>
<a
href="#"
onClick={(e) => {
e.preventDefault();
allProps.clearFilter();
}}
className="btn-reset text_mono-gray-7 d-flex align-items-center fw-5 gap_4"
>
<i className="icon-sync-alt-solid" />
Reset all
</a>
</div>
<div className="brand wg-filter">
<div className="box-fieldset-item">
{brands.map((brand, index) => (
<fieldset
onClick={() => allProps.setBrands(brand)}
className="fieldset-item"
key={brand}
>
<input
checked={allProps.brands.includes(brand)}
type="checkbox"
name="brand"
readOnly
className="tf-check"
/>
<label className="text_mono-gray text-body-1">
{brand.charAt(0).toUpperCase() + brand.slice(1)}
</label>
</fieldset>
))}
</div>
</div>
</div>
<div className="wrap-range">
<div id="range-price-1" className="range-price">
<h6 className="title text_mono-gray mb_55">Price Range</h6>
<div className="box-price-product mb_33">
<div className="box-price-item min">
<div className="price-val" id="price-min-value" data-currency="$">
{allProps.price[0]}
</div>
</div>
<div className="box-price-item max">
<div className="price-val" id="price-max-value" data-currency="$">
{allProps.price[1]}
</div>
</div>
<a href="#" className="btn-go">
{" "}
Go{" "}
</a>
</div>
<div className="price-val-range" id="price-value-range">
<Slider
value={allProps.price}
onChange={(price) => allProps.setPrice(price)}
range
min={0}
max={700}
/>
</div>
</div>
</div>
</>
);
}

View File

@ -0,0 +1,115 @@
"use client";
import { products } from "@/data/products";
import React from "react";
import { Swiper, SwiperSlide } from "swiper/react";
import Link from "next/link";
import Image from "next/image";
import { Pagination } from "swiper/modules";
import { useContextElement } from "@/context/Context";
export default function RelatedProducts() {
const { addProductToCart, isAddedToCartProducts } = useContextElement();
return (
<div className="section-related tf-spacing-38">
<div className="tf-container">
<div className="heading-section mb_32 d-flex justify-content-between mb_104">
<h3 className="">Related products</h3>
<Link href={`/shop`} className="tf-btn btn-primary2">
<span>See All</span>
<span className="bg-effect" />
</Link>
</div>
<Swiper
className="swiper sw-layout"
breakpoints={{
0: { slidesPerView: 2 },
575: {
slidesPerView: 2,
},
768: {
slidesPerView: 2,
spaceBetween: 20,
},
992: {
slidesPerView: 4,
spaceBetween: 24,
},
}}
spaceBetween={15}
modules={[Pagination]}
pagination={{
clickable: true,
el: ".spd13",
}}
>
{products.map((product, i) => (
<SwiperSlide key={i} className="swiper-slide">
<div className="product-item hover-image">
<Link
href={`/product-details/${product.id}`}
className="img-style"
>
<Image
className="lazyload"
alt="item"
src={product.imgSrc}
width={product.width}
height={product.height}
/>
</Link>
<div className="content">
<div className="info">
<div className="text-body-1 product-name mb_8">
<Link
href={`/product-details/${product.id}`}
className="link"
>
{product.title}
</Link>
</div>
<h6 className="price d-flex gap_10">
{product.oldPrice ? (
<>
<span className="new-price">
$
{product.price.toFixed(
product.price % 1 === 0 ? 0 : 2
)}
</span>
<span className="old-price sub-heading">
$
{product.oldPrice.toFixed(
product.oldPrice % 1 === 0 ? 0 : 2
)}
</span>
</>
) : (
`$${product.price.toFixed(
product.price % 1 === 0 ? 0 : 2
)}`
)}
</h6>
</div>
<a
href="#"
onClick={(e) => {
e.preventDefault();
addProductToCart(product.id);
}}
className={`add-cart ${
isAddedToCartProducts(product.id) ? "cart-added" : ""
}`}
>
<i className="icon-shopping-cart-solid" />
</a>
</div>
</div>
</SwiperSlide>
))}
<div className="sw-dots sw-pagination-layout d-flex justify-content-center mt_22 spd13" />
</Swiper>
</div>
</div>
);
}

472
components/shop/Shop.jsx Normal file
View File

@ -0,0 +1,472 @@
"use client";
import { products } from "@/data/products";
import React, { useEffect, useReducer } from "react";
import Image from "next/image";
import FilteringOptions from "./FilteringOptions";
import Link from "next/link";
import { initialState, reducer } from "@/reducer/FilterReducer";
import { useContextElement } from "@/context/Context";
export default function Shop() {
const { addProductToCart, isAddedToCartProducts } = useContextElement();
const [state, dispatch] = useReducer(reducer, initialState);
const {
price,
brands,
filtered,
sortingOption,
sorted,
currentPage,
itemPerPage,
} = state;
const allProps = {
...state,
setPrice: (value) => dispatch({ type: "SET_PRICE", payload: value }),
setBrands: (newBrand) => {
let newBrands = [...brands];
if (newBrands.includes(newBrand)) {
newBrands = newBrands.filter((brand) => brand != newBrand);
} else {
newBrands = [...newBrands, newBrand];
}
console.log(newBrands);
dispatch({ type: "SET_BRANDS", payload: newBrands });
},
setSortingOption: (value) =>
dispatch({ type: "SET_SORTING_OPTION", payload: value }),
setCurrentPage: (value) =>
dispatch({ type: "SET_CURRENT_PAGE", payload: value }),
setItemPerPage: (value) => {
dispatch({ type: "SET_CURRENT_PAGE", payload: 1 }),
dispatch({ type: "SET_ITEM_PER_PAGE", payload: value });
},
clearFilter: () => {
dispatch({ type: "CLEAR_FILTER" });
},
};
useEffect(() => {
let filteredArrays = [];
if (brands.length) {
const filteredByBrands = [...products].filter((elm) =>
brands.every((brand) => elm.filterBrands.includes(brand))
);
filteredArrays = [...filteredArrays, filteredByBrands];
}
const filteredByPrice = [...products].filter(
(elm) => elm.price >= price[0] && elm.price <= price[1]
);
filteredArrays = [...filteredArrays, filteredByPrice];
const commonItems = [...products].filter((item) =>
filteredArrays.every((array) => array.includes(item))
);
dispatch({ type: "SET_FILTERED", payload: commonItems });
}, [price, brands]);
useEffect(() => {
if (sortingOption === "Price Ascending") {
dispatch({
type: "SET_SORTED",
payload: [...filtered].sort((a, b) => a.price - b.price),
});
} else if (sortingOption === "Price Descending") {
dispatch({
type: "SET_SORTED",
payload: [...filtered].sort((a, b) => b.price - a.price),
});
} else if (sortingOption === "Title Ascending") {
dispatch({
type: "SET_SORTED",
payload: [...filtered].sort((a, b) => a.title.localeCompare(b.title)),
});
} else if (sortingOption === "Title Descending") {
dispatch({
type: "SET_SORTED",
payload: [...filtered].sort((a, b) => b.title.localeCompare(a.title)),
});
} else {
dispatch({ type: "SET_SORTED", payload: filtered });
}
dispatch({ type: "SET_CURRENT_PAGE", payload: 1 });
}, [filtered, sortingOption]);
return (
<div className="tf-spacing-41">
<div className="tf-container">
<div className="wrap-shop">
<div className="row">
<div className="col-xl-8">
<div className="left">
<div className="top mb_92">
<div className="text_mono-gray-8 text-body-1 result-count">
Showing 16 of 8 results
</div>
<div className="wrap d-flex">
<div className="wrap-sort">
<div className="text_mono-gray-8 text-body-1">
Sort by
</div>
<div
className="tf-dropdown-sort"
role="button"
data-bs-toggle="dropdown"
aria-expanded="false"
>
<div className="btn-select">
<span className="text-body-3 text-sort-value">
{sortingOption}
</span>
<span className="icon icon-angle-down-solid" />
</div>
<div className="dropdown-menu">
{[
"Sort by (Default)",
"Title Ascending",
"Title Descending",
"Price Ascending",
"Price Descending",
].map((elm, i) => (
<div
key={i}
className={`select-item ${
sortingOption == elm ? "active" : ""
}`}
onClick={() => allProps.setSortingOption(elm)}
data-sort-value="best-selling"
>
<span className="text-body-3 text-value-item">
{elm}
</span>
</div>
))}
</div>
</div>
</div>
<div className="wrap-layout">
<ul
className="nav-tab-filter group-layout"
role="tablist"
>
<li className="nav-tab-item" role="presentation">
<a
href="#gridLayout"
className="btn-layout grid nav-link-item active"
data-bs-toggle="tab"
>
<svg
width={22}
height={22}
viewBox="0 0 22 22"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M0.611328 7.94444H21.3891M21.3891 14.6667H0.611328"
stroke="black"
/>
<rect
x="0.5"
y="0.5"
width={21}
height={21}
stroke="black"
/>
<path d="M7.33398 0V20.7778" stroke="black" />
<path d="M14.666 0V20.7778" stroke="black" />
</svg>
</a>
</li>
<li className="nav-tab-item" role="presentation">
<a
href="#listLayout"
className="nav-link-item btn-layout list"
data-bs-toggle="tab"
>
<svg
width={22}
height={22}
viewBox="0 0 22 22"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M4.88867 4.8889H21.3887"
stroke="black"
/>
<circle
cx="1.22222"
cy="4.88889"
r="0.722222"
fill="#D9D9D9"
stroke="black"
/>
<path d="M4.88867 11H21.3887" stroke="black" />
<path
d="M1.94444 11C1.94444 11.3989 1.62109 11.7222 1.22222 11.7222C0.82335 11.7222 0.5 11.3989 0.5 11C0.5 10.6011 0.82335 10.2778 1.22222 10.2778C1.62109 10.2778 1.94444 10.6011 1.94444 11Z"
fill="#D9D9D9"
stroke="black"
/>
<path
d="M4.88867 17.1111H21.3887"
stroke="black"
/>
<path
d="M1.94444 17.1111C1.94444 17.51 1.62109 17.8333 1.22222 17.8333C0.82335 17.8333 0.5 17.51 0.5 17.1111C0.5 16.7122 0.82335 16.3889 1.22222 16.3889C1.62109 16.3889 1.94444 16.7122 1.94444 17.1111Z"
fill="#D9D9D9"
stroke="black"
/>
</svg>
</a>
</li>
</ul>
</div>
</div>
</div>
<div className="flat-animate-tab">
<div className="tab-content">
<div
className="tab-pane active show"
id="gridLayout"
role="tabpanel"
>
<div className="tf-grid-layout-2 md-col-3">
{sorted.map((product) => (
<div
className="product-item hover-image"
key={product.id}
>
<Link
href={`/product-details/${product.id}`}
className="img-style"
>
<Image
className="lazyload"
data-src={product.imgSrc}
alt="item"
src={product.imgSrc}
width={product.width}
height={product.height}
/>
</Link>
<div className="content">
<div className="info">
<div className="text-body-1 product-name mb_8">
<Link
href={`/product-details/${product.id}`}
className="link"
>
{product.title}
</Link>
</div>
<div className="h6 price d-flex gap_10">
{product.oldPrice ? (
<>
<span className="new-price">
$
{product.price.toFixed(
product.price % 1 === 0 ? 0 : 2
)}
</span>
<span className="old-price sub-heading">
$
{product.oldPrice.toFixed(
product.oldPrice % 1 === 0 ? 0 : 2
)}
</span>
</>
) : (
`$${product.price.toFixed(
product.price % 1 === 0 ? 0 : 2
)}`
)}
</div>
</div>
<a
href="#"
onClick={(e) => {
e.preventDefault();
addProductToCart(product.id);
}}
className={`add-cart ${
isAddedToCartProducts(product.id)
? "cart-added"
: ""
}`}
>
<i className="icon-shopping-cart-solid" />
</a>
</div>
</div>
))}
</div>
<ul className="wg-pagination d-flex justify-content-center gap_12 mt_58">
<li>
<a href="#">
<i className="icon-angle-left-solid" />
</a>
</li>
<li>
<a href="#" className="active">
1
</a>
</li>
<li>
<a href="#">...</a>
</li>
<li>
<a href="#">4</a>
</li>
<li>
<a href="#">
<i className="icon-angle-right-solid" />
</a>
</li>
</ul>
</div>
<div className="tab-pane" id="listLayout" role="tabpanel">
<div className="wrap-list d-flex gap-16 flex-direction-column">
{sorted.map((product, i) => (
<div
key={i}
className="product-item hover-image style-list"
>
<Link
href={`/product-details/${product.id}`}
className="img-style"
>
<Image
className="lazyload"
alt="item"
src={product.imgSrc}
width={product.width}
height={product.height}
/>
</Link>
<div className="content">
<div className="info">
<div className="text-body-1 product-name mb_8">
<Link
href={`/product-details/${product.id}`}
className="link"
>
{product.title}
</Link>
</div>
<div className="h6 price d-flex gap_10">
{product.oldPrice ? (
<>
<span className="new-price">
$
{product.price.toFixed(
product.price % 1 === 0 ? 0 : 2
)}
</span>
<span className="old-price sub-heading">
$
{product.oldPrice.toFixed(
product.oldPrice % 1 === 0 ? 0 : 2
)}
</span>
</>
) : (
`$${product.price.toFixed(
product.price % 1 === 0 ? 0 : 2
)}`
)}
</div>
</div>
<div className="list-product-btn">
<a
onClick={(e) => {
e.preventDefault();
addProductToCart(product.id);
}}
className="add-cart"
href="#"
>
{isAddedToCartProducts(product.id)
? "Already Added"
: "Add to Cart"}
</a>
<a
href="#"
className="box-icon wishlist btn-icon-action"
>
<span className="icon icon-heart" />
<span className="tooltip">Wishlist</span>
</a>
<a
href="#"
className="box-icon quickview tf-btn-loading"
>
<span className="icon icon-eye" />
<span className="tooltip">Quick View</span>
</a>
</div>
</div>
</div>
))}
</div>
<ul className="wg-pagination d-flex justify-content-center gap_12 mt_58">
<li>
<a href="#">
<i className="icon-angle-left-solid" />
</a>
</li>
<li>
<a href="#" className="active">
1
</a>
</li>
<li>
<a href="#">...</a>
</li>
<li>
<a href="#">4</a>
</li>
<li>
<a href="#">
<i className="icon-angle-right-solid" />
</a>
</li>
</ul>
</div>
</div>
</div>
</div>
</div>
<div className="col-xl-4">
<div className="right">
<div className="sildebar-fiiler canvas-filter">
<div className="canvas-wrapper">
<div className="canvas-header d-flex d-xl-none">
<h5 className="">
<span className="icon icon-filter" />
Filters
</h5>
<div className="close-filter">
<span className="icon-times-solid" />
</div>
</div>
<div className="canvas-body">
<FilteringOptions allProps={allProps} />
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
);
}

View File

@ -0,0 +1,173 @@
"use client";
import React from "react";
import Link from "next/link";
import Image from "next/image";
import { useContextElement } from "@/context/Context";
import DropdownSelect from "../common/DropdownSelect";
export default function ShopCart() {
const {
cartProducts,
setCartProducts,
totalPrice,
updateQuantity,
} = useContextElement();
const removeItem = (id) => {
setCartProducts((pre) => [...pre.filter((elm) => elm.id != id)]);
};
return (
<div className="cart-product tf-spacing-39">
<div className="tf-container">
<div className="row">
<div className="col-md-8">
<div className="left">
<h2 className="title">Products</h2>
<div className="tf-product-cart-wrap tf-cart-item">
{cartProducts.length ? (
<>
{cartProducts.map((product, i) => (
<div key={i} className="tf-cart-item_product file-delete">
<div className="product-item style-cart hover-image">
<fieldset className="fieldset-item">
<input
type="checkbox"
name="brand"
className="tf-check"
/>
</fieldset>
<Link
href={`/product-details/${product.id}`}
className="img-style"
>
<Image
className="lazyload"
alt="item"
src={product.imgSrc}
width={263}
height={220}
/>
</Link>
<div className="content">
<div className="info">
<div className="h5 product-name line-clamp-2 mb_16">
<Link
href={`/product-details/${product.id}`}
className="link"
>
{product.title}
</Link>
</div>
<div className="price d-flex gap_10 mb_33">
<span className="new-price h5">
${product.price.toFixed(2)}
</span>
{product.oldPrice && (
<span className="old-price h6">
${product.oldPrice.toFixed(2)}
</span>
)}
</div>
<div className="tf-product-info-quantity">
<div className="wg-quantity">
<span
className="btn-quantity btn-decrease"
onClick={() =>
updateQuantity(
product.id,
product.quantity - 1
)
}
>
-
</span>
<input
className="quantity-product"
type="text"
name="number"
readOnly
value={product.quantity}
/>
<span
className="btn-quantity btn-increase"
onClick={() =>
updateQuantity(
product.id,
product.quantity + 1
)
}
>
+
</span>
</div>
</div>
</div>
</div>
</div>
<div
onClick={() => removeItem(product.id)}
className="remove-cart"
>
<span className="remove icon-times-solid" />
</div>
</div>
))}
</>
) : (
<div className="">
<div className="col-4">
Your Cart is empty. Start adding favorite products to
cart!{" "}
</div>
<Link
className="tf-btn mt-4 mb-3 text-white"
style={{ width: "fit-content" }}
href="/shop"
>
Explore Products
</Link>
</div>
)}
</div>
</div>
</div>
<div className="col-md-4">
<div className="cart-totals">
<h2 className="title">Cart totals</h2>
{cartProducts.map((product, i) => (
<div key={i} className="info sub-heading d-flex">
<div className="name">{product.title}</div>
<span>x{product.quantity}</span>{" "}
<div className="price sub-heading">
${(product.price * product.quantity).toFixed(2)}
</div>
</div>
))}
<DropdownSelect
defaultOption={"Add a coupon"}
options={["coupon 10%", "coupon 20%"]}
addtionalParentClass="h6 text_black px-0"
/>
<div className="sub-total d-flex justify-content-between align-items-center h6">
<span>Subtotal</span>
<span>${totalPrice.toFixed(2)}</span>
</div>
<div className="total h4 d-flex justify-content-between align-items-center">
<span>Total</span>
<span>${totalPrice.toFixed(2)}</span>
</div>
<Link
href={`/checkout`}
className="tf-btn w-full btn-primary2 height-3"
>
<span className="text-body-1">Check Out</span>
<span className="bg-effect" />
</Link>
</div>
</div>
</div>
</div>
</div>
);
}

View File

@ -0,0 +1,299 @@
"use client";
import Image from "next/image";
import CommentBox from "./CommentBox";
import { useState } from "react";
export default function ShopDescription() {
const [activeTab, setActiveTab] = useState(1);
return (
<div className="tf-container">
<div className="widget-tabs style-1">
<ul className="widget-menu-tab overflow-x-auto">
<li
className={`item-title h5 ${activeTab == 1 ? "active" : ""}`}
onClick={() => setActiveTab(1)}
>
<span className="text-whitespace">Description</span>
</li>
<li
className={`item-title h5 ${activeTab == 2 ? "active" : ""}`}
onClick={() => setActiveTab(2)}
>
<span className="text-whitespace">Reviews (3)</span>
</li>
<li
className={`item-title h5 ${activeTab == 3 ? "active" : ""}`}
onClick={() => setActiveTab(3)}
>
<span className="text-whitespace">Additinal Information</span>
</li>
</ul>
<div className="widget-content-tab">
<div
className={`widget-content-inner ${
activeTab == 1 ? "active" : ""
} `}
>
<div className="tab-description d-grid gap_29">
<p className="text-body-1 text_mono-gray-8">
The 24-inch iMac M3 2023 has an impressively slim design.
Despite being slim, the iMac is also equipped with a diverse
connection port system such as Thunderbolt. In terms of color,
the 24-inch iMac M3 2023 impresses with seven different color
versions for users to choose from: Blue, Green, Pink, Silver,
Yellow, Orange and Purple.
</p>
<p className="text-body-1 text_mono-gray-8">
The iMac M3 2023 is equipped with a 24-inch screen with thin
screen borders for a wide display space. The screen is equipped
with an impressive high resolution of upto 4.5K and a brightness
of 500 nits for super sharp display. The device screen is also
equipped with a wide color gamut P3, so the details displayed on
the screen are extremely vivid
</p>
<p className="text-body-1 text_mono-gray-8">
The 24-inch iMac M3 2023 is equipped with the best camera system
compared to previous generations of iMac introduced by Apple.
Along with that is an integrated image processor, a processor
with the ability to analyze and improve pixels at 1 trillion
calculations per second. Thanks to that, the 24-inch iMac M3
2023 brings impressive video recording capabilities. In addition
to the sharp camera, the 24-inch iMac M3 2023 is also equipped
with a microphone that supports effective sound recording.
Thanks to that, users can record podcasts or livestreams without
the need for supporting equipment. In particular, the microphone
on the device is also designed with echo reduction and
beamforming technology to effectively reduce ambient noise
</p>
</div>
</div>
<div
className={`widget-content-inner ${
activeTab == 2 ? "active" : ""
} `}
>
<div className="tab-reviews write-cancel-review-wrap">
<div className="tab-reviews-heading">
<div className="top">
<div className="text-center">
<div className="number text-display">4.9</div>
<div className="ratings justify-content-center">
<i className="icon icon-star-solid" />
<i className="icon icon-star-solid" />
<i className="icon icon-star-solid" />
<i className="icon icon-star-solid" />
<i className="icon icon-star-solid" />
</div>
<p className="text_mono-gray-8">(168 Ratings)</p>
</div>
<div className="rating-score">
<div className="item">
<div className="number-1 text-body-2 text_mono-gray">
5
</div>
<i className="icon icon-star-solid" />
<div className="line-bg">
<div style={{ width: "94.67%" }} />
</div>
<div className="number-2 text-body-2 text_mono-gray">
59
</div>
</div>
<div className="item">
<div className="number-1 text-body-2 text_mono-gray">
4
</div>
<i className="icon icon-star-solid" />
<div className="line-bg">
<div style={{ width: "60%" }} />
</div>
<div className="number-2 text-body-2 text_mono-gray">
46
</div>
</div>
<div className="item">
<div className="number-1 text-body-2 text_mono-gray">
3
</div>
<i className="icon icon-star-solid" />
<div className="line-bg">
<div style={{ width: "0%" }} />
</div>
<div className="number-2 text-body-2 text_mono-gray">
0
</div>
</div>
<div className="item">
<div className="number-1 text-body-2 text_mono-gray">
2
</div>
<i className="icon icon-star-solid" />
<div className="line-bg">
<div style={{ width: "0%" }} />
</div>
<div className="number-2 text-body-2 text_mono-gray">
0
</div>
</div>
<div className="item">
<div className="number-1 text-body-2 text_mono-gray">
1
</div>
<i className="icon icon-star-solid" />
<div className="line-bg">
<div style={{ width: "0%" }} />
</div>
<div className="number-2 text-body-2 text_mono-gray">
0
</div>
</div>
</div>
</div>
</div>
<div className="reply-comment style-2">
<div className="reply-comment-heading mb_82">
<h2>3 Comments</h2>
</div>
<div className="wrap-comment">
<div className="reply-comment-wrap">
<div className="reply-comment-item">
<div className="heading mb_15">
<div className="box-user">
<div className="avatar">
<Image
alt="avatar"
src="/images/avatar/avatar-2.jpg"
width={119}
height={119}
/>
</div>
<div className="content">
<h5>Kobbie Dao</h5>
<p className="text-body-1 text_mono-gray-5">
September 30, 2023 / 9:30 AM
</p>
</div>
</div>
<a href="#" className="tf-btn btn-primary2">
<span>Reply</span>
<span className="bg-effect" />
</a>
</div>
<div className="comment text-body-1 text_black">
As a web designer myself, I couldn't agree more with the
sentiment that great design should be felt and
remembered long after the screen is turned off.
</div>
</div>
<div className="reply-comment-item type-reply">
<div className="heading mb_35">
<div className="box-user">
<div className="avatar">
<Image
alt="avatar"
src="/images/avatar/avatar-3.jpg"
width={119}
height={119}
/>
</div>
<div className="content">
<h5 className="text_black">Zalatan</h5>
<p className="text-body-1 text_mono-gray-5">
September 30, 2023 / 9:30 AM
</p>
</div>
</div>
<a href="#" className="tf-btn btn-primary2">
<span>Reply</span>
<span className="bg-effect" />
</a>
</div>
<div className="comment text-body-1 text_black">
Aute mi ut suspendisse velit leo, vel risus ac. Amet dui
dignissim fermentum malesuada auctor volutpat,
vestibulum ipsum nulla.
</div>
</div>
</div>
<div className="reply-comment-wrap">
<div className="reply-comment-item">
<div className="heading mb_15">
<div className="box-user">
<div className="avatar">
<Image
alt="avatar"
src="/images/avatar/avatar-4.jpg"
width={119}
height={119}
/>
</div>
<div className="content">
<h5 className="text_black">Bellingham</h5>
<p className="text-body-1 text_mono-gray-5">
September 30, 2023 / 9:30 AM
</p>
</div>
</div>
<a href="#" className="tf-btn btn-primary2">
<span>Reply</span>
<span className="bg-effect" />
</a>
</div>
<div className="comment text-body-1 text_black">
Aute mi ut suspendisse velit leo, vel risus ac. Amet dui
dignissim fermentum malesuada auctor volutpat,
vestibulum ipsum nulla.
</div>
</div>
</div>
</div>
<div className="leave-comment">
<div className="heading-title mb_56">
<h2 className="mb_18">Leave a Reply</h2>
<p className="text-body-1 text_mono-gray letter-spacing-1">
Your email address will not be published. Require field
are marked <span>*</span>
</p>
</div>
<CommentBox />
</div>
</div>
</div>
</div>
<div
className={`widget-content-inner ${
activeTab == 3 ? "active" : ""
} `}
>
<div className="tab-description d-grid gap_12">
<p className="text-body-1 text_mono-gray-8">
With the 2024 version, the Macbook Air is upgraded to a
15.3-inch screen with Liquid Retina resolution (2880 x 1864)
that reproduces detailed image quality, millions of pixels and a
wide spectrum P3 color range of up to 1 billion colors. Allows
you to perfectly perform graphic design tasks with strict color
requirements.
</p>
<p className="text-body-1 text_mono-gray-8">
500 nits brightness with True Tone Technology regulates vision
and vision extremely well, quickly adapting to ambient light
conditions to display the sharpest content from text to video.
</p>
<p className="text-body-1 text_mono-gray-8">
MacBook Air 15 inch M3 2024 8-core CPU - Screen
</p>
<p className="text-body-1 text_mono-gray-8">
Multi-dimensional surround sound system Dolby Atmos, Spatial
Audio combined with a high-quality linear speaker system brings
a complete and realistic entertainment experience with vivid
sound quality, clear bass, and sound amplification. Loud allows
you to immerse yourself in melodious music or vivid movies,
detailed sound is also extremely beneficial when participating
in video post-production editing and sound effects.
</p>
</div>
</div>
</div>
</div>
</div>
);
}

View File

@ -0,0 +1,371 @@
"use client";
import React, { useEffect, useRef, useState } from "react";
import Image from "next/image";
import Drift from "drift-zoom";
import PhotoSwipeLightbox from "photoswipe/lightbox";
import { Swiper, SwiperSlide } from "swiper/react";
import { FreeMode, Thumbs } from "swiper/modules";
import { useContextElement } from "@/context/Context";
const colorOptions = [
{
id: "blue-sapphire",
label: "Blue Sapphire",
price: null,
defaultChecked: false,
},
{
id: "seafoam-green",
label: "Seafoam Green",
price: "79.99",
defaultChecked: true,
},
{
id: "dusty-rose",
label: "Dusty Rose",
price: "89.99",
defaultChecked: false,
},
{
id: "light-gray",
label: "Light Gray",
price: "59.99",
defaultChecked: false,
},
];
export default function ShopDetails({ product }) {
const { addProductToCart, isAddedToCartProducts } = useContextElement();
const [value, setValue] = useState(1);
const slides = [
{
color: "blue-sapphire",
image: product.imgSrc,
},
{
color: "dusty-rose",
image: "/images/shop/thumbs-main-2.jpg",
},
{
color: "light-gray",
image: "/images/shop/thumbs-main-3.jpg",
},
{
color: "seafoam-green",
image: "/images/shop/thumbs-main-4.jpg",
},
];
const [activeColor, setActiveColor] = useState(
colorOptions.find((opt) => opt.defaultChecked)?.id || ""
);
const [swiperThumb, setSwiperThumb] = useState(null);
const lightboxRef = useRef(null);
useEffect(() => {
// Initialize PhotoSwipeLightbox
const lightbox = new PhotoSwipeLightbox({
gallery: "#gallery-swiper-started",
children: ".item",
pswpModule: () => import("photoswipe"),
});
lightbox.init();
// Store the lightbox instance in the ref for later use
lightboxRef.current = lightbox;
// Cleanup: destroy the lightbox when the component unmounts
return () => {
lightbox.destroy();
};
}, []);
useEffect(() => {
// Function to initialize Drift
// Function to check window width
const checkWindowSize = () => window.innerWidth >= 1200;
// Only proceed if window is wide enough
if (!checkWindowSize()) return;
const imageZoom = () => {
const driftAll = document.querySelectorAll(".tf-image-zoom");
const pane = document.querySelector(".tf-zoom-main");
driftAll.forEach((el) => {
new Drift(el, {
zoomFactor: 2,
paneContainer: pane,
inlinePane: false,
handleTouch: false,
hoverBoundingBox: true,
containInline: true,
});
});
};
imageZoom();
const zoomElements = document.querySelectorAll(".tf-image-zoom");
const handleMouseOver = (event) => {
const parent = event.target.closest(".section-image-zoom");
if (parent) {
parent.classList.add("zoom-active");
}
};
const handleMouseLeave = (event) => {
const parent = event.target.closest(".section-image-zoom");
if (parent) {
parent.classList.remove("zoom-active");
}
};
zoomElements.forEach((element) => {
element.addEventListener("mouseover", handleMouseOver);
element.addEventListener("mouseleave", handleMouseLeave);
});
// Cleanup event listeners on component unmount
return () => {
zoomElements.forEach((element) => {
element.removeEventListener("mouseover", handleMouseOver);
element.removeEventListener("mouseleave", handleMouseLeave);
});
};
}, []); // Empty dependency array to run only once on mount
return (
<div className="tf-spacing-1">
<div className="tf-container">
<div className="shop-details">
<div className="row">
<div className="col-lg-6">
<div className="left">
<div className="tf-product-media-wrap">
<div className="thumbs-slider">
<Swiper
dir="ltr"
className="swiper tf-product-media-main mb_20"
id="gallery-swiper-started"
modules={[Thumbs]}
thumbs={{ swiper: swiperThumb }}
>
{slides.map((slide, index) => (
<SwiperSlide
key={index}
className="swiper-slide"
data-color={slide.color}
>
<a
href={slide.image}
target="_blank"
className="item"
data-pswp-width="400px"
data-pswp-height="400px"
>
<Image
className="tf-image-zoom lazyload"
data-zoom={slide.image}
data-src={slide.image}
alt=""
src={slide.image}
width={836}
height={718}
/>
</a>
</SwiperSlide>
))}
</Swiper>
<Swiper
dir="ltr"
modules={[Thumbs, FreeMode]}
onSwiper={setSwiperThumb}
className="swiper tf-product-media-thumbs other-image-zoom"
{...{
spaceBetween: 24,
slidesPerView: "auto",
freeMode: true,
watchSlidesProgress: true,
observer: true,
observeParents: true,
}}
>
{slides.map((elm, i) => (
<SwiperSlide
key={i}
className="swiper-slide stagger-item"
>
<div className="item">
<Image
className="lazyload"
alt=""
src={elm.image}
width={191}
height={160}
/>
</div>
</SwiperSlide>
))}
</Swiper>
</div>
</div>
</div>
</div>
<div className="col-lg-6">
<div className="right">
<div className="tf-product-info-wrap position-relative">
<div className="tf-zoom-main" />
<div className="tf-product-info-list other-image-zoom">
<div className="tf-product-info-heading">
<div className="tf-product-info-name mb_24">
<h3 className="name mb_11">{product.title}</h3>
<div className="sub">
<div className="tf-product-info-rate">
<div className="ratings d-flex gap_8">
<i className="icon-star-solid" />
<i className="icon-star-solid" />
<i className="icon-star-solid" />
<i className="icon-star-half-alt-solid" />
<i className="icon-star1" />
</div>
<div className="text text-body-2 text_color-text-2 fw-5">
3 Review
</div>
</div>
</div>
</div>
<div className="tf-product-info-desc mb_12">
<div className="tf-product-info-price">
<h2 className="price-on-sale">
${product.price.toFixed(2)}
</h2>
{product.oldPrice && (
<h3 className="compare-at-price text_mono-gray-5">
${product.oldPrice.toFixed(2)}
</h3>
)}
</div>
</div>
</div>
<div className="tf-product-info-choose-option gap-19">
<div className="variant-picker-item mb_58">
<div className="variant-picker-label text-body-2 text_color-text-2 mb_6">
Select Color
</div>
<div className="variant-picker-values">
{colorOptions.map((color) => {
const inputId = `values-${color.id}`;
const isActive = activeColor === color.id;
return (
<React.Fragment key={color.id}>
<input
id={inputId}
type="radio"
name="color1"
checked={isActive}
onChange={() => setActiveColor(color.id)}
/>
<label
className={`hover-tooltip tooltip-bot radius-60 color-btn ${
isActive ? "active" : ""
}`}
htmlFor={inputId}
data-value={color.id}
data-color={color.id}
{...(color.price
? { "data-price": color.price }
: {})}
>
<span
className={`btn-checkbox bg-color-${color.id}`}
/>
<span className="tooltip">{color.label}</span>
</label>
</React.Fragment>
);
})}
</div>
</div>
<ul className="list mb_57">
<li className="text-body-2">
Condition: Machine Body. + 143W Power Supply
</li>
<li className="text-body-2">
Display : 24" 4.5K (4480x2520) , 500 nits , wide color
P3
</li>
<li className="text-body-2">
CPU: Apple M3 8-Core CPU 4.0Ghz
</li>
<li className="text-body-2">
GPU: 8-Core GPU ,16-Core Neural Engine
</li>
<li className="text-body-2">
RAM: 8GB of onboard " Unified "
</li>
<li className="text-body-2">Storage: 256GB PCIe</li>
<li className="text-body-2">
Connect : x2 Thunderbolt 3 | USB 4 ports , Jack 3.5,
Weight : 4,43kg
</li>
<li className="text-body-2">
Accessory : Mouse,Keyboard, Power Adapter, Cable C to
lightning.
</li>
</ul>
<div className="d-flex tf-product-wrap-btn gap_12 mb_23">
<div className="tf-product-info-quantity d-flex align-items-center">
<div className="title text-body-2 text_mono-gray-8">
QTY
</div>
<div className="wg-quantity">
<span
onClick={() =>
setValue((pre) => (pre == 1 ? 1 : pre - 1))
}
className="btn-quantity btn-decrease"
>
-
</span>
<input
className="quantity-product"
type="text"
name="number"
readOnly
value={value}
/>
<span
onClick={() => setValue((pre) => pre + 1)}
className="btn-quantity btn-increase"
>
+
</span>
</div>
</div>
<div className="tf-product-info-by-btn d-flex align-items-center w-full">
<a
href="#"
onClick={(e) => {
e.preventDefault();
addProductToCart(product.id, value);
}}
className="tf-btn w-full show-shopping-cart"
>
<span className="text-body-2 fw-4">
{isAddedToCartProducts(product.id)
? "Already Added"
: "Add To Cart"}
</span>
<span className="bg-effect" />
</a>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
);
}