hotfix: shoppify hydrogen initialization with mock data

This commit is contained in:
Harivansh Rathi 2025-02-20 19:47:43 -05:00
parent 357979d0af
commit 4e59c6866d
15 changed files with 6510 additions and 115 deletions

3
.env.example Normal file
View file

@ -0,0 +1,3 @@
# Shopify Store Configuration
VITE_SHOPIFY_STORE_DOMAIN=your-store.myshopify.com
VITE_SHOPIFY_STOREFRONT_TOKEN=your-storefront-access-token

40
.gitignore vendored
View file

@ -1,24 +1,36 @@
# Logs
logs
*.log
# Environment variables
.env
.env.local
.env.*.local
# Dependencies
node_modules/
.pnp/
.pnp.js
# Build output
dist/
build/
# Debug logs
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
node_modules
dist
dist-ssr
*.local
# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
.idea/
.vscode/
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
# OS generated files
.DS_Store
.DS_Store?
._*
.Spotlight-V100
.Trashes
ehthumbs.db
Thumbs.db

12
hydrogen.config.ts Normal file
View file

@ -0,0 +1,12 @@
import {defineConfig} from '@shopify/hydrogen/config';
export default defineConfig({
shopify: {
storeDomain: 'your-store.myshopify.com',
storefrontToken: 'your_storefront_api_token',
storefrontApiVersion: '2024-01', // Use the latest API version
},
session: {
storage: 'memory', // You can change this to 'redis' or other storage methods in production
},
});

6236
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -16,8 +16,14 @@
"@radix-ui/react-scroll-area": "^1.0.5",
"@radix-ui/react-separator": "^1.0.3",
"@radix-ui/react-slot": "^1.0.2",
"@shopify/cli": "^3.75.4",
"@shopify/cli-hydrogen": "^9.0.8",
"@shopify/hydrogen": "^2025.1.2",
"@shopify/hydrogen-react": "^2025.1.2",
"@shopify/storefront-kit-react": "^2023.1.3",
"class-variance-authority": "^0.7.0",
"clsx": "^2.1.0",
"graphql-tag": "^2.12.6",
"lucide-react": "^0.344.0",
"react": "^18.3.1",
"react-dom": "^18.3.1",
@ -43,4 +49,4 @@
"typescript-eslint": "^8.3.0",
"vite": "^5.4.2"
}
}
}

View file

