create-brainerce-store 1.17.0 → 1.19.0
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.
- package/dist/index.js +31 -9
- package/messages/en.json +366 -359
- package/messages/he.json +366 -359
- package/package.json +45 -45
- package/templates/nextjs/base/next.config.ts +31 -31
- package/templates/nextjs/base/scripts/fetch-store-info.mjs +81 -81
- package/templates/nextjs/base/src/app/.well-known/apple-developer-merchantid-domain-association/route.ts +26 -26
- package/templates/nextjs/base/src/app/account/layout.tsx +9 -9
- package/templates/nextjs/base/src/app/account/page.tsx +122 -122
- package/templates/nextjs/base/src/app/api/auth/logout/route.ts +14 -14
- package/templates/nextjs/base/src/app/api/auth/me/route.ts +56 -56
- package/templates/nextjs/base/src/app/api/auth/oauth-callback/route.ts +59 -59
- package/templates/nextjs/base/src/app/api/auth/reset-callback/route.ts +41 -41
- package/templates/nextjs/base/src/app/api/auth/reset-password/route.ts +77 -77
- package/templates/nextjs/base/src/app/api/store/[...path]/route.ts +198 -198
- package/templates/nextjs/base/src/app/auth/callback/page.tsx +92 -92
- package/templates/nextjs/base/src/app/cart/layout.tsx +9 -9
- package/templates/nextjs/base/src/app/cart/page.tsx +204 -199
- package/templates/nextjs/base/src/app/checkout/layout.tsx +9 -9
- package/templates/nextjs/base/src/app/checkout/page.tsx +860 -860
- package/templates/nextjs/base/src/app/forgot-password/page.tsx +112 -112
- package/templates/nextjs/base/src/app/layout.tsx.ejs +75 -0
- package/templates/nextjs/base/src/app/login/layout.tsx +9 -9
- package/templates/nextjs/base/src/app/login/page.tsx +59 -59
- package/templates/nextjs/base/src/app/order-confirmation/layout.tsx +9 -9
- package/templates/nextjs/base/src/app/order-confirmation/page.tsx +254 -254
- package/templates/nextjs/base/src/app/products/[slug]/page.tsx +67 -67
- package/templates/nextjs/base/src/app/products/[slug]/product-client-section.tsx +486 -486
- package/templates/nextjs/base/src/app/products/layout.tsx +18 -18
- package/templates/nextjs/base/src/app/products/page.tsx +431 -431
- package/templates/nextjs/base/src/app/register/layout.tsx +9 -9
- package/templates/nextjs/base/src/app/register/page.tsx +65 -65
- package/templates/nextjs/base/src/app/reset-password/page.tsx +132 -132
- package/templates/nextjs/base/src/app/robots.ts +14 -14
- package/templates/nextjs/base/src/app/sitemap.ts +25 -25
- package/templates/nextjs/base/src/app/verify-email/page.tsx +258 -258
- package/templates/nextjs/base/src/components/account/address-book.tsx +432 -432
- package/templates/nextjs/base/src/components/account/order-history.tsx +350 -350
- package/templates/nextjs/base/src/components/auth/oauth-buttons.tsx +137 -137
- package/templates/nextjs/base/src/components/auth/register-form.tsx +232 -232
- package/templates/nextjs/base/src/components/cart/cart-bundle-offer.tsx +247 -111
- package/templates/nextjs/base/src/components/cart/cart-item.tsx +153 -153
- package/templates/nextjs/base/src/components/cart/cart-upgrade-banner.tsx +142 -142
- package/templates/nextjs/base/src/components/cart/free-shipping-bar.tsx +59 -59
- package/templates/nextjs/base/src/components/checkout/checkout-form.tsx +415 -415
- package/templates/nextjs/base/src/components/checkout/order-bump-card.tsx +243 -83
- package/templates/nextjs/base/src/components/checkout/payment-step.tsx +519 -473
- package/templates/nextjs/base/src/components/layout/footer.tsx +41 -41
- package/templates/nextjs/base/src/components/layout/header.tsx +336 -336
- package/templates/nextjs/base/src/components/layout/language-switcher.tsx.ejs +63 -0
- package/templates/nextjs/base/src/components/products/discount-badge.tsx +22 -22
- package/templates/nextjs/base/src/components/products/frequently-bought-together.tsx +202 -202
- package/templates/nextjs/base/src/components/products/product-card.tsx +218 -218
- package/templates/nextjs/base/src/components/products/recommendation-section.tsx +107 -107
- package/templates/nextjs/base/src/components/products/stock-badge.tsx +63 -63
- package/templates/nextjs/base/src/components/products/variant-selector.tsx +292 -292
- package/templates/nextjs/base/src/components/seo/product-json-ld.tsx +72 -72
- package/templates/nextjs/base/src/i18n.ts.ejs +21 -0
- package/templates/nextjs/base/src/lib/auth.ts +149 -149
- package/templates/nextjs/base/src/lib/brainerce.ts.ejs +9 -0
- package/templates/nextjs/base/src/lib/translations.ts.ejs +31 -0
- package/templates/nextjs/base/src/middleware.ts.ejs +81 -0
- package/templates/nextjs/base/src/providers/store-provider.tsx.ejs +41 -0
- package/templates/nextjs/base/src/lib/translations.ts +0 -11
- package/templates/nextjs/base/src/middleware.ts +0 -25
|
@@ -1,59 +1,59 @@
|
|
|
1
|
-
'use client';
|
|
2
|
-
|
|
3
|
-
import { formatPrice } from 'brainerce';
|
|
4
|
-
import { useStoreInfo, useCart } from '@/providers/store-provider';
|
|
5
|
-
import { useTranslations } from '@/lib/translations';
|
|
6
|
-
import { cn } from '@/lib/utils';
|
|
7
|
-
|
|
8
|
-
interface FreeShippingBarProps {
|
|
9
|
-
className?: string;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export function FreeShippingBar({ className }: FreeShippingBarProps) {
|
|
13
|
-
const t = useTranslations('cart');
|
|
14
|
-
const { storeInfo } = useStoreInfo();
|
|
15
|
-
const { totals } = useCart();
|
|
16
|
-
|
|
17
|
-
const upsell = storeInfo?.upsell;
|
|
18
|
-
const threshold = upsell?.freeShippingThreshold;
|
|
19
|
-
const enabled = upsell?.freeShippingBarEnabled !== false;
|
|
20
|
-
|
|
21
|
-
// Don't render if disabled or no threshold configured
|
|
22
|
-
if (!enabled || !threshold || threshold <= 0) return null;
|
|
23
|
-
|
|
24
|
-
const subtotal = totals.subtotal;
|
|
25
|
-
const remaining = Math.max(0, threshold - subtotal);
|
|
26
|
-
const progress = Math.min(100, (subtotal / threshold) * 100);
|
|
27
|
-
const qualified = remaining <= 0;
|
|
28
|
-
const currency = storeInfo?.currency || 'USD';
|
|
29
|
-
|
|
30
|
-
// Don't show if already qualified
|
|
31
|
-
if (qualified) {
|
|
32
|
-
return (
|
|
33
|
-
<div className={cn('rounded-lg border border-green-200 bg-green-50 p-3', className)}>
|
|
34
|
-
<div className="flex items-center gap-2 text-sm font-medium text-green-700">
|
|
35
|
-
<svg className="h-4 w-4 shrink-0" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
36
|
-
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M5 13l4 4L19 7" />
|
|
37
|
-
</svg>
|
|
38
|
-
{t('freeShippingQualified')}
|
|
39
|
-
</div>
|
|
40
|
-
</div>
|
|
41
|
-
);
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
return (
|
|
45
|
-
<div className={cn('rounded-lg border border-amber-200 bg-amber-50 p-3', className)}>
|
|
46
|
-
<p className="mb-2 text-sm text-amber-800">
|
|
47
|
-
{t('freeShippingRemaining', {
|
|
48
|
-
amount: formatPrice(remaining, { currency }) as string,
|
|
49
|
-
})}
|
|
50
|
-
</p>
|
|
51
|
-
<div className="h-2 w-full overflow-hidden rounded-full bg-amber-200">
|
|
52
|
-
<div
|
|
53
|
-
className="h-full rounded-full bg-amber-500 transition-all duration-500 ease-out"
|
|
54
|
-
style={{ width: `${progress}%` }}
|
|
55
|
-
/>
|
|
56
|
-
</div>
|
|
57
|
-
</div>
|
|
58
|
-
);
|
|
59
|
-
}
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { formatPrice } from 'brainerce';
|
|
4
|
+
import { useStoreInfo, useCart } from '@/providers/store-provider';
|
|
5
|
+
import { useTranslations } from '@/lib/translations';
|
|
6
|
+
import { cn } from '@/lib/utils';
|
|
7
|
+
|
|
8
|
+
interface FreeShippingBarProps {
|
|
9
|
+
className?: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function FreeShippingBar({ className }: FreeShippingBarProps) {
|
|
13
|
+
const t = useTranslations('cart');
|
|
14
|
+
const { storeInfo } = useStoreInfo();
|
|
15
|
+
const { totals } = useCart();
|
|
16
|
+
|
|
17
|
+
const upsell = storeInfo?.upsell;
|
|
18
|
+
const threshold = upsell?.freeShippingThreshold;
|
|
19
|
+
const enabled = upsell?.freeShippingBarEnabled !== false;
|
|
20
|
+
|
|
21
|
+
// Don't render if disabled or no threshold configured
|
|
22
|
+
if (!enabled || !threshold || threshold <= 0) return null;
|
|
23
|
+
|
|
24
|
+
const subtotal = totals.subtotal;
|
|
25
|
+
const remaining = Math.max(0, threshold - subtotal);
|
|
26
|
+
const progress = Math.min(100, (subtotal / threshold) * 100);
|
|
27
|
+
const qualified = remaining <= 0;
|
|
28
|
+
const currency = storeInfo?.currency || 'USD';
|
|
29
|
+
|
|
30
|
+
// Don't show if already qualified
|
|
31
|
+
if (qualified) {
|
|
32
|
+
return (
|
|
33
|
+
<div className={cn('rounded-lg border border-green-200 bg-green-50 p-3', className)}>
|
|
34
|
+
<div className="flex items-center gap-2 text-sm font-medium text-green-700">
|
|
35
|
+
<svg className="h-4 w-4 shrink-0" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
36
|
+
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M5 13l4 4L19 7" />
|
|
37
|
+
</svg>
|
|
38
|
+
{t('freeShippingQualified')}
|
|
39
|
+
</div>
|
|
40
|
+
</div>
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return (
|
|
45
|
+
<div className={cn('rounded-lg border border-amber-200 bg-amber-50 p-3', className)}>
|
|
46
|
+
<p className="mb-2 text-sm text-amber-800">
|
|
47
|
+
{t('freeShippingRemaining', {
|
|
48
|
+
amount: formatPrice(remaining, { currency }) as string,
|
|
49
|
+
})}
|
|
50
|
+
</p>
|
|
51
|
+
<div className="h-2 w-full overflow-hidden rounded-full bg-amber-200">
|
|
52
|
+
<div
|
|
53
|
+
className="h-full rounded-full bg-amber-500 transition-all duration-500 ease-out"
|
|
54
|
+
style={{ width: `${progress}%` }}
|
|
55
|
+
/>
|
|
56
|
+
</div>
|
|
57
|
+
</div>
|
|
58
|
+
);
|
|
59
|
+
}
|