update product details

This commit is contained in:
Rami Bitar
2026-06-03 13:41:04 -04:00
parent 4aa55c2b89
commit 3cc7ec376c
42 changed files with 1965 additions and 972 deletions

View File

@@ -1,5 +1,5 @@
import React from 'react';
import { Link } from 'react-router';
import Link from 'next/link';
import { Card, CardContent } from '@/components/ui/card';
import { Typography } from '@/components/Typography';
@@ -22,7 +22,7 @@ interface CollectionCardProps {
const CollectionCard: React.FC<CollectionCardProps> = ({ collection }) => {
return (
<Link to={`/collections/${collection.handle}`} className="block group">
<Link href={`/collections/${collection.handle}`} className="block group">
<Card className="hover:shadow-xl transition-shadow duration-300 overflow-hidden py-0 gap-0">
{/* Collection Image */}
<div className="aspect-video overflow-hidden bg-muted">

View File

@@ -1,5 +1,5 @@
import { useEffect, useState } from "react";
import { Link } from "react-router";
import Link from "next/link";
import { shopifyFetch } from "@/services/shopify/client";
import { GET_COLLECTIONS_QUERY } from "@/graphql/collections";
import { Container } from "@/components/layout/Container";
@@ -71,7 +71,7 @@ export function CollectionGrid({
).map((c: CollectionRow) => (
<Link
key={c.id}
to={c.handle ? `/collections/${c.handle}` : "#"}
href={c.handle ? `/collections/${c.handle}` : "#"}
className="group block"
>
<div

View File

@@ -1,5 +1,5 @@
import { useState, useCallback } from 'react';
import { useParams } from 'react-router';
import { useParams } from 'next/navigation';
import { ChevronDown, SlidersHorizontal } from 'lucide-react';
import type { ShopifyCollection } from '@reacteditor/field-shopify';
import {
@@ -358,7 +358,9 @@ function buildProductFilters(active: ActiveFilters): ProductFilter[] {
export function CollectionView(props: CollectionProps) {
const { collection: selected, showDescription, showCoverImage, customCoverImage, columns, limit, defaultSort } = props;
const { handle: paramHandle } = useParams<{ handle?: string }>();
const params = useParams();
const paramHandle =
typeof params?.handle === 'string' ? params.handle : undefined;
const handle = selected?.handle ?? paramHandle ?? '';
const [sort, setSort] = useState<CollectionSortKey>(defaultSort);

View File

@@ -1,4 +1,4 @@
import { Link } from "react-router";
import Link from "next/link";
import type { ShopifyProduct } from "@reacteditor/field-shopify";
import { useProduct } from "@/hooks/use-shopify-products";
import { useShopifyCart } from "@/hooks/use-shopify-cart";
@@ -115,7 +115,7 @@ export function FeaturedProductView({
{ctaLabel}
</button>
<Link
to={`/products/${product.handle}`}
href={`/products/${product.handle}`}
className="inline-flex items-center justify-center rounded-md border border-foreground px-6 py-3 text-sm font-medium tracking-wide hover:opacity-80"
>
View details

View File

@@ -1,5 +1,5 @@
import * as React from "react";
import { Link } from "react-router";
import Link from "next/link";
import { Typography } from "@/components/Typography";
type ProductImage = { url: string; altText?: string };
@@ -41,7 +41,7 @@ export function ProductCard({
};
return (
<Link to={`/products/${product.handle}`} className="group block">
<Link href={`/products/${product.handle}`} className="group block">
<div
className={`relative w-full overflow-hidden rounded-md bg-muted ${aspectClass[aspect]}`}
>

View File

@@ -1,7 +1,7 @@
'use client';
import React, { useState, useEffect } from 'react';
import { Link } from 'react-router';
import Link from 'next/link';
import { useProduct, type Product } from '@/hooks/use-shopify-products';
import { useShopifyCart } from '@/hooks/use-shopify-cart';
import ProductDetailGallery from './product-detail-gallery';
@@ -164,13 +164,13 @@ const ProductDetail: React.FC<ProductDetailProps> = ({ handle: handleProp }) =>
<BreadcrumbList>
<BreadcrumbItem>
<BreadcrumbLink asChild>
<Link to="/">Home</Link>
<Link href="/">Home</Link>
</BreadcrumbLink>
</BreadcrumbItem>
<BreadcrumbSeparator />
<BreadcrumbItem>
<BreadcrumbLink asChild>
<Link to="/shop">Shop</Link>
<Link href="/shop">Shop</Link>
</BreadcrumbLink>
</BreadcrumbItem>
<BreadcrumbSeparator />

View File

@@ -1,5 +1,5 @@
import { useEffect, useState } from "react";
import { useParams } from "react-router";
import { useParams } from "next/navigation";
import type { ShopifyProduct } from "@reacteditor/field-shopify";
import { useProduct } from "@/hooks/use-shopify-products";
import { useShopifyCart } from "@/hooks/use-shopify-cart";
@@ -14,7 +14,9 @@ export type ProductDetailsProps = {
};
export function ProductDetailsView({ product: selected }: ProductDetailsProps) {
const { handle: paramHandle } = useParams<{ handle?: string }>();
const params = useParams();
const paramHandle =
typeof params?.handle === "string" ? params.handle : undefined;
const handle = selected?.handle ?? paramHandle ?? null;
const { product, loading } = useProduct(handle);
const cart = useShopifyCart();

View File

@@ -1,5 +1,5 @@
import { useEffect, useState } from "react";
import { Link } from "react-router";
import Link from "next/link";
import type { ShopifyCollection } from "@reacteditor/field-shopify";
import { getProducts } from "@/hooks/use-shopify-products";
import { getCollectionProducts } from "@/hooks/use-shopify-collections";
@@ -84,7 +84,7 @@ export function ProductsCarousel({
/>
{ctaLabel ? (
<Link
to={
href={
ctaHref ||
(collection?.handle ? `/collections/${collection.handle}` : "/collections")
}

View File

@@ -1,5 +1,5 @@
import { useEffect, useState } from "react";
import { Link } from "react-router";
import Link from "next/link";
import type { ShopifyCollection } from "@reacteditor/field-shopify";
import { getProducts } from "@/hooks/use-shopify-products";
import { getCollectionProducts } from "@/hooks/use-shopify-collections";
@@ -72,7 +72,7 @@ export function ProductsGrid({
/>
{ctaLabel ? (
<Link
to={ctaHref || (collection?.handle ? `/collections/${collection.handle}` : "/collections")}
href={ctaHref || (collection?.handle ? `/collections/${collection.handle}` : "/collections")}
className="text-sm font-medium tracking-wide hover:opacity-70"
>
{ctaLabel}

View File

@@ -1,5 +1,5 @@
import { useState, useEffect, useCallback } from 'react';
import { useSearchParams } from 'react-router';
import { useSearchParams, useRouter, usePathname } from 'next/navigation';
import { ChevronDown, SlidersHorizontal } from 'lucide-react';
import { useShopifySearch, type SearchFilters, type SortOption } from '@/hooks/use-shopify-search';
@@ -317,7 +317,9 @@ function Sidebar({
// ─── Main component ──────────────────────────────────────────────────────────
export function SearchProductsView(props: SearchProductsProps) {
const [searchParams, setSearchParams] = useSearchParams();
const searchParams = useSearchParams();
const router = useRouter();
const pathname = usePathname();
const initialQ = searchParams.get('q') ?? '';
const [query, setQuery] = useState(initialQ);
@@ -386,9 +388,10 @@ export function SearchProductsView(props: SearchProductsProps) {
// Sync ?q= param when query changes
useEffect(() => {
const params = new URLSearchParams(searchParams);
const params = new URLSearchParams(searchParams.toString());
if (query) params.set('q', query); else params.delete('q');
setSearchParams(params, { replace: true });
const qs = params.toString();
router.replace(qs ? `${pathname}?${qs}` : pathname, { scroll: false });
}, [query]);
const handleSearch = (e: React.FormEvent) => {