@ -1,79 +1,90 @@
import React, { useState } from 'react';
import { BrowserRouter as Router, Routes, Route, Link } from 'react-router-dom';
import { ProductsPage } from './pages/Products';
import { Header } from './components/Header';
import { ProductGrid } from './components/ProductGrid';
import { ProductDetails } from './components/ProductDetails';
import { products } from './data/products';
function App() {
const App: React.FC = () => {
const [selectedProduct, setSelectedProduct] = useState<string | null>(null);
const [selectedCategory, setSelectedCategory] = useState<string | null>(null);
const categories = Array.from(new Set(products.map((p) => p.category)));
const currentProduct = products.find((p) => p.id === selectedProduct);
return (
<div className="min-h-screen bg-background">
<Header />
<main className="max-w-7xl mx-auto px-4 py-8">
{!selectedProduct ? (
<>
<section className="text-center mb-12">
<h1 className="text-4xl font-bold mb-4">
Premium Supplements for Your Fitness Journey
</h1>
<p className="text-lg text-muted-foreground max-w-2xl mx-auto">
Discover our range of high-quality supplements designed to help you achieve your fitness goals.
</p>
</section>
<div className="mb-8">
<div className="flex flex-wrap gap-4 justify-center">
<button
onClick={() => setSelectedCategory(null)}
className={`px-4 py-2 rounded-full ${
!selectedCategory
? 'bg-primary text-primary-foreground'
: 'bg-secondary text-secondary-foreground'
}`}
>
All Products
</button>
{categories.map((category) => (
<button
key={category}
onClick={() => setSelectedCategory(category)}
className={`px-4 py-2 rounded-full ${
selectedCategory === category
? 'bg-primary text-primary-foreground'
: 'bg-secondary text-secondary-foreground'
}`}
>
{category}
</button>
))}
</div>
</div>
<ProductGrid
products={products}
category={selectedCategory ?? undefined}
onProductSelect={setSelectedProduct}
<Router>
<div className="min-h-screen bg-background">
<Header />
<main className="container mx-auto p-4">
<nav className="mb-4">
<Link to="/local-products" className="mr-4 text-primary hover:text-primary/80">
Local Products
</Link>
<Link to="/shopify-products" className="text-primary hover:text-primary/80">
Shopify Products
</Link>
</nav>
<Routes>
<Route
path="/local-products"
element={
<>
<div className="mb-8">
<div className="flex flex-wrap gap-4 justify-center">
<button
onClick={() => setSelectedCategory(null)}
className={`px-4 py-2 rounded-full ${
!selectedCategory
? 'bg-primary text-primary-foreground'
: 'bg-secondary text-secondary-foreground'
}`}
>
All Products
</button>
{categories.map((category) => (
<button
key={category}
onClick={() => setSelectedCategory(category)}
className={`px-4 py-2 rounded-full ${
selectedCategory === category
? 'bg-primary text-primary-foreground'
: 'bg-secondary text-secondary-foreground'
}`}
>
{category}
</button>
))}
</div>
</div>
{selectedProduct ? (
<div>
<button
onClick={() => setSelectedProduct(null)}
className="mb-8 text-primary hover:underline flex items-center gap-2"
>
Back to Products
</button>
<ProductDetails
product={products.find((p) => p.id === selectedProduct)!}
/>
</div>
) : (
<ProductGrid
products={products}
category={selectedCategory || undefined}
onProductSelect={setSelectedProduct}
/>
)}
</>
}
/>
</>
) : (
<div>
<button
onClick={() => setSelectedProduct(null)}
className="mb-8 text-primary hover:underline flex items-center gap-2"
>
Back to Products
</button>
{currentProduct && <ProductDetails product={currentProduct} />}
</div>
)}
</main>
</div>
<Route path="/shopify-products" element={<ProductsPage />} />
</Routes>
</main>
</div>
</Router>
);
}
};
export default App;
export default App;

View file

@ -0,0 +1,55 @@
import React from 'react';
import { Money, Image } from '@shopify/hydrogen-react';
import { ShoppingCart } from 'lucide-react';
import { Card, CardContent, CardFooter, CardHeader, CardTitle } from './ui/card';
import { Button } from './ui/button';
import { ShopifyProduct } from '../types/shopify';
interface ShopifyProductCardProps {
product: ShopifyProduct;
onSelect: (productId: string) => void;
}
export const ShopifyProductCard: React.FC<ShopifyProductCardProps> = ({ product, onSelect }) => {
if (!product) return null;
return (
<Card className="cursor-pointer" onClick={() => onSelect(product.id)}>
<CardHeader className="p-0">
{product.featuredImage && (
<Image
data={product.featuredImage}
alt={product.title}
className="w-full h-48 object-cover rounded-t-xl"
/>
)}
</CardHeader>
<CardContent className="p-4">
<div className="flex justify-between items-start mb-2">
<CardTitle className="text-lg">{product.title}</CardTitle>
<Money
data={product.priceRange.minVariantPrice}
className="text-lg font-bold text-primary"
/>
</div>
<p className="text-muted-foreground text-sm mb-4 line-clamp-2">
{product.description}
</p>
</CardContent>
<CardFooter>
<Button
onClick={(e) => {
e.stopPropagation();
// You'll need to implement your own add to cart logic here
console.log('Add to cart:', product.id);
}}
className="w-full"
size="lg"
>
<ShoppingCart className="w-4 h-4 mr-2" />
Add to Cart
</Button>
</CardFooter>
</Card>
);
};

View file

@ -0,0 +1,22 @@
import React from 'react';
import { ShopifyProductCard } from './ShopifyProductCard';
import { ShopifyProduct } from '../types/shopify';
export const ShopifyProductGrid: React.FC<{ products: ShopifyProduct[] }> = ({ products }) => {
const handleProductSelect = (productId: string) => {
// Handle product selection - you can implement navigation to product details page
console.log('Selected product:', productId);
};
return (
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6 p-6">
{products.map((product) => (
<ShopifyProductCard
key={product.id}
product={product}
onSelect={handleProductSelect}
/>
))}
</div>
);
};

