create-brainerce-store 1.4.1 → 1.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/dist/index.js +1 -1
  2. package/messages/en.json +9 -1
  3. package/messages/he.json +9 -1
  4. package/package.json +1 -1
  5. package/templates/nextjs/base/src/app/account/page.tsx +8 -4
  6. package/templates/nextjs/base/src/app/auth/callback/page.tsx +90 -90
  7. package/templates/nextjs/base/src/app/cart/page.tsx +110 -110
  8. package/templates/nextjs/base/src/app/checkout/page.tsx +614 -614
  9. package/templates/nextjs/base/src/app/login/page.tsx +58 -58
  10. package/templates/nextjs/base/src/app/order-confirmation/page.tsx +193 -193
  11. package/templates/nextjs/base/src/app/page.tsx +98 -98
  12. package/templates/nextjs/base/src/app/products/[slug]/page.tsx +435 -435
  13. package/templates/nextjs/base/src/app/products/page.tsx +246 -246
  14. package/templates/nextjs/base/src/app/register/page.tsx +68 -68
  15. package/templates/nextjs/base/src/app/verify-email/page.tsx +293 -293
  16. package/templates/nextjs/base/src/components/account/order-history.tsx +198 -198
  17. package/templates/nextjs/base/src/components/account/profile-section.tsx +189 -40
  18. package/templates/nextjs/base/src/components/auth/login-form.tsx +94 -94
  19. package/templates/nextjs/base/src/components/auth/oauth-buttons.tsx +137 -137
  20. package/templates/nextjs/base/src/components/auth/register-form.tsx +184 -184
  21. package/templates/nextjs/base/src/components/cart/cart-item.tsx +153 -153
  22. package/templates/nextjs/base/src/components/cart/cart-summary.tsx +70 -70
  23. package/templates/nextjs/base/src/components/cart/coupon-input.tsx +134 -134
  24. package/templates/nextjs/base/src/components/cart/reservation-countdown.tsx +103 -103
  25. package/templates/nextjs/base/src/components/checkout/checkout-form.tsx +305 -305
  26. package/templates/nextjs/base/src/components/checkout/delivery-method-step.tsx +64 -64
  27. package/templates/nextjs/base/src/components/checkout/payment-step.tsx +350 -344
  28. package/templates/nextjs/base/src/components/checkout/pickup-step.tsx +199 -199
  29. package/templates/nextjs/base/src/components/checkout/shipping-step.tsx +110 -110
  30. package/templates/nextjs/base/src/components/checkout/tax-display.tsx +65 -65
  31. package/templates/nextjs/base/src/components/layout/footer.tsx +38 -38
  32. package/templates/nextjs/base/src/components/layout/header.tsx +332 -332
  33. package/templates/nextjs/base/src/components/products/product-card.tsx +96 -96
  34. package/templates/nextjs/base/src/components/products/product-grid.tsx +35 -35
  35. package/templates/nextjs/base/src/components/shared/loading-spinner.tsx +32 -32
  36. package/templates/nextjs/base/src/lib/translations.ts +11 -11
  37. package/templates/nextjs/base/src/providers/store-provider.tsx.ejs +5 -1
