@sikka/aps 0.0.2 → 0.0.4

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.
@@ -1,409 +0,0 @@
1
- // src/react/TokenizationForm.tsx
2
- import { useState } from "react";
3
- import { jsx, jsxs } from "react/jsx-runtime";
4
- function detectCardBrand(cardNumber) {
5
- const number = cardNumber.replace(/\D/g, "");
6
- if (/^4/.test(number)) return "visa";
7
- if (/^5[1-5]/.test(number)) return "mastercard";
8
- if (/^3[47]/.test(number)) return "amex";
9
- if (/^6(?:011|5)/.test(number)) return "discover";
10
- if (/^(?:2131|1800|35)/.test(number)) return "jcb";
11
- if (/^9792/.test(number)) return "troy";
12
- if (/^50/.test(number) || /^4571/.test(number)) return "mada";
13
- return "unknown";
14
- }
15
- var DefaultIcons = {
16
- visa: /* @__PURE__ */ jsxs("svg", { viewBox: "0 0 48 48", className: "w-8 h-8", children: [
17
- /* @__PURE__ */ jsx("rect", { fill: "#1A1F71", rx: "4", width: "48", height: "48" }),
18
- /* @__PURE__ */ jsx(
19
- "path",
20
- {
21
- fill: "#fff",
22
- d: "M19.5 30h-3l1.9-11.5h3L19.5 30zm11.4 0h-2.7l-1.7-8.2c-.2-.9-.4-1.7-.5-2.6-.1 0-.2.1-.3.2-.6.8-1.3 1.6-1.9 2.4L22.5 30h-3l3.1-11.5h2.8l.4 2.1c.7-1 1.5-2 2.3-2.9.9-1.2 2-1.7 3.4-1.7.5 0 1 0 1.5.1l-2.1 13.9zm6.6-11.3c-.8-.3-2.6-.7-4.6-.7-5.1 0-8.7 2.7-8.7 6.5 0 2.9 2.6 4.5 4.6 5.5 2 .9 2.7 1.6 2.7 2.4 0 1.3-1.6 1.9-3 1.9-2 0-3.1-.3-4.8-1l-.7-.3-.7 4.3c1.2.5 3.4 1 5.7 1 5.4 0 8.9-2.7 8.9-6.8 0-2.3-1.4-4-4.4-5.5-1.8-.9-2.9-1.6-2.9-2.5 0-.8.9-1.7 2.8-1.7 1.6 0 2.8.3 3.7.7l.4.2.7-4.2z"
23
- }
24
- )
25
- ] }),
26
- mastercard: /* @__PURE__ */ jsxs("svg", { viewBox: "0 0 48 48", className: "w-8 h-8", children: [
27
- /* @__PURE__ */ jsx("rect", { fill: "#000", rx: "4", width: "48", height: "48" }),
28
- /* @__PURE__ */ jsx("circle", { fill: "#EB001B", cx: "18", cy: "24", r: "10" }),
29
- /* @__PURE__ */ jsx("circle", { fill: "#F79E1B", cx: "30", cy: "24", r: "10", opacity: "0.8" })
30
- ] }),
31
- amex: /* @__PURE__ */ jsxs("svg", { viewBox: "0 0 48 48", className: "w-8 h-8", children: [
32
- /* @__PURE__ */ jsx("rect", { fill: "#006FCF", rx: "4", width: "48", height: "48" }),
33
- /* @__PURE__ */ jsx(
34
- "path",
35
- {
36
- fill: "#fff",
37
- d: "M10 18h28v12H10V18zm2 2v8h24v-8H12z"
38
- }
39
- )
40
- ] }),
41
- mada: /* @__PURE__ */ jsxs("svg", { viewBox: "0 0 48 48", className: "w-8 h-8", children: [
42
- /* @__PURE__ */ jsx("rect", { fill: "#006C35", rx: "4", width: "48", height: "48" }),
43
- /* @__PURE__ */ jsx(
44
- "path",
45
- {
46
- fill: "#fff",
47
- d: "M12 20h24v8H12v-8zm2 2v4h20v-4H14z"
48
- }
49
- )
50
- ] }),
51
- unknown: /* @__PURE__ */ jsxs("svg", { viewBox: "0 0 48 48", className: "w-8 h-8", children: [
52
- /* @__PURE__ */ jsx("rect", { fill: "#666", rx: "4", width: "48", height: "48" }),
53
- /* @__PURE__ */ jsx("rect", { fill: "#999", x: "10", y: "18", width: "28", height: "12", rx: "2" })
54
- ] })
55
- };
56
- var defaultStyles = {
57
- container: {
58
- maxWidth: "480px",
59
- margin: "0 auto"
60
- },
61
- form: {
62
- display: "flex",
63
- flexDirection: "column",
64
- gap: "16px"
65
- },
66
- inputGroup: {
67
- display: "flex",
68
- flexDirection: "column",
69
- gap: "4px"
70
- },
71
- label: {
72
- fontSize: "14px",
73
- fontWeight: "500",
74
- color: "#374151"
75
- },
76
- input: {
77
- padding: "12px 16px",
78
- fontSize: "16px",
79
- border: "1px solid #D1D5DB",
80
- borderRadius: "8px",
81
- outline: "none",
82
- transition: "border-color 0.2s"
83
- },
84
- inputError: {
85
- borderColor: "#EF4444"
86
- },
87
- row: {
88
- display: "grid",
89
- gridTemplateColumns: "1fr 1fr",
90
- gap: "12px"
91
- },
92
- button: {
93
- padding: "14px 24px",
94
- fontSize: "16px",
95
- fontWeight: "600",
96
- color: "#fff",
97
- backgroundColor: "#7C3AED",
98
- border: "none",
99
- borderRadius: "8px",
100
- cursor: "pointer",
101
- transition: "background-color 0.2s"
102
- },
103
- buttonDisabled: {
104
- backgroundColor: "#A78BFA",
105
- cursor: "not-allowed"
106
- },
107
- securityNotice: {
108
- padding: "12px",
109
- backgroundColor: "#D1FAE5",
110
- borderRadius: "8px",
111
- fontSize: "13px",
112
- color: "#065F46"
113
- }
114
- };
115
- var TokenizationForm = ({
116
- actionUrl,
117
- formParams,
118
- customerEmail = "",
119
- onSuccess: _onSuccess,
120
- // Success is handled via returnUrl redirect
121
- onError,
122
- styles = {},
123
- icons = {},
124
- labels = {},
125
- placeholders = {},
126
- disableFormatting = false,
127
- showCardIcons = true,
128
- showSecurityNotice = true,
129
- className = {}
130
- }) => {
131
- const [cardNumber, setCardNumber] = useState("");
132
- const [expiryDate, setExpiryDate] = useState("");
133
- const [cvv, setCvv] = useState("");
134
- const [cardHolderName, setCardHolderName] = useState("");
135
- const [email, setEmail] = useState(customerEmail);
136
- const [loading, setLoading] = useState(false);
137
- const [errors, setErrors] = useState({});
138
- const [cardBrand, setCardBrand] = useState("unknown");
139
- const mergedStyles = {
140
- ...defaultStyles,
141
- ...styles
142
- };
143
- const mergedIcons = {
144
- ...DefaultIcons,
145
- ...icons
146
- };
147
- const mergedLabels = {
148
- cardNumber: "Card Number",
149
- cardHolder: "Card Holder Name",
150
- customerEmail: "Customer Email",
151
- expiryDate: "Expiry Date",
152
- cvv: "CVV",
153
- submitButton: "Secure Payment",
154
- processing: "Processing...",
155
- ...labels
156
- };
157
- const mergedPlaceholders = {
158
- cardNumber: "1234 5678 9012 3456",
159
- cardHolder: "John Doe",
160
- customerEmail: "customer@example.com",
161
- expiryDate: "MM/YY",
162
- cvv: "123",
163
- ...placeholders
164
- };
165
- const formatCardNumber = (value) => {
166
- if (disableFormatting) return value;
167
- const v = value.replace(/\s+/g, "").replace(/[^0-9]/gi, "");
168
- const matches = v.match(/\d{4,16}/g);
169
- const match = matches && matches[0] || "";
170
- const parts = [];
171
- for (let i = 0, len = match.length; i < len; i += 4) {
172
- parts.push(match.substring(i, i + 4));
173
- }
174
- if (parts.length) {
175
- return parts.join(" ");
176
- }
177
- return value;
178
- };
179
- const formatExpiryDate = (value) => {
180
- if (disableFormatting) return value;
181
- const v = value.replace(/\s+/g, "").replace(/[^0-9]/gi, "");
182
- if (v.length >= 2) {
183
- return v.substring(0, 2) + "/" + v.substring(2, 4);
184
- }
185
- return v;
186
- };
187
- const validateForm = () => {
188
- const newErrors = {};
189
- if (!cardNumber || cardNumber.replace(/\s/g, "").length < 13) {
190
- newErrors.cardNumber = "Invalid card number";
191
- }
192
- if (!expiryDate || expiryDate.length !== 5) {
193
- newErrors.expiryDate = "Invalid expiry date";
194
- }
195
- if (!cvv || cvv.length < 3) {
196
- newErrors.cvv = "Invalid CVV";
197
- }
198
- if (!cardHolderName || cardHolderName.length < 2) {
199
- newErrors.cardHolder = "Card holder name is required";
200
- }
201
- if (email && !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)) {
202
- newErrors.email = "Invalid email address";
203
- }
204
- setErrors(newErrors);
205
- return Object.keys(newErrors).length === 0;
206
- };
207
- const handleSubmit = (e) => {
208
- e.preventDefault();
209
- if (!validateForm()) {
210
- onError?.("Please fill in all required fields correctly");
211
- return;
212
- }
213
- setLoading(true);
214
- const form = document.createElement("form");
215
- form.method = "POST";
216
- form.action = actionUrl;
217
- form.style.display = "none";
218
- Object.entries(formParams).forEach(([key, value]) => {
219
- const input = document.createElement("input");
220
- input.type = "hidden";
221
- input.name = key;
222
- input.value = value;
223
- form.appendChild(input);
224
- });
225
- const addHiddenInput = (name, value) => {
226
- const input = document.createElement("input");
227
- input.type = "hidden";
228
- input.name = name;
229
- input.value = value;
230
- form.appendChild(input);
231
- };
232
- const cleanCardNumber = cardNumber.replace(/\s/g, "");
233
- const cleanExpiryDate = expiryDate.replace("/", "");
234
- addHiddenInput("card_number", cleanCardNumber);
235
- addHiddenInput("expiry_date", cleanExpiryDate);
236
- addHiddenInput("card_security_code", cvv);
237
- addHiddenInput("card_holder_name", cardHolderName);
238
- document.body.appendChild(form);
239
- form.submit();
240
- setLoading(false);
241
- };
242
- const handleCardNumberChange = (e) => {
243
- const formatted = formatCardNumber(e.target.value);
244
- setCardNumber(formatted);
245
- setCardBrand(detectCardBrand(formatted));
246
- if (errors.cardNumber) {
247
- setErrors({ ...errors, cardNumber: "" });
248
- }
249
- };
250
- const handleExpiryDateChange = (e) => {
251
- const formatted = formatExpiryDate(e.target.value);
252
- setExpiryDate(formatted);
253
- if (errors.expiryDate) {
254
- setErrors({ ...errors, expiryDate: "" });
255
- }
256
- };
257
- const handleCvvChange = (e) => {
258
- const value = e.target.value.replace(/\D/g, "").substring(0, 4);
259
- setCvv(value);
260
- if (errors.cvv) {
261
- setErrors({ ...errors, cvv: "" });
262
- }
263
- };
264
- return /* @__PURE__ */ jsx("div", { style: mergedStyles.container, className: className.container || "", children: /* @__PURE__ */ jsxs("form", { onSubmit: handleSubmit, style: mergedStyles.form, className: className.form || "", children: [
265
- /* @__PURE__ */ jsxs("div", { style: mergedStyles.inputGroup, className: className.inputGroup || "", children: [
266
- /* @__PURE__ */ jsx("label", { style: mergedStyles.label, className: className.label || "", children: mergedLabels.cardNumber }),
267
- /* @__PURE__ */ jsxs("div", { style: { position: "relative" }, children: [
268
- /* @__PURE__ */ jsx(
269
- "input",
270
- {
271
- type: "text",
272
- value: cardNumber,
273
- onChange: handleCardNumberChange,
274
- placeholder: mergedPlaceholders.cardNumber,
275
- maxLength: 19,
276
- required: true,
277
- style: {
278
- ...mergedStyles.input,
279
- ...errors.cardNumber ? mergedStyles.inputError : {},
280
- paddingRight: showCardIcons ? "60px" : "16px"
281
- },
282
- className: className.input || ""
283
- }
284
- ),
285
- showCardIcons && cardBrand !== "unknown" && /* @__PURE__ */ jsx(
286
- "div",
287
- {
288
- style: {
289
- position: "absolute",
290
- right: "12px",
291
- top: "50%",
292
- transform: "translateY(-50%)"
293
- },
294
- children: mergedIcons[cardBrand]
295
- }
296
- )
297
- ] }),
298
- errors.cardNumber && /* @__PURE__ */ jsx("span", { style: { color: "#EF4444", fontSize: "12px" }, children: errors.cardNumber })
299
- ] }),
300
- /* @__PURE__ */ jsxs("div", { style: mergedStyles.inputGroup, className: className.inputGroup || "", children: [
301
- /* @__PURE__ */ jsx("label", { style: mergedStyles.label, className: className.label || "", children: mergedLabels.cardHolder }),
302
- /* @__PURE__ */ jsx(
303
- "input",
304
- {
305
- type: "text",
306
- value: cardHolderName,
307
- onChange: (e) => {
308
- setCardHolderName(e.target.value);
309
- if (errors.cardHolder) {
310
- setErrors({ ...errors, cardHolder: "" });
311
- }
312
- },
313
- placeholder: mergedPlaceholders.cardHolder,
314
- required: true,
315
- style: {
316
- ...mergedStyles.input,
317
- ...errors.cardHolder ? mergedStyles.inputError : {}
318
- },
319
- className: className.input || ""
320
- }
321
- ),
322
- errors.cardHolder && /* @__PURE__ */ jsx("span", { style: { color: "#EF4444", fontSize: "12px" }, children: errors.cardHolder })
323
- ] }),
324
- /* @__PURE__ */ jsxs("div", { style: mergedStyles.inputGroup, className: className.inputGroup || "", children: [
325
- /* @__PURE__ */ jsx("label", { style: mergedStyles.label, className: className.label || "", children: mergedLabels.customerEmail }),
326
- /* @__PURE__ */ jsx(
327
- "input",
328
- {
329
- type: "email",
330
- value: email,
331
- onChange: (e) => {
332
- setEmail(e.target.value);
333
- if (errors.email) {
334
- setErrors({ ...errors, email: "" });
335
- }
336
- },
337
- placeholder: mergedPlaceholders.customerEmail,
338
- style: {
339
- ...mergedStyles.input,
340
- ...errors.email ? mergedStyles.inputError : {}
341
- },
342
- className: className.input || ""
343
- }
344
- ),
345
- errors.email && /* @__PURE__ */ jsx("span", { style: { color: "#EF4444", fontSize: "12px" }, children: errors.email }),
346
- /* @__PURE__ */ jsx("span", { style: { fontSize: "12px", color: "#6B7280" }, children: "Used to associate the saved card with the customer" })
347
- ] }),
348
- /* @__PURE__ */ jsxs("div", { style: mergedStyles.row, children: [
349
- /* @__PURE__ */ jsxs("div", { style: mergedStyles.inputGroup, className: className.inputGroup || "", children: [
350
- /* @__PURE__ */ jsx("label", { style: mergedStyles.label, className: className.label || "", children: mergedLabels.expiryDate }),
351
- /* @__PURE__ */ jsx(
352
- "input",
353
- {
354
- type: "text",
355
- value: expiryDate,
356
- onChange: handleExpiryDateChange,
357
- placeholder: mergedPlaceholders.expiryDate,
358
- maxLength: 5,
359
- required: true,
360
- style: {
361
- ...mergedStyles.input,
362
- ...errors.expiryDate ? mergedStyles.inputError : {}
363
- },
364
- className: className.input || ""
365
- }
366
- ),
367
- errors.expiryDate && /* @__PURE__ */ jsx("span", { style: { color: "#EF4444", fontSize: "12px" }, children: errors.expiryDate })
368
- ] }),
369
- /* @__PURE__ */ jsxs("div", { style: mergedStyles.inputGroup, className: className.inputGroup || "", children: [
370
- /* @__PURE__ */ jsx("label", { style: mergedStyles.label, className: className.label || "", children: mergedLabels.cvv }),
371
- /* @__PURE__ */ jsx(
372
- "input",
373
- {
374
- type: "text",
375
- value: cvv,
376
- onChange: handleCvvChange,
377
- placeholder: mergedPlaceholders.cvv,
378
- maxLength: 4,
379
- required: true,
380
- style: {
381
- ...mergedStyles.input,
382
- ...errors.cvv ? mergedStyles.inputError : {}
383
- },
384
- className: className.input || ""
385
- }
386
- ),
387
- errors.cvv && /* @__PURE__ */ jsx("span", { style: { color: "#EF4444", fontSize: "12px" }, children: errors.cvv })
388
- ] })
389
- ] }),
390
- showSecurityNotice && /* @__PURE__ */ jsx("div", { style: mergedStyles.securityNotice, children: "\u{1F512} Your card details are securely processed by Amazon Payment Services. We never store your card information." }),
391
- /* @__PURE__ */ jsx(
392
- "button",
393
- {
394
- type: "submit",
395
- disabled: loading,
396
- style: {
397
- ...mergedStyles.button,
398
- ...loading ? mergedStyles.buttonDisabled : {}
399
- },
400
- className: className.button || "",
401
- children: loading ? mergedLabels.processing : mergedLabels.submitButton
402
- }
403
- )
404
- ] }) });
405
- };
406
-
407
- export {
408
- TokenizationForm
409
- };