@wix/ditto-codegen-public 1.0.66 → 1.0.68

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.
@@ -0,0 +1,13 @@
1
+ # Wix Astro Blank Template
2
+
3
+ Our Astro templates are still in development and subject to change.
4
+
5
+ To use a template, follow the [Wix CLI for Headless Quick Start](https://dev.wix.com/docs/go-headless/develop-your-project/wix-managed-headless/get-started/quick-start), and select the desired template during the setup process.
6
+
7
+ ## Need help?
8
+
9
+ For documentation and support, check out:
10
+
11
+ - [Wix Headless Documentation](https://dev.wix.com/docs/go-headless)
12
+ - [Wix SDK Documentation](https://dev.wix.com/docs/sdk)
13
+ - [Community on Discord](https://discord.gg/n6TBrSnYTp)
@@ -0,0 +1,44 @@
1
+ {
2
+ "name": "my-custom-app",
3
+ "type": "module",
4
+ "version": "1.0.0",
5
+ "scripts": {
6
+ "astro": "astro",
7
+ "dev": "wix dev",
8
+ "build": "wix build",
9
+ "wix": "wix",
10
+ "preview": "wix preview",
11
+ "release": "wix release",
12
+ "generate": "wix generate",
13
+ "env": "wix env pull"
14
+ },
15
+ "dependencies": {
16
+ "@wix/app-management": "^1.0.122",
17
+ "@wix/astro": "^2.10.1",
18
+ "@wix/crm": "^1.0.1071",
19
+ "@wix/dashboard": "^1.3.36",
20
+ "@wix/data": "^1.0.290",
21
+ "@wix/essentials": "^0.1.23",
22
+ "@wix/sdk": "^1.15.23",
23
+ "@wix/stores": "^1.0.533",
24
+ "astro": "^5.8.0",
25
+ "typescript": "^5.8.3",
26
+ "@wix/design-system": "^1.217.0",
27
+ "@wix/ecom": "^1.0.1354",
28
+ "@wix/wix-ui-icons-common": "^3.90.0",
29
+ "@wix/auto-patterns": "^1.40.0",
30
+ "@wix/patterns": "^1.290.0",
31
+ "@wix/site-site": "^1.26.0",
32
+ "react-router-dom": "^6.0.0"
33
+ },
34
+ "devDependencies": {
35
+ "@astrojs/cloudflare": "^12.5.3",
36
+ "@astrojs/react": "^4.3.0",
37
+ "@types/react": "^18.3.1",
38
+ "@types/react-dom": "^18.3.1",
39
+ "@wix/cli": "^1.1.125",
40
+ "react": "18.3.1",
41
+ "react-dom": "18.3.1"
42
+ }
43
+ }
44
+
@@ -0,0 +1,135 @@
1
+ import { type FC } from 'react';
2
+ import {
3
+ Input,
4
+ InputArea,
5
+ Card,
6
+ FormField,
7
+ ToggleSwitch,
8
+ NumberInput,
9
+ Box,
10
+ type FormFieldProps,
11
+ } from '@wix/design-system';
12
+ import type { CartPopupOptions } from '../dashboard/pages/cart-popup-manager/page';
13
+
14
+ interface Props {
15
+ options: CartPopupOptions;
16
+ onChange: (options: CartPopupOptions) => void;
17
+ }
18
+
19
+ export const CartPopupSettings: FC<Props> = ({ options, onChange }) => {
20
+ const getFieldStatus = (
21
+ field: keyof CartPopupOptions,
22
+ required: boolean = false
23
+ ): Partial<FormFieldProps> => {
24
+ return required && !options[field]
25
+ ? {
26
+ status: 'error',
27
+ statusMessage: 'Required.',
28
+ }
29
+ : {};
30
+ };
31
+
32
+ return (
33
+ <Box direction="vertical" gap="24px">
34
+ <Card>
35
+ <Card.Header
36
+ title="Popup Content"
37
+ subtitle="Configure the text and coupon code displayed in the popup"
38
+ />
39
+ <Card.Divider />
40
+ <Card.Content>
41
+ <Box gap="18px" direction="vertical">
42
+ <FormField
43
+ label="Coupon Code"
44
+ required
45
+ {...getFieldStatus('couponCode', true)}
46
+ >
47
+ <Input
48
+ placeholder="SAVE20"
49
+ value={options.couponCode}
50
+ onChange={(e) =>
51
+ onChange({
52
+ ...options,
53
+ couponCode: e.currentTarget.value,
54
+ })
55
+ }
56
+ />
57
+ </FormField>
58
+
59
+ <FormField
60
+ label="Popup Headline"
61
+ required
62
+ {...getFieldStatus('popupHeadline', true)}
63
+ >
64
+ <Input
65
+ placeholder="Special Offer!"
66
+ value={options.popupHeadline}
67
+ onChange={(e) =>
68
+ onChange({
69
+ ...options,
70
+ popupHeadline: e.currentTarget.value,
71
+ })
72
+ }
73
+ />
74
+ </FormField>
75
+
76
+ <FormField
77
+ label="Popup Description"
78
+ required
79
+ {...getFieldStatus('popupDescription', true)}
80
+ >
81
+ <InputArea
82
+ placeholder="Apply this coupon to get a discount on your cart!"
83
+ value={options.popupDescription}
84
+ onChange={(e) =>
85
+ onChange({
86
+ ...options,
87
+ popupDescription: e.currentTarget.value,
88
+ })
89
+ }
90
+ rows={3}
91
+ />
92
+ </FormField>
93
+ </Box>
94
+ </Card.Content>
95
+ </Card>
96
+
97
+ <Card>
98
+ <Card.Header
99
+ title="Display Settings"
100
+ subtitle="Configure when and how the popup appears"
101
+ />
102
+ <Card.Divider />
103
+ <Card.Content>
104
+ <Box gap="18px" direction="vertical">
105
+ <FormField label="Enable Popup">
106
+ <ToggleSwitch
107
+ checked={options.enablePopup}
108
+ onChange={() =>
109
+ onChange({
110
+ ...options,
111
+ enablePopup: !options.enablePopup,
112
+ })
113
+ }
114
+ />
115
+ </FormField>
116
+
117
+ <FormField label="Minimum Cart Value">
118
+ <NumberInput
119
+ value={options.minimumCartValue}
120
+ onChange={(value) =>
121
+ onChange({
122
+ ...options,
123
+ minimumCartValue: value || 0,
124
+ })
125
+ }
126
+ min={0}
127
+ prefix="$"
128
+ />
129
+ </FormField>
130
+ </Box>
131
+ </Card.Content>
132
+ </Card>
133
+ </Box>
134
+ );
135
+ };
@@ -0,0 +1,7 @@
1
+ import * as extensions from '@wix/astro/builders';
2
+ export const dashboardpagecartPopupManager = extensions.backofficePage({
3
+ "id": "3304e8b7-4d5c-4719-86bb-68f6235a4bc5",
4
+ "title": "Cart Popup Manager",
5
+ "routePath": "cart-popup-manager",
6
+ "component": "./dashboard/pages/cart-popup-manager/page.tsx"
7
+ })
@@ -0,0 +1,133 @@
1
+ import { useEffect, useState, type FC } from 'react';
2
+ import { dashboard } from '@wix/dashboard';
3
+ import { embeddedScripts } from '@wix/app-management';
4
+ import {
5
+ Button,
6
+ Page,
7
+ Layout,
8
+ Cell,
9
+ Loader,
10
+ Box,
11
+ } from '@wix/design-system';
12
+ import '@wix/design-system/styles.global.css';
13
+ import withProviders from '../../withProviders';
14
+ import { CartPopupSettings } from '../../../components/cart-popup-settings';
15
+
16
+ export type CartPopupOptions = {
17
+ couponCode: string;
18
+ popupHeadline: string;
19
+ popupDescription: string;
20
+ minimumCartValue: number;
21
+ enablePopup: boolean;
22
+ };
23
+
24
+ const cartPopupDefaultOptions: CartPopupOptions = {
25
+ couponCode: '',
26
+ popupHeadline: 'Special Offer!',
27
+ popupDescription: 'Apply this coupon to get a discount on your cart!',
28
+ minimumCartValue: 0,
29
+ enablePopup: true,
30
+ };
31
+
32
+ const CartPopupManagerPage: FC = () => {
33
+ const [options, setOptions] = useState<CartPopupOptions>(cartPopupDefaultOptions);
34
+ const [isLoading, setIsLoading] = useState(true);
35
+ const [isSaving, setIsSaving] = useState(false);
36
+
37
+ useEffect(() => {
38
+ const loadSettings = async () => {
39
+ try {
40
+ const embeddedScript = await embeddedScripts.getEmbeddedScript();
41
+ const data = embeddedScript.parameters as Partial<Record<keyof CartPopupOptions, string>> || {};
42
+
43
+ setOptions((prev) => ({
44
+ ...prev,
45
+ couponCode: data?.couponCode || prev.couponCode,
46
+ popupHeadline: data?.popupHeadline || prev.popupHeadline,
47
+ popupDescription: data?.popupDescription || prev.popupDescription,
48
+ minimumCartValue: Number(data?.minimumCartValue) || prev.minimumCartValue,
49
+ enablePopup: data?.enablePopup === 'true' ? true : data?.enablePopup === 'false' ? false : prev.enablePopup,
50
+ }));
51
+ } catch (error) {
52
+ console.error('Failed to load settings:', error);
53
+ } finally {
54
+ setIsLoading(false);
55
+ }
56
+ };
57
+
58
+ loadSettings();
59
+ }, []);
60
+
61
+ const handleSave = async () => {
62
+ if (!options.couponCode || !options.popupHeadline || !options.popupDescription) {
63
+ dashboard.showToast({
64
+ message: 'Please fill in all required fields',
65
+ type: 'error',
66
+ });
67
+ return;
68
+ }
69
+
70
+ setIsSaving(true);
71
+ try {
72
+ // Convert all values to strings for embedded script parameters
73
+ await embeddedScripts.embedScript({
74
+ parameters: {
75
+ couponCode: options.couponCode,
76
+ popupHeadline: options.popupHeadline,
77
+ popupDescription: options.popupDescription,
78
+ minimumCartValue: String(options.minimumCartValue),
79
+ enablePopup: String(options.enablePopup),
80
+ },
81
+ });
82
+
83
+ dashboard.showToast({
84
+ message: 'Cart popup settings saved successfully!',
85
+ type: 'success',
86
+ });
87
+ } catch (error) {
88
+ console.error('Failed to save settings:', error);
89
+ dashboard.showToast({
90
+ message: 'Failed to save settings. Please try again.',
91
+ type: 'error',
92
+ });
93
+ } finally {
94
+ setIsSaving(false);
95
+ }
96
+ };
97
+
98
+ return (
99
+ <Page height="100vh">
100
+ <Page.Header
101
+ title="Cart Popup Manager"
102
+ subtitle="Configure your cart popup's content, coupon code, and display rules"
103
+ actionsBar={
104
+ <Button
105
+ skin="inverted"
106
+ disabled={!options.couponCode || !options.popupHeadline || !options.popupDescription || isSaving}
107
+ onClick={handleSave}
108
+ >
109
+ {isSaving ? 'Saving...' : 'Save'}
110
+ </Button>
111
+ }
112
+ />
113
+ <Page.Content>
114
+ {isLoading ? (
115
+ <Box align="center" verticalAlign="middle" height="50vh">
116
+ <Loader text="Loading cart popup settings..." />
117
+ </Box>
118
+ ) : (
119
+ <Layout gap="24px">
120
+ <Cell span={12}>
121
+ <CartPopupSettings
122
+ options={options}
123
+ onChange={setOptions}
124
+ />
125
+ </Cell>
126
+ </Layout>
127
+ )}
128
+ </Page.Content>
129
+ </Page>
130
+ );
131
+ };
132
+
133
+ export default withProviders(CartPopupManagerPage);
@@ -0,0 +1,16 @@
1
+ import React from 'react';
2
+ import { WixDesignSystemProvider } from '@wix/design-system';
3
+ import { i18n } from '@wix/essentials';
4
+
5
+ export default function withProviders<P extends {} = {}>(Component: React.FC<P>) {
6
+ return function DashboardProviders(props: P) {
7
+ const locale = i18n.getLocale();
8
+ return (
9
+ <WixDesignSystemProvider locale={locale} features={{ newColorsBranding: true }}>
10
+ <Component {...props} />
11
+ </WixDesignSystemProvider>
12
+ );
13
+ };
14
+ }
15
+
16
+ export { withProviders };
@@ -0,0 +1,12 @@
1
+ import { app } from '@wix/astro/builders';
2
+ import * as allExtensions from './index';
3
+
4
+ // Get all exported extensions
5
+ const extensionList = Object.values(allExtensions);
6
+
7
+ const appBuilder = app();
8
+ extensionList.forEach(extension => {
9
+ appBuilder.use(extension);
10
+ });
11
+
12
+ export default appBuilder;
@@ -0,0 +1,2 @@
1
+ export * from './site/embedded-scripts/cart-coupon-popup/extensions.ts';
2
+ export * from './dashboard/pages/cart-popup-manager/extensions.ts';
@@ -0,0 +1,562 @@
1
+ <div
2
+ id="popup-config"
3
+ data-coupon-code="{{couponCode}}"
4
+ data-popup-headline="{{popupHeadline}}"
5
+ data-popup-description="{{popupDescription}}"
6
+ data-minimum-cart-value="{{minimumCartValue}}"
7
+ data-enable-popup="{{enablePopup}}"
8
+ ></div>
9
+ <div id="cart-coupon-popup-container"></div>
10
+
11
+ <style>
12
+ .cart-coupon-popup {
13
+ position: fixed;
14
+ top: 0;
15
+ left: 0;
16
+ right: 0;
17
+ bottom: 0;
18
+ z-index: 10000;
19
+ background-color: rgba(0, 0, 0, 0.5);
20
+ display: flex;
21
+ justify-content: center;
22
+ align-items: center;
23
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
24
+ backdrop-filter: blur(4px);
25
+ }
26
+
27
+ .cart-coupon-popup.hidden {
28
+ display: none;
29
+ }
30
+
31
+ .popup-content {
32
+ max-width: 500px;
33
+ width: 90%;
34
+ max-height: 80vh;
35
+ overflow-y: auto;
36
+ border-radius: 12px;
37
+ box-shadow: 0 20px 40px rgba(0, 0, 0, 0.3);
38
+ position: relative;
39
+ animation: popupSlideIn 0.3s ease-out;
40
+ background-color: #FFFFFF;
41
+ }
42
+
43
+ @keyframes popupSlideIn {
44
+ from {
45
+ opacity: 0;
46
+ transform: scale(0.9) translateY(-20px);
47
+ }
48
+ to {
49
+ opacity: 1;
50
+ transform: scale(1) translateY(0);
51
+ }
52
+ }
53
+
54
+ .popup-header {
55
+ padding: 24px 24px 16px;
56
+ border-bottom: 1px solid rgba(0, 0, 0, 0.1);
57
+ position: relative;
58
+ }
59
+
60
+ .close-button {
61
+ position: absolute;
62
+ top: 16px;
63
+ right: 16px;
64
+ background: none;
65
+ border: none;
66
+ font-size: 24px;
67
+ cursor: pointer;
68
+ color: #666;
69
+ padding: 4px;
70
+ border-radius: 4px;
71
+ transition: all 0.2s ease;
72
+ }
73
+
74
+ .close-button:hover {
75
+ background-color: rgba(0, 0, 0, 0.1);
76
+ color: #333;
77
+ }
78
+
79
+ .popup-headline {
80
+ margin: 0 0 8px 0;
81
+ font-size: 24px;
82
+ font-weight: 700;
83
+ color: #333;
84
+ }
85
+
86
+ .popup-description {
87
+ margin: 0;
88
+ font-size: 16px;
89
+ color: #666;
90
+ line-height: 1.5;
91
+ }
92
+
93
+ .cart-section {
94
+ padding: 20px 24px;
95
+ border-bottom: 1px solid rgba(0, 0, 0, 0.1);
96
+ }
97
+
98
+ .cart-title {
99
+ margin: 0 0 16px 0;
100
+ font-size: 18px;
101
+ font-weight: 600;
102
+ color: #333;
103
+ }
104
+
105
+ .cart-items {
106
+ max-height: 200px;
107
+ overflow-y: auto;
108
+ }
109
+
110
+ .cart-item {
111
+ display: flex;
112
+ align-items: center;
113
+ padding: 12px 0;
114
+ border-bottom: 1px solid rgba(0, 0, 0, 0.05);
115
+ }
116
+
117
+ .cart-item:last-child {
118
+ border-bottom: none;
119
+ }
120
+
121
+ .item-details {
122
+ flex: 1;
123
+ }
124
+
125
+ .item-name {
126
+ font-weight: 600;
127
+ color: #333;
128
+ margin: 0 0 4px 0;
129
+ font-size: 14px;
130
+ }
131
+
132
+ .item-price {
133
+ color: #666;
134
+ font-size: 14px;
135
+ margin: 0;
136
+ }
137
+
138
+ .item-quantity {
139
+ color: #888;
140
+ font-size: 12px;
141
+ margin-left: 12px;
142
+ }
143
+
144
+ .cart-total {
145
+ margin-top: 16px;
146
+ padding-top: 16px;
147
+ border-top: 2px solid rgba(0, 0, 0, 0.1);
148
+ text-align: right;
149
+ }
150
+
151
+ .total-label {
152
+ font-size: 18px;
153
+ font-weight: 700;
154
+ color: #333;
155
+ }
156
+
157
+ .empty-cart {
158
+ text-align: center;
159
+ color: #888;
160
+ font-style: italic;
161
+ padding: 20px 0;
162
+ }
163
+
164
+ .coupon-section {
165
+ padding: 20px 24px;
166
+ }
167
+
168
+ .coupon-code {
169
+ background-color: #f8f9fa;
170
+ border: 2px dashed #007bff;
171
+ border-radius: 8px;
172
+ padding: 16px;
173
+ text-align: center;
174
+ margin: 16px 0;
175
+ }
176
+
177
+ .coupon-code-text {
178
+ font-family: 'Courier New', monospace;
179
+ font-size: 20px;
180
+ font-weight: 700;
181
+ color: #007bff;
182
+ margin: 0 0 8px 0;
183
+ }
184
+
185
+ .coupon-hint {
186
+ font-size: 12px;
187
+ color: #666;
188
+ margin: 0;
189
+ }
190
+
191
+ .action-buttons {
192
+ display: flex;
193
+ gap: 12px;
194
+ margin-top: 20px;
195
+ }
196
+
197
+ .btn {
198
+ width: 100%;
199
+ padding: 12px 20px;
200
+ border: none;
201
+ border-radius: 6px;
202
+ font-size: 16px;
203
+ font-weight: 600;
204
+ cursor: pointer;
205
+ transition: all 0.2s ease;
206
+ }
207
+
208
+ .btn-primary {
209
+ background-color: #007bff;
210
+ color: white;
211
+ }
212
+
213
+ .btn-primary:hover {
214
+ background-color: #0056b3;
215
+ transform: translateY(-1px);
216
+ }
217
+
218
+ .footer-options {
219
+ padding: 16px 24px;
220
+ background-color: #f8f9fa;
221
+ border-top: 1px solid rgba(0, 0, 0, 0.1);
222
+ border-radius: 0 0 12px 12px;
223
+ }
224
+
225
+ .dont-show-again {
226
+ display: flex;
227
+ align-items: center;
228
+ font-size: 14px;
229
+ color: #666;
230
+ }
231
+
232
+ .dont-show-again input {
233
+ margin-right: 8px;
234
+ }
235
+
236
+ .loading {
237
+ text-align: center;
238
+ padding: 40px 20px;
239
+ color: #666;
240
+ }
241
+
242
+ .error {
243
+ text-align: center;
244
+ padding: 20px;
245
+ color: #dc3545;
246
+ background-color: #f8d7da;
247
+ border-radius: 6px;
248
+ margin: 16px 0;
249
+ }
250
+
251
+ @media (max-width: 480px) {
252
+ .popup-content {
253
+ width: 95%;
254
+ margin: 20px;
255
+ }
256
+
257
+ .popup-header {
258
+ padding: 20px 20px 16px;
259
+ }
260
+
261
+ .cart-section,
262
+ .coupon-section {
263
+ padding: 16px 20px;
264
+ }
265
+
266
+ .action-buttons {
267
+ flex-direction: column;
268
+ }
269
+ }
270
+ </style>
271
+
272
+ <script type="module">
273
+ import { currentCart } from '@wix/ecom';
274
+
275
+ // Get configuration from data attributes
276
+ const config = document.getElementById('popup-config');
277
+ if (!config) throw new Error('Config element not found');
278
+
279
+ const {
280
+ couponCode,
281
+ popupHeadline,
282
+ popupDescription,
283
+ minimumCartValue,
284
+ enablePopup
285
+ } = config.dataset;
286
+
287
+ // Exit early if popup is disabled
288
+ if (enablePopup !== 'true') {
289
+ throw new Error('Popup disabled');
290
+ }
291
+
292
+ const container = document.getElementById('cart-coupon-popup-container');
293
+ if (!container) throw new Error('Container element not found');
294
+
295
+ let popupElement = null;
296
+ let cart = null;
297
+ let isLoading = false;
298
+
299
+ // Storage key for popup display control
300
+ const STORAGE_KEY_DONT_SHOW = 'cart-coupon-popup-dont-show';
301
+
302
+ // Check if popup should be shown
303
+ function shouldShowPopup() {
304
+ const dontShow = localStorage.getItem(STORAGE_KEY_DONT_SHOW);
305
+ console.log('dontShow',dontShow)
306
+ return dontShow !== 'true';
307
+ }
308
+
309
+
310
+ // Create popup HTML structure
311
+ function createPopupElement() {
312
+ const popup = document.createElement('div');
313
+ popup.className = 'cart-coupon-popup hidden';
314
+
315
+ popup.innerHTML = `
316
+ <div class="popup-content">
317
+ <div class="popup-header">
318
+ <button class="close-button" id="close-popup">&times;</button>
319
+ <h2 class="popup-headline">${escapeHtml(popupHeadline || 'Special Offer!')}</h2>
320
+ <p class="popup-description">${escapeHtml(popupDescription || 'Apply this coupon to get a discount on your cart!')}</p>
321
+ </div>
322
+
323
+ <div class="cart-section">
324
+ <h3 class="cart-title">Your Cart</h3>
325
+ <div id="cart-content">
326
+ <div class="loading">Loading cart...</div>
327
+ </div>
328
+ </div>
329
+
330
+ <div class="coupon-section">
331
+ <div class="coupon-code">
332
+ <div class="coupon-code-text">${escapeHtml(couponCode)}</div>
333
+ <p class="coupon-hint">Click to copy this coupon code</p>
334
+ </div>
335
+
336
+ <div class="action-buttons">
337
+ <button class="btn btn-primary" id="dismiss-popup">Close</button>
338
+ </div>
339
+ </div>
340
+
341
+ <div class="footer-options">
342
+ <label class="dont-show-again">
343
+ <input type="checkbox" id="dont-show-again">
344
+ Don't show this popup again
345
+ </label>
346
+ </div>
347
+ </div>
348
+ `;
349
+
350
+ return popup;
351
+ }
352
+
353
+ // Escape HTML to prevent XSS
354
+ function escapeHtml(text) {
355
+ const div = document.createElement('div');
356
+ div.textContent = text;
357
+ return div.innerHTML;
358
+ }
359
+
360
+ // Load current cart using Wix eCommerce API
361
+ async function loadCurrentCart() {
362
+ try {
363
+ isLoading = true;
364
+
365
+ // Get current cart
366
+ const currentCartData = await currentCart.getCurrentCart();
367
+ cart = currentCartData;
368
+
369
+ return currentCartData;
370
+ } catch (error) {
371
+ console.error('Failed to load cart:', error);
372
+ throw error;
373
+ } finally {
374
+ isLoading = false;
375
+ }
376
+ }
377
+
378
+
379
+ // Render cart items in the popup
380
+ function renderCartContent(cartData) {
381
+ const cartContent = document.getElementById('cart-content');
382
+ if (!cartContent) return;
383
+
384
+ if (!cartData || !cartData.lineItems || cartData.lineItems.length === 0) {
385
+ cartContent.innerHTML = '<div class="empty-cart">Your cart is empty</div>';
386
+ return;
387
+ }
388
+
389
+ const cartItemsHtml = cartData.lineItems.map(item => {
390
+ const itemName = item.productName?.original || 'Unknown Item';
391
+ const itemPrice = item.price?.formattedAmount || '$0.00';
392
+ const quantity = item.quantity || 1;
393
+
394
+ return `
395
+ <div class="cart-item">
396
+ <div class="item-details">
397
+ <div class="item-name">${escapeHtml(itemName)}</div>
398
+ <div class="item-price">${escapeHtml(itemPrice)}</div>
399
+ </div>
400
+ <div class="item-quantity">Qty: ${quantity}</div>
401
+ </div>
402
+ `;
403
+ }).join('');
404
+
405
+ // Calculate total (use subtotal if available, otherwise sum line items)
406
+ const totalAmount = cartData.subtotal?.formattedAmount ||
407
+ cartData.lineItems.reduce((sum, item) => {
408
+ const price = parseFloat(item.price?.amount || '0');
409
+ return sum + (price * (item.quantity || 1));
410
+ }, 0).toFixed(2);
411
+
412
+ cartContent.innerHTML = `
413
+ <div class="cart-items">
414
+ ${cartItemsHtml}
415
+ </div>
416
+ <div class="cart-total">
417
+ <div class="total-label">Total: ${typeof totalAmount === 'string' ? totalAmount : '$' + totalAmount}</div>
418
+ </div>
419
+ `;
420
+ }
421
+
422
+ // Check if cart meets minimum value requirement
423
+ function meetsMinimumValue(cartData) {
424
+ const minValue = parseFloat(minimumCartValue || '0');
425
+ if (minValue <= 0) return true;
426
+
427
+ if (!cartData || !cartData.lineItems || cartData.lineItems.length === 0) {
428
+ return false;
429
+ }
430
+
431
+ const cartValue = parseFloat(cartData.subtotal?.amount || '0');
432
+ return cartValue >= minValue;
433
+ }
434
+
435
+ // Show the popup
436
+ function showPopup() {
437
+ if (popupElement) {
438
+ popupElement.classList.remove('hidden');
439
+ }
440
+ }
441
+
442
+ // Hide the popup
443
+ function hidePopup(dontShowAgain = false) {
444
+ if (popupElement) {
445
+ popupElement.classList.add('hidden');
446
+ }
447
+
448
+ if (dontShowAgain) {
449
+ localStorage.setItem(STORAGE_KEY_DONT_SHOW, 'true');
450
+ }
451
+ }
452
+
453
+ // Handle coupon code click (copy to clipboard)
454
+ function handleCouponCodeClick() {
455
+ if (navigator.clipboard && navigator.clipboard.writeText) {
456
+ navigator.clipboard.writeText(couponCode).then(() => {
457
+ // Show temporary feedback
458
+ const codeElement = document.querySelector('.coupon-code-text');
459
+ if (codeElement) {
460
+ const originalText = codeElement.textContent;
461
+ codeElement.textContent = 'Copied!';
462
+ setTimeout(() => {
463
+ codeElement.textContent = originalText;
464
+ }, 1500);
465
+ }
466
+ }).catch(err => {
467
+ console.warn('Failed to copy coupon code:', err);
468
+ });
469
+ }
470
+ }
471
+
472
+ // Set up event listeners
473
+ function setupEventListeners() {
474
+ if (!popupElement) return;
475
+
476
+ // Close button
477
+ const closeBtn = popupElement.querySelector('#close-popup');
478
+ if (closeBtn) {
479
+ closeBtn.addEventListener('click', () => hidePopup());
480
+ }
481
+
482
+ // Dismiss button
483
+ const dismissBtn = popupElement.querySelector('#dismiss-popup');
484
+ if (dismissBtn) {
485
+ dismissBtn.addEventListener('click', () => {
486
+ const dontShowCheckbox = popupElement.querySelector('#dont-show-again');
487
+ const dontShow = dontShowCheckbox && dontShowCheckbox.checked;
488
+ hidePopup(dontShow);
489
+ });
490
+ }
491
+
492
+ // Coupon code click to copy
493
+ const couponCodeElement = popupElement.querySelector('.coupon-code');
494
+ if (couponCodeElement) {
495
+ couponCodeElement.addEventListener('click', handleCouponCodeClick);
496
+ couponCodeElement.style.cursor = 'pointer';
497
+ }
498
+
499
+ // Click outside to close
500
+ popupElement.addEventListener('click', (e) => {
501
+ if (e.target === popupElement) {
502
+ hidePopup();
503
+ }
504
+ });
505
+
506
+ // Escape key to close
507
+ document.addEventListener('keydown', (e) => {
508
+ if (e.key === 'Escape' && !popupElement.classList.contains('hidden')) {
509
+ hidePopup();
510
+ }
511
+ });
512
+ }
513
+
514
+ // Initialize the popup
515
+ async function initializePopup() {
516
+ try {
517
+ // Check if popup should be shown
518
+ if (!shouldShowPopup()) {
519
+ return;
520
+ }
521
+
522
+ // Create popup element
523
+ popupElement = createPopupElement();
524
+ container.appendChild(popupElement);
525
+
526
+ // Set up event listeners
527
+ setupEventListeners();
528
+
529
+ // Load cart data
530
+ const cartData = await loadCurrentCart();
531
+
532
+ // Check if cart meets minimum value requirement
533
+ if (!meetsMinimumValue(cartData)) {
534
+ return;
535
+ }
536
+
537
+ // Render cart content
538
+ renderCartContent(cartData);
539
+
540
+ // Show popup with a slight delay for better UX
541
+ setTimeout(() => {
542
+ showPopup();
543
+ }, 1000);
544
+
545
+ } catch (error) {
546
+ console.error('Failed to initialize cart coupon popup:', error);
547
+
548
+ // Show error state in popup if it exists
549
+ const cartContent = document.getElementById('cart-content');
550
+ if (cartContent) {
551
+ cartContent.innerHTML = '<div class="error">Failed to load cart. Please try again later.</div>';
552
+ }
553
+ }
554
+ }
555
+
556
+ // Start initialization when DOM is ready
557
+ if (document.readyState === 'loading') {
558
+ document.addEventListener('DOMContentLoaded', initializePopup);
559
+ } else {
560
+ initializePopup();
561
+ }
562
+ </script>
@@ -0,0 +1,8 @@
1
+ import * as extensions from '@wix/astro/builders';
2
+ export const embeddedscriptcartCouponPopup = extensions.embeddedScript({
3
+ "id": "dbdbfc9a-23d0-45f8-9cb7-4b9c357d366f",
4
+ "name": "Cart & Coupon Popup",
5
+ "source": "./site/embedded-scripts/cart-coupon-popup/embedded.html",
6
+ "placement": "BODY_END",
7
+ "scriptType": "FUNCTIONAL"
8
+ })
@@ -0,0 +1,10 @@
1
+ {
2
+ "extends": "astro/tsconfigs/strictest",
3
+ "compilerOptions": {
4
+ "jsx": "react-jsx",
5
+ "jsxImportSource": "react"
6
+ },
7
+ "include": [".astro/types.d.ts", "**/*"],
8
+ "exclude": ["dist"]
9
+ }
10
+
@@ -0,0 +1,4 @@
1
+ {
2
+ "appId": "7295bc1a-9a7b-4e62-bcd9-78f628dac739",
3
+ "siteId": "0e5795fd-bfa2-417a-995d-2daed0462a55"
4
+ }
package/dist/out.js CHANGED
@@ -120327,7 +120327,7 @@ var require_utils14 = __commonJS({
120327
120327
  content: zod_1.z.string().describe("Complete file content as a string (for JSON files, stringify the object). Required for insert and update operations.").optional()
120328
120328
  });
120329
120329
  exports2.FileSchema = zod_1.z.object({
120330
- files: zod_1.z.array(exports2.FileItemSchema).default([])
120330
+ files: zod_1.z.array(exports2.FileItemSchema).default([]).describe("An array of files")
120331
120331
  });
120332
120332
  var withCaching = (ttl = "5m") => {
120333
120333
  return {
@@ -120643,6 +120643,20 @@ var require_load_examples = __commonJS({
120643
120643
  "contact-created-logger/src/backend/events/contact-created-logger/event.ts"
120644
120644
  ]
120645
120645
  }
120646
+ },
120647
+ CouponPopup: {
120648
+ path: "coupon-popup",
120649
+ description: "A marketing app that displays a configurable coupon popup in the shopping cart, with a dashboard interface for managing popup settings and an embedded script to show the popup on the site",
120650
+ files: {
120651
+ [types.DashboardPage]: [
120652
+ "coupon-popup/src/dashboard/pages/cart-popup-manager/page.tsx",
120653
+ "coupon-popup/src/dashboard/withProviders.tsx",
120654
+ "coupon-popup/src/components/cart-popup-settings.tsx"
120655
+ ],
120656
+ [types.EmbeddedScript]: [
120657
+ "coupon-popup/src/site/embedded-scripts/cart-coupon-popup/embedded.html"
120658
+ ]
120659
+ }
120646
120660
  }
120647
120661
  };
120648
120662
  exports2.examples = {
@@ -120651,6 +120665,7 @@ var require_load_examples = __commonJS({
120651
120665
  appsExamples.SurveyManager,
120652
120666
  appsExamples.EventCountdown,
120653
120667
  appsExamples.SitePopup,
120668
+ appsExamples.CouponPopup,
120654
120669
  appsExamples.AIChatbot,
120655
120670
  appsExamples.CustomProductsCatalog,
120656
120671
  appsExamples.MixPanelAnalystic,
@@ -120662,6 +120677,7 @@ var require_load_examples = __commonJS({
120662
120677
  [types.EmbeddedScript]: [
120663
120678
  appsExamples.MixPanelAnalystic,
120664
120679
  appsExamples.SitePopup,
120680
+ appsExamples.CouponPopup,
120665
120681
  appsExamples.EventCountdown
120666
120682
  ],
120667
120683
  [types.ServicePluginExtension]: [appsExamples.SPISExample],
@@ -120752,7 +120768,7 @@ ${examples}
120752
120768
  const userMessage = (0, utils_1.buildUserPromptForCodeGenerationAgent)(params, primaryAction);
120753
120769
  const model = (0, anthropic_1.createAnthropic)({
120754
120770
  apiKey: this.apiKey
120755
- })("claude-sonnet-4-20250514");
120771
+ })("claude-sonnet-4-5-20250929");
120756
120772
  const result = await (0, ai_1.generateObject)({
120757
120773
  model,
120758
120774
  schema: utils_1.FileSchema,
@@ -124982,7 +124998,7 @@ var require_SiteComponentAgent = __commonJS({
124982
124998
  const appName = blueprint?.appName ? `'${blueprint.appName}'` : "";
124983
124999
  const primaryAction = `Customize the Wix CLI site component scaffolding for the app ${appName}`;
124984
125000
  const userMessage = (0, utils_1.buildUserPromptForCodeGenerationAgent)(params, primaryAction);
124985
- const model = (0, anthropic_1.createAnthropic)({ apiKey: this.apiKey })("claude-sonnet-4-20250514");
125001
+ const model = (0, anthropic_1.createAnthropic)({ apiKey: this.apiKey })("claude-sonnet-4-5-20250929");
124986
125002
  const result = await (0, ai_1.generateObject)({
124987
125003
  model,
124988
125004
  schema: utils_1.FileSchema,
@@ -125131,7 +125147,7 @@ ${examples}
125131
125147
  const appName = blueprint?.appName ? `'${blueprint.appName}'` : "";
125132
125148
  const primaryAction = `Customize backend event scaffolding for the app ${appName}`;
125133
125149
  const userMessage = (0, utils_1.buildUserPromptForCodeGenerationAgent)(params, primaryAction);
125134
- const model = (0, anthropic_1.createAnthropic)({ apiKey: this.apiKey })("claude-sonnet-4-20250514");
125150
+ const model = (0, anthropic_1.createAnthropic)({ apiKey: this.apiKey })("claude-sonnet-4-5-20250929");
125135
125151
  const result = await (0, ai_1.generateObject)({
125136
125152
  model,
125137
125153
  schema: utils_1.FileSchema,
@@ -125275,7 +125291,7 @@ var require_BackendApiAgent = __commonJS({
125275
125291
  const systemPrompt = this.buildSystemPrompt();
125276
125292
  const primaryAction = `Create Astro Server Endpoints for the app ${blueprint?.appName}`;
125277
125293
  const userMessage = (0, utils_1.buildUserPromptForCodeGenerationAgent)(params, primaryAction);
125278
- const model = (0, anthropic_1.createAnthropic)({ apiKey: this.apiKey })("claude-sonnet-4-20250514");
125294
+ const model = (0, anthropic_1.createAnthropic)({ apiKey: this.apiKey })("claude-sonnet-4-5-20250929");
125279
125295
  const result = await (0, ai_1.generateObject)({
125280
125296
  model,
125281
125297
  schema: utils_1.FileSchema,
@@ -125719,7 +125735,7 @@ var require_CustomElementAgent = __commonJS({
125719
125735
  const appName = blueprint?.appName ? `'${blueprint.appName}'` : "";
125720
125736
  const primaryAction = `Customize the Wix CLI custom element / site widget scaffolding for the app ${appName}`;
125721
125737
  const userMessage = (0, utils_1.buildUserPromptForCodeGenerationAgent)(params, primaryAction);
125722
- const model = (0, anthropic_1.createAnthropic)({ apiKey: this.apiKey })("claude-sonnet-4-20250514");
125738
+ const model = (0, anthropic_1.createAnthropic)({ apiKey: this.apiKey })("claude-sonnet-4-5-20250929");
125723
125739
  const result = await (0, ai_1.generateObject)({
125724
125740
  model,
125725
125741
  schema: utils_1.FileSchema,
@@ -127282,7 +127298,7 @@ ${examples}
127282
127298
  const appName = blueprint?.appName ? `'${blueprint.appName}'` : "";
127283
127299
  const primaryAction = `Customize the Wix CLI dashboard page scaffolding for the app ${appName}`;
127284
127300
  const userMessage = (0, utils_1.buildUserPromptForCodeGenerationAgent)(params, primaryAction);
127285
- const model = (0, anthropic_1.createAnthropic)({ apiKey: this.apiKey })("claude-sonnet-4-20250514");
127301
+ const model = (0, anthropic_1.createAnthropic)({ apiKey: this.apiKey })("claude-sonnet-4-5-20250929");
127286
127302
  const result = await (0, ai_1.generateObject)({
127287
127303
  model,
127288
127304
  schema: utils_1.FileSchema,
@@ -128473,7 +128489,7 @@ ${examples}
128473
128489
  const appName = blueprint?.appName ? `'${blueprint.appName}'` : "";
128474
128490
  const primaryAction = `Customize the Wix CLI embedded script scaffolding for the app ${appName}`;
128475
128491
  const userMessage = (0, utils_1.buildUserPromptForCodeGenerationAgent)(params, primaryAction);
128476
- const model = (0, anthropic_1.createAnthropic)({ apiKey: this.apiKey })("claude-sonnet-4-20250514");
128492
+ const model = (0, anthropic_1.createAnthropic)({ apiKey: this.apiKey })("claude-sonnet-4-5-20250929");
128477
128493
  const result = await (0, ai_1.generateObject)({
128478
128494
  model,
128479
128495
  schema: exports2.EmbeddedScriptSchema,
@@ -128852,7 +128868,7 @@ CURRENT FILE CONTENT:
128852
128868
  ${input.content}
128853
128869
 
128854
128870
  Please provide the complete fixed file content that resolves ALL the errors listed above.`;
128855
- const model = (0, anthropic_1.createAnthropic)({ apiKey: this.apiKey })("claude-sonnet-4-20250514");
128871
+ const model = (0, anthropic_1.createAnthropic)({ apiKey: this.apiKey })("claude-sonnet-4-5-20250929");
128856
128872
  try {
128857
128873
  const result = await (0, ai_1.generateObject)({
128858
128874
  model,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wix/ditto-codegen-public",
3
- "version": "1.0.66",
3
+ "version": "1.0.68",
4
4
  "description": "AI-powered Wix CLI app generator - standalone executable",
5
5
  "scripts": {
6
6
  "build": "node build.mjs",
@@ -24,5 +24,5 @@
24
24
  "@wix/ditto-codegen": "1.0.0",
25
25
  "esbuild": "^0.25.9"
26
26
  },
27
- "falconPackageHash": "ccdf783fad507eccb98247f2632438eb41c1753aec8f47dabb8001c0"
27
+ "falconPackageHash": "4ae2b155dff127877e1ed91ec5694d71bc9239525a1b59c397705bd8"
28
28
  }