View file

@ -0,0 +1,58 @@
import { ShopifyProduct } from '../types/shopify';
export const mockProducts: ShopifyProduct[] = [
{
id: '1',
title: 'Whey Protein Isolate',
description: 'Premium whey protein isolate for optimal muscle recovery and growth.',
handle: 'whey-protein-isolate',
priceRange: {
minVariantPrice: {
amount: '49.99',
currencyCode: 'USD'
}
},
featuredImage: {
url: 'https://images.unsplash.com/photo-1593095948071-474c5cc2989d?q=80&w=2670&auto=format&fit=crop',
altText: 'Whey Protein Container',
width: 800,
height: 800
}
},
{
id: '2',
title: 'Pre-Workout Energy',
description: 'Advanced pre-workout formula for enhanced performance and focus.',
handle: 'pre-workout-energy',
priceRange: {
minVariantPrice: {
amount: '39.99',
currencyCode: 'USD'
}
},
featuredImage: {
url: 'https://images.unsplash.com/photo-1594882645126-14020914d58d?q=80&w=2785&auto=format&fit=crop',
altText: 'Pre-workout Container',
width: 800,
height: 800
}
},
{
id: '3',
title: 'BCAA Complex',
description: 'Essential branched-chain amino acids for muscle support and recovery.',
handle: 'bcaa-complex',
priceRange: {
minVariantPrice: {
amount: '29.99',
currencyCode: 'USD'
}
},
featuredImage: {
url: 'https://images.unsplash.com/photo-1579722820308-d74e571900a9?q=80&w=2670&auto=format&fit=crop',
altText: 'BCAA Container',
width: 800,
height: 800
}
}
];

10
src/env.d.ts vendored Normal file
View file

@ -0,0 +1,10 @@
/// <reference types="vite/client" />
interface ImportMetaEnv {
readonly VITE_SHOPIFY_STORE_DOMAIN: string;
readonly VITE_SHOPIFY_STOREFRONT_TOKEN: string;
}
interface ImportMeta {
readonly env: ImportMetaEnv;
}

View file

@ -1,10 +1,19 @@
import React from 'react';
import { createRoot } from 'react-dom/client';
import { ShopifyProvider } from '@shopify/hydrogen-react';
import App from './App.tsx';
import './index.css';
createRoot(document.getElementById('root')!).render(
<React.StrictMode>
<App />
<ShopifyProvider
storeDomain={import.meta.env.VITE_SHOPIFY_STORE_DOMAIN}
storefrontToken={import.meta.env.VITE_SHOPIFY_STOREFRONT_TOKEN}
storefrontApiVersion="2024-01"
countryIsoCode="US"
languageIsoCode="EN"
>
<App />
</ShopifyProvider>
</React.StrictMode>
);
);

7
src/pages/Products.tsx Normal file
View file

@ -0,0 +1,7 @@
import React from 'react';
import { ShopifyProductGrid } from '../components/ShopifyProductGrid';
import { mockProducts } from '../data/mockShopifyProducts';
export const ProductsPage: React.FC = () => {
return <ShopifyProductGrid products={mockProducts} />;
};

View file

@ -42,4 +42,4 @@ export interface Product {
flavors: string[];
certifications: ProductCertification[];
studies: ProductStudy[];
}
}

18
src/types/shopify.ts Normal file
View file

@ -0,0 +1,18 @@
export interface ShopifyProduct {
id: string;
title: string;
description: string;
handle: string;
priceRange: {
minVariantPrice: {
amount: string;
currencyCode: 'USD' | 'EUR' | 'GBP' | 'CAD' | 'AUD';
};
};
featuredImage: {
url: string;
altText: string;
width: number;
height: number;
};
}

View file

@ -12,4 +12,4 @@ export default defineConfig({
'@': path.resolve(__dirname, './src'),
},
},
});
});