@easypayment/medusa-paypal-ui 0.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1 @@
1
+ MIT License
package/README.md ADDED
@@ -0,0 +1,53 @@
1
+ # @easypayment/medusa-paypal-ui (Enterprise Gold) — v1.0.3
2
+
3
+ Fixes included:
4
+ - Card Fields: uses `cardFieldsForm.submit()` (typed)
5
+ - Card Fields: `PayPalCardFieldsProvider` includes required `onError`
6
+ - Build: ESM outputs `dist/index.mjs` to match `package.json` exports
7
+
8
+ ## Install (local file package)
9
+
10
+ In your storefront `package.json`:
11
+
12
+ ```json
13
+ {
14
+ "dependencies": {
15
+ "@easypayment/medusa-paypal-ui": "file:./packages/medusa-paypal-ui-enterprise-gold",
16
+ "@paypal/react-paypal-js": "^8.8.0"
17
+ }
18
+ }
19
+ ```
20
+
21
+ Then:
22
+
23
+ ```bash
24
+ npm i
25
+ ```
26
+
27
+ ## Build
28
+
29
+ ```bash
30
+ cd packages/medusa-paypal-ui-enterprise-gold
31
+ npm run build
32
+ ```
33
+
34
+ ## Use in Medusa Next checkout (recommended adapter)
35
+
36
+ ```tsx
37
+ import { MedusaNextPayPalAdapter } from "@easypayment/medusa-paypal-ui"
38
+
39
+ <MedusaNextPayPalAdapter
40
+ cartId={cart.id}
41
+ selectedProviderId={selectedProviderId}
42
+ baseUrl={process.env.NEXT_PUBLIC_MEDUSA_BACKEND_URL!}
43
+ publishableApiKey={process.env.NEXT_PUBLIC_MEDUSA_PUBLISHABLE_KEY}
44
+ providerIds={{ paypal: "paypal", paypalCard: "paypal_card" }}
45
+ onPaid={() => window.location.reload()}
46
+ />
47
+ ```
48
+
49
+ ## Tests
50
+
51
+ ```bash
52
+ npm test
53
+ ```
package/dist/index.cjs ADDED
@@ -0,0 +1,246 @@
1
+ 'use strict';
2
+
3
+ var react = require('react');
4
+ var reactPaypalJs = require('@paypal/react-paypal-js');
5
+ var jsxRuntime = require('react/jsx-runtime');
6
+
7
+ // src/client/http.ts
8
+ function createHttpClient(opts) {
9
+ const base = opts.baseUrl.replace(/\/+$/, "");
10
+ async function request(path, init) {
11
+ const url = `${base}${path.startsWith("/") ? "" : "/"}${path}`;
12
+ const headers = {
13
+ Accept: "application/json",
14
+ ...init?.headers
15
+ };
16
+ if (opts.publishableApiKey) {
17
+ headers["x-publishable-api-key"] = opts.publishableApiKey;
18
+ }
19
+ const res = await fetch(url, { ...init, headers, credentials: "include" });
20
+ const text = await res.text().catch(() => "");
21
+ if (!res.ok) {
22
+ throw new Error(text || `Request failed (${res.status})`);
23
+ }
24
+ return text ? JSON.parse(text) : {};
25
+ }
26
+ return { request };
27
+ }
28
+
29
+ // src/client/paypal.ts
30
+ function createPayPalStoreApi(opts) {
31
+ const http = createHttpClient(opts);
32
+ return {
33
+ getConfig(cartId) {
34
+ const q = cartId ? `?cart_id=${encodeURIComponent(cartId)}` : "";
35
+ return http.request(`/store/paypal/config${q}`);
36
+ },
37
+ getSettings() {
38
+ return http.request(`/store/paypal/settings`);
39
+ },
40
+ createOrder(cartId) {
41
+ return http.request(`/store/paypal/create-order`, {
42
+ method: "POST",
43
+ headers: { "Content-Type": "application/json" },
44
+ body: JSON.stringify({ cart_id: cartId })
45
+ });
46
+ },
47
+ captureOrder(cartId, orderId) {
48
+ return http.request(`/store/paypal/capture-order`, {
49
+ method: "POST",
50
+ headers: { "Content-Type": "application/json" },
51
+ body: JSON.stringify({ cart_id: cartId, order_id: orderId })
52
+ });
53
+ }
54
+ };
55
+ }
56
+ function usePayPalConfig({ baseUrl, publishableApiKey, cartId }) {
57
+ const api = react.useMemo(
58
+ () => createPayPalStoreApi({ baseUrl, publishableApiKey }),
59
+ [baseUrl, publishableApiKey]
60
+ );
61
+ const [config, setConfig] = react.useState(null);
62
+ const [loading, setLoading] = react.useState(false);
63
+ const [error, setError] = react.useState(null);
64
+ react.useEffect(() => {
65
+ let mounted = true;
66
+ (async () => {
67
+ try {
68
+ setLoading(true);
69
+ setError(null);
70
+ const cfg = await api.getConfig(cartId);
71
+ if (mounted) setConfig(cfg);
72
+ } catch (e) {
73
+ if (mounted) setError(e?.message || "Failed to load PayPal config");
74
+ } finally {
75
+ if (mounted) setLoading(false);
76
+ }
77
+ })();
78
+ return () => {
79
+ mounted = false;
80
+ };
81
+ }, [api, cartId]);
82
+ return { config, loading, error };
83
+ }
84
+ function PayPalProvider(props) {
85
+ const { config, intent = "capture", children } = props;
86
+ const options = react.useMemo(() => {
87
+ return {
88
+ "client-id": config.client_id,
89
+ currency: config.currency,
90
+ intent,
91
+ components: config.client_token ? "buttons,card-fields" : "buttons",
92
+ "data-client-token": config.client_token || void 0
93
+ };
94
+ }, [config, intent]);
95
+ return /* @__PURE__ */ jsxRuntime.jsx(reactPaypalJs.PayPalScriptProvider, { options, children });
96
+ }
97
+ function PayPalCurrencyNotice({ config }) {
98
+ if (config.currency_supported) return null;
99
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { padding: 12, border: "1px solid #ddd", borderRadius: 10 }, children: [
100
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: { fontWeight: 600, marginBottom: 6 }, children: "PayPal currency issue" }),
101
+ /* @__PURE__ */ jsxRuntime.jsx("ul", { style: { margin: 0, paddingLeft: 18 }, children: (config.currency_errors || []).map((e, i) => /* @__PURE__ */ jsxRuntime.jsx("li", { children: e }, i)) })
102
+ ] });
103
+ }
104
+ function PayPalSmartButtons(props) {
105
+ const { baseUrl, publishableApiKey, cartId, config, onPaid, onError } = props;
106
+ const api = react.useMemo(
107
+ () => createPayPalStoreApi({ baseUrl, publishableApiKey }),
108
+ [baseUrl, publishableApiKey]
109
+ );
110
+ const [error, setError] = react.useState(null);
111
+ if (!config.currency_supported) return null;
112
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
113
+ /* @__PURE__ */ jsxRuntime.jsx(
114
+ reactPaypalJs.PayPalButtons,
115
+ {
116
+ style: { layout: "vertical" },
117
+ createOrder: async () => {
118
+ setError(null);
119
+ const r = await api.createOrder(cartId);
120
+ return r.id;
121
+ },
122
+ onApprove: async (data) => {
123
+ setError(null);
124
+ const orderId = String(data?.orderID || "");
125
+ const result = await api.captureOrder(cartId, orderId);
126
+ onPaid?.(result);
127
+ },
128
+ onError: (err) => {
129
+ const msg = err?.message || "PayPal error";
130
+ setError(msg);
131
+ onError?.(msg);
132
+ }
133
+ }
134
+ ),
135
+ error ? /* @__PURE__ */ jsxRuntime.jsx("div", { style: { marginTop: 10, color: "crimson" }, children: error }) : null
136
+ ] });
137
+ }
138
+ function SubmitButton({ disabled, label }) {
139
+ const { cardFieldsForm } = reactPaypalJs.usePayPalCardFields();
140
+ return /* @__PURE__ */ jsxRuntime.jsx(
141
+ "button",
142
+ {
143
+ type: "button",
144
+ disabled: disabled || !cardFieldsForm,
145
+ onClick: () => cardFieldsForm?.submit(),
146
+ style: { padding: "10px 12px", borderRadius: 10, border: "1px solid #ddd" },
147
+ children: label
148
+ }
149
+ );
150
+ }
151
+ function PayPalAdvancedCard(props) {
152
+ const { baseUrl, publishableApiKey, cartId, config, onPaid, onError } = props;
153
+ const api = react.useMemo(
154
+ () => createPayPalStoreApi({ baseUrl, publishableApiKey }),
155
+ [baseUrl, publishableApiKey]
156
+ );
157
+ const [error, setError] = react.useState(null);
158
+ const [submitting, setSubmitting] = react.useState(false);
159
+ if (!config.currency_supported) return null;
160
+ if (!config.client_token) {
161
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { style: { padding: 12, border: "1px solid #ddd", borderRadius: 10 }, children: "CardFields unavailable: missing client_token from backend." });
162
+ }
163
+ return /* @__PURE__ */ jsxRuntime.jsx(
164
+ reactPaypalJs.PayPalCardFieldsProvider,
165
+ {
166
+ createOrder: async () => {
167
+ setError(null);
168
+ const r = await api.createOrder(cartId);
169
+ return r.id;
170
+ },
171
+ onApprove: async (data) => {
172
+ try {
173
+ setSubmitting(true);
174
+ setError(null);
175
+ const orderId = String(data?.orderID || "");
176
+ const result = await api.captureOrder(cartId, orderId);
177
+ onPaid?.(result);
178
+ } catch (e) {
179
+ const msg = e?.message || "Card payment failed";
180
+ setError(msg);
181
+ onError?.(msg);
182
+ } finally {
183
+ setSubmitting(false);
184
+ }
185
+ },
186
+ onError: (e) => {
187
+ const msg = e?.message || "CardFields error";
188
+ setError(msg);
189
+ onError?.(msg);
190
+ },
191
+ children: /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "grid", gap: 10 }, children: [
192
+ /* @__PURE__ */ jsxRuntime.jsx(reactPaypalJs.PayPalNameField, {}),
193
+ /* @__PURE__ */ jsxRuntime.jsx(reactPaypalJs.PayPalNumberField, {}),
194
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "grid", gridTemplateColumns: "1fr 1fr", gap: 10 }, children: [
195
+ /* @__PURE__ */ jsxRuntime.jsx(reactPaypalJs.PayPalExpiryField, {}),
196
+ /* @__PURE__ */ jsxRuntime.jsx(reactPaypalJs.PayPalCVVField, {})
197
+ ] }),
198
+ /* @__PURE__ */ jsxRuntime.jsx(SubmitButton, { disabled: submitting, label: submitting ? "Processing..." : "Pay by Card" }),
199
+ error ? /* @__PURE__ */ jsxRuntime.jsx("div", { style: { color: "crimson" }, children: error }) : null
200
+ ] })
201
+ }
202
+ );
203
+ }
204
+ function MedusaNextPayPalAdapter(props) {
205
+ const { cartId, selectedProviderId, baseUrl, publishableApiKey, providerIds, onPaid } = props;
206
+ const paypalProviderId = providerIds?.paypal || "paypal";
207
+ const paypalCardProviderId = providerIds?.paypalCard || "paypal_card";
208
+ const shouldRender = selectedProviderId === paypalProviderId || selectedProviderId === paypalCardProviderId;
209
+ const { config, loading, error } = usePayPalConfig({ baseUrl, publishableApiKey, cartId });
210
+ if (!shouldRender) return null;
211
+ if (loading) return /* @__PURE__ */ jsxRuntime.jsx("div", { children: "Loading PayPal\u2026" });
212
+ if (error) return /* @__PURE__ */ jsxRuntime.jsx("div", { style: { color: "crimson" }, children: error });
213
+ if (!config) return null;
214
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "grid", gap: 12 }, children: [
215
+ /* @__PURE__ */ jsxRuntime.jsx(PayPalCurrencyNotice, { config }),
216
+ /* @__PURE__ */ jsxRuntime.jsx(PayPalProvider, { config, intent: "capture", children: selectedProviderId === paypalCardProviderId ? /* @__PURE__ */ jsxRuntime.jsx(
217
+ PayPalAdvancedCard,
218
+ {
219
+ baseUrl,
220
+ publishableApiKey,
221
+ cartId,
222
+ config,
223
+ onPaid
224
+ }
225
+ ) : /* @__PURE__ */ jsxRuntime.jsx(
226
+ PayPalSmartButtons,
227
+ {
228
+ baseUrl,
229
+ publishableApiKey,
230
+ cartId,
231
+ config,
232
+ onPaid
233
+ }
234
+ ) })
235
+ ] });
236
+ }
237
+
238
+ exports.MedusaNextPayPalAdapter = MedusaNextPayPalAdapter;
239
+ exports.PayPalAdvancedCard = PayPalAdvancedCard;
240
+ exports.PayPalCurrencyNotice = PayPalCurrencyNotice;
241
+ exports.PayPalProvider = PayPalProvider;
242
+ exports.PayPalSmartButtons = PayPalSmartButtons;
243
+ exports.createPayPalStoreApi = createPayPalStoreApi;
244
+ exports.usePayPalConfig = usePayPalConfig;
245
+ //# sourceMappingURL=index.cjs.map
246
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/client/http.ts","../src/client/paypal.ts","../src/hooks/usePayPalConfig.ts","../src/components/PayPalProvider.tsx","../src/components/PayPalCurrencyNotice.tsx","../src/components/PayPalSmartButtons.tsx","../src/components/PayPalAdvancedCard.tsx","../src/adapters/MedusaNextPayPalAdapter.tsx"],"names":["useMemo","useState","useEffect","jsx","PayPalScriptProvider","jsxs","PayPalButtons","usePayPalCardFields","PayPalCardFieldsProvider","PayPalNameField","PayPalNumberField","PayPalExpiryField","PayPalCVVField"],"mappings":"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","file":"index.cjs","sourcesContent":["export type HttpOptions = {\n baseUrl: string\n publishableApiKey?: string\n}\n\nexport function createHttpClient(opts: HttpOptions) {\n const base = opts.baseUrl.replace(/\\/+$/, \"\")\n\n async function request<T>(path: string, init?: RequestInit): Promise<T> {\n const url = `${base}${path.startsWith(\"/\") ? \"\" : \"/\"}${path}`\n const headers: Record<string, string> = {\n Accept: \"application/json\",\n ...(init?.headers as any),\n }\n\n if (opts.publishableApiKey) {\n headers[\"x-publishable-api-key\"] = opts.publishableApiKey\n }\n\n const res = await fetch(url, { ...init, headers, credentials: \"include\" })\n const text = await res.text().catch(() => \"\")\n\n if (!res.ok) {\n throw new Error(text || `Request failed (${res.status})`)\n }\n\n return (text ? JSON.parse(text) : {}) as T\n }\n\n return { request }\n}\n","import type { PayPalConfig, PayPalSettingsResponse } from \"./types\"\nimport { createHttpClient, type HttpOptions } from \"./http\"\n\nexport function createPayPalStoreApi(opts: HttpOptions) {\n const http = createHttpClient(opts)\n\n return {\n getConfig(cartId?: string) {\n const q = cartId ? `?cart_id=${encodeURIComponent(cartId)}` : \"\"\n return http.request<PayPalConfig>(`/store/paypal/config${q}`)\n },\n\n getSettings() {\n return http.request<PayPalSettingsResponse>(`/store/paypal/settings`)\n },\n\n createOrder(cartId: string) {\n return http.request<{ id: string }>(`/store/paypal/create-order`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ cart_id: cartId }),\n })\n },\n\n captureOrder(cartId: string, orderId: string) {\n return http.request<any>(`/store/paypal/capture-order`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ cart_id: cartId, order_id: orderId }),\n })\n },\n }\n}\n","import { useEffect, useMemo, useState } from \"react\"\nimport { createPayPalStoreApi } from \"../client/paypal\"\nimport type { PayPalConfig } from \"../client/types\"\n\ntype Args = {\n baseUrl: string\n publishableApiKey?: string\n cartId?: string\n}\n\nexport function usePayPalConfig({ baseUrl, publishableApiKey, cartId }: Args) {\n const api = useMemo(\n () => createPayPalStoreApi({ baseUrl, publishableApiKey }),\n [baseUrl, publishableApiKey]\n )\n\n const [config, setConfig] = useState<PayPalConfig | null>(null)\n const [loading, setLoading] = useState(false)\n const [error, setError] = useState<string | null>(null)\n\n useEffect(() => {\n let mounted = true\n ;(async () => {\n try {\n setLoading(true)\n setError(null)\n const cfg = await api.getConfig(cartId)\n if (mounted) setConfig(cfg)\n } catch (e: any) {\n if (mounted) setError(e?.message || \"Failed to load PayPal config\")\n } finally {\n if (mounted) setLoading(false)\n }\n })()\n\n return () => {\n mounted = false\n }\n }, [api, cartId])\n\n return { config, loading, error }\n}\n","\"use client\"\n\nimport React, { useMemo } from \"react\"\nimport { PayPalScriptProvider } from \"@paypal/react-paypal-js\"\nimport type { PayPalConfig } from \"../client/types\"\n\nexport function PayPalProvider(props: {\n config: PayPalConfig\n intent?: \"capture\" | \"authorize\"\n children: React.ReactNode\n}) {\n const { config, intent = \"capture\", children } = props\n\n const options = useMemo(() => {\n return {\n \"client-id\": config.client_id,\n currency: config.currency,\n intent,\n components: config.client_token ? \"buttons,card-fields\" : \"buttons\",\n \"data-client-token\": config.client_token || undefined,\n } as any\n }, [config, intent])\n\n return <PayPalScriptProvider options={options}>{children}</PayPalScriptProvider>\n}\n","\"use client\"\n\nimport React from \"react\"\nimport type { PayPalConfig } from \"../client/types\"\n\nexport function PayPalCurrencyNotice({ config }: { config: PayPalConfig }) {\n if (config.currency_supported) return null\n\n return (\n <div style={{ padding: 12, border: \"1px solid #ddd\", borderRadius: 10 }}>\n <div style={{ fontWeight: 600, marginBottom: 6 }}>PayPal currency issue</div>\n <ul style={{ margin: 0, paddingLeft: 18 }}>\n {(config.currency_errors || []).map((e, i) => (\n <li key={i}>{e}</li>\n ))}\n </ul>\n </div>\n )\n}\n","\"use client\"\n\nimport React, { useMemo, useState } from \"react\"\nimport { PayPalButtons } from \"@paypal/react-paypal-js\"\nimport { createPayPalStoreApi } from \"../client/paypal\"\nimport type { PayPalConfig } from \"../client/types\"\n\nexport function PayPalSmartButtons(props: {\n baseUrl: string\n publishableApiKey?: string\n cartId: string\n config: PayPalConfig\n onPaid?: (result: any) => void\n onError?: (message: string) => void\n}) {\n const { baseUrl, publishableApiKey, cartId, config, onPaid, onError } = props\n const api = useMemo(\n () => createPayPalStoreApi({ baseUrl, publishableApiKey }),\n [baseUrl, publishableApiKey]\n )\n\n const [error, setError] = useState<string | null>(null)\n\n if (!config.currency_supported) return null\n\n return (\n <div>\n <PayPalButtons\n style={{ layout: \"vertical\" }}\n createOrder={async () => {\n setError(null)\n const r = await api.createOrder(cartId)\n return r.id\n }}\n onApprove={async (data: any) => {\n setError(null)\n const orderId = String(data?.orderID || \"\")\n const result = await api.captureOrder(cartId, orderId)\n onPaid?.(result)\n }}\n onError={(err: any) => {\n const msg = err?.message || \"PayPal error\"\n setError(msg)\n onError?.(msg)\n }}\n />\n {error ? <div style={{ marginTop: 10, color: \"crimson\" }}>{error}</div> : null}\n </div>\n )\n}\n","\"use client\"\n\nimport React, { useMemo, useState } from \"react\"\nimport {\n PayPalCardFieldsProvider,\n PayPalNameField,\n PayPalNumberField,\n PayPalExpiryField,\n PayPalCVVField,\n usePayPalCardFields,\n} from \"@paypal/react-paypal-js\"\nimport { createPayPalStoreApi } from \"../client/paypal\"\nimport type { PayPalConfig } from \"../client/types\"\n\nfunction SubmitButton({ disabled, label }: { disabled: boolean; label: string }) {\n const { cardFieldsForm } = usePayPalCardFields()\n\n return (\n <button\n type=\"button\"\n disabled={disabled || !cardFieldsForm}\n onClick={() => cardFieldsForm?.submit()}\n style={{ padding: \"10px 12px\", borderRadius: 10, border: \"1px solid #ddd\" }}\n >\n {label}\n </button>\n )\n}\n\nexport function PayPalAdvancedCard(props: {\n baseUrl: string\n publishableApiKey?: string\n cartId: string\n config: PayPalConfig\n onPaid?: (result: any) => void\n onError?: (message: string) => void\n}) {\n const { baseUrl, publishableApiKey, cartId, config, onPaid, onError } = props\n const api = useMemo(\n () => createPayPalStoreApi({ baseUrl, publishableApiKey }),\n [baseUrl, publishableApiKey]\n )\n\n const [error, setError] = useState<string | null>(null)\n const [submitting, setSubmitting] = useState(false)\n\n if (!config.currency_supported) return null\n\n if (!config.client_token) {\n return (\n <div style={{ padding: 12, border: \"1px solid #ddd\", borderRadius: 10 }}>\n CardFields unavailable: missing client_token from backend.\n </div>\n )\n }\n\n return (\n <PayPalCardFieldsProvider\n createOrder={async () => {\n setError(null)\n const r = await api.createOrder(cartId)\n return r.id\n }}\n onApprove={async (data: any) => {\n try {\n setSubmitting(true)\n setError(null)\n const orderId = String(data?.orderID || \"\")\n const result = await api.captureOrder(cartId, orderId)\n onPaid?.(result)\n } catch (e: any) {\n const msg = e?.message || \"Card payment failed\"\n setError(msg)\n onError?.(msg)\n } finally {\n setSubmitting(false)\n }\n }}\n onError={(e: any) => {\n const msg = e?.message || \"CardFields error\"\n setError(msg)\n onError?.(msg)\n }}\n >\n <div style={{ display: \"grid\", gap: 10 }}>\n <PayPalNameField />\n <PayPalNumberField />\n <div style={{ display: \"grid\", gridTemplateColumns: \"1fr 1fr\", gap: 10 }}>\n <PayPalExpiryField />\n <PayPalCVVField />\n </div>\n\n <SubmitButton disabled={submitting} label={submitting ? \"Processing...\" : \"Pay by Card\"} />\n\n {error ? <div style={{ color: \"crimson\" }}>{error}</div> : null}\n </div>\n </PayPalCardFieldsProvider>\n )\n}\n","\"use client\"\n\nimport React from \"react\"\nimport type { PayPalConfig } from \"../client/types\"\nimport { usePayPalConfig } from \"../hooks/usePayPalConfig\"\nimport { PayPalProvider } from \"../components/PayPalProvider\"\nimport { PayPalCurrencyNotice } from \"../components/PayPalCurrencyNotice\"\nimport { PayPalSmartButtons } from \"../components/PayPalSmartButtons\"\nimport { PayPalAdvancedCard } from \"../components/PayPalAdvancedCard\"\n\nexport type MedusaNextPayPalAdapterProps = {\n cartId: string\n selectedProviderId: string | null | undefined\n baseUrl: string\n publishableApiKey?: string\n providerIds?: {\n paypal?: string\n paypalCard?: string\n }\n onPaid?: (result: any) => void\n}\n\nexport function MedusaNextPayPalAdapter(props: MedusaNextPayPalAdapterProps) {\n const { cartId, selectedProviderId, baseUrl, publishableApiKey, providerIds, onPaid } = props\n\n const paypalProviderId = providerIds?.paypal || \"paypal\"\n const paypalCardProviderId = providerIds?.paypalCard || \"paypal_card\"\n\n const shouldRender =\n selectedProviderId === paypalProviderId || selectedProviderId === paypalCardProviderId\n\n const { config, loading, error } = usePayPalConfig({ baseUrl, publishableApiKey, cartId })\n\n if (!shouldRender) return null\n if (loading) return <div>Loading PayPal…</div>\n if (error) return <div style={{ color: \"crimson\" }}>{error}</div>\n if (!config) return null\n\n return (\n <div style={{ display: \"grid\", gap: 12 }}>\n <PayPalCurrencyNotice config={config as PayPalConfig} />\n\n <PayPalProvider config={config as PayPalConfig} intent=\"capture\">\n {selectedProviderId === paypalCardProviderId ? (\n <PayPalAdvancedCard\n baseUrl={baseUrl}\n publishableApiKey={publishableApiKey}\n cartId={cartId}\n config={config as PayPalConfig}\n onPaid={onPaid}\n />\n ) : (\n <PayPalSmartButtons\n baseUrl={baseUrl}\n publishableApiKey={publishableApiKey}\n cartId={cartId}\n config={config as PayPalConfig}\n onPaid={onPaid}\n />\n )}\n </PayPalProvider>\n </div>\n )\n}\n"]}
@@ -0,0 +1,89 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import React from 'react';
3
+
4
+ type PayPalConfig = {
5
+ environment: "sandbox" | "live";
6
+ client_id: string;
7
+ currency: string;
8
+ currency_supported: boolean;
9
+ currency_errors: string[];
10
+ supported_currencies: string[];
11
+ client_token?: string;
12
+ };
13
+ type PayPalSettingsResponse = {
14
+ data?: {
15
+ api_details?: {
16
+ currency_code?: string;
17
+ };
18
+ paypal_settings?: Record<string, any>;
19
+ onboarding_config?: Record<string, any>;
20
+ };
21
+ } | any;
22
+
23
+ type HttpOptions = {
24
+ baseUrl: string;
25
+ publishableApiKey?: string;
26
+ };
27
+
28
+ declare function createPayPalStoreApi(opts: HttpOptions): {
29
+ getConfig(cartId?: string): Promise<PayPalConfig>;
30
+ getSettings(): Promise<any>;
31
+ createOrder(cartId: string): Promise<{
32
+ id: string;
33
+ }>;
34
+ captureOrder(cartId: string, orderId: string): Promise<any>;
35
+ };
36
+
37
+ type Args = {
38
+ baseUrl: string;
39
+ publishableApiKey?: string;
40
+ cartId?: string;
41
+ };
42
+ declare function usePayPalConfig({ baseUrl, publishableApiKey, cartId }: Args): {
43
+ config: PayPalConfig | null;
44
+ loading: boolean;
45
+ error: string | null;
46
+ };
47
+
48
+ declare function PayPalProvider(props: {
49
+ config: PayPalConfig;
50
+ intent?: "capture" | "authorize";
51
+ children: React.ReactNode;
52
+ }): react_jsx_runtime.JSX.Element;
53
+
54
+ declare function PayPalCurrencyNotice({ config }: {
55
+ config: PayPalConfig;
56
+ }): react_jsx_runtime.JSX.Element | null;
57
+
58
+ declare function PayPalSmartButtons(props: {
59
+ baseUrl: string;
60
+ publishableApiKey?: string;
61
+ cartId: string;
62
+ config: PayPalConfig;
63
+ onPaid?: (result: any) => void;
64
+ onError?: (message: string) => void;
65
+ }): react_jsx_runtime.JSX.Element | null;
66
+
67
+ declare function PayPalAdvancedCard(props: {
68
+ baseUrl: string;
69
+ publishableApiKey?: string;
70
+ cartId: string;
71
+ config: PayPalConfig;
72
+ onPaid?: (result: any) => void;
73
+ onError?: (message: string) => void;
74
+ }): react_jsx_runtime.JSX.Element | null;
75
+
76
+ type MedusaNextPayPalAdapterProps = {
77
+ cartId: string;
78
+ selectedProviderId: string | null | undefined;
79
+ baseUrl: string;
80
+ publishableApiKey?: string;
81
+ providerIds?: {
82
+ paypal?: string;
83
+ paypalCard?: string;
84
+ };
85
+ onPaid?: (result: any) => void;
86
+ };
87
+ declare function MedusaNextPayPalAdapter(props: MedusaNextPayPalAdapterProps): react_jsx_runtime.JSX.Element | null;
88
+
89
+ export { MedusaNextPayPalAdapter, type MedusaNextPayPalAdapterProps, PayPalAdvancedCard, type PayPalConfig, PayPalCurrencyNotice, PayPalProvider, type PayPalSettingsResponse, PayPalSmartButtons, createPayPalStoreApi, usePayPalConfig };
@@ -0,0 +1,89 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import React from 'react';
3
+
4
+ type PayPalConfig = {
5
+ environment: "sandbox" | "live";
6
+ client_id: string;
7
+ currency: string;
8
+ currency_supported: boolean;
9
+ currency_errors: string[];
10
+ supported_currencies: string[];
11
+ client_token?: string;
12
+ };
13
+ type PayPalSettingsResponse = {
14
+ data?: {
15
+ api_details?: {
16
+ currency_code?: string;
17
+ };
18
+ paypal_settings?: Record<string, any>;
19
+ onboarding_config?: Record<string, any>;
20
+ };
21
+ } | any;
22
+
23
+ type HttpOptions = {
24
+ baseUrl: string;
25
+ publishableApiKey?: string;
26
+ };
27
+
28
+ declare function createPayPalStoreApi(opts: HttpOptions): {
29
+ getConfig(cartId?: string): Promise<PayPalConfig>;
30
+ getSettings(): Promise<any>;
31
+ createOrder(cartId: string): Promise<{
32
+ id: string;
33
+ }>;
34
+ captureOrder(cartId: string, orderId: string): Promise<any>;
35
+ };
36
+
37
+ type Args = {
38
+ baseUrl: string;
39
+ publishableApiKey?: string;
40
+ cartId?: string;
41
+ };
42
+ declare function usePayPalConfig({ baseUrl, publishableApiKey, cartId }: Args): {
43
+ config: PayPalConfig | null;
44
+ loading: boolean;
45
+ error: string | null;
46
+ };
47
+
48
+ declare function PayPalProvider(props: {
49
+ config: PayPalConfig;
50
+ intent?: "capture" | "authorize";
51
+ children: React.ReactNode;
52
+ }): react_jsx_runtime.JSX.Element;
53
+
54
+ declare function PayPalCurrencyNotice({ config }: {
55
+ config: PayPalConfig;
56
+ }): react_jsx_runtime.JSX.Element | null;
57
+
58
+ declare function PayPalSmartButtons(props: {
59
+ baseUrl: string;
60
+ publishableApiKey?: string;
61
+ cartId: string;
62
+ config: PayPalConfig;
63
+ onPaid?: (result: any) => void;
64
+ onError?: (message: string) => void;
65
+ }): react_jsx_runtime.JSX.Element | null;
66
+
67
+ declare function PayPalAdvancedCard(props: {
68
+ baseUrl: string;
69
+ publishableApiKey?: string;
70
+ cartId: string;
71
+ config: PayPalConfig;
72
+ onPaid?: (result: any) => void;
73
+ onError?: (message: string) => void;
74
+ }): react_jsx_runtime.JSX.Element | null;
75
+
76
+ type MedusaNextPayPalAdapterProps = {
77
+ cartId: string;
78
+ selectedProviderId: string | null | undefined;
79
+ baseUrl: string;
80
+ publishableApiKey?: string;
81
+ providerIds?: {
82
+ paypal?: string;
83
+ paypalCard?: string;
84
+ };
85
+ onPaid?: (result: any) => void;
86
+ };
87
+ declare function MedusaNextPayPalAdapter(props: MedusaNextPayPalAdapterProps): react_jsx_runtime.JSX.Element | null;
88
+
89
+ export { MedusaNextPayPalAdapter, type MedusaNextPayPalAdapterProps, PayPalAdvancedCard, type PayPalConfig, PayPalCurrencyNotice, PayPalProvider, type PayPalSettingsResponse, PayPalSmartButtons, createPayPalStoreApi, usePayPalConfig };
package/dist/index.mjs ADDED
@@ -0,0 +1,238 @@
1
+ import { useMemo, useState, useEffect } from 'react';
2
+ import { PayPalScriptProvider, PayPalButtons, PayPalCardFieldsProvider, PayPalNameField, PayPalNumberField, PayPalExpiryField, PayPalCVVField, usePayPalCardFields } from '@paypal/react-paypal-js';
3
+ import { jsx, jsxs } from 'react/jsx-runtime';
4
+
5
+ // src/client/http.ts
6
+ function createHttpClient(opts) {
7
+ const base = opts.baseUrl.replace(/\/+$/, "");
8
+ async function request(path, init) {
9
+ const url = `${base}${path.startsWith("/") ? "" : "/"}${path}`;
10
+ const headers = {
11
+ Accept: "application/json",
12
+ ...init?.headers
13
+ };
14
+ if (opts.publishableApiKey) {
15
+ headers["x-publishable-api-key"] = opts.publishableApiKey;
16
+ }
17
+ const res = await fetch(url, { ...init, headers, credentials: "include" });
18
+ const text = await res.text().catch(() => "");
19
+ if (!res.ok) {
20
+ throw new Error(text || `Request failed (${res.status})`);
21
+ }
22
+ return text ? JSON.parse(text) : {};
23
+ }
24
+ return { request };
25
+ }
26
+
27
+ // src/client/paypal.ts
28
+ function createPayPalStoreApi(opts) {
29
+ const http = createHttpClient(opts);
30
+ return {
31
+ getConfig(cartId) {
32
+ const q = cartId ? `?cart_id=${encodeURIComponent(cartId)}` : "";
33
+ return http.request(`/store/paypal/config${q}`);
34
+ },
35
+ getSettings() {
36
+ return http.request(`/store/paypal/settings`);
37
+ },
38
+ createOrder(cartId) {
39
+ return http.request(`/store/paypal/create-order`, {
40
+ method: "POST",
41
+ headers: { "Content-Type": "application/json" },
42
+ body: JSON.stringify({ cart_id: cartId })
43
+ });
44
+ },
45
+ captureOrder(cartId, orderId) {
46
+ return http.request(`/store/paypal/capture-order`, {
47
+ method: "POST",
48
+ headers: { "Content-Type": "application/json" },
49
+ body: JSON.stringify({ cart_id: cartId, order_id: orderId })
50
+ });
51
+ }
52
+ };
53
+ }
54
+ function usePayPalConfig({ baseUrl, publishableApiKey, cartId }) {
55
+ const api = useMemo(
56
+ () => createPayPalStoreApi({ baseUrl, publishableApiKey }),
57
+ [baseUrl, publishableApiKey]
58
+ );
59
+ const [config, setConfig] = useState(null);
60
+ const [loading, setLoading] = useState(false);
61
+ const [error, setError] = useState(null);
62
+ useEffect(() => {
63
+ let mounted = true;
64
+ (async () => {
65
+ try {
66
+ setLoading(true);
67
+ setError(null);
68
+ const cfg = await api.getConfig(cartId);
69
+ if (mounted) setConfig(cfg);
70
+ } catch (e) {
71
+ if (mounted) setError(e?.message || "Failed to load PayPal config");
72
+ } finally {
73
+ if (mounted) setLoading(false);
74
+ }
75
+ })();
76
+ return () => {
77
+ mounted = false;
78
+ };
79
+ }, [api, cartId]);
80
+ return { config, loading, error };
81
+ }
82
+ function PayPalProvider(props) {
83
+ const { config, intent = "capture", children } = props;
84
+ const options = useMemo(() => {
85
+ return {
86
+ "client-id": config.client_id,
87
+ currency: config.currency,
88
+ intent,
89
+ components: config.client_token ? "buttons,card-fields" : "buttons",
90
+ "data-client-token": config.client_token || void 0
91
+ };
92
+ }, [config, intent]);
93
+ return /* @__PURE__ */ jsx(PayPalScriptProvider, { options, children });
94
+ }
95
+ function PayPalCurrencyNotice({ config }) {
96
+ if (config.currency_supported) return null;
97
+ return /* @__PURE__ */ jsxs("div", { style: { padding: 12, border: "1px solid #ddd", borderRadius: 10 }, children: [
98
+ /* @__PURE__ */ jsx("div", { style: { fontWeight: 600, marginBottom: 6 }, children: "PayPal currency issue" }),
99
+ /* @__PURE__ */ jsx("ul", { style: { margin: 0, paddingLeft: 18 }, children: (config.currency_errors || []).map((e, i) => /* @__PURE__ */ jsx("li", { children: e }, i)) })
100
+ ] });
101
+ }
102
+ function PayPalSmartButtons(props) {
103
+ const { baseUrl, publishableApiKey, cartId, config, onPaid, onError } = props;
104
+ const api = useMemo(
105
+ () => createPayPalStoreApi({ baseUrl, publishableApiKey }),
106
+ [baseUrl, publishableApiKey]
107
+ );
108
+ const [error, setError] = useState(null);
109
+ if (!config.currency_supported) return null;
110
+ return /* @__PURE__ */ jsxs("div", { children: [
111
+ /* @__PURE__ */ jsx(
112
+ PayPalButtons,
113
+ {
114
+ style: { layout: "vertical" },
115
+ createOrder: async () => {
116
+ setError(null);
117
+ const r = await api.createOrder(cartId);
118
+ return r.id;
119
+ },
120
+ onApprove: async (data) => {
121
+ setError(null);
122
+ const orderId = String(data?.orderID || "");
123
+ const result = await api.captureOrder(cartId, orderId);
124
+ onPaid?.(result);
125
+ },
126
+ onError: (err) => {
127
+ const msg = err?.message || "PayPal error";
128
+ setError(msg);
129
+ onError?.(msg);
130
+ }
131
+ }
132
+ ),
133
+ error ? /* @__PURE__ */ jsx("div", { style: { marginTop: 10, color: "crimson" }, children: error }) : null
134
+ ] });
135
+ }
136
+ function SubmitButton({ disabled, label }) {
137
+ const { cardFieldsForm } = usePayPalCardFields();
138
+ return /* @__PURE__ */ jsx(
139
+ "button",
140
+ {
141
+ type: "button",
142
+ disabled: disabled || !cardFieldsForm,
143
+ onClick: () => cardFieldsForm?.submit(),
144
+ style: { padding: "10px 12px", borderRadius: 10, border: "1px solid #ddd" },
145
+ children: label
146
+ }
147
+ );
148
+ }
149
+ function PayPalAdvancedCard(props) {
150
+ const { baseUrl, publishableApiKey, cartId, config, onPaid, onError } = props;
151
+ const api = useMemo(
152
+ () => createPayPalStoreApi({ baseUrl, publishableApiKey }),
153
+ [baseUrl, publishableApiKey]
154
+ );
155
+ const [error, setError] = useState(null);
156
+ const [submitting, setSubmitting] = useState(false);
157
+ if (!config.currency_supported) return null;
158
+ if (!config.client_token) {
159
+ return /* @__PURE__ */ jsx("div", { style: { padding: 12, border: "1px solid #ddd", borderRadius: 10 }, children: "CardFields unavailable: missing client_token from backend." });
160
+ }
161
+ return /* @__PURE__ */ jsx(
162
+ PayPalCardFieldsProvider,
163
+ {
164
+ createOrder: async () => {
165
+ setError(null);
166
+ const r = await api.createOrder(cartId);
167
+ return r.id;
168
+ },
169
+ onApprove: async (data) => {
170
+ try {
171
+ setSubmitting(true);
172
+ setError(null);
173
+ const orderId = String(data?.orderID || "");
174
+ const result = await api.captureOrder(cartId, orderId);
175
+ onPaid?.(result);
176
+ } catch (e) {
177
+ const msg = e?.message || "Card payment failed";
178
+ setError(msg);
179
+ onError?.(msg);
180
+ } finally {
181
+ setSubmitting(false);
182
+ }
183
+ },
184
+ onError: (e) => {
185
+ const msg = e?.message || "CardFields error";
186
+ setError(msg);
187
+ onError?.(msg);
188
+ },
189
+ children: /* @__PURE__ */ jsxs("div", { style: { display: "grid", gap: 10 }, children: [
190
+ /* @__PURE__ */ jsx(PayPalNameField, {}),
191
+ /* @__PURE__ */ jsx(PayPalNumberField, {}),
192
+ /* @__PURE__ */ jsxs("div", { style: { display: "grid", gridTemplateColumns: "1fr 1fr", gap: 10 }, children: [
193
+ /* @__PURE__ */ jsx(PayPalExpiryField, {}),
194
+ /* @__PURE__ */ jsx(PayPalCVVField, {})
195
+ ] }),
196
+ /* @__PURE__ */ jsx(SubmitButton, { disabled: submitting, label: submitting ? "Processing..." : "Pay by Card" }),
197
+ error ? /* @__PURE__ */ jsx("div", { style: { color: "crimson" }, children: error }) : null
198
+ ] })
199
+ }
200
+ );
201
+ }
202
+ function MedusaNextPayPalAdapter(props) {
203
+ const { cartId, selectedProviderId, baseUrl, publishableApiKey, providerIds, onPaid } = props;
204
+ const paypalProviderId = providerIds?.paypal || "paypal";
205
+ const paypalCardProviderId = providerIds?.paypalCard || "paypal_card";
206
+ const shouldRender = selectedProviderId === paypalProviderId || selectedProviderId === paypalCardProviderId;
207
+ const { config, loading, error } = usePayPalConfig({ baseUrl, publishableApiKey, cartId });
208
+ if (!shouldRender) return null;
209
+ if (loading) return /* @__PURE__ */ jsx("div", { children: "Loading PayPal\u2026" });
210
+ if (error) return /* @__PURE__ */ jsx("div", { style: { color: "crimson" }, children: error });
211
+ if (!config) return null;
212
+ return /* @__PURE__ */ jsxs("div", { style: { display: "grid", gap: 12 }, children: [
213
+ /* @__PURE__ */ jsx(PayPalCurrencyNotice, { config }),
214
+ /* @__PURE__ */ jsx(PayPalProvider, { config, intent: "capture", children: selectedProviderId === paypalCardProviderId ? /* @__PURE__ */ jsx(
215
+ PayPalAdvancedCard,
216
+ {
217
+ baseUrl,
218
+ publishableApiKey,
219
+ cartId,
220
+ config,
221
+ onPaid
222
+ }
223
+ ) : /* @__PURE__ */ jsx(
224
+ PayPalSmartButtons,
225
+ {
226
+ baseUrl,
227
+ publishableApiKey,
228
+ cartId,
229
+ config,
230
+ onPaid
231
+ }
232
+ ) })
233
+ ] });
234
+ }
235
+
236
+ export { MedusaNextPayPalAdapter, PayPalAdvancedCard, PayPalCurrencyNotice, PayPalProvider, PayPalSmartButtons, createPayPalStoreApi, usePayPalConfig };
237
+ //# sourceMappingURL=index.mjs.map
238
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/client/http.ts","../src/client/paypal.ts","../src/hooks/usePayPalConfig.ts","../src/components/PayPalProvider.tsx","../src/components/PayPalCurrencyNotice.tsx","../src/components/PayPalSmartButtons.tsx","../src/components/PayPalAdvancedCard.tsx","../src/adapters/MedusaNextPayPalAdapter.tsx"],"names":["useMemo","jsx","useState","jsxs"],"mappings":"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","file":"index.mjs","sourcesContent":["export type HttpOptions = {\n baseUrl: string\n publishableApiKey?: string\n}\n\nexport function createHttpClient(opts: HttpOptions) {\n const base = opts.baseUrl.replace(/\\/+$/, \"\")\n\n async function request<T>(path: string, init?: RequestInit): Promise<T> {\n const url = `${base}${path.startsWith(\"/\") ? \"\" : \"/\"}${path}`\n const headers: Record<string, string> = {\n Accept: \"application/json\",\n ...(init?.headers as any),\n }\n\n if (opts.publishableApiKey) {\n headers[\"x-publishable-api-key\"] = opts.publishableApiKey\n }\n\n const res = await fetch(url, { ...init, headers, credentials: \"include\" })\n const text = await res.text().catch(() => \"\")\n\n if (!res.ok) {\n throw new Error(text || `Request failed (${res.status})`)\n }\n\n return (text ? JSON.parse(text) : {}) as T\n }\n\n return { request }\n}\n","import type { PayPalConfig, PayPalSettingsResponse } from \"./types\"\nimport { createHttpClient, type HttpOptions } from \"./http\"\n\nexport function createPayPalStoreApi(opts: HttpOptions) {\n const http = createHttpClient(opts)\n\n return {\n getConfig(cartId?: string) {\n const q = cartId ? `?cart_id=${encodeURIComponent(cartId)}` : \"\"\n return http.request<PayPalConfig>(`/store/paypal/config${q}`)\n },\n\n getSettings() {\n return http.request<PayPalSettingsResponse>(`/store/paypal/settings`)\n },\n\n createOrder(cartId: string) {\n return http.request<{ id: string }>(`/store/paypal/create-order`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ cart_id: cartId }),\n })\n },\n\n captureOrder(cartId: string, orderId: string) {\n return http.request<any>(`/store/paypal/capture-order`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ cart_id: cartId, order_id: orderId }),\n })\n },\n }\n}\n","import { useEffect, useMemo, useState } from \"react\"\nimport { createPayPalStoreApi } from \"../client/paypal\"\nimport type { PayPalConfig } from \"../client/types\"\n\ntype Args = {\n baseUrl: string\n publishableApiKey?: string\n cartId?: string\n}\n\nexport function usePayPalConfig({ baseUrl, publishableApiKey, cartId }: Args) {\n const api = useMemo(\n () => createPayPalStoreApi({ baseUrl, publishableApiKey }),\n [baseUrl, publishableApiKey]\n )\n\n const [config, setConfig] = useState<PayPalConfig | null>(null)\n const [loading, setLoading] = useState(false)\n const [error, setError] = useState<string | null>(null)\n\n useEffect(() => {\n let mounted = true\n ;(async () => {\n try {\n setLoading(true)\n setError(null)\n const cfg = await api.getConfig(cartId)\n if (mounted) setConfig(cfg)\n } catch (e: any) {\n if (mounted) setError(e?.message || \"Failed to load PayPal config\")\n } finally {\n if (mounted) setLoading(false)\n }\n })()\n\n return () => {\n mounted = false\n }\n }, [api, cartId])\n\n return { config, loading, error }\n}\n","\"use client\"\n\nimport React, { useMemo } from \"react\"\nimport { PayPalScriptProvider } from \"@paypal/react-paypal-js\"\nimport type { PayPalConfig } from \"../client/types\"\n\nexport function PayPalProvider(props: {\n config: PayPalConfig\n intent?: \"capture\" | \"authorize\"\n children: React.ReactNode\n}) {\n const { config, intent = \"capture\", children } = props\n\n const options = useMemo(() => {\n return {\n \"client-id\": config.client_id,\n currency: config.currency,\n intent,\n components: config.client_token ? \"buttons,card-fields\" : \"buttons\",\n \"data-client-token\": config.client_token || undefined,\n } as any\n }, [config, intent])\n\n return <PayPalScriptProvider options={options}>{children}</PayPalScriptProvider>\n}\n","\"use client\"\n\nimport React from \"react\"\nimport type { PayPalConfig } from \"../client/types\"\n\nexport function PayPalCurrencyNotice({ config }: { config: PayPalConfig }) {\n if (config.currency_supported) return null\n\n return (\n <div style={{ padding: 12, border: \"1px solid #ddd\", borderRadius: 10 }}>\n <div style={{ fontWeight: 600, marginBottom: 6 }}>PayPal currency issue</div>\n <ul style={{ margin: 0, paddingLeft: 18 }}>\n {(config.currency_errors || []).map((e, i) => (\n <li key={i}>{e}</li>\n ))}\n </ul>\n </div>\n )\n}\n","\"use client\"\n\nimport React, { useMemo, useState } from \"react\"\nimport { PayPalButtons } from \"@paypal/react-paypal-js\"\nimport { createPayPalStoreApi } from \"../client/paypal\"\nimport type { PayPalConfig } from \"../client/types\"\n\nexport function PayPalSmartButtons(props: {\n baseUrl: string\n publishableApiKey?: string\n cartId: string\n config: PayPalConfig\n onPaid?: (result: any) => void\n onError?: (message: string) => void\n}) {\n const { baseUrl, publishableApiKey, cartId, config, onPaid, onError } = props\n const api = useMemo(\n () => createPayPalStoreApi({ baseUrl, publishableApiKey }),\n [baseUrl, publishableApiKey]\n )\n\n const [error, setError] = useState<string | null>(null)\n\n if (!config.currency_supported) return null\n\n return (\n <div>\n <PayPalButtons\n style={{ layout: \"vertical\" }}\n createOrder={async () => {\n setError(null)\n const r = await api.createOrder(cartId)\n return r.id\n }}\n onApprove={async (data: any) => {\n setError(null)\n const orderId = String(data?.orderID || \"\")\n const result = await api.captureOrder(cartId, orderId)\n onPaid?.(result)\n }}\n onError={(err: any) => {\n const msg = err?.message || \"PayPal error\"\n setError(msg)\n onError?.(msg)\n }}\n />\n {error ? <div style={{ marginTop: 10, color: \"crimson\" }}>{error}</div> : null}\n </div>\n )\n}\n","\"use client\"\n\nimport React, { useMemo, useState } from \"react\"\nimport {\n PayPalCardFieldsProvider,\n PayPalNameField,\n PayPalNumberField,\n PayPalExpiryField,\n PayPalCVVField,\n usePayPalCardFields,\n} from \"@paypal/react-paypal-js\"\nimport { createPayPalStoreApi } from \"../client/paypal\"\nimport type { PayPalConfig } from \"../client/types\"\n\nfunction SubmitButton({ disabled, label }: { disabled: boolean; label: string }) {\n const { cardFieldsForm } = usePayPalCardFields()\n\n return (\n <button\n type=\"button\"\n disabled={disabled || !cardFieldsForm}\n onClick={() => cardFieldsForm?.submit()}\n style={{ padding: \"10px 12px\", borderRadius: 10, border: \"1px solid #ddd\" }}\n >\n {label}\n </button>\n )\n}\n\nexport function PayPalAdvancedCard(props: {\n baseUrl: string\n publishableApiKey?: string\n cartId: string\n config: PayPalConfig\n onPaid?: (result: any) => void\n onError?: (message: string) => void\n}) {\n const { baseUrl, publishableApiKey, cartId, config, onPaid, onError } = props\n const api = useMemo(\n () => createPayPalStoreApi({ baseUrl, publishableApiKey }),\n [baseUrl, publishableApiKey]\n )\n\n const [error, setError] = useState<string | null>(null)\n const [submitting, setSubmitting] = useState(false)\n\n if (!config.currency_supported) return null\n\n if (!config.client_token) {\n return (\n <div style={{ padding: 12, border: \"1px solid #ddd\", borderRadius: 10 }}>\n CardFields unavailable: missing client_token from backend.\n </div>\n )\n }\n\n return (\n <PayPalCardFieldsProvider\n createOrder={async () => {\n setError(null)\n const r = await api.createOrder(cartId)\n return r.id\n }}\n onApprove={async (data: any) => {\n try {\n setSubmitting(true)\n setError(null)\n const orderId = String(data?.orderID || \"\")\n const result = await api.captureOrder(cartId, orderId)\n onPaid?.(result)\n } catch (e: any) {\n const msg = e?.message || \"Card payment failed\"\n setError(msg)\n onError?.(msg)\n } finally {\n setSubmitting(false)\n }\n }}\n onError={(e: any) => {\n const msg = e?.message || \"CardFields error\"\n setError(msg)\n onError?.(msg)\n }}\n >\n <div style={{ display: \"grid\", gap: 10 }}>\n <PayPalNameField />\n <PayPalNumberField />\n <div style={{ display: \"grid\", gridTemplateColumns: \"1fr 1fr\", gap: 10 }}>\n <PayPalExpiryField />\n <PayPalCVVField />\n </div>\n\n <SubmitButton disabled={submitting} label={submitting ? \"Processing...\" : \"Pay by Card\"} />\n\n {error ? <div style={{ color: \"crimson\" }}>{error}</div> : null}\n </div>\n </PayPalCardFieldsProvider>\n )\n}\n","\"use client\"\n\nimport React from \"react\"\nimport type { PayPalConfig } from \"../client/types\"\nimport { usePayPalConfig } from \"../hooks/usePayPalConfig\"\nimport { PayPalProvider } from \"../components/PayPalProvider\"\nimport { PayPalCurrencyNotice } from \"../components/PayPalCurrencyNotice\"\nimport { PayPalSmartButtons } from \"../components/PayPalSmartButtons\"\nimport { PayPalAdvancedCard } from \"../components/PayPalAdvancedCard\"\n\nexport type MedusaNextPayPalAdapterProps = {\n cartId: string\n selectedProviderId: string | null | undefined\n baseUrl: string\n publishableApiKey?: string\n providerIds?: {\n paypal?: string\n paypalCard?: string\n }\n onPaid?: (result: any) => void\n}\n\nexport function MedusaNextPayPalAdapter(props: MedusaNextPayPalAdapterProps) {\n const { cartId, selectedProviderId, baseUrl, publishableApiKey, providerIds, onPaid } = props\n\n const paypalProviderId = providerIds?.paypal || \"paypal\"\n const paypalCardProviderId = providerIds?.paypalCard || \"paypal_card\"\n\n const shouldRender =\n selectedProviderId === paypalProviderId || selectedProviderId === paypalCardProviderId\n\n const { config, loading, error } = usePayPalConfig({ baseUrl, publishableApiKey, cartId })\n\n if (!shouldRender) return null\n if (loading) return <div>Loading PayPal…</div>\n if (error) return <div style={{ color: \"crimson\" }}>{error}</div>\n if (!config) return null\n\n return (\n <div style={{ display: \"grid\", gap: 12 }}>\n <PayPalCurrencyNotice config={config as PayPalConfig} />\n\n <PayPalProvider config={config as PayPalConfig} intent=\"capture\">\n {selectedProviderId === paypalCardProviderId ? (\n <PayPalAdvancedCard\n baseUrl={baseUrl}\n publishableApiKey={publishableApiKey}\n cartId={cartId}\n config={config as PayPalConfig}\n onPaid={onPaid}\n />\n ) : (\n <PayPalSmartButtons\n baseUrl={baseUrl}\n publishableApiKey={publishableApiKey}\n cartId={cartId}\n config={config as PayPalConfig}\n onPaid={onPaid}\n />\n )}\n </PayPalProvider>\n </div>\n )\n}\n"]}
package/package.json ADDED
@@ -0,0 +1,49 @@
1
+ {
2
+ "name": "@easypayment/medusa-paypal-ui",
3
+ "version": "0.0.3",
4
+ "description": "Enterprise Gold PayPal UI module for Medusa v2 storefront (Next.js)",
5
+ "license": "MIT",
6
+ "type": "module",
7
+ "sideEffects": false,
8
+ "main": "./dist/index.cjs",
9
+ "module": "./dist/index.mjs",
10
+ "types": "./dist/index.d.ts",
11
+ "files": [
12
+ "dist",
13
+ "README.md",
14
+ "LICENSE"
15
+ ],
16
+ "exports": {
17
+ ".": {
18
+ "types": "./dist/index.d.ts",
19
+ "import": "./dist/index.mjs",
20
+ "require": "./dist/index.cjs"
21
+ },
22
+ "./package.json": "./package.json"
23
+ },
24
+ "peerDependencies": {
25
+ "next": ">=14",
26
+ "react": ">=18",
27
+ "react-dom": ">=18"
28
+ },
29
+ "dependencies": {
30
+ "@paypal/react-paypal-js": "^8.8.0"
31
+ },
32
+ "devDependencies": {
33
+ "@testing-library/jest-dom": "^6.5.0",
34
+ "@testing-library/react": "^16.0.0",
35
+ "@types/react": "^19.2.14",
36
+ "@types/react-dom": "^19.2.3",
37
+ "jsdom": "^24.0.0",
38
+ "tsup": "^8.0.0",
39
+ "typescript": "^5.0.0",
40
+ "vitest": "^2.0.5"
41
+ },
42
+ "scripts": {
43
+ "build": "tsup",
44
+ "dev": "tsup --watch",
45
+ "test": "vitest run",
46
+ "test:watch": "vitest",
47
+ "prepublishOnly": "npm run build"
48
+ }
49
+ }