@@ -1,98 +1,98 @@
1
- 'use client';
2
-
3
- import { useEffect, useState } from 'react';
4
- import Link from 'next/link';
5
- import type { Product, DiscountBanner } from 'brainerce';
6
- import { getClient } from '@/lib/brainerce';
7
- import { useStoreInfo } from '@/providers/store-provider';
8
- import { ProductGrid } from '@/components/products/product-grid';
9
- import { LoadingSpinner } from '@/components/shared/loading-spinner';
10
- import { useTranslations } from '@/lib/translations';
11
-
12
- export default function HomePage() {
13
- const { storeInfo, loading: storeLoading } = useStoreInfo();
14
- const [products, setProducts] = useState<Product[]>([]);
15
- const [banners, setBanners] = useState<DiscountBanner[]>([]);
16
- const [loading, setLoading] = useState(true);
17
- const t = useTranslations('home');
18
- const tc = useTranslations('common');
19
-
20
- useEffect(() => {
21
- async function load() {
22
- try {
23
- const client = getClient();
24
- const [productsRes, bannersRes] = await Promise.allSettled([
25
- client.getProducts({ limit: 8, sortBy: 'createdAt', sortOrder: 'desc' }),
26
- client.getDiscountBanners(),
27
- ]);
28
-
29
- if (productsRes.status === 'fulfilled') {
30
- setProducts(productsRes.value.data);
31
- }
32
- if (bannersRes.status === 'fulfilled') {
33
- setBanners(bannersRes.value);
34
- }
35
- } catch (err) {
36
- console.error('Failed to load home page data:', err);
37
- } finally {
38
- setLoading(false);
39
- }
40
- }
41
-
42
- load();
43
- }, []);
44
-
45
- if (storeLoading || loading) {
46
- return (
47
- <div className="flex min-h-[60vh] items-center justify-center">
48
- <LoadingSpinner size="lg" />
49
- </div>
50
- );
51
- }
52
-
53
- return (
54
- <div>
55
- {/* Discount Banners */}
56
- {banners.length > 0 && (
57
- <div className="bg-primary text-primary-foreground">
58
- <div className="mx-auto max-w-7xl px-4 py-2 sm:px-6 lg:px-8">
59
- <div className="flex items-center justify-center gap-4 overflow-x-auto text-sm font-medium">
60
- {banners.map((banner) => (
61
- <span key={banner.ruleId}>{banner.text}</span>
62
- ))}
63
- </div>
64
- </div>
65
- </div>
66
- )}
67
-
68
- {/* Hero Section */}
69
- <section className="bg-muted">
70
- <div className="mx-auto max-w-7xl px-4 py-20 text-center sm:px-6 lg:px-8">
71
- <h1 className="text-foreground text-4xl font-bold tracking-tight sm:text-5xl">
72
- {t('welcomeTo')} {storeInfo?.name || tc('store')}
73
- </h1>
74
- <p className="text-muted-foreground mx-auto mt-4 max-w-2xl text-lg">
75
- {t('heroSubtitle')}
76
- </p>
77
- <Link
78
- href="/products"
79
- className="bg-primary text-primary-foreground mt-8 inline-flex items-center rounded px-6 py-3 font-medium transition-opacity hover:opacity-90"
80
- >
81
- {tc('shopNow')}
82
- </Link>
83
- </div>
84
- </section>
85
-
86
- {/* Featured Products */}
87
- <section className="mx-auto max-w-7xl px-4 py-16 sm:px-6 lg:px-8">
88
- <div className="mb-8 flex items-center justify-between">
89
- <h2 className="text-foreground text-2xl font-bold">{t('featuredProducts')}</h2>
90
- <Link href="/products" className="text-primary text-sm font-medium hover:underline">
91
- {tc('viewAll')}
92
- </Link>
93
- </div>
94
- <ProductGrid products={products} />
95
- </section>
96
- </div>
97
- );
98
- }
1
+ 'use client';
2
+
3
+ import { useEffect, useState } from 'react';
4
+ import Link from 'next/link';
5
+ import type { Product, DiscountBanner } from 'brainerce';
6
+ import { getClient } from '@/lib/brainerce';
7
+ import { useStoreInfo } from '@/providers/store-provider';
8
+ import { ProductGrid } from '@/components/products/product-grid';
9
+ import { LoadingSpinner } from '@/components/shared/loading-spinner';
10
+ import { useTranslations } from '@/lib/translations';
11
+
12
+ export default function HomePage() {
13
+ const { storeInfo, loading: storeLoading } = useStoreInfo();
14
+ const [products, setProducts] = useState<Product[]>([]);
15
+ const [banners, setBanners] = useState<DiscountBanner[]>([]);
16
+ const [loading, setLoading] = useState(true);
17
+ const t = useTranslations('home');
18
+ const tc = useTranslations('common');
19
+
20
+ useEffect(() => {
21
+ async function load() {
22
+ try {
23
+ const client = getClient();
24
+ const [productsRes, bannersRes] = await Promise.allSettled([
25
+ client.getProducts({ limit: 8, sortBy: 'createdAt', sortOrder: 'desc' }),
26
+ client.getDiscountBanners(),
27
+ ]);
28
+
29
+ if (productsRes.status === 'fulfilled') {
30
+ setProducts(productsRes.value.data);
31
+ }
32
+ if (bannersRes.status === 'fulfilled') {
33
+ setBanners(bannersRes.value);
34
+ }
35
+ } catch (err) {
36
+ console.error('Failed to load home page data:', err);
37
+ } finally {
38
+ setLoading(false);
39
+ }
40
+ }
41
+
42
+ load();
43
+ }, []);
44
+
45
+ if (storeLoading || loading) {
46
+ return (
47
+ <div className="flex min-h-[60vh] items-center justify-center">
48
+ <LoadingSpinner size="lg" />
49
+ </div>
50
+ );
51
+ }
52
+
53
+ return (
54
+ <div>
55
+ {/* Discount Banners */}
56
+ {banners.length > 0 && (
57
+ <div className="bg-primary text-primary-foreground">
58
+ <div className="mx-auto max-w-7xl px-4 py-2 sm:px-6 lg:px-8">
59
+ <div className="flex items-center justify-center gap-4 overflow-x-auto text-sm font-medium">
60
+ {banners.map((banner) => (
61
+ <span key={banner.ruleId}>{banner.text}</span>
62
+ ))}
63
+ </div>
64
+ </div>
65
+ </div>
66
+ )}
67
+
68
+ {/* Hero Section */}
69
+ <section className="bg-muted">
70
+ <div className="mx-auto max-w-7xl px-4 py-20 text-center sm:px-6 lg:px-8">
71
+ <h1 className="text-foreground text-4xl font-bold tracking-tight sm:text-5xl">
72
+ {t('welcomeTo')} {storeInfo?.name || tc('store')}
73
+ </h1>
74
+ <p className="text-muted-foreground mx-auto mt-4 max-w-2xl text-lg">
75
+ {t('heroSubtitle')}
76
+ </p>
77
+ <Link
78
+ href="/products"
79
+ className="bg-primary text-primary-foreground mt-8 inline-flex items-center rounded px-6 py-3 font-medium transition-opacity hover:opacity-90"
80
+ >
81
+ {tc('shopNow')}
82
+ </Link>
83
+ </div>
84
+ </section>
85
+
86
+ {/* Featured Products */}
87
+ <section className="mx-auto max-w-7xl px-4 py-16 sm:px-6 lg:px-8">
88
+ <div className="mb-8 flex items-center justify-between">
89
+ <h2 className="text-foreground text-2xl font-bold">{t('featuredProducts')}</h2>
90
+ <Link href="/products" className="text-primary text-sm font-medium hover:underline">
91
+ {tc('viewAll')}
92
+ </Link>
93
+ </div>
94
+ <ProductGrid products={products} />
95
+ </section>
96
+ </div>
97
+ );
98
+ }