@shopify/ui-extensions 2026.1.1 → 2026.1.2

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 (182) hide show
  1. package/build/cjs/surfaces/checkout/preact/metafield.js +1 -0
  2. package/build/cjs/surfaces/checkout/preact/metafields.js +1 -0
  3. package/build/esm/surfaces/checkout/preact/metafield.mjs +1 -0
  4. package/build/esm/surfaces/checkout/preact/metafields.mjs +1 -0
  5. package/build/esnext/surfaces/checkout/preact/metafield.esnext +1 -0
  6. package/build/esnext/surfaces/checkout/preact/metafields.esnext +1 -0
  7. package/build/ts/surfaces/admin/api/action/action.doc.d.ts.map +1 -1
  8. package/build/ts/surfaces/admin/api/block/block.doc.d.ts.map +1 -1
  9. package/build/ts/surfaces/admin/api/checkout-rules/validation-settings.doc.d.ts.map +1 -1
  10. package/build/ts/surfaces/admin/api/customer-segment-template/customer-segment-template.doc.d.ts.map +1 -1
  11. package/build/ts/surfaces/admin/api/discount-function-settings/discount-function-settings.doc.d.ts.map +1 -1
  12. package/build/ts/surfaces/admin/api/intents/intents.doc.d.ts.map +1 -1
  13. package/build/ts/surfaces/admin/api/order-routing-rule/order-routing-rule.doc.d.ts.map +1 -1
  14. package/build/ts/surfaces/admin/api/picker/picker.doc.d.ts.map +1 -1
  15. package/build/ts/surfaces/admin/api/print-action/print-action.doc.d.ts.map +1 -1
  16. package/build/ts/surfaces/admin/api/product-configuration/product-details-configuration.doc.d.ts.map +1 -1
  17. package/build/ts/surfaces/admin/api/product-configuration/product-variant-details-configuration.doc.d.ts.map +1 -1
  18. package/build/ts/surfaces/admin/api/purchase-options-card-action.doc.d.ts.map +1 -1
  19. package/build/ts/surfaces/admin/api/resource-picker/resource-picker.doc.d.ts.map +1 -1
  20. package/build/ts/surfaces/admin/api/should-render/should-render.doc.d.ts.map +1 -1
  21. package/build/ts/surfaces/admin/api/standard/standard.doc.d.ts.map +1 -1
  22. package/build/ts/surfaces/admin/api/standard/storage.d.ts +1 -1
  23. package/build/ts/surfaces/admin/extension-targets.d.ts +1 -1
  24. package/build/ts/surfaces/checkout/api/address-autocomplete/standard.d.ts +5 -0
  25. package/build/ts/surfaces/checkout/api/address-autocomplete/standard.d.ts.map +1 -1
  26. package/build/ts/surfaces/checkout/api/standard/standard.d.ts +4 -2
  27. package/build/ts/surfaces/checkout/api/standard/standard.d.ts.map +1 -1
  28. package/build/ts/surfaces/checkout/preact/metafield.d.ts +1 -0
  29. package/build/ts/surfaces/checkout/preact/metafield.d.ts.map +1 -1
  30. package/build/ts/surfaces/checkout/preact/metafields.d.ts +1 -0
  31. package/build/ts/surfaces/checkout/preact/metafields.d.ts.map +1 -1
  32. package/build/ts/surfaces/point-of-sale/components/Badge/Badge.doc.d.ts.map +1 -1
  33. package/build/ts/surfaces/point-of-sale/components/EmptyState.d.ts +44 -34
  34. package/build/ts/surfaces/point-of-sale/components/Icon/Icon.doc.d.ts.map +1 -1
  35. package/build/ts/surfaces/point-of-sale/components/Image/Image.doc.d.ts.map +1 -1
  36. package/build/ts/surfaces/point-of-sale/components/Link/Link.doc.d.ts.map +1 -1
  37. package/build/ts/surfaces/point-of-sale/components/Modal/Modal.doc.d.ts.map +1 -1
  38. package/build/ts/surfaces/point-of-sale/components/Page/Page.doc.d.ts.map +1 -1
  39. package/build/ts/surfaces/point-of-sale/components/Stack/Stack.doc.d.ts.map +1 -1
  40. package/build/ts/surfaces/point-of-sale/components/Stack.d.ts +10 -10
  41. package/build/ts/surfaces/point-of-sale/components/Tabs/Tabs.doc.d.ts.map +1 -1
  42. package/build/ts/surfaces/point-of-sale/components/Text/Text.doc.d.ts.map +1 -1
  43. package/build/ts/surfaces/point-of-sale/components/TextField.d.ts +1 -1
  44. package/build/ts/surfaces/point-of-sale/components/Tile/Tile.doc.d.ts.map +1 -1
  45. package/build/ts/surfaces/point-of-sale/components/components-shared.d.ts +3249 -2916
  46. package/build/tsconfig.tsbuildinfo +1 -1
  47. package/package.json +1 -1
  48. package/src/surfaces/admin/api/action/examples/handle-errors.jsx +47 -0
  49. package/src/surfaces/admin/api/action/examples/process-selected-products.jsx +33 -0
  50. package/src/surfaces/admin/api/action/examples/select-additional-resources.jsx +46 -0
  51. package/src/surfaces/admin/api/block/examples/display-product-info.jsx +46 -0
  52. package/src/surfaces/admin/api/block/examples/navigate-to-action.jsx +50 -0
  53. package/src/surfaces/admin/api/block/examples/select-related-products.jsx +46 -0
  54. package/src/surfaces/admin/api/checkout-rules/examples/configure-shipping-restrictions.jsx +52 -0
  55. package/src/surfaces/admin/api/checkout-rules/examples/load-validation-config.jsx +55 -0
  56. package/src/surfaces/admin/api/checkout-rules/examples/set-minimum-quantity.jsx +40 -0
  57. package/src/surfaces/admin/api/customer-segment-template/examples/abandoned-cart-recovery.jsx +30 -0
  58. package/src/surfaces/admin/api/customer-segment-template/examples/birthday-this-month.jsx +32 -0
  59. package/src/surfaces/admin/api/customer-segment-template/examples/high-value-customers.jsx +27 -0
  60. package/src/surfaces/admin/api/discount-function-settings/examples/configure-discount-threshold.jsx +39 -0
  61. package/src/surfaces/admin/api/discount-function-settings/examples/configure-eligibility-rules.jsx +45 -0
  62. package/src/surfaces/admin/api/discount-function-settings/examples/load-existing-settings.jsx +45 -0
  63. package/src/surfaces/admin/api/intents/examples/create-article.jsx +35 -0
  64. package/src/surfaces/admin/api/intents/examples/create-catalog.jsx +35 -0
  65. package/src/surfaces/admin/api/intents/examples/create-collection.jsx +35 -0
  66. package/src/surfaces/admin/api/intents/examples/create-customer.jsx +35 -0
  67. package/src/surfaces/admin/api/intents/examples/create-discount.jsx +35 -0
  68. package/src/surfaces/admin/api/intents/examples/create-market.jsx +35 -0
  69. package/src/surfaces/admin/api/intents/examples/create-menu.jsx +35 -0
  70. package/src/surfaces/admin/api/intents/examples/create-metafield-definition.jsx +35 -0
  71. package/src/surfaces/admin/api/intents/examples/create-metaobject-definition.jsx +35 -0
  72. package/src/surfaces/admin/api/intents/examples/create-metaobject.jsx +35 -0
  73. package/src/surfaces/admin/api/intents/examples/create-page.jsx +35 -0
  74. package/src/surfaces/admin/api/intents/examples/create-product.jsx +37 -0
  75. package/src/surfaces/admin/api/intents/examples/create-variant.jsx +35 -0
  76. package/src/surfaces/admin/api/intents/examples/edit-article.jsx +41 -0
  77. package/src/surfaces/admin/api/intents/examples/edit-catalog.jsx +41 -0
  78. package/src/surfaces/admin/api/intents/examples/edit-collection.jsx +41 -0
  79. package/src/surfaces/admin/api/intents/examples/edit-customer.jsx +41 -0
  80. package/src/surfaces/admin/api/intents/examples/edit-discount.jsx +41 -0
  81. package/src/surfaces/admin/api/intents/examples/edit-market.jsx +41 -0
  82. package/src/surfaces/admin/api/intents/examples/edit-menu.jsx +41 -0
  83. package/src/surfaces/admin/api/intents/examples/edit-metafield-definition.jsx +41 -0
  84. package/src/surfaces/admin/api/intents/examples/edit-metaobject-definition.jsx +41 -0
  85. package/src/surfaces/admin/api/intents/examples/edit-metaobject.jsx +41 -0
  86. package/src/surfaces/admin/api/intents/examples/edit-page.jsx +41 -0
  87. package/src/surfaces/admin/api/intents/examples/edit-product.jsx +41 -0
  88. package/src/surfaces/admin/api/intents/examples/edit-variant.jsx +41 -0
  89. package/src/surfaces/admin/api/order-routing-rule/examples/configure-location-priority.jsx +46 -0
  90. package/src/surfaces/admin/api/order-routing-rule/examples/remove-deprecated-settings.jsx +35 -0
  91. package/src/surfaces/admin/api/order-routing-rule/examples/set-routing-criteria.jsx +57 -0
  92. package/src/surfaces/admin/api/picker/examples/direct-api.jsx +42 -0
  93. package/src/surfaces/admin/api/picker/examples/disabled.jsx +23 -0
  94. package/src/surfaces/admin/api/picker/examples/minimal.jsx +37 -0
  95. package/src/surfaces/admin/api/picker/examples/multiple-limit.jsx +26 -0
  96. package/src/surfaces/admin/api/picker/examples/multiple-true.jsx +25 -0
  97. package/src/surfaces/admin/api/picker/examples/preselected.jsx +23 -0
  98. package/src/surfaces/admin/api/picker/examples/template-picker.jsx +58 -0
  99. package/src/surfaces/admin/api/print-action/examples/custom-product-labels.jsx +44 -0
  100. package/src/surfaces/admin/api/print-action/examples/generate-packing-slip.jsx +28 -0
  101. package/src/surfaces/admin/api/print-action/examples/shipping-manifest.jsx +58 -0
  102. package/src/surfaces/admin/api/product-configuration/examples/create-variant-component.jsx +56 -0
  103. package/src/surfaces/admin/api/product-configuration/examples/load-bundle-config.jsx +47 -0
  104. package/src/surfaces/admin/api/product-configuration/examples/load-variant-bundle-config.jsx +54 -0
  105. package/src/surfaces/admin/api/product-configuration/examples/navigate-to-component.jsx +27 -0
  106. package/src/surfaces/admin/api/product-configuration/examples/select-bundle-components.jsx +50 -0
  107. package/src/surfaces/admin/api/product-configuration/examples/select-variant-components.jsx +50 -0
  108. package/src/surfaces/admin/api/purchase-options-card/examples/manage-subscription.jsx +45 -0
  109. package/src/surfaces/admin/api/purchase-options-card/examples/remove-from-plan.jsx +44 -0
  110. package/src/surfaces/admin/api/purchase-options-card/examples/validate-selling-plan.jsx +47 -0
  111. package/src/surfaces/admin/api/resource-picker/examples/action.jsx +25 -0
  112. package/src/surfaces/admin/api/resource-picker/examples/collection-picker.jsx +22 -0
  113. package/src/surfaces/admin/api/resource-picker/examples/filter-query.jsx +22 -0
  114. package/src/surfaces/admin/api/resource-picker/examples/filters.jsx +27 -0
  115. package/src/surfaces/admin/api/resource-picker/examples/multiple-limited.jsx +25 -0
  116. package/src/surfaces/admin/api/resource-picker/examples/multiple-unlimited.jsx +25 -0
  117. package/src/surfaces/admin/api/resource-picker/examples/product-picker.jsx +22 -0
  118. package/src/surfaces/admin/api/resource-picker/examples/product-variant-picker.jsx +22 -0
  119. package/src/surfaces/admin/api/resource-picker/examples/query.jsx +25 -0
  120. package/src/surfaces/admin/api/resource-picker/examples/selection-ids.jsx +28 -0
  121. package/src/surfaces/admin/api/resource-picker/examples/selection.jsx +22 -0
  122. package/src/surfaces/admin/api/should-render/examples/bulk-selection-check.jsx +8 -0
  123. package/src/surfaces/admin/api/should-render/examples/check-order-status.jsx +7 -0
  124. package/src/surfaces/admin/api/should-render/examples/check-product-tag.jsx +7 -0
  125. package/src/surfaces/admin/api/standard/examples/authenticate-backend-request.jsx +40 -0
  126. package/src/surfaces/admin/api/standard/examples/persist-settings.jsx +43 -0
  127. package/src/surfaces/admin/api/standard/examples/query-and-mutate.jsx +75 -0
  128. package/src/surfaces/admin/api/standard/storage.ts +1 -1
  129. package/src/surfaces/admin/extension-targets.ts +1 -1
  130. package/src/surfaces/checkout/api/address-autocomplete/standard.ts +5 -0
  131. package/src/surfaces/checkout/api/standard/standard.ts +4 -2
  132. package/src/surfaces/checkout/preact/metafield.ts +1 -0
  133. package/src/surfaces/checkout/preact/metafields.ts +1 -0
  134. package/src/surfaces/point-of-sale/components/EmptyState.d.ts +44 -34
  135. package/src/surfaces/point-of-sale/components/Stack.d.ts +10 -10
  136. package/src/surfaces/point-of-sale/components/TextField.d.ts +1 -1
  137. package/src/surfaces/point-of-sale/components/components-shared.d.ts +3249 -2916
  138. package/src/surfaces/point-of-sale/components.d.ts +6504 -5829
  139. package/src/surfaces/admin/api/intents/examples/create-article.js +0 -9
  140. package/src/surfaces/admin/api/intents/examples/create-catalog.js +0 -9
  141. package/src/surfaces/admin/api/intents/examples/create-collection.js +0 -9
  142. package/src/surfaces/admin/api/intents/examples/create-customer.js +0 -9
  143. package/src/surfaces/admin/api/intents/examples/create-discount.js +0 -11
  144. package/src/surfaces/admin/api/intents/examples/create-market.js +0 -9
  145. package/src/surfaces/admin/api/intents/examples/create-menu.js +0 -9
  146. package/src/surfaces/admin/api/intents/examples/create-metafield-definition.js +0 -11
  147. package/src/surfaces/admin/api/intents/examples/create-metaobject-definition.js +0 -9
  148. package/src/surfaces/admin/api/intents/examples/create-metaobject.js +0 -11
  149. package/src/surfaces/admin/api/intents/examples/create-page.js +0 -9
  150. package/src/surfaces/admin/api/intents/examples/create-product.js +0 -9
  151. package/src/surfaces/admin/api/intents/examples/create-variant.js +0 -11
  152. package/src/surfaces/admin/api/intents/examples/edit-article.js +0 -11
  153. package/src/surfaces/admin/api/intents/examples/edit-catalog.js +0 -11
  154. package/src/surfaces/admin/api/intents/examples/edit-collection.js +0 -11
  155. package/src/surfaces/admin/api/intents/examples/edit-customer.js +0 -11
  156. package/src/surfaces/admin/api/intents/examples/edit-discount.js +0 -11
  157. package/src/surfaces/admin/api/intents/examples/edit-market.js +0 -11
  158. package/src/surfaces/admin/api/intents/examples/edit-menu.js +0 -11
  159. package/src/surfaces/admin/api/intents/examples/edit-metafield-definition.js +0 -12
  160. package/src/surfaces/admin/api/intents/examples/edit-metaobject-definition.js +0 -11
  161. package/src/surfaces/admin/api/intents/examples/edit-metaobject.js +0 -12
  162. package/src/surfaces/admin/api/intents/examples/edit-page.js +0 -11
  163. package/src/surfaces/admin/api/intents/examples/edit-product.js +0 -11
  164. package/src/surfaces/admin/api/intents/examples/edit-variant.js +0 -12
  165. package/src/surfaces/admin/api/picker/examples/direct-api.js +0 -73
  166. package/src/surfaces/admin/api/picker/examples/disabled.js +0 -16
  167. package/src/surfaces/admin/api/picker/examples/minimal.js +0 -16
  168. package/src/surfaces/admin/api/picker/examples/multiple-limit.js +0 -21
  169. package/src/surfaces/admin/api/picker/examples/multiple-true.js +0 -21
  170. package/src/surfaces/admin/api/picker/examples/preselected.js +0 -16
  171. package/src/surfaces/admin/api/picker/examples/template-picker.js +0 -37
  172. package/src/surfaces/admin/api/resource-picker/examples/action.js +0 -4
  173. package/src/surfaces/admin/api/resource-picker/examples/collection-picker.js +0 -1
  174. package/src/surfaces/admin/api/resource-picker/examples/filter-query.js +0 -6
  175. package/src/surfaces/admin/api/resource-picker/examples/filters.js +0 -9
  176. package/src/surfaces/admin/api/resource-picker/examples/multiple-limited.js +0 -4
  177. package/src/surfaces/admin/api/resource-picker/examples/multiple-unlimited.js +0 -4
  178. package/src/surfaces/admin/api/resource-picker/examples/product-picker.js +0 -3
  179. package/src/surfaces/admin/api/resource-picker/examples/product-variant-picker.js +0 -1
  180. package/src/surfaces/admin/api/resource-picker/examples/query.js +0 -4
  181. package/src/surfaces/admin/api/resource-picker/examples/selection-ids.js +0 -16
  182. package/src/surfaces/admin/api/resource-picker/examples/selection.js +0 -7
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shopify/ui-extensions",
3
- "version": "2026.1.1",
3
+ "version": "2026.1.2",
4
4
  "scripts": {
5
5
  "docs:admin": "node ./docs/surfaces/admin/build-docs.mjs",
6
6
  "docs:checkout": "bash ./docs/surfaces/checkout/build-docs.sh",
@@ -0,0 +1,47 @@
1
+ import {render} from 'preact';
2
+ import {useState} from 'preact/hooks';
3
+
4
+ export default async () => {
5
+ render(<Extension />, document.body);
6
+ };
7
+
8
+ function Extension() {
9
+ const {data} = shopify;
10
+ const [error, setError] = useState(null);
11
+ const [loading, setLoading] = useState(false);
12
+
13
+ const handleFulfill = async () => {
14
+ setLoading(true);
15
+ setError(null);
16
+
17
+ try {
18
+ const orderId = data.selected[0]?.id;
19
+
20
+ const response = await fetch(`/api/orders/${orderId}/fulfill`, {
21
+ method: 'POST',
22
+ });
23
+
24
+ const result = await response.json();
25
+
26
+ if (!response.ok) {
27
+ throw new Error(result.error || 'Fulfillment failed');
28
+ }
29
+
30
+ console.log('Order fulfilled:', result);
31
+ shopify.close();
32
+ } catch (err) {
33
+ setError(err.message);
34
+ } finally {
35
+ setLoading(false);
36
+ }
37
+ };
38
+
39
+ return (
40
+ <s-admin-action title="Fulfill Order">
41
+ {error && <s-banner status="critical">{error}</s-banner>}
42
+ <s-button onClick={handleFulfill} disabled={loading}>
43
+ {loading ? 'Fulfilling...' : 'Fulfill Order'}
44
+ </s-button>
45
+ </s-admin-action>
46
+ );
47
+ }
@@ -0,0 +1,33 @@
1
+ import {render} from 'preact';
2
+
3
+ export default async () => {
4
+ render(<Extension />, document.body);
5
+ };
6
+
7
+ function Extension() {
8
+ const {data} = shopify;
9
+
10
+ const handleProcess = async () => {
11
+ const productIds = data.selected.map((item) => item.id);
12
+
13
+ const response = await fetch('/api/bulk-process', {
14
+ method: 'POST',
15
+ headers: {'Content-Type': 'application/json'},
16
+ body: JSON.stringify({productIds}),
17
+ });
18
+
19
+ if (response.ok) {
20
+ console.log('Products processed successfully');
21
+ shopify.close();
22
+ } else {
23
+ console.error('Failed to process products');
24
+ }
25
+ };
26
+
27
+ return (
28
+ <s-admin-action title="Bulk Process">
29
+ <s-text>Processing {data.selected.length} products</s-text>
30
+ <s-button onClick={handleProcess}>Process Products</s-button>
31
+ </s-admin-action>
32
+ );
33
+ }
@@ -0,0 +1,46 @@
1
+ import {render} from 'preact';
2
+ import {useState} from 'preact/hooks';
3
+
4
+ export default async () => {
5
+ render(<Extension />, document.body);
6
+ };
7
+
8
+ function Extension() {
9
+ const {data} = shopify;
10
+ const [selected, setSelected] = useState(null);
11
+
12
+ const currentProductId = data.selected[0]?.id;
13
+
14
+ const handleSelectProducts = async () => {
15
+ const selectedProducts = await shopify.resourcePicker({
16
+ type: 'product',
17
+ multiple: 5,
18
+ action: 'select',
19
+ });
20
+
21
+ if (selectedProducts) {
22
+ setSelected(selectedProducts);
23
+
24
+ await fetch('/api/create-bundle', {
25
+ method: 'POST',
26
+ headers: {'Content-Type': 'application/json'},
27
+ body: JSON.stringify({
28
+ mainProduct: currentProductId,
29
+ components: selectedProducts.map((p) => p.id),
30
+ }),
31
+ });
32
+
33
+ shopify.close();
34
+ }
35
+ };
36
+
37
+ return (
38
+ <s-admin-action title="Create Bundle">
39
+ <s-text>Main product: {currentProductId}</s-text>
40
+ <s-button onClick={handleSelectProducts}>
41
+ Select Component Products
42
+ </s-button>
43
+ {selected && <s-text>Selected {selected.length} products</s-text>}
44
+ </s-admin-action>
45
+ );
46
+ }
@@ -0,0 +1,46 @@
1
+ import {render} from 'preact';
2
+ import {useState, useEffect} from 'preact/hooks';
3
+
4
+ export default async () => {
5
+ render(<Extension />, document.body);
6
+ };
7
+
8
+ function Extension() {
9
+ const {data} = shopify;
10
+ const [product, setProduct] = useState(null);
11
+
12
+ useEffect(() => {
13
+ const fetchProduct = async () => {
14
+ const productId = data.selected[0]?.id;
15
+
16
+ const {data: productData} = await shopify.query(
17
+ `query GetProduct($id: ID!) {
18
+ product(id: $id) {
19
+ title
20
+ totalInventory
21
+ status
22
+ }
23
+ }`,
24
+ {variables: {id: productId}},
25
+ );
26
+
27
+ setProduct(productData.product);
28
+ };
29
+
30
+ fetchProduct();
31
+ }, [data]);
32
+
33
+ return (
34
+ <s-admin-block heading="Product Information">
35
+ {product ? (
36
+ <>
37
+ <s-text>Title: {product.title}</s-text>
38
+ <s-text>Inventory: {product.totalInventory}</s-text>
39
+ <s-text>Status: {product.status}</s-text>
40
+ </>
41
+ ) : (
42
+ <s-spinner />
43
+ )}
44
+ </s-admin-block>
45
+ );
46
+ }
@@ -0,0 +1,50 @@
1
+ import {render} from 'preact';
2
+ import {useState, useEffect} from 'preact/hooks';
3
+
4
+ export default async () => {
5
+ render(<Extension />, document.body);
6
+ };
7
+
8
+ function Extension() {
9
+ const {data} = shopify;
10
+ const [eligible, setEligible] = useState(false);
11
+ const [checking, setChecking] = useState(true);
12
+
13
+ useEffect(() => {
14
+ const checkEligibility = async () => {
15
+ const productId = data.selected[0]?.id;
16
+
17
+ if (!productId) {
18
+ setChecking(false);
19
+ return;
20
+ }
21
+
22
+ const response = await fetch(`/api/products/${productId}/check-eligibility`, {
23
+ method: 'GET',
24
+ headers: {'Content-Type': 'application/json'},
25
+ });
26
+
27
+ const {eligible} = await response.json();
28
+ setEligible(eligible);
29
+ setChecking(false);
30
+ };
31
+
32
+ checkEligibility();
33
+ }, [data]);
34
+
35
+ const handleNavigate = () => {
36
+ shopify.navigation.navigate('extension://my-product-action-extension-handle');
37
+ };
38
+
39
+ return (
40
+ <s-admin-block heading="Advanced Actions">
41
+ {checking ? (
42
+ <s-spinner />
43
+ ) : eligible ? (
44
+ <s-button onClick={handleNavigate}>Launch Advanced Workflow</s-button>
45
+ ) : (
46
+ <s-text>Product not eligible for advanced actions</s-text>
47
+ )}
48
+ </s-admin-block>
49
+ );
50
+ }
@@ -0,0 +1,46 @@
1
+ import {render} from 'preact';
2
+ import {useState} from 'preact/hooks';
3
+
4
+ export default async () => {
5
+ render(<Extension />, document.body);
6
+ };
7
+
8
+ function Extension() {
9
+ const {data} = shopify;
10
+ const [relatedCount, setRelatedCount] = useState(0);
11
+
12
+ const currentProductId = data.selected[0]?.id;
13
+
14
+ const handleSelectRelated = async () => {
15
+ const selectedProducts = await shopify.resourcePicker({
16
+ type: 'product',
17
+ multiple: true,
18
+ filter: {
19
+ hidden: false,
20
+ draft: false,
21
+ },
22
+ });
23
+
24
+ if (selectedProducts) {
25
+ await fetch('/api/product-recommendations', {
26
+ method: 'POST',
27
+ headers: {'Content-Type': 'application/json'},
28
+ body: JSON.stringify({
29
+ productId: currentProductId,
30
+ relatedProducts: selectedProducts.map((p) => p.id),
31
+ }),
32
+ });
33
+
34
+ setRelatedCount(selectedProducts.length);
35
+ }
36
+ };
37
+
38
+ return (
39
+ <s-admin-block heading="Product Recommendations">
40
+ <s-button onClick={handleSelectRelated}>Select Related Products</s-button>
41
+ {relatedCount > 0 && (
42
+ <s-text>Added {relatedCount} related products</s-text>
43
+ )}
44
+ </s-admin-block>
45
+ );
46
+ }
@@ -0,0 +1,52 @@
1
+ import {render} from 'preact';
2
+ import {useState} from 'preact/hooks';
3
+
4
+ export default async () => {
5
+ render(<Extension />, document.body);
6
+ };
7
+
8
+ function Extension() {
9
+ const {data} = shopify;
10
+ const [countries, setCountries] = useState('US, CA, GB');
11
+ const [errorMsg, setErrorMsg] = useState('Shipping not available to your location');
12
+
13
+ const handleSave = async () => {
14
+ const blockedCountries = countries.split(',').map((c) => c.trim());
15
+
16
+ await shopify.applyMetafieldChange({
17
+ type: 'updateMetafield',
18
+ namespace: 'validation',
19
+ key: 'blocked_shipping_countries',
20
+ value: JSON.stringify(blockedCountries),
21
+ valueType: 'json',
22
+ });
23
+
24
+ await shopify.applyMetafieldChange({
25
+ type: 'updateMetafield',
26
+ namespace: 'validation',
27
+ key: 'error_message',
28
+ value: errorMsg,
29
+ valueType: 'single_line_text_field',
30
+ });
31
+ };
32
+
33
+ return (
34
+ <s-function-settings>
35
+ <s-stack direction="block">
36
+ <s-text-field
37
+ label="Blocked countries (comma-separated)"
38
+ value={countries}
39
+ onChange={(value) => setCountries(value)}
40
+ />
41
+ <s-text-field
42
+ label="Error message"
43
+ value={errorMsg}
44
+ onChange={(value) => setErrorMsg(value)}
45
+ />
46
+ <s-button onClick={handleSave}>Save Restrictions</s-button>
47
+ <s-text>Validation ID: {data.validation?.id}</s-text>
48
+ <s-text>Function ID: {data.shopifyFunction.id}</s-text>
49
+ </s-stack>
50
+ </s-function-settings>
51
+ );
52
+ }
@@ -0,0 +1,55 @@
1
+ import {render} from 'preact';
2
+ import {useState, useEffect} from 'preact/hooks';
3
+
4
+ export default async () => {
5
+ render(<Extension />, document.body);
6
+ };
7
+
8
+ function Extension() {
9
+ const {data} = shopify;
10
+ const [mode, setMode] = useState('loading');
11
+ const [settings, setSettings] = useState({});
12
+
13
+ useEffect(() => {
14
+ const initializeSettings = async () => {
15
+ if (data.validation) {
16
+ const config = data.validation.metafields.reduce((acc, field) => {
17
+ acc[field.key] = field.value;
18
+ return acc;
19
+ }, {});
20
+
21
+ setSettings(config);
22
+ setMode('edit');
23
+ } else {
24
+ await shopify.applyMetafieldChange({
25
+ type: 'updateMetafield',
26
+ namespace: 'validation',
27
+ key: 'default_rule',
28
+ value: 'require_minimum_cart_total',
29
+ valueType: 'single_line_text_field',
30
+ });
31
+
32
+ setMode('created');
33
+ }
34
+ };
35
+
36
+ initializeSettings();
37
+ }, [data]);
38
+
39
+ return (
40
+ <s-function-settings>
41
+ {mode === 'loading' && <s-spinner />}
42
+ {mode === 'edit' && (
43
+ <>
44
+ <s-text>Editing existing validation</s-text>
45
+ {Object.entries(settings).map(([key, value]) => (
46
+ <s-text key={key}>
47
+ {key}: {value}
48
+ </s-text>
49
+ ))}
50
+ </>
51
+ )}
52
+ {mode === 'created' && <s-text>Created new validation configuration</s-text>}
53
+ </s-function-settings>
54
+ );
55
+ }
@@ -0,0 +1,40 @@
1
+ import {render} from 'preact';
2
+ import {useState} from 'preact/hooks';
3
+
4
+ export default async () => {
5
+ render(<Extension />, document.body);
6
+ };
7
+
8
+ function Extension() {
9
+ const [quantity, setQuantity] = useState('3');
10
+ const [result, setResult] = useState(null);
11
+
12
+ const handleSave = async () => {
13
+ const res = await shopify.applyMetafieldChange({
14
+ type: 'updateMetafield',
15
+ namespace: 'validation',
16
+ key: 'minimum_quantity',
17
+ value: quantity,
18
+ valueType: 'number_integer',
19
+ });
20
+
21
+ setResult(res);
22
+ };
23
+
24
+ return (
25
+ <s-function-settings>
26
+ <s-number-field
27
+ label="Minimum quantity"
28
+ value={quantity}
29
+ onChange={(value) => setQuantity(value)}
30
+ />
31
+ <s-button onClick={handleSave}>Save Validation</s-button>
32
+ {result?.type === 'success' && (
33
+ <s-banner status="success">Minimum quantity configured</s-banner>
34
+ )}
35
+ {result?.type === 'error' && (
36
+ <s-banner status="critical">{result.message}</s-banner>
37
+ )}
38
+ </s-function-settings>
39
+ );
40
+ }
@@ -0,0 +1,30 @@
1
+ export default () => {
2
+ return {
3
+ templates: [
4
+ {
5
+ title: 'Cart abandoners',
6
+ description: [
7
+ 'Customers who abandoned carts in the last 7 days',
8
+ 'Use this segment for email recovery campaigns',
9
+ ],
10
+ query: `{
11
+ abandoned_checkouts_count: {
12
+ min: 1
13
+ }
14
+ last_abandoned_order_date: {
15
+ min: "${new Date(Date.now() - 7 * 24 * 60 * 60 * 1000).toISOString()}"
16
+ }
17
+ }`,
18
+ queryToInsert: `{
19
+ abandoned_checkouts_count: {
20
+ min: 1
21
+ }
22
+ last_abandoned_order_date: {
23
+ min: "LAST_7_DAYS"
24
+ }
25
+ }`,
26
+ createdOn: '2025-01-15T00:00:00Z',
27
+ },
28
+ ],
29
+ };
30
+ };
@@ -0,0 +1,32 @@
1
+ export default () => {
2
+ return {
3
+ templates: [
4
+ {
5
+ title: 'Birthday this month',
6
+ description: 'Customers with birthdays in the current month',
7
+ query: `{
8
+ metafields: {
9
+ key: "birth_date"
10
+ namespace: "customer"
11
+ value: {
12
+ month: ${new Date().getMonth() + 1}
13
+ }
14
+ }
15
+ }`,
16
+ queryToInsert: `{
17
+ metafields: {
18
+ key: "birth_date"
19
+ namespace: "customer"
20
+ value: {
21
+ month: ${new Date().getMonth() + 1}
22
+ }
23
+ }
24
+ }`,
25
+ dependencies: {
26
+ standardMetafields: ['facts.birth_date'],
27
+ },
28
+ createdOn: '2025-01-15T00:00:00Z',
29
+ },
30
+ ],
31
+ };
32
+ };
@@ -0,0 +1,27 @@
1
+ export default () => {
2
+ return {
3
+ templates: [
4
+ {
5
+ title: shopify.i18n.translate('templates.highValue.title'),
6
+ description: shopify.i18n.translate('templates.highValue.description'),
7
+ query: `{
8
+ total_spent: {
9
+ min: 500
10
+ }
11
+ orders_count: {
12
+ min: 5
13
+ }
14
+ }`,
15
+ queryToInsert: `{
16
+ total_spent: {
17
+ min: 500
18
+ }
19
+ orders_count: {
20
+ min: 5
21
+ }
22
+ }`,
23
+ createdOn: '2025-01-15T00:00:00Z',
24
+ },
25
+ ],
26
+ };
27
+ };
@@ -0,0 +1,39 @@
1
+ import {render} from 'preact';
2
+ import {useState} from 'preact/hooks';
3
+
4
+ export default async () => {
5
+ render(<Extension />, document.body);
6
+ };
7
+
8
+ function Extension() {
9
+ const [threshold, setThreshold] = useState('50.00');
10
+ const [saved, setSaved] = useState(false);
11
+
12
+ const handleSave = async () => {
13
+ const result = await shopify.applyMetafieldChange({
14
+ type: 'updateMetafield',
15
+ namespace: 'discount-config',
16
+ key: 'minimum_purchase',
17
+ value: threshold,
18
+ valueType: 'number_decimal',
19
+ });
20
+
21
+ if (result.type === 'success') {
22
+ setSaved(true);
23
+ } else {
24
+ console.error('Configuration failed:', result.message);
25
+ }
26
+ };
27
+
28
+ return (
29
+ <s-function-settings>
30
+ <s-text-field
31
+ label="Minimum purchase amount"
32
+ value={threshold}
33
+ onChange={(value) => setThreshold(value)}
34
+ />
35
+ <s-button onClick={handleSave}>Save Threshold</s-button>
36
+ {saved && <s-banner status="success">Threshold configured!</s-banner>}
37
+ </s-function-settings>
38
+ );
39
+ }
@@ -0,0 +1,45 @@
1
+ import {render} from 'preact';
2
+ import {useState} from 'preact/hooks';
3
+
4
+ export default async () => {
5
+ render(<Extension />, document.body);
6
+ };
7
+
8
+ function Extension() {
9
+ const [tags, setTags] = useState('vip, wholesale, premium');
10
+ const [maxUses, setMaxUses] = useState('5');
11
+
12
+ const handleSave = async () => {
13
+ await shopify.applyMetafieldChange({
14
+ type: 'updateMetafield',
15
+ namespace: 'discount-config',
16
+ key: 'eligible_customer_tags',
17
+ value: JSON.stringify(tags.split(',').map((t) => t.trim())),
18
+ valueType: 'json',
19
+ });
20
+
21
+ await shopify.applyMetafieldChange({
22
+ type: 'updateMetafield',
23
+ namespace: 'discount-config',
24
+ key: 'max_uses_per_customer',
25
+ value: maxUses,
26
+ valueType: 'number_integer',
27
+ });
28
+ };
29
+
30
+ return (
31
+ <s-function-settings>
32
+ <s-text-field
33
+ label="Eligible customer tags (comma-separated)"
34
+ value={tags}
35
+ onChange={(value) => setTags(value)}
36
+ />
37
+ <s-number-field
38
+ label="Max uses per customer"
39
+ value={maxUses}
40
+ onChange={(value) => setMaxUses(value)}
41
+ />
42
+ <s-button onClick={handleSave}>Save Eligibility Rules</s-button>
43
+ </s-function-settings>
44
+ );
45
+ }
@@ -0,0 +1,45 @@
1
+ import {render} from 'preact';
2
+ import {useState, useEffect} from 'preact/hooks';
3
+
4
+ export default async () => {
5
+ render(<Extension />, document.body);
6
+ };
7
+
8
+ function Extension() {
9
+ const {data} = shopify;
10
+ const [settings, setSettings] = useState({});
11
+
12
+ useEffect(() => {
13
+ const initializeSettings = async () => {
14
+ const existingSettings = data.metafields.reduce((acc, field) => {
15
+ acc[field.key] = field.value;
16
+ return acc;
17
+ }, {});
18
+
19
+ setSettings(existingSettings);
20
+
21
+ if (!existingSettings.eligible_tags) {
22
+ await shopify.applyMetafieldChange({
23
+ type: 'updateMetafield',
24
+ namespace: 'discount-config',
25
+ key: 'eligible_tags',
26
+ value: JSON.stringify(['vip', 'wholesale']),
27
+ valueType: 'json',
28
+ });
29
+ }
30
+ };
31
+
32
+ initializeSettings();
33
+ }, [data]);
34
+
35
+ return (
36
+ <s-function-settings>
37
+ <s-text>Current settings:</s-text>
38
+ {Object.entries(settings).map(([key, value]) => (
39
+ <s-text key={key}>
40
+ {key}: {String(value)}
41
+ </s-text>
42
+ ))}
43
+ </s-function-settings>
44
+ );
45
+ }
@@ -0,0 +1,35 @@
1
+ import {render} from 'preact';
2
+ import {useState} from 'preact/hooks';
3
+
4
+ export default async () => {
5
+ render(<Extension />, document.body);
6
+ };
7
+
8
+ function Extension() {
9
+ const [result, setResult] = useState(null);
10
+ const [creating, setCreating] = useState(false);
11
+
12
+ const handleCreate = async () => {
13
+ setCreating(true);
14
+
15
+ const activity = await shopify.intents.invoke('create:shopify/Article');
16
+ const response = await activity.complete;
17
+
18
+ setResult(response);
19
+ setCreating(false);
20
+ };
21
+
22
+ return (
23
+ <s-admin-block heading="Create Article">
24
+ <s-button onClick={handleCreate} disabled={creating}>
25
+ {creating ? 'Creating...' : 'Launch Article Creator'}
26
+ </s-button>
27
+ {result?.code === 'ok' && (
28
+ <s-banner status="success">Article created successfully!</s-banner>
29
+ )}
30
+ {result?.code === 'closed' && (
31
+ <s-text>Creation cancelled</s-text>
32
+ )}
33
+ </s-admin-block>
34
+ );
35
+ }