• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

Adyen / adyen-web / 9001078091

08 May 2024 11:31AM UTC coverage: 68.83%. First build
9001078091

Pull #2673

github

web-flow
Merge 58d188c81 into 33729afe1
Pull Request #2673: [waiting for translation]feat: add Upi intent flow

3253 of 5217 branches covered (62.35%)

Branch coverage included in aggregate %.

65 of 71 new or added lines in 10 files covered. (91.55%)

5412 of 7372 relevant lines covered (73.41%)

95.27 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

83.33
/packages/lib/src/components/UPI/components/UPIComponent/UPIComponent.tsx
1
import { Fragment, h, RefObject } from 'preact';
2
import { useCallback, useEffect, useState } from 'preact/hooks';
3
import useCoreContext from '../../../../core/Context/useCoreContext';
4
import { PayButtonFunctionProps, UIElementStatus } from '../../../types';
5
import { VpaInputHandlers } from '../VpaInput/VpaInput';
6
import VpaInput from '../VpaInput';
7
import SegmentedControl from '../../../internal/SegmentedControl';
8
import { App, UpiMode } from '../../types';
9
import useImage from '../../../../core/Context/useImage';
10
import UPIIntentAppList from '../UPIIntentAppList';
11
import useUpiSegmentedControlOptions from './useUpiSegmentedControlOptions';
12
import { A11Y } from './constants';
13
import './UPIComponent.scss';
14
import ContentSeparator from '../../../internal/ContentSeparator';
15

16
type UpiData = { app?: App; virtualPaymentAddress?: string };
17

18
type OnChangeProps = { data: UpiData; valid; errors; isValid: boolean };
19

20
interface UPIComponentProps {
21
    defaultMode: UpiMode;
22
    showPayButton: boolean;
23
    apps?: Array<App>;
24

25
    ref?(ref: RefObject<typeof UPIComponent>): void;
26

27
    payButton?(props: PayButtonFunctionProps): h.JSX.Element;
28

29
    onChange({ data, valid, errors, isValid }: OnChangeProps): void;
30

31
    onUpdateMode?(mode: UpiMode): void;
32
}
33

34
export default function UPIComponent({ defaultMode, onChange, onUpdateMode, payButton, showPayButton, apps = [] }: UPIComponentProps): h.JSX.Element {
20✔
35
    const { i18n } = useCoreContext();
34✔
36
    const getImage = useImage();
34✔
37
    const [status, setStatus] = useState<UIElementStatus>('ready');
34✔
38
    const [isValid, setIsValid] = useState<boolean>(true);
34✔
39
    const [mode, setMode] = useState<UpiMode>(defaultMode);
34✔
40
    const [vpa, setVpa] = useState<string>('');
34✔
41
    const [vpaInputHandlers, setVpaInputHandlers] = useState<VpaInputHandlers>(null);
34✔
42
    const [selectedApp, setSelectedApp] = useState<App>(null);
34✔
43
    const [valid, setValid] = useState(null);
34✔
44
    const [errors, setErrors] = useState(null);
34✔
45
    const segmentedControlOptions = useUpiSegmentedControlOptions(apps, mode);
34✔
46

47
    this.setStatus = (status: UIElementStatus) => {
34✔
48
        setStatus(status);
×
49
    };
50

51
    this.showValidation = () => {
34✔
NEW
52
        vpaInputHandlers?.validateInput();
×
53
    };
54

55
    const onSetVpaInputHandlers = useCallback((handlers: VpaInputHandlers) => {
34✔
56
        setVpaInputHandlers(handlers);
4✔
57
    }, []);
58

59
    const onChangeUpiMode = useCallback(
34✔
60
        (newMode: UpiMode) => {
61
            setMode(newMode);
2✔
62
            onUpdateMode(newMode);
2✔
63
        },
64
        [onUpdateMode]
65
    );
66

67
    const handleAppSelect = useCallback(
34✔
68
        (app: App) => {
69
            if (app?.id === selectedApp?.id) return;
2!
70

71
            setSelectedApp(app);
2✔
72
            setIsValid(true);
2✔
73
        },
74
        [selectedApp]
75
    );
76

77
    const handleVpaInputChange = useCallback(({ data: { virtualPaymentAddress }, errors, valid, isValid }: OnChangeProps) => {
34✔
NEW
78
        setVpa(virtualPaymentAddress);
×
NEW
79
        setErrors(errors);
×
NEW
80
        setValid(valid);
×
NEW
81
        setIsValid(isValid);
×
82
    }, []);
83

84
    useEffect(() => {
34✔
85
        if (mode !== UpiMode.QrCode) {
12✔
86
            onChange({
10✔
87
                data: { ...(vpa && { virtualPaymentAddress: vpa }), ...(selectedApp && { app: selectedApp }) },
22!
88
                errors,
89
                valid,
90
                isValid
91
            });
92
        }
93
    }, [vpa, selectedApp, errors, valid, isValid, mode]);
94

95
    return (
34✔
96
        <Fragment>
97
            <p className="adyen-checkout_upi-mode-selection-text">{i18n.get('upi.modeSelection')}</p>
98
            <SegmentedControl
99
                onChange={onChangeUpiMode}
100
                selectedValue={mode}
101
                disabled={status === 'loading'}
102
                classNameModifiers={['upi-margin-bottom']}
103
                options={segmentedControlOptions}
104
            />
105
            <ContentSeparator label={i18n.get('upi.completePayment')} />
106
            {mode === UpiMode.Intent && (
46✔
107
                <div id={A11Y.AreaId.INTENT} aria-labelledby={A11Y.ButtonId.INTENT} className="adyen-checkout-upi-area-intent" role="region">
108
                    <UPIIntentAppList
109
                        disabled={status === 'loading'}
110
                        apps={apps}
111
                        selectedAppId={selectedApp?.id}
112
                        onAppSelect={handleAppSelect}
113
                        onVpaInputChange={handleVpaInputChange}
114
                        onSetInputHandlers={onSetVpaInputHandlers}
115
                    />
116

117
                    {showPayButton &&
20✔
118
                        payButton({
119
                            label: i18n.get('continue'),
120
                            status,
121
                            disabled: selectedApp == null
122
                        })}
123
                </div>
124
            )}
125
            {mode === UpiMode.Vpa && (
46✔
126
                <div id={A11Y.AreaId.VPA} aria-labelledby={A11Y.ButtonId.VPA} className="adyen-checkout-upi-area-vpa" role="region">
127
                    <VpaInput disabled={status === 'loading'} onChange={onChange} onSetInputHandlers={onSetVpaInputHandlers} />
128

129
                    {showPayButton &&
14✔
130
                        payButton({
131
                            label: i18n.get('continue'),
132
                            status
133
                        })}
134
                </div>
135
            )}
136
            {mode === UpiMode.QrCode && (
44✔
137
                <div id={A11Y.AreaId.QR} aria-labelledby={A11Y.ButtonId.QR} className="adyen-checkout-upi-area-qr-code" role="region">
138
                    {showPayButton &&
10!
139
                        payButton({
140
                            label: i18n.get('generateQRCode'),
141
                            icon: getImage({ imageFolder: 'components/' })('qr'),
142
                            status
143
                        })}
144
                </div>
145
            )}
146
        </Fragment>
147
    );
148
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc