create-nextblock 0.15.5 → 0.15.9
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/package.json +50 -26
- package/templates/nextblock-template/app/ToasterProvider.tsx +26 -17
- package/templates/nextblock-template/app/actions/contactSellerActions.test.ts +280 -0
- package/templates/nextblock-template/app/actions/contactSellerActions.ts +222 -0
- package/templates/nextblock-template/app/actions/email-retry.test.ts +62 -0
- package/templates/nextblock-template/app/actions/email.ts +241 -110
- package/templates/nextblock-template/app/actions/formActions.ts +245 -116
- package/templates/nextblock-template/app/actions/interactions.ts +489 -396
- package/templates/nextblock-template/app/actions/threadActions.ts +166 -0
- package/templates/nextblock-template/app/api/checkout/route.ts +162 -146
- package/templates/nextblock-template/app/api/cron/reset-sandbox/route.ts +14 -0
- package/templates/nextblock-template/app/api/cron/reset-sandbox/sandboxResetSql.ts +664 -1
- package/templates/nextblock-template/app/checkout/page.tsx +57 -52
- package/templates/nextblock-template/app/cms/CmsClientLayout.tsx +552 -529
- package/templates/nextblock-template/app/cms/blocks/editors/FormBlockEditor.tsx +304 -181
- package/templates/nextblock-template/app/cms/components/ContactReminderBanner.tsx +75 -0
- package/templates/nextblock-template/app/cms/components/PaymentsReminderBanner.tsx +58 -0
- package/templates/nextblock-template/app/cms/components/VisibilityControl.tsx +542 -528
- package/templates/nextblock-template/app/cms/inquiries/actions.ts +66 -0
- package/templates/nextblock-template/app/cms/inquiries/page.tsx +12 -0
- package/templates/nextblock-template/app/cms/interactions/page.tsx +12 -51
- package/templates/nextblock-template/app/cms/layout.tsx +101 -73
- package/templates/nextblock-template/app/cms/messages/MessagesClient.tsx +661 -0
- package/templates/nextblock-template/app/cms/messages/actions.ts +404 -0
- package/templates/nextblock-template/app/cms/messages/loadInbox.ts +333 -0
- package/templates/nextblock-template/app/cms/messages/page.tsx +87 -0
- package/templates/nextblock-template/app/cms/messages/require-admin.ts +37 -0
- package/templates/nextblock-template/app/cms/products/[id]/edit/page.tsx +370 -362
- package/templates/nextblock-template/app/cms/revisions/service.ts +20 -0
- package/templates/nextblock-template/app/cms/settings/email/components/EmailForm.tsx +227 -185
- package/templates/nextblock-template/app/layout.tsx +671 -667
- package/templates/nextblock-template/app/lib/seo.ts +319 -311
- package/templates/nextblock-template/app/product/[slug]/page.tsx +502 -482
- package/templates/nextblock-template/app/providers.tsx +96 -96
- package/templates/nextblock-template/app/thread/ThreadView.tsx +164 -0
- package/templates/nextblock-template/app/thread/[token]/route.ts +57 -0
- package/templates/nextblock-template/app/thread/layout.tsx +15 -0
- package/templates/nextblock-template/app/thread/page.tsx +98 -0
- package/templates/nextblock-template/components/BlockRenderer.tsx +312 -296
- package/templates/nextblock-template/components/ContactSellerSection.tsx +188 -0
- package/templates/nextblock-template/components/PostCommentsSection.tsx +378 -369
- package/templates/nextblock-template/components/ProductReviewsSection.tsx +426 -419
- package/templates/nextblock-template/components/StaffReplies.tsx +102 -0
- package/templates/nextblock-template/components/blocks/renderers/CartBlockRenderer.tsx +18 -17
- package/templates/nextblock-template/components/blocks/renderers/CheckoutBlockRenderer.tsx +20 -19
- package/templates/nextblock-template/components/blocks/renderers/FeaturedProductBlockRenderer.tsx +25 -22
- package/templates/nextblock-template/components/blocks/renderers/FormBlockRenderer.tsx +385 -381
- package/templates/nextblock-template/components/blocks/renderers/ProductDetailsBlockRenderer.tsx +157 -92
- package/templates/nextblock-template/components/blocks/renderers/ProductGridBlockRenderer.tsx +34 -31
- package/templates/nextblock-template/components/blocks/renderers/SectionBlockRenderer.tsx +612 -600
- package/templates/nextblock-template/components/commerce/PaymentReadinessBoundary.tsx +32 -0
- package/templates/nextblock-template/docs/05-DEVELOPER-GUIDE.md +25 -19
- package/templates/nextblock-template/docs/06-CLI-AND-SCAFFOLDING.md +1 -1
- package/templates/nextblock-template/docs/08-NEXTBLOCK-CORTEX-AI-ARCHITECTURE.md +2 -2
- package/templates/nextblock-template/docs/12-VERCEL-DEPLOYMENT.md +32 -9
- package/templates/nextblock-template/docs/14-MESSAGES-INBOX.md +309 -0
- package/templates/nextblock-template/docs/README.md +42 -41
- package/templates/nextblock-template/docs/TECHNICAL_SPECIFICATION.md +540 -542
- package/templates/nextblock-template/docs/assets/lighthouse-scores.png +0 -0
- package/templates/nextblock-template/lib/blocks/blockColors.test.ts +22 -2
- package/templates/nextblock-template/lib/blocks/blockColors.ts +44 -1
- package/templates/nextblock-template/lib/blocks/blockRegistry.ts +761 -753
- package/templates/nextblock-template/lib/cms/contact-reminder.ts +64 -0
- package/templates/nextblock-template/lib/cms/payments-reminder.ts +98 -0
- package/templates/nextblock-template/lib/cms/unread-messages.ts +42 -0
- package/templates/nextblock-template/lib/commerce/seller-contact.ts +162 -0
- package/templates/nextblock-template/lib/config/email-settings.ts +323 -254
- package/templates/nextblock-template/lib/config/email-tls.test.ts +57 -0
- package/templates/nextblock-template/lib/email/placeholder-address.test.ts +59 -0
- package/templates/nextblock-template/lib/email/placeholder-address.ts +39 -0
- package/templates/nextblock-template/lib/messages/thread-reference.test.ts +70 -0
- package/templates/nextblock-template/lib/messages/thread-token.test.ts +93 -0
- package/templates/nextblock-template/lib/messages/thread-token.ts +157 -0
- package/templates/nextblock-template/lib/messages/threads.ts +579 -0
- package/templates/nextblock-template/lib/setup/migrations-bundle.ts +20 -0
- package/templates/nextblock-template/lib/site-url.test.ts +89 -0
- package/templates/nextblock-template/lib/site-url.ts +102 -48
- package/templates/nextblock-template/package.json +14 -1
- package/templates/nextblock-template/public/assets/nextblock-banner.jpg +0 -0
package/templates/nextblock-template/components/blocks/renderers/ProductDetailsBlockRenderer.tsx
CHANGED
|
@@ -1,92 +1,157 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import { ProductDetailsLayout } from '@nextblock-cms/ecommerce/components/ProductDetailsLayout';
|
|
3
|
-
import type { VisualEditAttributes, VisualEditingDocumentContext } from '../../../lib/visual-editing/types';
|
|
4
|
-
import {
|
|
5
|
-
import
|
|
6
|
-
import
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
if (
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
.
|
|
60
|
-
.
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { ProductDetailsLayout } from '@nextblock-cms/ecommerce/components/ProductDetailsLayout';
|
|
3
|
+
import type { VisualEditAttributes, VisualEditingDocumentContext } from '../../../lib/visual-editing/types';
|
|
4
|
+
import { headers } from 'next/headers';
|
|
5
|
+
import { createClient } from "@nextblock-cms/db/server";
|
|
6
|
+
import { getProviderReadiness } from "@nextblock-cms/ecommerce/server";
|
|
7
|
+
import BlockRenderer from "../../BlockRenderer";
|
|
8
|
+
import ProductReviewsSection from "../../ProductReviewsSection";
|
|
9
|
+
import ContactSellerSection from "../../ContactSellerSection";
|
|
10
|
+
import PaymentReadinessBoundary from "../../commerce/PaymentReadinessBoundary";
|
|
11
|
+
|
|
12
|
+
interface ProductDetailsBlockRendererProps {
|
|
13
|
+
visualEditAttributes?: VisualEditAttributes;
|
|
14
|
+
productVisualEditingEnabled?: boolean;
|
|
15
|
+
excludeProductId?: string;
|
|
16
|
+
languageId: number;
|
|
17
|
+
visualEditing?: VisualEditingDocumentContext;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export default async function ProductDetailsBlockRenderer({
|
|
21
|
+
visualEditAttributes,
|
|
22
|
+
productVisualEditingEnabled = false,
|
|
23
|
+
excludeProductId,
|
|
24
|
+
languageId,
|
|
25
|
+
visualEditing,
|
|
26
|
+
}: ProductDetailsBlockRendererProps) {
|
|
27
|
+
const supabase = createClient();
|
|
28
|
+
|
|
29
|
+
let descriptionBlocks: any[] = [];
|
|
30
|
+
let productSlug = "";
|
|
31
|
+
let productDraftId: number | null = null;
|
|
32
|
+
// Default to purchasable: a store that is set up correctly must never be degraded by
|
|
33
|
+
// a lookup that failed for some unrelated reason.
|
|
34
|
+
let canPurchase = true;
|
|
35
|
+
|
|
36
|
+
if (excludeProductId) {
|
|
37
|
+
const { data: productInfo } = await supabase
|
|
38
|
+
.from('products')
|
|
39
|
+
.select('slug, payment_provider')
|
|
40
|
+
.eq('id', excludeProductId)
|
|
41
|
+
.maybeSingle();
|
|
42
|
+
|
|
43
|
+
if (productInfo) {
|
|
44
|
+
productSlug = productInfo.slug;
|
|
45
|
+
|
|
46
|
+
const provider = productInfo.payment_provider;
|
|
47
|
+
if (provider === 'stripe' || provider === 'freemius') {
|
|
48
|
+
try {
|
|
49
|
+
const readiness = await getProviderReadiness(provider);
|
|
50
|
+
canPurchase = readiness.ready;
|
|
51
|
+
} catch (error) {
|
|
52
|
+
console.error('[ProductDetails] Could not resolve payment readiness:', error);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
if (productVisualEditingEnabled) {
|
|
58
|
+
const { data: draftData } = await supabase
|
|
59
|
+
.from('product_drafts')
|
|
60
|
+
.select('id, blocks')
|
|
61
|
+
.eq('product_id', excludeProductId)
|
|
62
|
+
.maybeSingle();
|
|
63
|
+
|
|
64
|
+
if (draftData) {
|
|
65
|
+
productDraftId = draftData.id;
|
|
66
|
+
if (draftData.blocks && Array.isArray(draftData.blocks)) {
|
|
67
|
+
descriptionBlocks = draftData.blocks;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
if (descriptionBlocks.length === 0) {
|
|
73
|
+
const { data: liveBlocks } = await supabase
|
|
74
|
+
.from('blocks')
|
|
75
|
+
.select('*')
|
|
76
|
+
.eq('product_id', excludeProductId)
|
|
77
|
+
.order('order', { ascending: true });
|
|
78
|
+
descriptionBlocks = liveBlocks || [];
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const productDescriptionVisualEditing = {
|
|
83
|
+
enabled: productVisualEditingEnabled,
|
|
84
|
+
documentType: "product" as const,
|
|
85
|
+
documentId: excludeProductId!,
|
|
86
|
+
slug: productSlug,
|
|
87
|
+
languageId: languageId,
|
|
88
|
+
draftId: productDraftId,
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
// Bot protection for the enquiry form, resolved the same way BlockRenderer does for
|
|
92
|
+
// the contact-form block. Only read when the form will actually render.
|
|
93
|
+
let botProtection: { provider: 'none' | 'turnstile' | 'recaptcha'; siteKey: string } = {
|
|
94
|
+
provider: 'none',
|
|
95
|
+
siteKey: '',
|
|
96
|
+
};
|
|
97
|
+
let scriptNonce = '';
|
|
98
|
+
|
|
99
|
+
if (!canPurchase && excludeProductId) {
|
|
100
|
+
try {
|
|
101
|
+
scriptNonce = (await headers()).get('x-nonce') || '';
|
|
102
|
+
} catch (error) {
|
|
103
|
+
console.error('[Bot Protection] Error loading CSP nonce in ProductDetails:', error);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
try {
|
|
107
|
+
const { data: publicSetting } = await supabase
|
|
108
|
+
.from('site_settings')
|
|
109
|
+
.select('value')
|
|
110
|
+
.eq('key', 'bot_protection_public')
|
|
111
|
+
.maybeSingle();
|
|
112
|
+
if (publicSetting?.value) {
|
|
113
|
+
const publicVal = publicSetting.value as Record<string, any>;
|
|
114
|
+
botProtection = {
|
|
115
|
+
provider: publicVal.provider || 'none',
|
|
116
|
+
siteKey: publicVal.siteKey || '',
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
} catch (error) {
|
|
120
|
+
console.error('[Bot Protection] Error loading settings in ProductDetails:', error);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
const descriptionNode = descriptionBlocks.length > 0 ? (
|
|
125
|
+
<BlockRenderer
|
|
126
|
+
blocks={descriptionBlocks}
|
|
127
|
+
languageId={languageId}
|
|
128
|
+
productVisualEditingEnabled={productVisualEditingEnabled}
|
|
129
|
+
visualEditing={productDescriptionVisualEditing}
|
|
130
|
+
/>
|
|
131
|
+
) : undefined;
|
|
132
|
+
|
|
133
|
+
// Only resolved when actually needed — a working store pays nothing for this.
|
|
134
|
+
const purchaseFallbackNode =
|
|
135
|
+
!canPurchase && excludeProductId ? (
|
|
136
|
+
<ContactSellerSection
|
|
137
|
+
productId={excludeProductId}
|
|
138
|
+
botProtectionProvider={botProtection.provider}
|
|
139
|
+
botProtectionSiteKey={botProtection.siteKey}
|
|
140
|
+
scriptNonce={scriptNonce}
|
|
141
|
+
/>
|
|
142
|
+
) : undefined;
|
|
143
|
+
|
|
144
|
+
return (
|
|
145
|
+
<div {...visualEditAttributes}>
|
|
146
|
+
<PaymentReadinessBoundary>
|
|
147
|
+
<ProductDetailsLayout
|
|
148
|
+
visualEditingEnabled={productVisualEditingEnabled}
|
|
149
|
+
descriptionNode={descriptionNode}
|
|
150
|
+
reviewsNode={excludeProductId ? <ProductReviewsSection productId={excludeProductId} /> : undefined}
|
|
151
|
+
canPurchase={canPurchase}
|
|
152
|
+
purchaseFallbackNode={purchaseFallbackNode}
|
|
153
|
+
/>
|
|
154
|
+
</PaymentReadinessBoundary>
|
|
155
|
+
</div>
|
|
156
|
+
);
|
|
157
|
+
}
|
package/templates/nextblock-template/components/blocks/renderers/ProductGridBlockRenderer.tsx
CHANGED
|
@@ -1,31 +1,34 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import
|
|
3
|
-
import
|
|
4
|
-
import type {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import PaymentReadinessBoundary from '../../commerce/PaymentReadinessBoundary';
|
|
3
|
+
import { ProductGridBlock } from '../../../lib/blocks/ProductGridBlock';
|
|
4
|
+
import type { ProductGridBlockContent } from '../../../lib/blocks/ecommerce-block-schemas';
|
|
5
|
+
import type { VisualEditAttributes } from '../../../lib/visual-editing/types';
|
|
6
|
+
|
|
7
|
+
interface ProductGridBlockRendererProps {
|
|
8
|
+
content: ProductGridBlockContent;
|
|
9
|
+
languageId: number;
|
|
10
|
+
excludeProductId?: string;
|
|
11
|
+
excludeTranslationGroupId?: string | null;
|
|
12
|
+
visualEditAttributes?: VisualEditAttributes;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export default function ProductGridBlockRenderer({
|
|
16
|
+
content,
|
|
17
|
+
languageId,
|
|
18
|
+
excludeProductId,
|
|
19
|
+
excludeTranslationGroupId,
|
|
20
|
+
visualEditAttributes,
|
|
21
|
+
}: ProductGridBlockRendererProps) {
|
|
22
|
+
return (
|
|
23
|
+
<div {...visualEditAttributes}>
|
|
24
|
+
<PaymentReadinessBoundary>
|
|
25
|
+
<ProductGridBlock
|
|
26
|
+
content={content}
|
|
27
|
+
languageId={languageId}
|
|
28
|
+
excludeProductId={excludeProductId}
|
|
29
|
+
excludeTranslationGroupId={excludeTranslationGroupId}
|
|
30
|
+
/>
|
|
31
|
+
</PaymentReadinessBoundary>
|
|
32
|
+
</div>
|
|
33
|
+
);
|
|
34
|
+
}
|