111 lines
3.2 KiB
TypeScript
111 lines
3.2 KiB
TypeScript
import "@shopify/ui-extensions/preact";
|
|
import { render } from "preact";
|
|
import { useEffect, useState } from "preact/hooks";
|
|
|
|
const APP_URL_PROD = "https://invoice-app.linumiq.com";
|
|
const APP_URL_DEV = "https://invoice-app-dev.linumiq.com";
|
|
const DEV_SHOPS = new Set(["linumiq-dev.myshopify.com"]);
|
|
|
|
function resolveAppUrl(shopify: any): string {
|
|
const shop: string | undefined =
|
|
shopify?.shop?.myshopifyDomain ?? shopify?.shop?.value?.myshopifyDomain;
|
|
if (shop && DEV_SHOPS.has(shop)) return APP_URL_DEV;
|
|
return APP_URL_PROD;
|
|
}
|
|
|
|
interface PaymentInstructions {
|
|
language: "de" | "en";
|
|
heading: string;
|
|
giroCodeUrl: string;
|
|
recipient: string;
|
|
bankName: string;
|
|
iban: string;
|
|
bic: string;
|
|
amountFormatted: string;
|
|
reference: string;
|
|
dueDateFormatted: string | null;
|
|
instructions: string;
|
|
labels: {
|
|
recipient: string;
|
|
bank: string;
|
|
iban: string;
|
|
bic: string;
|
|
amount: string;
|
|
reference: string;
|
|
};
|
|
}
|
|
|
|
export default async () => {
|
|
render(<Extension />, document.body);
|
|
};
|
|
|
|
function Extension() {
|
|
const shopify = (globalThis as any).shopify;
|
|
const [data, setData] = useState<PaymentInstructions | null>(null);
|
|
const [done, setDone] = useState(false);
|
|
|
|
useEffect(() => {
|
|
let cancelled = false;
|
|
async function load() {
|
|
try {
|
|
const orderId: string | undefined = shopify?.orderConfirmation?.value?.order?.id;
|
|
if (!orderId) {
|
|
setDone(true);
|
|
return;
|
|
}
|
|
const token: string = await shopify.sessionToken.get();
|
|
const appUrl = resolveAppUrl(shopify);
|
|
const res = await fetch(
|
|
`${appUrl}/api/public/payment-info?orderId=${encodeURIComponent(orderId)}`,
|
|
{ headers: { Authorization: `Bearer ${token}` } },
|
|
);
|
|
if (!res.ok) {
|
|
setDone(true);
|
|
return;
|
|
}
|
|
const json = (await res.json()) as {
|
|
showPaymentInstructions: boolean;
|
|
payload?: PaymentInstructions;
|
|
};
|
|
if (cancelled) return;
|
|
if (json.showPaymentInstructions && json.payload) {
|
|
setData(json.payload);
|
|
}
|
|
} catch {
|
|
// swallow; render nothing
|
|
} finally {
|
|
if (!cancelled) setDone(true);
|
|
}
|
|
}
|
|
load();
|
|
return () => {
|
|
cancelled = true;
|
|
};
|
|
}, []);
|
|
|
|
if (!done || !data) {
|
|
return null;
|
|
}
|
|
|
|
return (
|
|
<s-section heading={data.heading}>
|
|
<s-paragraph>{data.instructions}</s-paragraph>
|
|
<s-grid gridTemplateColumns="200px 1fr" gap="base" alignItems="start">
|
|
<s-image src={data.giroCodeUrl} alt="GiroCode" inlineSize="fill" aspectRatio="1" />
|
|
<s-stack direction="block" gap="small-200">
|
|
<s-text>{data.labels.recipient}: {data.recipient}</s-text>
|
|
{data.bankName ? (
|
|
<s-text>{data.labels.bank}: {data.bankName}</s-text>
|
|
) : null}
|
|
<s-text>{data.labels.iban}: {data.iban}</s-text>
|
|
{data.bic ? (
|
|
<s-text>{data.labels.bic}: {data.bic}</s-text>
|
|
) : null}
|
|
<s-text>{data.labels.amount}: {data.amountFormatted}</s-text>
|
|
<s-text>{data.labels.reference}: {data.reference}</s-text>
|
|
</s-stack>
|
|
</s-grid>
|
|
</s-section>
|
|
);
|
|
}
|