diff --git a/eslint.config.mjs b/eslint.config.mjs index de3ec78..7024953 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -1,4 +1,3 @@ - import eslint from '@eslint/js'; import tseslint from 'typescript-eslint'; @@ -20,7 +19,7 @@ export default tseslint.config( '@typescript-eslint': tseslint.plugin, }, rules: { - 'react-hooks/exhaustive-deps': 'off', + 'react-hooks/exhaustive-deps': 'off', '@typescript-eslint/no-unsafe-function-type': 'off', '@typescript-eslint/no-explicit-any': 'warn', 'no-prototype-builtins': 'off', @@ -28,14 +27,21 @@ export default tseslint.config( '@typescript-eslint/no-unused-vars': ['off'], '@typescript-eslint/no-unused-expressions': 'off', '@typescript-eslint/no-require-imports': 'warn', + 'quotes': ['error', 'double'], }, }, { files: ['**/*.ts', '**/*.tsx'], - ignores: ['**/__tests__/**', '**/*.test.ts', '**/*.test.tsx', '**/*.spec.ts', '**/*.spec.tsx'], + ignores: [ + '**/__tests__/**', + '**/*.test.ts', + '**/*.test.tsx', + '**/*.spec.ts', + '**/*.spec.tsx', + ], rules: { '@typescript-eslint/ban-ts-comment': 'off', '@typescript-eslint/no-unused-vars': 'off', }, } -); \ No newline at end of file +); diff --git a/package.json b/package.json index 9043d9b..f6278d4 100644 --- a/package.json +++ b/package.json @@ -135,7 +135,7 @@ "error", { "quoteProps": "consistent", - "singleQuote": true, + "singleQuote": false, "tabWidth": 2, "trailingComma": "es5", "useTabs": false @@ -149,7 +149,7 @@ ], "prettier": { "quoteProps": "consistent", - "singleQuote": true, + "singleQuote": false, "tabWidth": 2, "trailingComma": "es5", "useTabs": false diff --git a/src/assets/images/konbiniImages/family-mart.png b/src/assets/images/konbiniImages/family-mart.png deleted file mode 100644 index fa9c0b7..0000000 Binary files a/src/assets/images/konbiniImages/family-mart.png and /dev/null differ diff --git a/src/assets/images/konbiniImages/family-mart@1x.png b/src/assets/images/konbiniImages/family-mart@1x.png new file mode 100644 index 0000000..d60557d Binary files /dev/null and b/src/assets/images/konbiniImages/family-mart@1x.png differ diff --git a/src/assets/images/konbiniImages/family-mart@2x.png b/src/assets/images/konbiniImages/family-mart@2x.png new file mode 100644 index 0000000..1c57ddd Binary files /dev/null and b/src/assets/images/konbiniImages/family-mart@2x.png differ diff --git a/src/assets/images/konbiniImages/family-mart@3x.png b/src/assets/images/konbiniImages/family-mart@3x.png new file mode 100644 index 0000000..d5f63d9 Binary files /dev/null and b/src/assets/images/konbiniImages/family-mart@3x.png differ diff --git a/src/assets/images/konbiniImages/lawson.png b/src/assets/images/konbiniImages/lawson.png deleted file mode 100644 index 8a03415..0000000 Binary files a/src/assets/images/konbiniImages/lawson.png and /dev/null differ diff --git a/src/assets/images/konbiniImages/lawson@1x.png b/src/assets/images/konbiniImages/lawson@1x.png new file mode 100644 index 0000000..b4d53e7 Binary files /dev/null and b/src/assets/images/konbiniImages/lawson@1x.png differ diff --git a/src/assets/images/konbiniImages/lawson@2x.png b/src/assets/images/konbiniImages/lawson@2x.png new file mode 100644 index 0000000..6fc935a Binary files /dev/null and b/src/assets/images/konbiniImages/lawson@2x.png differ diff --git a/src/assets/images/konbiniImages/lawson@3x.png b/src/assets/images/konbiniImages/lawson@3x.png new file mode 100644 index 0000000..691f86d Binary files /dev/null and b/src/assets/images/konbiniImages/lawson@3x.png differ diff --git a/src/assets/images/konbiniImages/seven-eleven.png b/src/assets/images/konbiniImages/seven-eleven.png deleted file mode 100644 index 97de3be..0000000 Binary files a/src/assets/images/konbiniImages/seven-eleven.png and /dev/null differ diff --git a/src/assets/images/konbiniImages/seven-eleven@1x.png b/src/assets/images/konbiniImages/seven-eleven@1x.png new file mode 100644 index 0000000..a4f0b30 Binary files /dev/null and b/src/assets/images/konbiniImages/seven-eleven@1x.png differ diff --git a/src/assets/images/konbiniImages/seven-eleven@2x.png b/src/assets/images/konbiniImages/seven-eleven@2x.png new file mode 100644 index 0000000..e79e684 Binary files /dev/null and b/src/assets/images/konbiniImages/seven-eleven@2x.png differ diff --git a/src/assets/images/konbiniImages/seven-eleven@3x.png b/src/assets/images/konbiniImages/seven-eleven@3x.png new file mode 100644 index 0000000..9382ac3 Binary files /dev/null and b/src/assets/images/konbiniImages/seven-eleven@3x.png differ diff --git a/src/assets/images/paymentMethodImages/credit_card.png b/src/assets/images/paymentMethodImages/credit_card.png deleted file mode 100644 index ba04bfa..0000000 Binary files a/src/assets/images/paymentMethodImages/credit_card.png and /dev/null differ diff --git a/src/assets/images/paymentMethodImages/credit_card@1x.png b/src/assets/images/paymentMethodImages/credit_card@1x.png new file mode 100644 index 0000000..ebd9739 Binary files /dev/null and b/src/assets/images/paymentMethodImages/credit_card@1x.png differ diff --git a/src/assets/images/paymentMethodImages/credit_card@2x.png b/src/assets/images/paymentMethodImages/credit_card@2x.png new file mode 100644 index 0000000..2bfb7ee Binary files /dev/null and b/src/assets/images/paymentMethodImages/credit_card@2x.png differ diff --git a/src/assets/images/paymentMethodImages/credit_card@3x.png b/src/assets/images/paymentMethodImages/credit_card@3x.png new file mode 100644 index 0000000..93c7cb1 Binary files /dev/null and b/src/assets/images/paymentMethodImages/credit_card@3x.png differ diff --git a/src/assets/images/paymentMethodImages/konbini.png b/src/assets/images/paymentMethodImages/konbini.png deleted file mode 100644 index d55909c..0000000 Binary files a/src/assets/images/paymentMethodImages/konbini.png and /dev/null differ diff --git a/src/assets/images/paymentMethodImages/konbini@1x.png b/src/assets/images/paymentMethodImages/konbini@1x.png new file mode 100644 index 0000000..977067c Binary files /dev/null and b/src/assets/images/paymentMethodImages/konbini@1x.png differ diff --git a/src/assets/images/paymentMethodImages/konbini@2x.png b/src/assets/images/paymentMethodImages/konbini@2x.png new file mode 100644 index 0000000..d8160e7 Binary files /dev/null and b/src/assets/images/paymentMethodImages/konbini@2x.png differ diff --git a/src/assets/images/paymentMethodImages/konbini@3x.png b/src/assets/images/paymentMethodImages/konbini@3x.png new file mode 100644 index 0000000..f794b6b Binary files /dev/null and b/src/assets/images/paymentMethodImages/konbini@3x.png differ diff --git a/src/assets/images/paymentMethodImages/paypay.png b/src/assets/images/paymentMethodImages/paypay.png deleted file mode 100644 index 23d22c2..0000000 Binary files a/src/assets/images/paymentMethodImages/paypay.png and /dev/null differ diff --git a/src/assets/images/paymentMethodImages/paypay@1x.png b/src/assets/images/paymentMethodImages/paypay@1x.png new file mode 100644 index 0000000..866cc06 Binary files /dev/null and b/src/assets/images/paymentMethodImages/paypay@1x.png differ diff --git a/src/assets/images/paymentMethodImages/paypay@2x.png b/src/assets/images/paymentMethodImages/paypay@2x.png new file mode 100644 index 0000000..76968f3 Binary files /dev/null and b/src/assets/images/paymentMethodImages/paypay@2x.png differ diff --git a/src/assets/images/paymentMethodImages/paypay@3x.png b/src/assets/images/paymentMethodImages/paypay@3x.png new file mode 100644 index 0000000..8a0c4ca Binary files /dev/null and b/src/assets/images/paymentMethodImages/paypay@3x.png differ diff --git a/src/components/LightBox.tsx b/src/components/LightBox.tsx index 0338e4a..12260b7 100644 --- a/src/components/LightBox.tsx +++ b/src/components/LightBox.tsx @@ -4,12 +4,11 @@ import { useTranslation } from "react-i18next"; import { ThemeSchemeType } from "../util/types"; -import Thunder from "../assets/images/thunder.png" +import Thunder from "../assets/images/thunder.png"; import { resizeFonts, responsiveScale } from "../theme/scalling"; import { useCurrentTheme } from "../theme/useCurrentTheme"; - type Props = { content: string; }; @@ -52,14 +51,13 @@ const getStyles = (theme: ThemeSchemeType) => { backgroundColor: theme.BACKGROUND_COLOR, width: responsiveScale(38), height: responsiveScale(38), - display: 'flex', - justifyContent: 'center', - alignItems: 'center' + display: "flex", + justifyContent: "center", + alignItems: "center", }, icon: { width: responsiveScale(18), height: responsiveScale(18), - } + }, }); - -} \ No newline at end of file +}; diff --git a/src/components/Pill.tsx b/src/components/Pill.tsx index 4b7a75f..042e82a 100644 --- a/src/components/Pill.tsx +++ b/src/components/Pill.tsx @@ -68,10 +68,10 @@ const getStyles = (theme: ThemeSchemeType) => { }, icon: { marginRight: responsiveScale(8), - flex:1 + flex: 1, }, label: { - width: '90%', + width: "90%", fontSize: resizeFonts(14), color: theme.TEXT_COLOR, fontWeight: "500", diff --git a/src/components/PillContainer.tsx b/src/components/PillContainer.tsx index 48a44b9..54b0bd3 100644 --- a/src/components/PillContainer.tsx +++ b/src/components/PillContainer.tsx @@ -17,11 +17,26 @@ type Props = { selectedItem: PaymentType; }; +const squareSizeImages = [ + PaymentType.CREDIT, + PaymentType.KONBINI, + PaymentType.PAY_PAY, +]; + const PillContainer = ({ onSelect, selectedItem }: Props) => { const { paymentMethods } = useContext(StateContext); const getIcon = (slug: PaymentType) => { - return ; + return ( + + ); }; const renderItem = ({ item }: { item: sessionShowPaymentMethodType }) => { @@ -57,8 +72,11 @@ const styles = StyleSheet.create({ }, image: { width: responsiveScale(38), - height: responsiveScale(24), - resizeMode: "contain", + height: responsiveScale(32), + }, + squareImage: { + width: responsiveScale(32), + height: responsiveScale(32), }, }); diff --git a/src/components/ResponseScreen.tsx b/src/components/ResponseScreen.tsx index d03c49c..a371b42 100644 --- a/src/components/ResponseScreen.tsx +++ b/src/components/ResponseScreen.tsx @@ -2,7 +2,11 @@ import { useCallback, useMemo } from "react"; import { Image, StyleSheet, View, ImageSourcePropType } from "react-native"; -import { ResponseScreenStatuses, ThemeSchemeType, PaymentType } from "../util/types"; +import { + ResponseScreenStatuses, + ThemeSchemeType, + PaymentType, +} from "../util/types"; import { resizeFonts, responsiveScale } from "../theme/scalling"; import { useCurrentTheme } from "../theme/useCurrentTheme"; @@ -10,6 +14,10 @@ import { useCurrentTheme } from "../theme/useCurrentTheme"; import KomojuText from "./KomojuText"; import SubmitButton from "./SubmitButton"; +import successIcon from "../assets/images/success.png"; +import errorIcon from "../assets/images/error.png"; +import awaitingPaymentIcon from "../assets/images/awaitingPayment.png"; + type StatusConfig = { title: string; defaultMessage: string; @@ -21,27 +29,27 @@ const statusConfigs: Partial> = { [ResponseScreenStatuses.SUCCESS]: { title: "PAYMENT_SUCCESS", defaultMessage: "ORDER_THANK_YOU_NOTE", - image: require("../assets/images/success.png"), + image: successIcon, }, [ResponseScreenStatuses.FAILED]: { title: "PAYMENT_FAILED", defaultMessage: "PAYMENT_RE_TRY_MSG", - image: require("../assets/images/error.png"), + image: errorIcon, }, [ResponseScreenStatuses.CANCELLED]: { title: "PAYMENT_CANCELLED", defaultMessage: "PAYMENT_CANCELLED_MSG", - image: require("../assets/images/error.png"), + image: errorIcon, }, [ResponseScreenStatuses.COMPLETE]: { title: "PAYMENT_WAITING", defaultMessage: "PAYMENT_WAITING_MSG", - image: require("../assets/images/awaitingPayment.png"), + image: awaitingPaymentIcon, }, [ResponseScreenStatuses.EXPIRED]: { title: "SESSION_EXPIRED", defaultMessage: "SESSION_EXPIRED_MSG", - image: require("../assets/images/error.png"), + image: errorIcon, }, }; @@ -50,10 +58,16 @@ type Props = { message?: string; onPressLabel: string; onPress: () => void; - paymentType: PaymentType + paymentType: PaymentType; }; -const ResponseScreen = ({ status, message, onPress, onPressLabel, paymentType }: Props) => { +const ResponseScreen = ({ + status, + message, + onPress, + onPressLabel, + paymentType, +}: Props) => { const theme = useCurrentTheme(); const styles = getStyles(theme); diff --git a/src/context/KomojuProvider.tsx b/src/context/KomojuProvider.tsx index a7d88f0..7917d0b 100644 --- a/src/context/KomojuProvider.tsx +++ b/src/context/KomojuProvider.tsx @@ -1,9 +1,9 @@ -import { KomojuProviderIprops } from '../util/types'; +import { KomojuProviderIprops } from "../util/types"; -import '../assets/languages/i18n'; -import { MainStateProvider } from './MainStateProvider'; -import StateProvider from './StateProvider'; -import { ThemeProvider } from './ThemeContext'; +import "../assets/languages/i18n"; +import { MainStateProvider } from "./MainStateProvider"; +import StateProvider from "./StateProvider"; +import { ThemeProvider } from "./ThemeContext"; export const KomojuProvider = (props: KomojuProviderIprops) => { return ( diff --git a/src/context/MainStateProvider.tsx b/src/context/MainStateProvider.tsx index 8b6289a..f6d907b 100644 --- a/src/context/MainStateProvider.tsx +++ b/src/context/MainStateProvider.tsx @@ -1,26 +1,21 @@ -import { - useCallback, - useContext, - useMemo, - useRef, - useState, -} from 'react'; +import { useCallback, useContext, useMemo, useRef, useState } from "react"; -import PaymentModal from '../components/PaymentModal'; -import Sheet, { SheetRefProps } from '../components/Sheet'; +import PaymentModal from "../components/PaymentModal"; +import Sheet, { SheetRefProps } from "../components/Sheet"; import { CreatePaymentFuncType, initialState, InitPrams, - KomojuProviderIprops} from '../util/types'; + KomojuProviderIprops, +} from "../util/types"; -import '../assets/languages/i18n'; -import { Actions, DispatchContext, KomojuContext } from './state'; -import useBackgroundHandler from '../hooks/useBackgroundHandler'; -import useDeepLinkHandler from '../hooks/useDeepLinkHandler'; -import usePaymentHandler from '../hooks/usePaymentHandler'; -import useMainStateUtils from '../hooks/useMainStateUtils'; +import "../assets/languages/i18n"; +import { Actions, DispatchContext, KomojuContext } from "./state"; +import useBackgroundHandler from "../hooks/useBackgroundHandler"; +import useDeepLinkHandler from "../hooks/useDeepLinkHandler"; +import usePaymentHandler from "../hooks/usePaymentHandler"; +import useMainStateUtils from "../hooks/useMainStateUtils"; export const MainStateProvider = (props: KomojuProviderIprops) => { const dispatch = useContext(DispatchContext); @@ -32,7 +27,7 @@ export const MainStateProvider = (props: KomojuProviderIprops) => { // ref to hold client provided onDismiss callback const onDismissCallback = useRef(null); // ref to hold client provided session Id - const sessionIdRef = useRef(''); + const sessionIdRef = useRef(""); // Get all the util functions that needs to function the Main State const { @@ -46,7 +41,7 @@ export const MainStateProvider = (props: KomojuProviderIprops) => { closePaymentSheet, onUserCancel, openPaymentSheet, - resetGlobalStates + resetGlobalStates, } = useMainStateUtils({ props: props, sheetRef: sheetRef, @@ -54,7 +49,7 @@ export const MainStateProvider = (props: KomojuProviderIprops) => { toggleUIVisibility: (value: boolean) => setModalVisible(value), initialState: initialState, onDismissCallback: onDismissCallback, - }) + }); // Handle events when module goes foreground useBackgroundHandler({ @@ -67,8 +62,8 @@ export const MainStateProvider = (props: KomojuProviderIprops) => { onPaymentCancelled: onPaymentCancelled, onSessionExpired: onSessionExpired, onPaymentFailed: onPaymentFailed, - onPaymentSuccess: onPaymentSuccess - }) + onPaymentSuccess: onPaymentSuccess, + }); // Handle deep-links of the module useDeepLinkHandler({ @@ -80,8 +75,8 @@ export const MainStateProvider = (props: KomojuProviderIprops) => { onPaymentAwaiting: onPaymentAwaiting, onPaymentCancelled: onPaymentCancelled, onPaymentFailed: onPaymentFailed, - onPaymentSuccess: onPaymentSuccess - }) + onPaymentSuccess: onPaymentSuccess, + }); // Handle validations of the session and pay for session const { sessionPay, validateSession } = usePaymentHandler({ @@ -91,8 +86,8 @@ export const MainStateProvider = (props: KomojuProviderIprops) => { onPaymentAwaiting: onPaymentAwaiting, onPaymentFailed: onPaymentFailed, onPaymentSuccess: onPaymentSuccess, - closePaymentSheet: closePaymentSheet - }) + closePaymentSheet: closePaymentSheet, + }); const createPayment = useCallback( ({ sessionId, onComplete, onDismiss }: CreatePaymentFuncType) => { @@ -127,8 +122,8 @@ export const MainStateProvider = (props: KomojuProviderIprops) => { }, []); // TODO: Fix this type error - - const initializeKomoju = useCallback((_params: InitPrams) => { }, []); + + const initializeKomoju = useCallback((_params: InitPrams) => {}, []); // Conditionally rendering the payment ui const renderPaymentUI = useMemo(() => { diff --git a/src/context/StateProvider.tsx b/src/context/StateProvider.tsx index 9169972..6756f5f 100644 --- a/src/context/StateProvider.tsx +++ b/src/context/StateProvider.tsx @@ -1,8 +1,8 @@ -import { ReactNode, useReducer } from 'react'; +import { ReactNode, useReducer } from "react"; -import { DispatchContext, StateContext, reducer } from './state'; +import { DispatchContext, StateContext, reducer } from "./state"; -import { initialState } from '../util/types'; +import { initialState } from "../util/types"; /** * StateProvider component to provide state and dispatch contexts to its children. diff --git a/src/context/ThemeContext.tsx b/src/context/ThemeContext.tsx index 95fbfc3..c9462e9 100644 --- a/src/context/ThemeContext.tsx +++ b/src/context/ThemeContext.tsx @@ -1,9 +1,9 @@ // ThemeContext.tsx -import React, { createContext, useContext, useState, useEffect } from 'react'; +import React, { createContext, useContext, useState, useEffect } from "react"; -import { Appearance } from 'react-native'; +import { Appearance } from "react-native"; -import { ThemeModes } from '../util/constants'; +import { ThemeModes } from "../util/constants"; interface ThemeContextType { mode: ThemeModes; @@ -17,12 +17,12 @@ export const ThemeProvider: React.FC<{ children: React.ReactNode }> = ({ }) => { const [mode, setMode] = useState(() => { const colorScheme = Appearance.getColorScheme(); - return colorScheme === 'dark' ? ThemeModes.dark : ThemeModes.light; + return colorScheme === "dark" ? ThemeModes.dark : ThemeModes.light; }); useEffect(() => { const subscription = Appearance.addChangeListener(({ colorScheme }) => { - setMode(colorScheme === 'dark' ? ThemeModes.dark : ThemeModes.light); + setMode(colorScheme === "dark" ? ThemeModes.dark : ThemeModes.light); }); return () => subscription.remove(); @@ -44,7 +44,7 @@ export const ThemeProvider: React.FC<{ children: React.ReactNode }> = ({ export const useTheme = (): ThemeContextType => { const context = useContext(ThemeContext); if (context === undefined) { - throw new Error('useTheme must be used within a ThemeProvider'); + throw new Error("useTheme must be used within a ThemeProvider"); } return context; }; diff --git a/src/context/state.ts b/src/context/state.ts index 4153621..0908e91 100644 --- a/src/context/state.ts +++ b/src/context/state.ts @@ -1,6 +1,6 @@ -import { createContext } from 'react'; +import { createContext } from "react"; -import { noop } from '../util/constants'; +import { noop } from "../util/constants"; import { ActionType, CreatePaymentFuncType, @@ -8,30 +8,30 @@ import { PaymentType, State, initialState, -} from '../util/types'; +} from "../util/types"; /** * Action types for the reducer */ export const Actions = { - RESET_STATES: 'RESET_STATES', - SET_CARDHOLDER_NAME: 'SET_CARDHOLDER_NAME', - SET_CARD_NUMBER: 'SET_CARD_NUMBER', - SET_PAYMENT_OPTION: 'SET_PAYMENT_OPTION', - SET_CARD_EXPIRED_DATE: 'SET_CARD_EXPIRED_DATE', - SET_CARD_CVV: 'SET_CARD_CVV', - SET_NAME: 'SET_NAME', - SET_EMAIL: 'SET_EMAIL', - SET_TRANSFER_FORM_FIELDS: 'SET_TRANSFER_FORM_FIELDS', - SET_SINGLE_INPUT_FORM_FIELD: 'SET_SINGLE_INPUT_FORM_FIELD', - SET_LOADING: 'SET_LOADING', - SET_CURRENCY: 'SET_CURRENCY', - SET_AMOUNT: 'SET_AMOUNT', - SET_SELECTED_STORE: 'SET_SELECTED_STORE', - SET_PAYMENT_STATE: 'SET_PAYMENT_STATE', - SET_PAYMENT_METHODS: 'SET_PAYMENT_METHODS', - SESSION_PAY: 'SESSION_PAY', + RESET_STATES: "RESET_STATES", + SET_CARDHOLDER_NAME: "SET_CARDHOLDER_NAME", + SET_CARD_NUMBER: "SET_CARD_NUMBER", + SET_PAYMENT_OPTION: "SET_PAYMENT_OPTION", + SET_CARD_EXPIRED_DATE: "SET_CARD_EXPIRED_DATE", + SET_CARD_CVV: "SET_CARD_CVV", + SET_NAME: "SET_NAME", + SET_EMAIL: "SET_EMAIL", + SET_TRANSFER_FORM_FIELDS: "SET_TRANSFER_FORM_FIELDS", + SET_SINGLE_INPUT_FORM_FIELD: "SET_SINGLE_INPUT_FORM_FIELD", + SET_LOADING: "SET_LOADING", + SET_CURRENCY: "SET_CURRENCY", + SET_AMOUNT: "SET_AMOUNT", + SET_SELECTED_STORE: "SET_SELECTED_STORE", + SET_PAYMENT_STATE: "SET_PAYMENT_STATE", + SET_PAYMENT_METHODS: "SET_PAYMENT_METHODS", + SESSION_PAY: "SESSION_PAY", }; /** diff --git a/src/hooks/useBackgroundHandler.tsx b/src/hooks/useBackgroundHandler.tsx index f115686..38a5960 100644 --- a/src/hooks/useBackgroundHandler.tsx +++ b/src/hooks/useBackgroundHandler.tsx @@ -1,21 +1,24 @@ -import React, { MutableRefObject, useEffect } from 'react' -import { View, Text, AppState, AppStateStatus } from 'react-native' -import { KomojuProviderIprops, PaymentStatuses, TokenResponseStatuses } from '../util/types'; -import sessionShow from '../services/sessionShow'; - +import { MutableRefObject, useEffect } from "react"; +import { AppState, AppStateStatus } from "react-native"; +import { + KomojuProviderIprops, + PaymentStatuses, + TokenResponseStatuses, +} from "../util/types"; +import sessionShow from "../services/sessionShow"; type Props = { - props: KomojuProviderIprops, - startLoading: () => void - stopLoading: () => void - sessionIdRef: MutableRefObject - onCompleteCallback: MutableRefObject - onPaymentSuccess: () => void - onPaymentAwaiting: () => void - onPaymentCancelled: () => void - onSessionExpired: () => void - onPaymentFailed: () => void -} + props: KomojuProviderIprops; + startLoading: () => void; + stopLoading: () => void; + sessionIdRef: MutableRefObject; + onCompleteCallback: MutableRefObject; + onPaymentSuccess: () => void; + onPaymentAwaiting: () => void; + onPaymentCancelled: () => void; + onSessionExpired: () => void; + onPaymentFailed: () => void; +}; const useBackgroundHandler = ({ props, @@ -27,9 +30,8 @@ const useBackgroundHandler = ({ onPaymentCancelled, onPaymentFailed, onSessionExpired, - onPaymentSuccess + onPaymentSuccess, }: Props) => { - useEffect(() => { // Add event listener for deep links const windowChangeListener = AppState.addEventListener( @@ -78,7 +80,7 @@ const useBackgroundHandler = ({ sessionResponse?.status === PaymentStatuses.ERROR || sessionResponse?.payment?.status === PaymentStatuses.ERROR || sessionResponse?.secure_token?.verification_status === - TokenResponseStatuses.ERROR + TokenResponseStatuses.ERROR ) { onPaymentFailed(); } @@ -89,6 +91,6 @@ const useBackgroundHandler = ({ }; return undefined; -} +}; -export default useBackgroundHandler \ No newline at end of file +export default useBackgroundHandler; diff --git a/src/hooks/useDeepLinkHandler.tsx b/src/hooks/useDeepLinkHandler.tsx index 327ac57..8812107 100644 --- a/src/hooks/useDeepLinkHandler.tsx +++ b/src/hooks/useDeepLinkHandler.tsx @@ -1,89 +1,92 @@ -import { Linking } from 'react-native' -import { MutableRefObject, useEffect } from 'react' -import { KomojuProviderIprops, PaymentStatuses, TokenResponseStatuses } from '../util/types' -import sessionShow from '../services/sessionShow' +import { Linking } from "react-native"; +import { MutableRefObject, useEffect } from "react"; +import { + KomojuProviderIprops, + PaymentStatuses, + TokenResponseStatuses, +} from "../util/types"; +import sessionShow from "../services/sessionShow"; type Props = { - props: KomojuProviderIprops, - startLoading: () => void - stopLoading: () => void - sessionIdRef: MutableRefObject - onCompleteCallback: MutableRefObject - onPaymentSuccess: () => void - onPaymentAwaiting: () => void - onPaymentCancelled: () => void - onPaymentFailed: () => void -} + props: KomojuProviderIprops; + startLoading: () => void; + stopLoading: () => void; + sessionIdRef: MutableRefObject; + onCompleteCallback: MutableRefObject; + onPaymentSuccess: () => void; + onPaymentAwaiting: () => void; + onPaymentCancelled: () => void; + onPaymentFailed: () => void; +}; const useDeepLinkHandler = ({ - props, - startLoading, - stopLoading, - sessionIdRef, - onCompleteCallback, - onPaymentAwaiting, - onPaymentCancelled, - onPaymentFailed, - onPaymentSuccess + props, + startLoading, + stopLoading, + sessionIdRef, + onCompleteCallback, + onPaymentAwaiting, + onPaymentCancelled, + onPaymentFailed, + onPaymentSuccess, }: Props) => { + useEffect(() => { + // Add event listener for deep links + const subscription = Linking.addEventListener( + "url", + handleDeepLinkStateChange + ); - useEffect(() => { - // Add event listener for deep links - const subscription = Linking.addEventListener( - 'url', - handleDeepLinkStateChange - ); - - return () => { - subscription.remove(); - }; - }, [props]); + return () => { + subscription.remove(); + }; + }, [props]); - const handleDeepLinkStateChange = async () => { - startLoading(); + const handleDeepLinkStateChange = async () => { + startLoading(); - // if this is a session flow, check until session response changes from 'pending' to 'completed' or 'error' - const sessionShowPayload = { - publishableKey: props.publishableKey, - sessionId: sessionIdRef.current, - }; + // if this is a session flow, check until session response changes from 'pending' to 'completed' or 'error' + const sessionShowPayload = { + publishableKey: props.publishableKey, + sessionId: sessionIdRef.current, + }; - // fetch session status to check if the payment is completed - let sessionResponse = await sessionShow(sessionShowPayload); + // fetch session status to check if the payment is completed + let sessionResponse = await sessionShow(sessionShowPayload); - // Polling until session verification status changes - while ( - sessionResponse?.status === PaymentStatuses.PENDING && - sessionResponse?.payment?.status !== PaymentStatuses.CANCELLED && - sessionResponse?.secure_token?.verification_status !== - TokenResponseStatuses.ERROR - ) { - sessionResponse = await sessionShow(sessionShowPayload); - } + // Polling until session verification status changes + while ( + sessionResponse?.status === PaymentStatuses.PENDING && + sessionResponse?.payment?.status !== PaymentStatuses.CANCELLED && + sessionResponse?.secure_token?.verification_status !== + TokenResponseStatuses.ERROR + ) { + sessionResponse = await sessionShow(sessionShowPayload); + } - // if payment success showing success screen or if failed showing error screen - if (sessionResponse?.status === PaymentStatuses.SUCCESS) { - if (sessionResponse?.payment?.status === TokenResponseStatuses.CAPTURED) { - onPaymentSuccess(); - } else { - onPaymentAwaiting(); - } - // calling user passed onComplete method with session response data - onCompleteCallback.current && - // TODO: Fix this type error - // @ts-expect-error - Argument of type 'PaymentSessionResponse' is not assignable to parameter of type 'string'. - onCompleteCallback.current(sessionResponse); - } else if (sessionResponse?.payment?.status === PaymentStatuses.CANCELLED) { - onPaymentCancelled(); - } else { - onPaymentFailed(); - } + // if payment success showing success screen or if failed showing error screen + if (sessionResponse?.status === PaymentStatuses.SUCCESS) { + if (sessionResponse?.payment?.status === TokenResponseStatuses.CAPTURED) { + onPaymentSuccess(); + } else { + onPaymentAwaiting(); + } + // calling user passed onComplete method with session response data + onCompleteCallback.current && + // TODO: Fix this type error + // @ts-expect-error - Argument of type 'PaymentSessionResponse' is not assignable to parameter of type 'string'. + onCompleteCallback.current(sessionResponse); + } else if (sessionResponse?.payment?.status === PaymentStatuses.CANCELLED) { + onPaymentCancelled(); + } else { + onPaymentFailed(); + } - // after all api calls are done stopping the loading indicator - stopLoading(); - }; + // after all api calls are done stopping the loading indicator + stopLoading(); + }; - return undefined; -} + return undefined; +}; -export default useDeepLinkHandler \ No newline at end of file +export default useDeepLinkHandler; diff --git a/src/hooks/useMainStateUtils.tsx b/src/hooks/useMainStateUtils.tsx index c01457c..777fabd 100644 --- a/src/hooks/useMainStateUtils.tsx +++ b/src/hooks/useMainStateUtils.tsx @@ -1,134 +1,137 @@ -import { MutableRefObject, RefObject, useContext } from 'react' +import { MutableRefObject, RefObject, useContext } from "react"; -import { Actions, DispatchContext } from '../context/state'; -import { SheetRefProps } from '../components/Sheet'; -import { KomojuProviderIprops, ResponseScreenStatuses, State } from '../util/types'; -import sessionShow from '../services/sessionShow'; +import { Actions, DispatchContext } from "../context/state"; +import { SheetRefProps } from "../components/Sheet"; +import { + KomojuProviderIprops, + ResponseScreenStatuses, + State, +} from "../util/types"; +import sessionShow from "../services/sessionShow"; type Props = { - props: KomojuProviderIprops, - sheetRef: RefObject, - sessionIdRef: MutableRefObject - toggleUIVisibility: (value: boolean) => void, - initialState: State, - onDismissCallback: MutableRefObject, -} + props: KomojuProviderIprops; + sheetRef: RefObject; + sessionIdRef: MutableRefObject; + toggleUIVisibility: (value: boolean) => void; + initialState: State; + onDismissCallback: MutableRefObject; +}; const useMainStateUtils = ({ - props, - sheetRef, - sessionIdRef, - toggleUIVisibility, - initialState, - onDismissCallback - + props, + sheetRef, + sessionIdRef, + toggleUIVisibility, + initialState, + onDismissCallback, }: Props) => { - const dispatch = useContext(DispatchContext); - const openPaymentSheet = () => { - if (props?.useBottomSheet) { - sheetRef?.current?.open(); - } else { - toggleUIVisibility(true); - } - }; - - const closePaymentSheet = () => { - // TODO: Fix this type error - // @ts-expect-error - Object is possibly 'null'. - sheetRef?.current?.close(false); - toggleUIVisibility(false); - }; - - const resetGlobalStates = () => - dispatch({ - type: Actions.RESET_STATES, - payload: initialState, - }); - - // when payment is success global state is rest and invoking the success screen - const onPaymentSuccess = () => { - resetGlobalStates(); - dispatch({ - type: Actions.SET_PAYMENT_STATE, - payload: ResponseScreenStatuses.SUCCESS, - }); - }; - - // when payment is failed invoking the error screen - const onPaymentFailed = () => - dispatch({ - type: Actions.SET_PAYMENT_STATE, - payload: ResponseScreenStatuses.FAILED, - }); - - // when payment is cancelled by the user - const onPaymentCancelled = () => { - resetGlobalStates(); - dispatch({ - type: Actions.SET_PAYMENT_STATE, - payload: ResponseScreenStatuses.CANCELLED, - }); - }; - - // when payment is completed but awaiting payment - const onPaymentAwaiting = () => { - resetGlobalStates(); - dispatch({ - type: Actions.SET_PAYMENT_STATE, - payload: ResponseScreenStatuses.COMPLETE, - }); - }; - - // when payment is failed invoking the error screen - const onSessionExpired = () => - dispatch({ - type: Actions.SET_PAYMENT_STATE, - payload: ResponseScreenStatuses.EXPIRED, - }); - - const onUserCancel = async () => { - if (onDismissCallback.current) { - const sessionShowPayload = { - publishableKey: props?.publishableKey, - sessionId: sessionIdRef.current, - }; - - // fetch session status to check if the payment is completed - const sessionResponse = await sessionShow(sessionShowPayload); - // invoking client provided onDismiss callback - // TODO: Fix this type error - // @ts-expect-error - Argument of type 'PaymentSessionResponse' is not assignable to parameter of type 'string'. - onDismissCallback.current(sessionResponse); - } - }; - - // showing overlay loading indicator disabling all interactions - const startLoading = () => - dispatch({ - type: Actions.SET_LOADING, - payload: true, - }); - - // Hiding overlay loading indicator - const stopLoading = () => - dispatch({ - type: Actions.SET_LOADING, - payload: false, - }); - - return { - openPaymentSheet, - closePaymentSheet, - onPaymentSuccess, - onPaymentFailed, - onPaymentCancelled, - onPaymentAwaiting, - onSessionExpired, - onUserCancel, - startLoading, - stopLoading, - resetGlobalStates + const dispatch = useContext(DispatchContext); + const openPaymentSheet = () => { + if (props?.useBottomSheet) { + sheetRef?.current?.open(); + } else { + toggleUIVisibility(true); } -} - -export default useMainStateUtils \ No newline at end of file + }; + + const closePaymentSheet = () => { + // TODO: Fix this type error + // @ts-expect-error - Object is possibly 'null'. + sheetRef?.current?.close(false); + toggleUIVisibility(false); + }; + + const resetGlobalStates = () => + dispatch({ + type: Actions.RESET_STATES, + payload: initialState, + }); + + // when payment is success global state is rest and invoking the success screen + const onPaymentSuccess = () => { + resetGlobalStates(); + dispatch({ + type: Actions.SET_PAYMENT_STATE, + payload: ResponseScreenStatuses.SUCCESS, + }); + }; + + // when payment is failed invoking the error screen + const onPaymentFailed = () => + dispatch({ + type: Actions.SET_PAYMENT_STATE, + payload: ResponseScreenStatuses.FAILED, + }); + + // when payment is cancelled by the user + const onPaymentCancelled = () => { + resetGlobalStates(); + dispatch({ + type: Actions.SET_PAYMENT_STATE, + payload: ResponseScreenStatuses.CANCELLED, + }); + }; + + // when payment is completed but awaiting payment + const onPaymentAwaiting = () => { + resetGlobalStates(); + dispatch({ + type: Actions.SET_PAYMENT_STATE, + payload: ResponseScreenStatuses.COMPLETE, + }); + }; + + // when payment is failed invoking the error screen + const onSessionExpired = () => + dispatch({ + type: Actions.SET_PAYMENT_STATE, + payload: ResponseScreenStatuses.EXPIRED, + }); + + const onUserCancel = async () => { + if (onDismissCallback.current) { + const sessionShowPayload = { + publishableKey: props?.publishableKey, + sessionId: sessionIdRef.current, + }; + + // fetch session status to check if the payment is completed + const sessionResponse = await sessionShow(sessionShowPayload); + // invoking client provided onDismiss callback + // TODO: Fix this type error + // @ts-expect-error - Argument of type 'PaymentSessionResponse' is not assignable to parameter of type 'string'. + onDismissCallback.current(sessionResponse); + } + }; + + // showing overlay loading indicator disabling all interactions + const startLoading = () => + dispatch({ + type: Actions.SET_LOADING, + payload: true, + }); + + // Hiding overlay loading indicator + const stopLoading = () => + dispatch({ + type: Actions.SET_LOADING, + payload: false, + }); + + return { + openPaymentSheet, + closePaymentSheet, + onPaymentSuccess, + onPaymentFailed, + onPaymentCancelled, + onPaymentAwaiting, + onSessionExpired, + onUserCancel, + startLoading, + stopLoading, + resetGlobalStates, + }; +}; + +export default useMainStateUtils; diff --git a/src/hooks/usePaymentHandler.tsx b/src/hooks/usePaymentHandler.tsx index 368235f..e385425 100644 --- a/src/hooks/usePaymentHandler.tsx +++ b/src/hooks/usePaymentHandler.tsx @@ -1,124 +1,130 @@ -import { useContext } from 'react' -import { Alert, Linking } from 'react-native' -import i18next from 'i18next'; - -import { CreatePaymentFuncType, KomojuProviderIprops, PaymentStatuses, sessionPayProps, TokenResponseStatuses } from '../util/types' -import sessionShow from '../services/sessionShow' -import { validateSessionResponse } from '../util/validator' -import { Actions, DispatchContext } from '../context/state'; -import { parsePaymentMethods } from '../util/helpers'; -import payForSession from '../services/payForSessionService'; +import { useContext } from "react"; +import { Alert, Linking } from "react-native"; +import i18next from "i18next"; + +import { + CreatePaymentFuncType, + KomojuProviderIprops, + PaymentStatuses, + sessionPayProps, + TokenResponseStatuses, +} from "../util/types"; +import sessionShow from "../services/sessionShow"; +import { validateSessionResponse } from "../util/validator"; +import { Actions, DispatchContext } from "../context/state"; +import { parsePaymentMethods } from "../util/helpers"; +import payForSession from "../services/payForSessionService"; type Props = { - props: KomojuProviderIprops, - startLoading: () => void - stopLoading: () => void - onPaymentSuccess: () => void - onPaymentAwaiting: () => void - onPaymentFailed: () => void - closePaymentSheet: () => void -} + props: KomojuProviderIprops; + startLoading: () => void; + stopLoading: () => void; + onPaymentSuccess: () => void; + onPaymentAwaiting: () => void; + onPaymentFailed: () => void; + closePaymentSheet: () => void; +}; const usePaymentHandler = ({ - props, - startLoading, - stopLoading, - onPaymentAwaiting, - onPaymentFailed, - onPaymentSuccess, - closePaymentSheet + props, + startLoading, + stopLoading, + onPaymentAwaiting, + onPaymentFailed, + onPaymentSuccess, + closePaymentSheet, }: Props) => { - const dispatch = useContext(DispatchContext); - - // validating the provided session ID by user before proceeding - const validateSession = async (sessionId: string) => { - startLoading(); - - // Fetching session data from given session ID - const sessionData = await sessionShow({ - sessionId, - publishableKey: props.publishableKey, - }); - - // validating the session data and closing the payment gateway if data is not valid - if (validateSessionResponse(sessionData)) { - closePaymentSheet(); - Alert.alert('Error', 'Invalid Session'); - } else { - // if explicitly language is not set. set to the localization from session - if (props?.language) { - i18next.changeLanguage(props?.language); - } else { - i18next.changeLanguage(sessionData?.default_locale); - } - - // if session is valid setting amount, currency type at global store for future use - dispatch({ type: Actions.SET_AMOUNT, payload: sessionData?.amount }); - dispatch({ type: Actions.SET_CURRENCY, payload: sessionData?.currency }); - - // if user provided explicitly payments methods via props, will give priority to that over session payment methods - const paymentMethods = parsePaymentMethods( - props?.paymentMethods, - sessionData?.payment_methods - ); - - // setting the payment methods in global state - dispatch({ - type: Actions.SET_PAYMENT_METHODS, - payload: paymentMethods, - }); - // setting the current selected payment method as the first payment method on the list - dispatch({ - type: Actions.SET_PAYMENT_OPTION, - payload: paymentMethods ? paymentMethods[0]?.type : '', - }); - } - stopLoading(); - }; - - // Session pay callback. this method handles all the payment logic and APIs - const sessionPay = ({ sessionId }: CreatePaymentFuncType) => { - return async ({ paymentType, paymentDetails }: sessionPayProps) => { - // Start of the payment handling method - startLoading(); - - // initiate payment for the session ID with payment details - const response = await payForSession({ - paymentType, - sessionId, - publishableKey: props.publishableKey, - paymentDetails, - }); - - stopLoading(); - - if (response?.status === PaymentStatuses.PENDING) { - openURL(response.redirect_url); - } else if (response?.status === PaymentStatuses.SUCCESS) { - if (response?.payment?.status === TokenResponseStatuses.CAPTURED) { - onPaymentSuccess(); - } else if (response?.payment?.payment_details?.instructions_url) { - openURL(response?.payment?.payment_details?.instructions_url); - onPaymentAwaiting(); - } - } else { - onPaymentFailed(); - } - }; - }; - - const openURL = async (url: string) => { - try { - await Linking.openURL(url); - } catch (err) { - Alert.alert('Redirection not working. Please contact support!'); + const dispatch = useContext(DispatchContext); + + // validating the provided session ID by user before proceeding + const validateSession = async (sessionId: string) => { + startLoading(); + + // Fetching session data from given session ID + const sessionData = await sessionShow({ + sessionId, + publishableKey: props.publishableKey, + }); + + // validating the session data and closing the payment gateway if data is not valid + if (validateSessionResponse(sessionData)) { + closePaymentSheet(); + Alert.alert("Error", "Invalid Session"); + } else { + // if explicitly language is not set. set to the localization from session + if (props?.language) { + i18next.changeLanguage(props?.language); + } else { + i18next.changeLanguage(sessionData?.default_locale); + } + + // if session is valid setting amount, currency type at global store for future use + dispatch({ type: Actions.SET_AMOUNT, payload: sessionData?.amount }); + dispatch({ type: Actions.SET_CURRENCY, payload: sessionData?.currency }); + + // if user provided explicitly payments methods via props, will give priority to that over session payment methods + const paymentMethods = parsePaymentMethods( + props?.paymentMethods, + sessionData?.payment_methods + ); + + // setting the payment methods in global state + dispatch({ + type: Actions.SET_PAYMENT_METHODS, + payload: paymentMethods, + }); + // setting the current selected payment method as the first payment method on the list + dispatch({ + type: Actions.SET_PAYMENT_OPTION, + payload: paymentMethods ? paymentMethods[0]?.type : "", + }); + } + stopLoading(); + }; + + // Session pay callback. this method handles all the payment logic and APIs + const sessionPay = ({ sessionId }: CreatePaymentFuncType) => { + return async ({ paymentType, paymentDetails }: sessionPayProps) => { + // Start of the payment handling method + startLoading(); + + // initiate payment for the session ID with payment details + const response = await payForSession({ + paymentType, + sessionId, + publishableKey: props.publishableKey, + paymentDetails, + }); + + stopLoading(); + + if (response?.status === PaymentStatuses.PENDING) { + openURL(response.redirect_url); + } else if (response?.status === PaymentStatuses.SUCCESS) { + if (response?.payment?.status === TokenResponseStatuses.CAPTURED) { + onPaymentSuccess(); + } else if (response?.payment?.payment_details?.instructions_url) { + openURL(response?.payment?.payment_details?.instructions_url); + onPaymentAwaiting(); } + } else { + onPaymentFailed(); + } }; + }; - return { - sessionPay, - validateSession + const openURL = async (url: string) => { + try { + await Linking.openURL(url); + } catch (err) { + Alert.alert("Redirection not working. Please contact support!"); } -} + }; + + return { + sessionPay, + validateSession, + }; +}; -export default usePaymentHandler \ No newline at end of file +export default usePaymentHandler; diff --git a/src/index.tsx b/src/index.tsx index bd8d9c2..18f549a 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -1,9 +1,13 @@ -import { useContext } from 'react'; +import { useContext } from "react"; -import { KomojuProvider } from './context/KomojuProvider'; -import { KomojuContext } from './context/state'; +import { KomojuProvider } from "./context/KomojuProvider"; +import { KomojuContext } from "./context/state"; -import { LanguageTypes, PaymentType, SessionShowResponseType } from './util/types'; +import { + LanguageTypes, + PaymentType, + SessionShowResponseType, +} from "./util/types"; /** * KomojuSDK provides context utilities for the Komoju payment system. diff --git a/src/services/payForSessionService.ts b/src/services/payForSessionService.ts index 5e038a2..a43084e 100644 --- a/src/services/payForSessionService.ts +++ b/src/services/payForSessionService.ts @@ -1,10 +1,10 @@ -import { BASE_URL_API, API_HEADER } from '../util/constants'; -import { getMonthYearFromExpiry, printLog } from '../util/helpers'; +import { BASE_URL_API, API_HEADER } from "../util/constants"; +import { getMonthYearFromExpiry, printLog } from "../util/helpers"; import { payForSessionProps, PaymentType, SessionPayResponseType, -} from '../util/types'; +} from "../util/types"; /** * Processes a payment for a given session. @@ -42,12 +42,12 @@ const payForSession = async ({ // TODO: Fix this type error const { month, year } = getMonthYearFromExpiry( - paymentDetails?.cardExpiredDate || '' + paymentDetails?.cardExpiredDate || "" ); // refactoring number to remove all unsavory empty spaces from credit card number // TODO: Fix this type error - const number = paymentDetails?.cardNumber?.replaceAll(' ', ''); + const number = paymentDetails?.cardNumber?.replaceAll(" ", ""); // credit card payment_details mandatory parameters type, number, month, year payment_details = { @@ -117,7 +117,7 @@ const payForSession = async ({ method: "POST", headers: API_HEADER(publishableKey), body: JSON.stringify({ - capture: 'auto', + capture: "auto", payment_details, }), }; @@ -130,8 +130,8 @@ const payForSession = async ({ } catch (e) { // logging out any exceptions for debugging printLog({ - logName: 'Error:', - message: 'Unable to Process Payment', + logName: "Error:", + message: "Unable to Process Payment", }); return null; } diff --git a/src/services/sessionShow.ts b/src/services/sessionShow.ts index 9df0a08..d22d0c3 100644 --- a/src/services/sessionShow.ts +++ b/src/services/sessionShow.ts @@ -1,6 +1,6 @@ -import { BASE_URL_API, API_HEADER } from '../util/constants'; -import { printLog } from '../util/helpers'; -import { SessionShowResponseType } from '../util/types'; +import { BASE_URL_API, API_HEADER } from "../util/constants"; +import { printLog } from "../util/helpers"; +import { SessionShowResponseType } from "../util/types"; type SessionShowProps = { sessionId: string; @@ -24,8 +24,8 @@ const sessionShow = async ({ return data; } catch (e) { printLog({ - logName: 'Error:', - message: 'Invalid Session', + logName: "Error:", + message: "Invalid Session", }); return null; } diff --git a/src/theme/defaultColorTheme.ts b/src/theme/defaultColorTheme.ts index 4e2e4c7..adfc3de 100644 --- a/src/theme/defaultColorTheme.ts +++ b/src/theme/defaultColorTheme.ts @@ -3,16 +3,16 @@ const darkTheme = { BACKGROUND_COLOR: "#1E1E1E", ERROR: "#fc4747", TEXT_COLOR: "#fff", - INPUT_BACKGROUND: '#2C2C2C', - INPUT_TEXT: '#F7F8F8', - INPUT_PLACEHOLDER: '#958d8e', - INVERTED_CONTENT: '#1D1617', + INPUT_BACKGROUND: "#2C2C2C", + INPUT_TEXT: "#F7F8F8", + INPUT_PLACEHOLDER: "#958d8e", + INVERTED_CONTENT: "#1D1617", WHITE50: "#00000080", - CARD_BACKGROUND: '#171717', - CARD_BORDER: '#33414c', - LIGHT_BOX: '#2C2C2C', - CARD_SHADOW_IOS_COLOR: '#000', - CARD_SHADOW_ANDROID_COLOR: '#000', + CARD_BACKGROUND: "#171717", + CARD_BORDER: "#33414c", + LIGHT_BOX: "#2C2C2C", + CARD_SHADOW_IOS_COLOR: "#000", + CARD_SHADOW_ANDROID_COLOR: "#000", }; const lightTheme = { @@ -20,19 +20,19 @@ const lightTheme = { BACKGROUND_COLOR: "#FFFFFF", ERROR: "#fc5d5d", TEXT_COLOR: "#172E44", - INPUT_BACKGROUND: '#FFFFFF', - INPUT_TEXT: '#172E44', - INPUT_PLACEHOLDER: '#ADA4A5', - INVERTED_CONTENT: '#fff', - WHITE50: '#00000050', - CARD_BACKGROUND: '#ffffff', - CARD_BORDER: '#CAD6E1', - LIGHT_BOX: '#F3F7F9', - CARD_SHADOW_IOS_COLOR: '#D9D9D9', - CARD_SHADOW_ANDROID_COLOR: '#c4c2c2', + INPUT_BACKGROUND: "#FFFFFF", + INPUT_TEXT: "#172E44", + INPUT_PLACEHOLDER: "#ADA4A5", + INVERTED_CONTENT: "#fff", + WHITE50: "#00000050", + CARD_BACKGROUND: "#ffffff", + CARD_BORDER: "#CAD6E1", + LIGHT_BOX: "#F3F7F9", + CARD_SHADOW_IOS_COLOR: "#D9D9D9", + CARD_SHADOW_ANDROID_COLOR: "#c4c2c2", }; export const appTheme = { dark: darkTheme, - light: lightTheme -} + light: lightTheme, +}; diff --git a/src/theme/scalling.ts b/src/theme/scalling.ts index cc86115..b232845 100644 --- a/src/theme/scalling.ts +++ b/src/theme/scalling.ts @@ -1,9 +1,9 @@ -import { Dimensions, PixelRatio, Platform } from 'react-native'; +import { Dimensions, PixelRatio, Platform } from "react-native"; const figmaScreenWidth = 390; const figmaScreenHeight = 844; -const { width, height } = Dimensions.get('window'); +const { width, height } = Dimensions.get("window"); const screenWidth = Math.min(width, height); const screenHeight = Math.max(width, height); @@ -20,7 +20,7 @@ export const responsiveScale = (size: number): number => { }; export const resizeFonts = (size: number): number => { - const fontScale = Platform.OS === 'ios' ? 1 : PixelRatio.getFontScale(); + const fontScale = Platform.OS === "ios" ? 1 : PixelRatio.getFontScale(); const spFontSize = size * fontScale; return spFontSize; }; diff --git a/src/theme/useCurrentTheme.ts b/src/theme/useCurrentTheme.ts index fada9fd..535912a 100644 --- a/src/theme/useCurrentTheme.ts +++ b/src/theme/useCurrentTheme.ts @@ -1,8 +1,8 @@ -import { useColorScheme } from 'react-native'; +import { useColorScheme } from "react-native"; -import { useTheme } from '../context/ThemeContext'; +import { useTheme } from "../context/ThemeContext"; -import { appTheme } from './defaultColorTheme'; +import { appTheme } from "./defaultColorTheme"; export const useCurrentTheme = () => { const { mode } = useTheme(); diff --git a/src/util/constants.ts b/src/util/constants.ts index ff5a8d7..3be3b61 100644 --- a/src/util/constants.ts +++ b/src/util/constants.ts @@ -4,11 +4,11 @@ export const noop = () => {}; export const BASE_URL = "https://komoju.com"; export const BASE_URL_API = `${BASE_URL}/api/v1`; export const API_HEADER = (publishableKey: string) => ({ - accept: "application/json", + "accept": "application/json", "content-type": "application/json", "KOMOJU-VIA": "mobile_react", "X-KOMOJU-API-VERSION": "2024-07-15", - Authorization: `Basic ${btoa(publishableKey + ":")}`, + "Authorization": `Basic ${btoa(publishableKey + ":")}`, }); export const paymentSuccessCtaText = "BACK_TO_STORE"; diff --git a/src/util/helpers.ts b/src/util/helpers.ts index 4d577cd..ad8a12a 100644 --- a/src/util/helpers.ts +++ b/src/util/helpers.ts @@ -1,6 +1,6 @@ -import { Dimensions, Platform } from 'react-native'; +import { Dimensions, Platform } from "react-native"; -import { cardTypeRegex } from './constants'; +import { cardTypeRegex } from "./constants"; import { brandsType, CardTypes, @@ -9,7 +9,7 @@ import { KonbiniType, PaymentType, sessionShowPaymentMethodType, -} from './types'; +} from "./types"; export const isDevApp = __DEV__; @@ -24,51 +24,52 @@ export const printLog = ({ }; export const formatExpiry = (expiry: string) => { - const prevExpiry = expiry.split(' / ').join('/'); + const prevExpiry = expiry.split(" / ").join("/"); if (!prevExpiry) return null; // TODO: Fix this type error - let expiryDate: any = prevExpiry; + let expiryDate: string | string[] = prevExpiry; if (/^[2-9]$/.test(expiryDate)) { expiryDate = `0${expiryDate}`; } if (prevExpiry.length === 2 && +prevExpiry > 12) { const [head, ...tail] = prevExpiry; - expiryDate = `0${head}/${tail.join('')}`; + expiryDate = `0${head}/${tail.join("")}`; } if (/^1[/-]$/.test(expiryDate)) { - return `01 / `; + return "01 / "; } expiryDate = expiryDate.match(/(\d{1,2})/g) || []; if (expiryDate.length === 1) { - if (prevExpiry.includes('/')) { + if (prevExpiry.includes("/")) { return expiryDate[0]; } - if (/\d{2}/.test(expiryDate)) { - return `${expiryDate[0]} / `; - } + if (typeof expiryDate === "string") + if (/\d{2}/.test(expiryDate)) { + return `${expiryDate[0]} / `; + } } if (expiryDate.length > 2) { const [, month, year] = - expiryDate.join('').match(/^(\d{2}).*(\d{2})$/) || []; - return [month, year].join(' / '); + expiryDate.join("").match(/^(\d{2}).*(\d{2})$/) || []; + return [month, year].join(" / "); } - return expiryDate.join(' / '); + return expiryDate.join(" / "); }; export const getMonthYearFromExpiry = (expiry: string) => { - const splitValues = expiry.split(' / '); + const splitValues = expiry.split(" / "); return { month: splitValues[0], year: splitValues[1] }; }; export const formatCreditCardNumber = (cardNumber: string) => { const formatCardNumberArray = []; - const cardNumberArray = cardNumber.replaceAll(' ', '').split(''); + const cardNumberArray = cardNumber.replaceAll(" ", "").split(""); let startOffset = 0; let loopCounter = 4; const totalNumberOfIterations = Math.ceil(cardNumberArray.length / 4) * 4; @@ -79,11 +80,11 @@ export const formatCreditCardNumber = (cardNumber: string) => { startOffset += 4; loopCounter += 4; } - return formatCardNumberArray.map((el) => el.join('')).join(' '); + return formatCardNumberArray.map((el) => el.join("")).join(" "); }; function thousandSeparator(number: string) { - return number.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ','); + return number.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ","); } export const formatCurrency = ({ @@ -161,7 +162,7 @@ export const parsePaymentMethods = ( // Determine the card type based on the card number export const determineCardType = ( cardNumber: string -): CardTypes | 'unknown' | null => { +): CardTypes | "unknown" | null => { if (cardTypeRegex.amex.exec(cardNumber)) { return CardTypes.AMEX; } else if (cardTypeRegex.diner.exec(cardNumber)) { @@ -175,10 +176,10 @@ export const determineCardType = ( } else if (cardTypeRegex.visa.exec(cardNumber)) { return CardTypes.VISA; } else if (cardNumber.length > 2) { - return 'unknown'; + return "unknown"; } else return null; }; -export const isAndroid = () => Platform.OS === 'android'; -export const isIOS = () => Platform.OS === 'ios'; -export const { height: SCREEN_HEIGHT } = Dimensions.get('window'); +export const isAndroid = () => Platform.OS === "android"; +export const isIOS = () => Platform.OS === "ios"; +export const { height: SCREEN_HEIGHT } = Dimensions.get("window"); diff --git a/src/util/types.ts b/src/util/types.ts index 9165595..1514f62 100644 --- a/src/util/types.ts +++ b/src/util/types.ts @@ -1,4 +1,4 @@ -import { Dispatch, ReactNode, SetStateAction } from 'react'; +import { Dispatch, ReactNode, SetStateAction } from "react"; export type InitPrams = { publishableKey: string; @@ -31,43 +31,43 @@ export type KomojuContext = { }; export enum LanguageTypes { - ENGLISH = 'en', - JAPANESE = 'ja', + ENGLISH = "en", + JAPANESE = "ja", } export enum PaymentType { - KONBINI = 'konbini', - CREDIT = 'credit_card', - PAY_PAY = 'paypay', - LINE_PAY = 'linepay', - MER_PAY = 'merpay', - BANK_TRANSFER = 'bank_transfer', - PAY_EASY = 'pay_easy', - WEB_MONEY = 'web_money', - BIT_CASH = 'bit_cash', - NET_CASH = 'net_cash', - PAIDY = 'paidy', - RAKUTEN = 'rakutenpay', - AU_PAY = 'aupay', - ALI_PAY = 'alipay', + KONBINI = "konbini", + CREDIT = "credit_card", + PAY_PAY = "paypay", + LINE_PAY = "linepay", + MER_PAY = "merpay", + BANK_TRANSFER = "bank_transfer", + PAY_EASY = "pay_easy", + WEB_MONEY = "web_money", + BIT_CASH = "bit_cash", + NET_CASH = "net_cash", + PAIDY = "paidy", + RAKUTEN = "rakutenpay", + AU_PAY = "aupay", + ALI_PAY = "alipay", } export enum KonbiniType { - SEVEN_ELEVEN = 'seven-eleven', - LAWSON = 'lawson', - FAMILY_MART = 'family-mart', - MINI_stop = 'ministop', - DAILY_YAMAZAKI = 'daily-yamazaki', - SEICOMART = 'seicomart', + SEVEN_ELEVEN = "seven-eleven", + LAWSON = "lawson", + FAMILY_MART = "family-mart", + MINI_stop = "ministop", + DAILY_YAMAZAKI = "daily-yamazaki", + SEICOMART = "seicomart", } export enum CardTypes { - VISA = 'visa', - AMEX = 'american_express', - MASTER = 'master', - JCB = 'jcb', - DINERS_CLUB = 'diners_club', - DISCOVER = 'discover', + VISA = "visa", + AMEX = "american_express", + MASTER = "master", + JCB = "jcb", + DINERS_CLUB = "diners_club", + DISCOVER = "discover", } export enum PaymentStatuses { @@ -79,17 +79,17 @@ export enum PaymentStatuses { } export enum TokenResponseStatuses { - SUCCESS = 'OK', - CAPTURED = 'captured', - PENDING = 'NEEDS_VERIFY', - ERROR = 'ERRORED', + SUCCESS = "OK", + CAPTURED = "captured", + PENDING = "NEEDS_VERIFY", + ERROR = "ERRORED", } export enum ResponseScreenStatuses { /** When a payment is fully complete Displaying success screen immediately and disabling the cancel payment popup */ - SUCCESS = 'success', + SUCCESS = "success", /** Displaying failed screen immediately */ - FAILED = 'failed', + FAILED = "failed", /** For displaying payment instruction screens and disabling the cancel payment popup */ COMPLETE = "complete", /** For displaying payment instruction screens for cancelled by the user */ @@ -99,13 +99,13 @@ export enum ResponseScreenStatuses { } export enum CurrencySign { - JPY = '¥', - USD = '$', + JPY = "¥", + USD = "$", } export enum CurrencyTypes { - JPY = 'JPY', - USD = 'USD', + JPY = "JPY", + USD = "USD", } export type payForSessionProps = { @@ -268,39 +268,39 @@ export const initialState: State = { loading: false, /** credit card payment related states start */ - cardholderName: '', - cardCVV: '', - cardNumber: '', - cardExpiredDate: '', + cardholderName: "", + cardCVV: "", + cardNumber: "", + cardExpiredDate: "", /** credit card payment related states end */ /** konbini pay related states start */ /** konbini pay default selected to 7-eleven store */ - selectedStore: 'seven-eleven', - name: '', - email: '', + selectedStore: "seven-eleven", + name: "", + email: "", /** konbini pay related states start */ /** Bank transfer and Pay Easy related states start */ transferFormFields: { - lastName: '', - firstName: '', - lastNamePhonetic: '', - firstNamePhonetic: '', - email: '', - phone: '', + lastName: "", + firstName: "", + lastNamePhonetic: "", + firstNamePhonetic: "", + email: "", + phone: "", }, /** Bank transfer and Pay Easy related states end */ sessionPay: () => {}, - amount: '', + amount: "", currency: CurrencyTypes.JPY, - paymentState: '', + paymentState: "", paymentMethods: [], }; // TODO: Fix this type error -export type ActionType = { type: string; payload: any }; +export type ActionType = { type: string; payload: State[keyof State] }; export interface ThemeSchemeType { PRIMARY_COLOR: string; diff --git a/src/util/validator.ts b/src/util/validator.ts index 4085352..91c01b5 100644 --- a/src/util/validator.ts +++ b/src/util/validator.ts @@ -1,4 +1,4 @@ -import { emailRegex } from './constants'; +import { emailRegex } from "./constants"; import { cardValidationFuncProps, konbiniValidationFuncProps, @@ -6,12 +6,12 @@ import { SessionShowResponseType, setInputErrorType, TransferFormFieldsType, -} from './types'; +} from "./types"; const MAX_CARD_LENGTH = 19; export const isCardNumberValid = (cardString: string) => { - const text = cardString.replaceAll(' ', ''); + const text = cardString.replaceAll(" ", ""); try { if (text?.length <= 0) { return true; @@ -37,7 +37,7 @@ export const validateCardExpiry = (expiry: string) => { if (expiry?.length <= 0) { return true; } - const derivedExpiry = expiry.replace(' / ', ''); + const derivedExpiry = expiry.replace(" / ", ""); if (derivedExpiry.length > 4) { return false;