825 lines
19 KiB
Markdown
825 lines
19 KiB
Markdown
You’ve got a solid feature there — the main issue is that your setup is straddling two different eras of the admin UI extensions stack:
|
||
|
||
Your API version 2025-07 + @shopify/ui-extensions-react/admin usage is the old React-based model.
|
||
Your tsconfig.json + shopify.d.ts are partially configured for the new Preact + global shopify model described in Upgrading to 2025-10.
|
||
This mismatch can cause confusing type errors and runtime issues.
|
||
|
||
Below I’ll walk through:
|
||
|
||
What’s “off” in your current setup.
|
||
Two clear paths:
|
||
A. Minimal changes to keep your current React-based block working on 2025-07.
|
||
B. Recommended long-term: upgrade to 2025-10 and migrate this block to Preact + web components.
|
||
1. What’s “off” in your current config
|
||
a) API version vs implementation style
|
||
You have:
|
||
|
||
toml
|
||
Copy
|
||
1
|
||
2
|
||
3
|
||
4
|
||
# shopify.extension.toml
|
||
api_version = "2025-07"
|
||
...
|
||
target = "admin.order-details.block.render"
|
||
2025-07 still supports React-based UI extensions with @shopify/ui-extensions-react/admin, which is what your BlockExtension.jsx is using.
|
||
|
||
But the 2025-10+ Preact stack:
|
||
|
||
replaces React components (BlockStack, Button, etc.) with Polaris web components (<s-stack>, <s-button>, etc.),
|
||
and uses the global shopify object instead of useApi().
|
||
Your BlockExtension.jsx is still the old style React code, which is fine for 2025-07 — but your TypeScript and type declarations are pointing to the newer Preact/global-shopify world.
|
||
|
||
b) Mixing React extensions with Preact hooks
|
||
You’re doing:
|
||
|
||
js
|
||
Copy
|
||
1
|
||
2
|
||
3
|
||
4
|
||
5
|
||
6
|
||
7
|
||
8
|
||
9
|
||
10
|
||
11
|
||
12
|
||
13
|
||
14
|
||
import {
|
||
reactExtension,
|
||
BlockStack,
|
||
InlineStack,
|
||
Text,
|
||
Button,
|
||
Banner,
|
||
Divider,
|
||
Heading,
|
||
Box,
|
||
Link,
|
||
useApi,
|
||
} from '@shopify/ui-extensions-react/admin';
|
||
import { useState, useEffect, useCallback } from 'preact/hooks';
|
||
For React-based extensions, Shopify’s docs expect:
|
||
|
||
reactExtension + React components, and
|
||
Hooks imported from react, not preact/hooks.
|
||
Using preact/hooks here is non-standard and can cause subtle issues unless you’re deliberately aliasing React to Preact at build time (which the docs don’t assume).
|
||
|
||
c) tsconfig.json and shopify.d.ts
|
||
Your tsconfig.json:
|
||
|
||
json
|
||
Copy
|
||
1
|
||
2
|
||
3
|
||
4
|
||
5
|
||
6
|
||
7
|
||
{
|
||
"compilerOptions": {
|
||
"jsx": "react-jsx",
|
||
"jsxImportSource": "preact",
|
||
...
|
||
}
|
||
}
|
||
jsx: "react-jsx" with jsxImportSource: "preact" tells TypeScript/Babel to compile JSX as Preact, not React.
|
||
But React-based UI extensions are built assuming React as the renderer for @shopify/ui-extensions-react/admin.
|
||
Your shopify.d.ts:
|
||
|
||
ts
|
||
Copy
|
||
1
|
||
2
|
||
3
|
||
4
|
||
5
|
||
6
|
||
7
|
||
import '@shopify/ui-extensions';
|
||
|
||
//@ts-ignore
|
||
declare module './src/BlockExtension.jsx' {
|
||
const shopify: import('@shopify/ui-extensions/admin.order-details.block.render').Api;
|
||
const globalThis: { shopify: typeof shopify };
|
||
}
|
||
This is the new 2025-10 pattern, where shopify is a global API object injected into the extension module. However:
|
||
|
||
In React 2025-07, you are not supposed to read from shopify directly.
|
||
Instead, you use useApi() from @shopify/ui-extensions-react/admin.
|
||
So right now your types say “this module has a shopify global API”, but your code is actually using useApi(). That’s just confusing for tooling.
|
||
|
||
2. Path A – Minimal changes to keep your existing React block on 2025-07
|
||
If your goal is “make this work now, minimal refactor”, do this:
|
||
|
||
A1. Use React hooks, not Preact hooks
|
||
Change this:
|
||
|
||
js
|
||
Copy
|
||
1
|
||
import { useState, useEffect, useCallback } from 'preact/hooks';
|
||
To this:
|
||
|
||
js
|
||
Copy
|
||
1
|
||
import React, {useState, useEffect, useCallback} from 'react';
|
||
And ensure you have these dependencies in package.json (versions per Upgrading to 2025-10, but locked to 2025.4 or 2025.7):
|
||
|
||
json
|
||
Copy
|
||
1
|
||
2
|
||
3
|
||
4
|
||
5
|
||
6
|
||
7
|
||
8
|
||
9
|
||
10
|
||
11
|
||
{
|
||
"dependencies": {
|
||
"react": "^18.0.0",
|
||
"@shopify/ui-extensions": "2025.4.x", // or 2025.7.x
|
||
"@shopify/ui-extensions-react": "2025.4.x", // or 2025.7.x
|
||
"react-reconciler": "0.29.0"
|
||
},
|
||
"devDependencies": {
|
||
"@types/react": "^18.0.0"
|
||
}
|
||
}
|
||
A2. Simplify tsconfig.json for React
|
||
For a React-based extension, a simple tsconfig.json in the extension directory is enough:
|
||
|
||
json
|
||
Copy
|
||
1
|
||
2
|
||
3
|
||
4
|
||
5
|
||
6
|
||
7
|
||
8
|
||
9
|
||
10
|
||
11
|
||
12
|
||
{
|
||
"compilerOptions": {
|
||
"jsx": "react-jsx",
|
||
"target": "ES2020",
|
||
"checkJs": true,
|
||
"allowJs": true,
|
||
"moduleResolution": "node",
|
||
"esModuleInterop": true,
|
||
"noEmit": true,
|
||
"skipLibCheck": true
|
||
}
|
||
}
|
||
Remove jsxImportSource: "preact" — you’re not compiling JSX as Preact here.
|
||
A3. Remove the shopify.d.ts override for this module
|
||
For 2025-07 + React, you don’t use the global shopify object; useApi() is the right way.
|
||
|
||
You can delete or comment out this shopify.d.ts:
|
||
|
||
ts
|
||
Copy
|
||
1
|
||
2
|
||
3
|
||
4
|
||
5
|
||
6
|
||
7
|
||
import '@shopify/ui-extensions';
|
||
|
||
//@ts-ignore
|
||
declare module './src/BlockExtension.jsx' {
|
||
const shopify: import('@shopify/ui-extensions/admin.order-details.block.render').Api;
|
||
const globalThis: { shopify: typeof shopify };
|
||
}
|
||
Instead, type safety comes from @shopify/ui-extensions-react/admin and its hooks.
|
||
|
||
A4. Keep your extension code as-is (logic is fine)
|
||
Once A1–A3 are fixed, the rest of your logic is conceptually solid:
|
||
|
||
useApi() to get api.data.selected?.[0]?.id for the order ID.
|
||
api.query(...) to read metafields (hutko/fiscal_receipts, fiscal_info_*, fiscal_storage_*).
|
||
Local helpers openBase64AsBlob and downloadBase64AsFile.
|
||
Rendering a nice stack of receipts.
|
||
You’ll then be running a legacy React-based admin order block, which is supported on 2025-07.
|
||
|
||
3. Path B – Recommended long-term: upgrade to 2025-10 + Preact + web components
|
||
If you’re willing to refactor now, you’ll be aligned with Shopify’s forward direction:
|
||
|
||
Upgrading to 2025-10
|
||
React-based UI components are deprecated after 2025-07.
|
||
Preact + Polaris web components (<s-admin-block>, <s-stack>, <s-banner>, <s-button>, etc.) are the new model.
|
||
At a high level, you would:
|
||
|
||
B1. Update shopify.extension.toml
|
||
toml
|
||
Copy
|
||
1
|
||
2
|
||
3
|
||
4
|
||
5
|
||
6
|
||
7
|
||
8
|
||
9
|
||
10
|
||
11
|
||
12
|
||
13
|
||
14
|
||
api_version = "2025-10"
|
||
|
||
[[extensions]]
|
||
name = "t:name"
|
||
handle = "fiscal-order-block"
|
||
type = "ui_extension"
|
||
uid = "dfc94970-d01c-b839-2220-ffd1b6ab1c86ac3cce4a"
|
||
|
||
[[extensions.targeting]]
|
||
module = "./src/BlockExtension.jsx"
|
||
target = "admin.order-details.block.render"
|
||
|
||
[extensions.capabilities]
|
||
network_access = true
|
||
B2. Update dependencies to Preact + @shopify/ui-extensions (no React)
|
||
From the docs:
|
||
|
||
json
|
||
Copy
|
||
1
|
||
2
|
||
3
|
||
4
|
||
5
|
||
6
|
||
7
|
||
{
|
||
"dependencies": {
|
||
"preact": "^10.10.x",
|
||
"@preact/signals": "^2.3.x",
|
||
"@shopify/ui-extensions": "2025.10.x"
|
||
}
|
||
}
|
||
B3. Keep your current tsconfig.json (it’s already Preact-ready)
|
||
Your current tsconfig.json is already aligned with the Preact model from the upgrade guide:
|
||
|
||
json
|
||
Copy
|
||
1
|
||
2
|
||
3
|
||
4
|
||
5
|
||
6
|
||
7
|
||
8
|
||
9
|
||
10
|
||
11
|
||
12
|
||
13
|
||
{
|
||
"compilerOptions": {
|
||
"jsx": "react-jsx",
|
||
"jsxImportSource": "preact",
|
||
"target": "ES2020",
|
||
"checkJs": true,
|
||
"allowJs": true,
|
||
"moduleResolution": "node",
|
||
"esModuleInterop": true,
|
||
"noEmit": true,
|
||
"skipLibCheck": true
|
||
}
|
||
}
|
||
That’s exactly what Shopify suggests for Preact-based extensions.
|
||
|
||
B4. Rewrite BlockExtension.jsx to:
|
||
Use import '@shopify/ui-extensions/preact'; and render from preact.
|
||
Use Polaris web components instead of React components:
|
||
BlockStack → <s-stack>
|
||
InlineStack → <s-stack direction="inline">
|
||
Box → <s-box>
|
||
Banner → <s-banner>
|
||
Button → <s-button>
|
||
Link → <s-link>
|
||
Divider → <s-divider>
|
||
etc.
|
||
Use the global shopify object instead of useApi():
|
||
const orderId = shopify.data.selected?.[0]?.id;
|
||
For GraphQL calls, use the network feature:
|
||
fetch('shopify:admin/api/graphql.json', { ... }).
|
||
You’d also then use shopify.d.ts to type the global shopify object, but in the new style.
|
||
|
||
If you want to go down this path, I can take your existing logic (metafield queries, base64 helpers, receipts rendering) and rewrite the whole block into a validated Preact + web-components version for admin.order-details.block.render.
|
||
|
||
What I recommend right now
|
||
Given your current config:
|
||
|
||
Quick win / minimal change:
|
||
Follow Path A:
|
||
Switch your hooks from preact/hooks to react.
|
||
Adjust tsconfig.json to be React-oriented.
|
||
Remove the shopify.d.ts global override.
|
||
Ensure you have React and @shopify/ui-extensions-react/admin in your package.json.
|
||
That should get your existing block working reliably on 2025-07.
|
||
|
||
Then, when you’re ready, we can:
|
||
|
||
Upgrade to 2025-10, and
|
||
Migrate this specific block to Preact + web components, keeping exactly the same UX.
|
||
If you tell me which path you want (A: keep React on 2025-07, or B: migrate now to Preact/2025-10), I’ll either:
|
||
|
||
Give you the exact diffs to make your current React block correct, or
|
||
Provide a full Preact + <s-*> implementation of your fiscal receipts block for admin.order-details.block.render and explain the changes line-by-line.
|
||
|
||
|
||
|
||
|
||
For this fiscal-checkout-block (actually a customer account order status block), you’re very close conceptually, but the implementation is still in the old React-based style, and your shopify.extension.toml is pinned to 2025-07, not 2025-10.
|
||
|
||
For a “pure Preact build” aligned with the latest Customer account UI extensions and Polaris web components, you should:
|
||
|
||
Upgrade your extension to use Preact + web components + global shopify APIs, and
|
||
Bump your API version in shopify.extension.toml.
|
||
Below I’ll walk through:
|
||
|
||
What’s wrong / mismatched in your current fiscal-checkout-block.
|
||
A validated Preact + web components rewrite of OrderStatusExtension.jsx for customer-account.order-status.block.render.
|
||
The shopify.extension.toml change you’ll want for a 2025‑10 style build.
|
||
Notes on your GraphQL + metafield access.
|
||
1. Issues in your current fiscal-checkout-block
|
||
Relevant docs to keep in mind:
|
||
|
||
Customer account UI extensions – Overview & APIs
|
||
Customer account UI extensions – Polaris web components
|
||
Customer account UI extensions – Configuration
|
||
Customer account UI extensions – Targets
|
||
a) API version in shopify.extension.toml
|
||
You have:
|
||
|
||
toml
|
||
Copy
|
||
1
|
||
2
|
||
3
|
||
api_version = "2025-07"
|
||
...
|
||
target = "customer-account.order-status.block.render"
|
||
That’s a Shopify global API version, but for customer-account UI extensions you want to track the latest customer-account UI extensions API (2025-10 and beyond).
|
||
Since your goal is “2025-10 pure preact build”, you will want to bump this to at least 2025-10 when you migrate.
|
||
(I’ll show what to change after the code.)
|
||
|
||
b) Using React wrappers + Preact hooks instead of the Preact/web‑components model
|
||
Your current code:
|
||
|
||
js
|
||
Copy
|
||
1
|
||
2
|
||
3
|
||
4
|
||
5
|
||
6
|
||
7
|
||
8
|
||
9
|
||
10
|
||
11
|
||
12
|
||
13
|
||
14
|
||
15
|
||
import {
|
||
reactExtension,
|
||
BlockStack,
|
||
InlineStack,
|
||
Text,
|
||
Button,
|
||
Banner,
|
||
Divider,
|
||
Heading,
|
||
View,
|
||
Link,
|
||
Spinner,
|
||
useApi,
|
||
} from '@shopify/ui-extensions-react/customer-account';
|
||
import { useState, useEffect, useCallback } from 'preact/hooks';
|
||
Problems:
|
||
|
||
reactExtension + React components (BlockStack, Button, etc.) are part of the React-based API, not the web components model.
|
||
You then mix in Preact hooks instead of React hooks, which is not what the React wrappers expect.
|
||
For the 2025-10+ Polaris UI Framework, customer account extensions are intended to use:
|
||
import '@shopify/ui-extensions/preact';
|
||
render from preact
|
||
Polaris web components: <s-stack>, <s-text>, <s-banner>, <s-button>, <s-link>, <s-divider>, etc.
|
||
The global shopify object for contextual APIs (like shopify.order).
|
||
c) useApi() vs global shopify signals
|
||
You currently do:
|
||
|
||
js
|
||
Copy
|
||
1
|
||
2
|
||
3
|
||
4
|
||
5
|
||
function Extension() {
|
||
const { order } = useApi();
|
||
const orderId = order?.id?.value || order?.id;
|
||
...
|
||
}
|
||
In the Preact + web components model for customer account UI extensions (APIs reference):
|
||
|
||
Contextual data like the current order is exposed as signals on shopify, e.g. shopify.order.
|
||
APIs with a .value property are signals: you access shopify.order.value inside your component.
|
||
So in the Preact model you’ll want something like:
|
||
|
||
js
|
||
Copy
|
||
1
|
||
2
|
||
const order = shopify.order.value;
|
||
const orderId = order?.id;
|
||
2. Migrated Preact + web components OrderStatusExtension.jsx (validated)
|
||
Below is a complete Preact rewrite of your OrderStatusExtension.jsx for the target customer-account.order-status.block.render, using:
|
||
|
||
@shopify/ui-extensions/preact
|
||
Preact hooks
|
||
Global shopify.order
|
||
Polaris web components:
|
||
<s-box>, <s-stack>, <s-spinner>, <s-text>, <s-banner>, <s-divider>, <s-button>, <s-link>
|
||
This code has been validated against the polaris-customer-account-extensions API for the target customer-account.order-status.block.render.
|
||
|
||
tsx
|
||
Copy
|
||
197
|
||
198
|
||
199
|
||
200
|
||
201
|
||
202
|
||
203
|
||
204
|
||
205
|
||
206
|
||
207
|
||
208
|
||
209
|
||
210
|
||
211
|
||
212
|
||
213
|
||
214
|
||
215
|
||
216
|
||
217
|
||
218
|
||
219
|
||
220
|
||
221
|
||
222
|
||
223
|
||
224
|
||
225
|
||
226
|
||
227
|
||
228
|
||
229
|
||
230
|
||
231
|
||
232
|
||
233
|
||
234
|
||
235
|
||
236
|
||
237
|
||
238
|
||
239
|
||
240
|
||
241
|
||
242
|
||
243
|
||
244
|
||
245
|
||
246
|
||
247
|
||
248
|
||
249
|
||
250
|
||
251
|
||
252
|
||
253
|
||
254
|
||
255
|
||
256
|
||
257
|
||
258
|
||
259
|
||
260
|
||
261
|
||
262
|
||
263
|
||
264
|
||
265
|
||
266
|
||
267
|
||
268
|
||
269
|
||
270
|
||
271
|
||
272
|
||
273
|
||
274
|
||
275
|
||
276
|
||
277
|
||
278
|
||
279
|
||
280
|
||
281
|
||
282
|
||
283
|
||
284
|
||
285
|
||
import '@shopify/ui-extensions/preact';
|
||
{receipts.map((receipt) => (
|
||
<s-box
|
||
key={receipt.id}
|
||
padding="base"
|
||
border="base"
|
||
border-radius="base"
|
||
>
|
||
<s-stack gap="base">
|
||
{/* Receipt summary */}
|
||
<s-stack gap="none">
|
||
{receipt.info.display_datetime ? (
|
||
<>
|
||
<s-text font-weight="bold">
|
||
{receipt.info.display_datetime}
|
||
</s-text>
|
||
{receipt.info.amount && (
|
||
<s-text>{receipt.info.amount} грн</s-text>
|
||
)}
|
||
{receipt.info.fiscal_number && (
|
||
<s-text>
|
||
ФН: {receipt.info.fiscal_number}
|
||
</s-text>
|
||
)}
|
||
</>
|
||
) : (
|
||
<s-text>
|
||
Receipt {receipt.id} — waiting for fiscalisation
|
||
</s-text>
|
||
)}
|
||
</s-stack>
|
||
|
||
<s-divider />
|
||
|
||
{/* Action buttons */}
|
||
<s-stack direction="inline" gap="base">
|
||
{receipt.storage.html && (
|
||
<s-button
|
||
variant="primary"
|
||
onClick={() =>
|
||
openBase64AsBlob(receipt.storage.html, 'text/html')
|
||
}
|
||
>
|
||
View Receipt
|
||
</s-button>
|
||
)}
|
||
{receipt.storage.xml && (
|
||
<s-button
|
||
onClick={() =>
|
||
downloadBase64AsFile(
|
||
receipt.storage.xml,
|
||
`fiscal_receipt_${receipt.id}.xml`,
|
||
'application/xml',
|
||
)
|
||
}
|
||
>
|
||
Download XML
|
||
</s-button>
|
||
)}
|
||
</s-stack>
|
||
|
||
{/* External links */}
|
||
{receipt.info.links && (
|
||
<s-stack direction="inline" gap="base">
|
||
{receipt.info.links.tax_service && (
|
||
<s-link href={receipt.info.links.tax_service} target="_blank">
|
||
Tax Service
|
||
</s-link>
|
||
)}
|
||
{receipt.info.links.external_provider && (
|
||
<s-link
|
||
href={receipt.info.links.external_provider}
|
||
target="_blank"
|
||
>
|
||
Provider
|
||
</s-link>
|
||
)}
|
||
{receipt.info.links.pdf && (
|
||
<s-link href={receipt.info.links.pdf} target="_blank">
|
||
PDF
|
||
</s-link>
|
||
)}
|
||
</s-stack>
|
||
)}
|
||
</s-stack>
|
||
</s-box>
|
||
))}
|
||
</s-stack>
|
||
);
|
||
}
|
||
Key differences vs your original:
|
||
|
||
Entry point:
|
||
Old: export default reactExtension(..., () => <Extension />);
|
||
New: export default function extension() { render(<Extension />, document.body); }
|
||
Context API:
|
||
Old: const { order } = useApi();
|
||
New: const order = shopify.order.value;
|
||
UI layer:
|
||
Old: React components (BlockStack, View, Button, Link, etc.).
|
||
New: Polaris web components: <s-stack>, <s-box>, <s-banner>, <s-button>, <s-link>, etc.
|
||
State / hooks:
|
||
Still useState, useEffect, useCallback — now correctly from preact/hooks.
|
||
3. Updating shopify.extension.toml for a 2025‑10 Preact build
|
||
Currently:
|
||
|
||
toml
|
||
Copy
|
||
1
|
||
2
|
||
3
|
||
4
|
||
5
|
||
6
|
||
7
|
||
8
|
||
9
|
||
10
|
||
11
|
||
12
|
||
13
|
||
14
|
||
15
|
||
16
|
||
17
|
||
18
|
||
api_version = "2025-07"
|
||
uid = "ca81c72e-43fb-0709-a9a3-373f38c511faf3b68f36"
|
||
|
||
[[extensions]]
|
||
name = "Fiscal Receipt Info"
|
||
handle = "fiscal-checkout-block"
|
||
type = "ui_extension"
|
||
|
||
[[extensions.targeting]]
|
||
module = "./src/OrderStatusExtension.jsx"
|
||
target = "customer-account.order-status.block.render"
|
||
|
||
[extensions.capabilities]
|
||
network_access = true
|
||
|
||
[[extensions.metafields]]
|
||
namespace = "hutko"
|
||
key = "fiscal_receipts"
|
||
For a Preact + web components build aligned with the latest customer account UI extensions API, update to:
|
||
|
||
toml
|
||
Copy
|
||
1
|
||
2
|
||
3
|
||
4
|
||
5
|
||
6
|
||
7
|
||
8
|
||
9
|
||
10
|
||
11
|
||
12
|
||
13
|
||
14
|
||
15
|
||
16
|
||
17
|
||
18
|
||
api_version = "2025-10"
|
||
uid = "ca81c72e-43fb-0709-a9a3-373f38c511faf3b68f36"
|
||
|
||
[[extensions]]
|
||
name = "Fiscal Receipt Info"
|
||
handle = "fiscal-checkout-block"
|
||
type = "ui_extension"
|
||
|
||
[[extensions.targeting]]
|
||
module = "./src/OrderStatusExtension.jsx"
|
||
target = "customer-account.order-status.block.render"
|
||
|
||
[extensions.capabilities]
|
||
network_access = true
|
||
|
||
[[extensions.metafields]]
|
||
namespace = "hutko"
|
||
key = "fiscal_receipts"
|
||
Keep the same target (customer-account.order-status.block.render), which is one of the documented customer account targets.
|
||
Just bump api_version and ensure your package.json has the Preact dependencies:
|
||
json
|
||
Copy
|
||
1
|
||
2
|
||
3
|
||
4
|
||
5
|
||
6
|
||
7
|
||
{
|
||
"dependencies": {
|
||
"preact": "^10.10.x",
|
||
"@preact/signals": "^2.3.x",
|
||
"@shopify/ui-extensions": "2025.10.x"
|
||
}
|
||
}
|
||
4. Notes on your GraphQL and metafield usage
|
||
Your original logic:
|
||
|
||
Index metafield:
|
||
Operation
|
||
Open in GraphiQL
|
||
Copy
|
||
1
|
||
2
|
||
3
|
||
4
|
||
5
|
||
query getOrderMetafield($id: ID!) {
|
||
order(id: $id) {
|
||
metafield(namespace: "hutko", key: "fiscal_receipts") { value }
|
||
}
|
||
}
|
||
Per-receipt metafields:
|
||
Operation
|
||
Open in GraphiQL
|
||
Copy
|
||
1
|
||
2
|
||
3
|
||
4
|
||
5
|
||
6
|
||
query getReceiptData($orderId: ID!, $infoKey: String!, $storageKey: String!) {
|
||
order(id: $orderId) {
|
||
info: metafield(namespace: "hutko", key: $infoKey) { value }
|
||
storage: metafield(namespace: "hutko", key: $storageKey) { value }
|
||
}
|
||
}
|
||
and then JSON parse on each value.
|
||
|
||
This pattern is totally fine to keep in the Preact version — the only changes I made are:
|
||
|
||
Bumping API_VERSION from '2025-07' to '2025-10'.
|
||
Using shopify.order.value rather than useApi() to get orderId.
|
||
If your metafield schema is already live in production, this Preact migration should not require any back‑end changes.
|
||
|
||
What to do next
|
||
Replace your OrderStatusExtension.jsx with the Preact/web-components version above.
|
||
Update shopify.extension.toml to api_version = "2025-10".
|
||
Ensure package.json for this extension has:
|
||
preact, @preact/signals, @shopify/ui-extensions (and no @shopify/ui-extensions-react/...).
|
||
Run:
|
||
bash
|
||
Copy
|
||
1
|
||
shopify app dev
|
||
And test on the Order status page under the customer-account.order-status.block.render target.
|
||
|
||
If you’d like, you can paste your package.json for this extension and I’ll align it exactly with the 2025‑10 Preact + customer-account UI extensions stack, and we can similarly migrate your admin.order-details.block.render block so both sides (admin + customer account) use the same Preact/web-components approach.
|
||
|
||
Sources
|
||
API: Customer Account Ui Extensions
|
||
Customer account UI extensions
|
||
API: Customer Account Ui Extensions > Polaris Web Components
|
||
Polaris web components
|
||
API: Customer Account Ui Extensions > Configuration
|
||
Customer account UI extensions – Configuration |