@sikka/hawa 0.0.3 → 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.
Files changed (49) hide show
  1. package/.github/workflows/hawa-publish-push.yml +45 -0
  2. package/.github/workflows/hawa-publish.yml +2 -0
  3. package/es/index.es.js +1 -0
  4. package/lib/index.js +1 -0
  5. package/package.json +18 -8
  6. package/rollup.config.js +2 -2
  7. package/src/Assets/images/card-background/1.jpeg +0 -0
  8. package/src/Assets/images/card-background/10.jpeg +0 -0
  9. package/src/Assets/images/card-background/11.jpeg +0 -0
  10. package/src/Assets/images/card-background/12.jpeg +0 -0
  11. package/src/Assets/images/card-background/13.jpeg +0 -0
  12. package/src/Assets/images/card-background/14.jpeg +0 -0
  13. package/src/Assets/images/card-background/15.jpeg +0 -0
  14. package/src/Assets/images/card-background/16.jpeg +0 -0
  15. package/src/Assets/images/card-background/17.jpeg +0 -0
  16. package/src/Assets/images/card-background/18.jpeg +0 -0
  17. package/src/Assets/images/card-background/19.jpeg +0 -0
  18. package/src/Assets/images/card-background/2.jpeg +0 -0
  19. package/src/Assets/images/card-background/20.jpeg +0 -0
  20. package/src/Assets/images/card-background/21.jpeg +0 -0
  21. package/src/Assets/images/card-background/22.jpeg +0 -0
  22. package/src/Assets/images/card-background/23.jpeg +0 -0
  23. package/src/Assets/images/card-background/24.jpeg +0 -0
  24. package/src/Assets/images/card-background/25.jpeg +0 -0
  25. package/src/Assets/images/card-background/3.jpeg +0 -0
  26. package/src/Assets/images/card-background/4.jpeg +0 -0
  27. package/src/Assets/images/card-background/5.jpeg +0 -0
  28. package/src/Assets/images/card-background/6.jpeg +0 -0
  29. package/src/Assets/images/card-background/7.jpeg +0 -0
  30. package/src/Assets/images/card-background/8.jpeg +0 -0
  31. package/src/Assets/images/card-background/9.jpeg +0 -0
  32. package/src/Assets/images/card-type/amex.png +0 -0
  33. package/src/Assets/images/card-type/diners.png +0 -0
  34. package/src/Assets/images/card-type/discover.png +0 -0
  35. package/src/Assets/images/card-type/mastercard.png +0 -0
  36. package/src/Assets/images/card-type/troy.png +0 -0
  37. package/src/Assets/images/card-type/unionpay.png +0 -0
  38. package/src/Assets/images/card-type/visa.png +0 -0
  39. package/src/blocks/Payment/Form/CForm.js +326 -0
  40. package/src/blocks/Payment/Form/Card.js +242 -0
  41. package/src/blocks/Payment/Gateway/GooglePay.js +251 -0
  42. package/src/blocks/Payment/Gateway/Payfort.js +90 -0
  43. package/src/blocks/Payment/Gateway/Paypal.js +138 -0
  44. package/src/blocks/Payment/Gateway/Wallet.js +149 -0
  45. package/src/blocks/Payment/PaymentMethod.js +132 -0
  46. package/src/blocks/index.js +13 -0
  47. package/src/index.js +2 -1
  48. package/src/styles.scss +679 -0
  49. package/tools/build-styles.js +17 -0
@@ -0,0 +1,326 @@
1
+ import React, { useEffect, useState, useRef } from "react";
2
+ import sha256 from "crypto-js/sha256";
3
+ import Button from "@material-ui/core/Button";
4
+ import CircularProgress from "@material-ui/core/CircularProgress";
5
+ import useTranslation from "next-translate/useTranslation";
6
+ import axios from "axios";
7
+
8
+ const currentYear = new Date().getFullYear();
9
+ const monthsArr = Array.from({ length: 12 }, (x, i) => {
10
+ const month = i + 1;
11
+ return month <= 9 ? "0" + month : month;
12
+ });
13
+ const yearsArr = Array.from({ length: 9 }, (_x, i) => currentYear + i);
14
+
15
+ export default function CForm({
16
+ cardHolder,
17
+ cardMonth,
18
+ cardYear,
19
+ cardCvv,
20
+ onUpdateState,
21
+ cardNumberRef,
22
+ cardHolderRef,
23
+ cardDateRef,
24
+ cardCvvRef,
25
+ onCardInputFocus,
26
+ onCardInputBlur,
27
+ children,
28
+ selectedPaymentMethod,
29
+ transaction
30
+ }) {
31
+ const payfortFormref = useRef();
32
+ const [loading, setLoading] = useState(false);
33
+ const [cardNumber, setCardNumber] = useState("");
34
+ const [accessCode, setAccessCode] = useState("");
35
+ const [merchantIdentifier, setMerchantIdentifier] = useState("");
36
+ const [shaRequestPassphrase, setSHARequestPassphrase] = useState("");
37
+ const [expiryDate, setExpiryDate] = useState("");
38
+ const [signature, setSignature] = useState("");
39
+ const [ip, setIP] = useState("");
40
+ const { t, lang } = useTranslation("common");
41
+
42
+ const handleFormChange = (event) => {
43
+ const { name, value } = event.target;
44
+
45
+ onUpdateState(name, value);
46
+ };
47
+
48
+ const getData = async () => {
49
+ const res = await axios.get("https://geolocation-db.com/json/");
50
+ console.log(res.data);
51
+ setIP(res.data.IPv4);
52
+ };
53
+
54
+ const generateSignature = () => {
55
+ // Calculate request signature
56
+ let shaString = "";
57
+
58
+ // array request
59
+ let arrData = {
60
+ access_code: process.env.NEXT_PUBLIC_QAWAIM_SOFTWARE_PAYFOR_ACCESS_TOKEN,
61
+ language: lang,
62
+ merchant_identifier:
63
+ process.env.NEXT_PUBLIC_QAWAIM_SOFTWARE_PAYFOR_MERCHANT_ID,
64
+ merchant_reference: "",
65
+ return_url: `${process.env.NEXT_PUBLIC_QAWAIM_USER_PORTAL_URL}/aps_online/response`,
66
+ service_command: "TOKENIZATION"
67
+ };
68
+
69
+ if (
70
+ transaction &&
71
+ transaction?.getTransactionByIDInvoice?.transaction_payment_token
72
+ ) {
73
+ arrData.token_name =
74
+ transaction?.getTransactionByIDInvoice?.transaction_payment_token;
75
+ }
76
+
77
+ console.log("arrData=", arrData);
78
+
79
+ shaString = `${process.env.NEXT_PUBLIC_QAWAIM_SOFTWARE_PAYFOR_SHA_REQUEST_PHRASE}${shaString}`;
80
+ for (const [key, value] of Object.entries(arrData)) {
81
+ shaString = `${shaString}${key}=${value}`;
82
+ }
83
+ shaString = `${shaString}${process.env.NEXT_PUBLIC_QAWAIM_SOFTWARE_PAYFOR_SHA_REQUEST_PHRASE}`;
84
+
85
+ console.log("shaString=", shaString);
86
+
87
+ // your request signature
88
+ let signature = sha256(shaString);
89
+
90
+ console.log("signature=", signature);
91
+ setSignature(signature);
92
+ };
93
+ useEffect(() => {
94
+ if (selectedPaymentMethod && selectedPaymentMethod !== "APPLEPAY") {
95
+ getData();
96
+ generateSignature();
97
+ }
98
+ }, [selectedPaymentMethod, accessCode, shaRequestPassphrase]);
99
+
100
+ useEffect(() => {
101
+ if (cardMonth && cardYear) {
102
+ setExpiryDate(`${cardYear.substring(2)}${cardMonth}`);
103
+ }
104
+ }, [cardMonth, cardYear]);
105
+
106
+ // TODO: We can improve the regex check with a better approach like in the card component.
107
+ const onCardNumberChange = (event) => {
108
+ let { value, name } = event.target;
109
+ let cardNumber = value;
110
+ value = value.replace(/\D/g, "");
111
+ if (/^3[47]\d{0,13}$/.test(value)) {
112
+ cardNumber = value
113
+ .replace(/(\d{4})/, "$1 ")
114
+ .replace(/(\d{4}) (\d{6})/, "$1 $2 ");
115
+ } else if (/^3(?:0[0-5]|[68]\d)\d{0,11}$/.test(value)) {
116
+ // diner's club, 14 digits
117
+ cardNumber = value
118
+ .replace(/(\d{4})/, "$1 ")
119
+ .replace(/(\d{4}) (\d{6})/, "$1 $2 ");
120
+ } else if (/^\d{0,16}$/.test(value)) {
121
+ // regular cc number, 16 digits
122
+ cardNumber = value
123
+ .replace(/(\d{4})/, "$1 ")
124
+ .replace(/(\d{4}) (\d{4})/, "$1 $2 ")
125
+ .replace(/(\d{4}) (\d{4}) (\d{4})/, "$1 $2 $3 ");
126
+ }
127
+
128
+ setCardNumber(cardNumber.trimRight());
129
+ onUpdateState(name, cardNumber);
130
+ };
131
+
132
+ const onCvvFocus = (event) => {
133
+ onUpdateState("isCardFlipped", true);
134
+ };
135
+
136
+ const onCvvBlur = (event) => {
137
+ onUpdateState("isCardFlipped", false);
138
+ };
139
+
140
+ const handlePayfortForm = (e) => {
141
+
142
+ };
143
+
144
+ // NOTE: Currently the cursor on the card number field gets reset if we remove a number, the code bellow was used
145
+ // in class components, need to transform this to work with functional components.
146
+ // getSnapshotBeforeUpdate() {
147
+ // return this.props.cardNumberRef.current.selectionStart;
148
+ // }
149
+
150
+ // const componentDidUpdate = function (prevProps, prevState, cursorIdx) {
151
+ // const node = cardNumberRef.current;
152
+ // const { cardNumber: cardNum } = state;
153
+ // const { cardNumber: prevCardNum } = prevState;
154
+ // if (
155
+ // cardNum.length > prevCardNum.length &&
156
+ // cardNum[cursorIdx - 1] === ' '
157
+ // ) {
158
+ // cursorIdx += 1;
159
+ // } else if (prevCardNum[cursorIdx - 1] === ' ') {
160
+ // cursorIdx -= 1;
161
+ // }
162
+ // node.selectionStart = node.selectionEnd = cursorIdx;
163
+ // };
164
+
165
+ return (
166
+ <div className="card-form">
167
+ <div className="card-list">{children}</div>
168
+ <div className="card-form__inner">
169
+ <div className="card-input">
170
+ <label htmlFor="cardNumber" className="card-input__label">
171
+ {t("cardNumber")}
172
+ </label>
173
+ <input
174
+ type="tel"
175
+ name="cardNumber"
176
+ className="card-input__input"
177
+ autoComplete="off"
178
+ onChange={onCardNumberChange}
179
+ maxLength="19"
180
+ ref={cardNumberRef}
181
+ onFocus={(e) => onCardInputFocus(e, "cardNumber")}
182
+ onBlur={onCardInputBlur}
183
+ value={cardNumber}
184
+ />
185
+ </div>
186
+
187
+ <div className="card-input">
188
+ <label htmlFor="cardName" className="card-input__label">
189
+ {t("cardHolder")}
190
+ </label>
191
+ <input
192
+ type="text"
193
+ className="card-input__input"
194
+ autoComplete="off"
195
+ name="cardHolder"
196
+ onChange={handleFormChange}
197
+ ref={cardHolderRef}
198
+ onFocus={(e) => onCardInputFocus(e, "cardHolder")}
199
+ onBlur={onCardInputBlur}
200
+ />
201
+ </div>
202
+
203
+ <div className="card-form__row">
204
+ <div className="card-form__col">
205
+ <div className="card-form__group">
206
+ <label htmlFor="cardMonth" className="card-input__label">
207
+ {t("cardExpiration")}
208
+ </label>
209
+ <select
210
+ className="card-input__input -select"
211
+ value={cardMonth}
212
+ name="cardMonth"
213
+ onChange={handleFormChange}
214
+ ref={cardDateRef}
215
+ onFocus={(e) => onCardInputFocus(e, "cardDate")}
216
+ onBlur={onCardInputBlur}
217
+ >
218
+ <option value="" disabled>
219
+ {t("cardMonth")}
220
+ </option>
221
+
222
+ {monthsArr.map((val, index) => (
223
+ <option key={index} value={val}>
224
+ {val}
225
+ </option>
226
+ ))}
227
+ </select>
228
+ <select
229
+ name="cardYear"
230
+ className="card-input__input -select"
231
+ value={cardYear}
232
+ onChange={handleFormChange}
233
+ onFocus={(e) => onCardInputFocus(e, "cardDate")}
234
+ onBlur={onCardInputBlur}
235
+ >
236
+ <option value="" disabled>
237
+ {t("cardYear")}
238
+ </option>
239
+
240
+ {yearsArr.map((val, index) => (
241
+ <option key={index} value={val}>
242
+ {val}
243
+ </option>
244
+ ))}
245
+ </select>
246
+ </div>
247
+ </div>
248
+ <div className="card-form__col -cvv">
249
+ <div className="card-input">
250
+ <label htmlFor="cardCvv" className="card-input__label">
251
+ {t("cvv")}
252
+ </label>
253
+ <input
254
+ type="tel"
255
+ className="card-input__input"
256
+ maxLength="4"
257
+ autoComplete="off"
258
+ name="cardCvv"
259
+ onChange={handleFormChange}
260
+ onFocus={onCvvFocus}
261
+ onBlur={onCvvBlur}
262
+ ref={cardCvvRef}
263
+ />
264
+ </div>
265
+ </div>
266
+ </div>
267
+ <div className="card-input" style={{ marginTop: "20px" }}>
268
+ <form
269
+ ref={payfortFormref}
270
+ action={`${process.env.NEXT_PUBLIC_QAWAIM_SOFTWARE_PAYFOR_ENVIRONMENT_URL}`}
271
+ method="POST"
272
+ >
273
+ <input type="hidden" name="access_code" value={`${accessCode}`} />
274
+ <input type="hidden" name="card_holder_name" value={cardHolder} />
275
+ <input
276
+ type="hidden"
277
+ name="card_number"
278
+ value={cardNumber.replace(/\s/g, "")}
279
+ />
280
+ <input type="hidden" name="card_security_code" value={cardCvv} />
281
+ <input type="hidden" name="expiry_date" value={expiryDate} />
282
+ <input type="hidden" name="language" value={lang} />
283
+ <input
284
+ type="hidden"
285
+ name="merchant_identifier"
286
+ value={`${merchantIdentifier}`}
287
+ />
288
+ <input type="hidden" name="merchant_reference" value={""} />
289
+ <input type="hidden" name="remember_me" value="NO" />
290
+ <input
291
+ type="hidden"
292
+ name="return_url"
293
+ value={`${process.env.NEXT_PUBLIC_QAWAIM_USER_PORTAL_URL}/aps_online/register`}
294
+ />
295
+ <input type="hidden" name="service_command" value="TOKENIZATION" />
296
+ <input type="hidden" name="signature" value={signature} />
297
+ {transaction &&
298
+ transaction?.getTransactionByIDInvoice
299
+ ?.transaction_payment_token && (
300
+ <input
301
+ type="hidden"
302
+ name="token_name"
303
+ value={
304
+ transaction?.getTransactionByIDInvoice
305
+ ?.transaction_payment_token
306
+ }
307
+ />
308
+ )}
309
+ </form>
310
+ <Button variant="contained" color="primary" fullWidth onClick={handlePayfortForm}>
311
+ {loading ? (
312
+ <CircularProgress
313
+ variant="indeterminate"
314
+ style={{ color: "white", display: "none" }}
315
+ size={25}
316
+ />
317
+ ) : (
318
+ <span className="pay-new-btn-txt">{t("pay-now")}</span>
319
+ )}
320
+ </Button>
321
+ </div>
322
+ </div>
323
+ </div>
324
+ );
325
+ }
326
+
@@ -0,0 +1,242 @@
1
+ import React, { useState, useEffect, useCallback, useMemo } from "react";
2
+ import {
3
+ CSSTransition,
4
+ TransitionGroup,
5
+ SwitchTransition
6
+ } from "react-transition-group";
7
+
8
+ const CARDS = {
9
+ visa: "^4",
10
+ amex: "^(34|37)",
11
+ mastercard: "^5[1-5]",
12
+ discover: "^6011",
13
+ unionpay: "^62",
14
+ troy: "^9792",
15
+ diners: "^(30[0-5]|36)"
16
+ };
17
+
18
+ const cardBackgroundName = () => {
19
+ let random = Math.floor(Math.random() * 25 + 1);
20
+ return `${random}.jpeg`;
21
+ };
22
+
23
+ const BACKGROUND_IMG = cardBackgroundName();
24
+
25
+ const Card = ({
26
+ cardHolder,
27
+ cardNumber,
28
+ cardMonth,
29
+ cardYear,
30
+ cardCvv,
31
+ isCardFlipped,
32
+ currentFocusedElm,
33
+ onCardElementClick,
34
+ cardNumberRef,
35
+ cardHolderRef,
36
+ cardDateRef
37
+ }) => {
38
+ const [style, setStyle] = useState(null);
39
+
40
+ const cardType = (cardNumber) => {
41
+ const number = cardNumber;
42
+ let re;
43
+ for (const [card, pattern] of Object.entries(CARDS)) {
44
+ re = new RegExp(pattern);
45
+ if (number.match(re) != null) {
46
+ return card;
47
+ }
48
+ }
49
+
50
+ return "visa"; // default type
51
+ };
52
+
53
+ const useCardType = useMemo(() => {
54
+ return cardType(cardNumber);
55
+ }, [cardNumber]);
56
+
57
+ const outlineElementStyle = (element) => {
58
+ return element
59
+ ? {
60
+ width: `${element.offsetWidth}px`,
61
+ height: `${element.offsetHeight}px`,
62
+ transform: `translateX(${element.offsetLeft}px) translateY(${element.offsetTop}px)`
63
+ }
64
+ : null;
65
+ };
66
+
67
+ useEffect(() => {
68
+ if (currentFocusedElm) {
69
+ const style = outlineElementStyle(currentFocusedElm.current);
70
+ setStyle(style);
71
+ }
72
+ }, [currentFocusedElm]);
73
+
74
+ const maskCardNumber = (cardNumber) => {
75
+ let cardNumberArr = cardNumber.split("");
76
+ cardNumberArr.forEach((val, index) => {
77
+ if (index > 4 && index < 14) {
78
+ if (cardNumberArr[index] !== " ") {
79
+ cardNumberArr[index] = "*";
80
+ }
81
+ }
82
+ });
83
+
84
+ return cardNumberArr;
85
+ };
86
+
87
+ return (
88
+ <div className={"card-item " + (isCardFlipped ? "-active" : "")}>
89
+ <div className="card-item__side -front">
90
+ <div
91
+ className={`card-item__focus ${currentFocusedElm ? `-active` : ``}`}
92
+ style={style}
93
+ />
94
+ <div className="card-item__cover">
95
+ <img
96
+ alt=""
97
+ src={`/card-background/${BACKGROUND_IMG}`}
98
+ className="card-item__bg"
99
+ />
100
+ </div>
101
+
102
+ <div className="card-item__wrapper">
103
+ <div className="card-item__top">
104
+ <img src={"/chip.png"} alt="" className="card-item__chip" />
105
+ <div className="card-item__type">
106
+ <img
107
+ alt={useCardType}
108
+ src={`/card-type/${useCardType}.png`}
109
+ className="card-item__typeImg"
110
+ />
111
+ </div>
112
+ </div>
113
+
114
+ <label
115
+ className="card-item__number"
116
+ ref={cardNumberRef}
117
+ onClick={() => onCardElementClick("cardNumber")}
118
+ >
119
+ <TransitionGroup className="slide-fade-up" component="div">
120
+ {cardNumber ? (
121
+ maskCardNumber(cardNumber).map((val, index) => (
122
+ <CSSTransition
123
+ classNames="slide-fade-up"
124
+ timeout={250}
125
+ key={index}
126
+ >
127
+ <div className="card-item__numberItem">{val}</div>
128
+ </CSSTransition>
129
+ ))
130
+ ) : (
131
+ <CSSTransition classNames="slide-fade-up" timeout={250}>
132
+ <div className="card-item__numberItem">#</div>
133
+ </CSSTransition>
134
+ )}
135
+ </TransitionGroup>
136
+ </label>
137
+ <div className="card-item__content">
138
+ <label
139
+ className="card-item__info"
140
+ onClick={() => onCardElementClick("cardHolder")}
141
+ ref={cardHolderRef}
142
+ >
143
+ <div className="card-item__holder">Card Holder</div>
144
+ <div className="card-item__name">
145
+ <TransitionGroup component="div" className="slide-fade-up">
146
+ {cardHolder === "FULL NAME" ? (
147
+ <CSSTransition classNames="slide-fade-up" timeout={250}>
148
+ <div>FULL NAME</div>
149
+ </CSSTransition>
150
+ ) : (
151
+ cardHolder.split("").map((val, index) => (
152
+ <CSSTransition
153
+ timeout={250}
154
+ classNames="slide-fade-right"
155
+ key={index}
156
+ >
157
+ <span className="card-item__nameItem">{val}</span>
158
+ </CSSTransition>
159
+ ))
160
+ )}
161
+ </TransitionGroup>
162
+ </div>
163
+ </label>
164
+ <div
165
+ className="card-item__date"
166
+ onClick={() => onCardElementClick("cardDate")}
167
+ ref={cardDateRef}
168
+ >
169
+ <label className="card-item__dateTitle">Expires</label>
170
+ <label className="card-item__dateItem">
171
+ <SwitchTransition in-out>
172
+ <CSSTransition
173
+ classNames="slide-fade-up"
174
+ timeout={200}
175
+ key={cardMonth}
176
+ >
177
+ <span>{!cardMonth ? "MM" : cardMonth} </span>
178
+ </CSSTransition>
179
+ </SwitchTransition>
180
+ </label>
181
+ /
182
+ <label htmlFor="cardYear" className="card-item__dateItem">
183
+ <SwitchTransition out-in>
184
+ <CSSTransition
185
+ classNames="slide-fade-up"
186
+ timeout={250}
187
+ key={cardYear}
188
+ >
189
+ <span>
190
+ {!cardYear ? "YY" : cardYear.toString().substr(-2)}
191
+ </span>
192
+ </CSSTransition>
193
+ </SwitchTransition>
194
+ </label>
195
+ </div>
196
+ <div
197
+ className="card-item__date"
198
+ onClick={() => onCardElementClick("cardDate")}
199
+ ref={cardDateRef}
200
+ ></div>
201
+ </div>
202
+ </div>
203
+ </div>
204
+
205
+ <div className="card-item__side -back">
206
+ <div className="card-item__cover">
207
+ <img
208
+ alt=""
209
+ src={`/card-background/${BACKGROUND_IMG}`}
210
+ className="card-item__bg"
211
+ />
212
+ </div>
213
+ <div className="card-item__band" />
214
+ <div className="card-item__cvv">
215
+ <div className="card-item__cvvTitle">CVV</div>
216
+ <div className="card-item__cvvBand">
217
+ <TransitionGroup>
218
+ {cardCvv.split("").map((val, index) => (
219
+ <CSSTransition
220
+ classNames="zoom-in-out"
221
+ key={index}
222
+ timeout={250}
223
+ >
224
+ <span>*</span>
225
+ </CSSTransition>
226
+ ))}
227
+ </TransitionGroup>
228
+ </div>
229
+ <div className="card-item__type">
230
+ <img
231
+ alt="card-type"
232
+ src={"/card-type/visa.png"}
233
+ className="card-item__typeImg"
234
+ />
235
+ </div>
236
+ </div>
237
+ </div>
238
+ </div>
239
+ );
240
+ };
241
+
242
+ export default Card;