Card Activation and Set Pin Example

<!-- Import Scripts -->
<script src="https://widgets-sandbox.synctera.com/assets/card-activation/card-activation_v1.0.1.js"></script>
<script src="https://widgets-sandbox.synctera.com/assets/set-pin/set-pin_v1.0.1.js"></script>

<!-- OR --> 

<!-- Import Production Scripts -->
<script src="https://widgets.synctera.com/assets/card-activation/card-activation_v1.0.1.js"></script>
<script src="https://widgets.synctera.com/assets/set-pin/set-pin_v1.0.1.js"></script>
.synctera-container {
    display: flex;
    flex-direction: column;
    align-items: center;
}

.synctera-form-container {
    min-width: 320px;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 1rem;
    border: 1px solid #ddd;
    border-radius: 4px;
    padding: 1rem;
}

.synctera-header {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.5rem;
}

.synctera-header-title {
    font-size: 2rem;
    font-weight: 700;
}

.synctera-header-subtitle {
    font-size: 1rem;
}

.synctera-input-container {
    position: relative;
    display: flex;
    flex-direction: column;
    align-items: flex-start;
}

.synctera-label {
    font-weight: bold;
    margin-bottom: 5px;
    /* These fonts will automatically be sent to the iframe (after sanitization) */
    font-family: 'system-ui', '-apple-system', 'BlinkMacSystemFont', 'Segoe UI', 'Roboto',
        'Helvetica Neue', 'Arial', sans-serif;
    font-weight: 500;
}

.synctera-input-error {
    color: #e31b0c;
    font-size: 0.8rem;
}

.synctera-custom-styles {
    /* Set on the web component tag */
    box-sizing: border-box;
    border: 1px solid #ddd;
    min-width: 240px;
    height: 40px;
    border-radius: 4px;
    padding: 0 8px;
}

.synctera-custom-styles[_hover] {
    border: 1px solid #616161;
}

.synctera-custom-styles[_focus] {
    border: 2px solid #2564eb;
    padding: 0 7px;
}

.synctera-custom-styles[_disabled] {
    background: #d3d3d3;
}

.synctera-custom-styles[_user-invalid] {
    border-color: #e31b0c;
}

.synctera-custom-styles,
.synctera-placeholder {
    /* These fonts will automatically be sent to the iframe (after sanitization) */
    font-family: 'system-ui', '-apple-system', 'BlinkMacSystemFont', 'Segoe UI', 'Roboto',
        'Helvetica Neue', 'Arial', sans-serif;
    font-size: 1rem;
    line-height: 1.625em;
    font-weight: 400;
    color: rgba(0, 0, 0, 0.87);
}

.synctera-placeholder {
    position: absolute;
    display: none;
    top: 30px;
    left: 10px;
    color: rgba(0, 0, 0, 0.2);
    z-index: -1;
}

.synctera-custom-styles[_blank]+.synctera-placeholder {
    display: block;
}

.synctera-custom-styles[_focus]+.synctera-placeholder {
    display: none;
}

.synctera-button-container {
    display: flex;
    justify-content: center;
    align-items: center;
    width: 100%;
    gap: 1rem;
}

.synctera-submit-button {
    background-color: #1976d2;
    color: white;
    padding: 10px 20px;
    border: none;
    border-radius: 4px;
    font-size: 1rem;
    cursor: pointer;
    transition:
        background-color 0.3s,
        transform 0.3s;
    width: 100%;
}

.synctera-submit-button:hover {
    background-color: #155fa9;
}

.synctera-submit-button:active {
    transform: scale(0.97);
    transition: transform 0.1s ease-in-out;
}

.synctera-submit-button:disabled {
    background-color: #d3d3d3;
    cursor: not-allowed;
}

.synctera-cancel-button {
    background-color: #fff;
    color: #333;
    padding: 10px 20px;
    border: 1px solid #ddd;
    border-radius: 4px;
    font-size: 1rem;
    cursor: pointer;
    transition:
        background-color 0.3s,
        transform 0.3s;
    width: 100%;
}

.synctera-cancel-button:hover {
    background-color: #e0e0e0;
}

.synctera-cancel-button:active {
    transform: scale(0.97);
    transition: transform 0.1s ease-in-out;
}

.synctera-cancel-button:disabled {
    background-color: #d3d3d3;
    cursor: not-allowed;
}

.synctera-hidden {
    display: none;
}
<div id="synctera-success" class="synctera-container synctera-hidden">
    <div class="synctera-form-container">Card activation was successful.</div>
</div>

<div id="card-activation-container" class="synctera-container">
    <div class="synctera-form-container">
        <div class="synctera-header">
            <h2 class="synctera-header-title">Activate Card</h2>
            <h4 class="synctera-header-subtitle">Enter your card details to activate</h4>
        </div>
        <div class="synctera-input-container">
            <div class="synctera-label">Card Number</div>
            <card-pan id="card-pan" token="hidden-token" class="synctera-custom-styles"
                environment="SANDBOX"></card-pan>
            <div class="synctera-placeholder">4111 1111 1111 1111</div>
            <div id="card-pan-error" class="synctera-input-error synctera-hidden">
                Card must be 16 digits
            </div>
        </div>
        <div class="synctera-input-container">
            <div class="synctera-label">Security Code</div>
            <card-cvv id="card-cvv" class="synctera-custom-styles"></card-cvv>
            <div class="synctera-placeholder">123</div>
            <div id="card-cvv-error" class="synctera-input-error synctera-hidden">
                Security code must be 3 digits
            </div>
        </div>
        <div class="synctera-button-container">
            <button id="card-activation-cancel-button" class="synctera-cancel-button">Cancel</button>
            <button id="card-activation-submit-button" class="synctera-submit-button" disabled>
                Activate
            </button>
        </div>
    </div>
</div>

<div id="set-pin-container" class="synctera-container synctera-hidden">
    <div class="synctera-form-container">
        <div class="synctera-header">
            <h2 class="synctera-header-title">Set Pin</h2>
            <h4 class="synctera-header-subtitle">Enter your 4-digit card PIN</h4>
        </div>
        <div class="synctera-input-container">
            <div class="synctera-label">New PIN</div>
            <set-pin id="set-pin-controller" class="synctera-custom-styles" token="hidden-token"
                environment="SANDBOX"></set-pin>
            <div class="synctera-placeholder">1234</div>
            <div id="set-pin-error" class="synctera-input-error synctera-hidden">PIN must be 4 digits</div>
        </div>
        <div class="synctera-input-container">
            <div class="synctera-label">Confirm new PIN</div>
            <set-pin id="set-pin-confirm" class="synctera-custom-styles" isConfirm></set-pin>
            <div class="synctera-placeholder">1234</div>
            <div id="set-pin-confirm-error" class="synctera-input-error synctera-hidden">PINs must Match</div>
        </div>
        <div class="synctera-button-container">
            <button id="set-pin-cancel-button" class="synctera-cancel-button">Cancel</button>
            <button id="set-pin-submit-button" class="synctera-submit-button" disabled>Submit</button>
        </div>
    </div>
</div>
const BASE_URL = 'http://your-server-url.com';
// Helpers
async function getCardToken(input, type = 'ACTIVATE', cardId) {
    // Make an api call to your server to get the card token
    const response = await fetch(
        `${BASE_URL}/api/cardToken?widgetType=${type}&cardId=${cardId}`
    );
    const data = await response.json();
    if (!data.widget_token) // update a error field 

        input.token = data.widget_token;
}

// Card Activation
let cardActivation = document.getElementById('card-pan');
let cardCvvInput = document.getElementById('card-cvv');
let cardPanError = document.getElementById('card-pan-error');
let cardCvvError = document.getElementById('card-cvv-error');
let cardActivationSubmit = document.getElementById('card-activation-submit-button');
let cardActivationCancel = document.getElementById('card-activation-cancel-button');
let cardActivationValid = false;

getCardToken(cardActivation, 'ACTIVATE', 'card-guid');

cardActivation.addEventListener('load', function () {
    console.log('Card Activation Widget Loaded');
});

cardActivation.addEventListener('validity', function (e) {
    // Check if the form is valid
    cardActivationValid = e.target.isValid;
    cardActivationSubmit.disabled = !cardActivationValid;

    // Update validation warnings
    if (cardActivationValid) {
        cardPanError.classList.add('synctera-hidden');
        cardCvvError.classList.add('synctera-hidden');
    } else {
        if (cardCvvInput.hasAttribute('_user-invalid')) {
            cardCvvError.classList.remove('synctera-hidden');
        } else {
            cardCvvError.classList.add('synctera-hidden');
        }
        if (cardActivation.hasAttribute('_user-invalid')) {
            cardPanError.classList.remove('synctera-hidden');
        } else {
            cardPanError.classList.add('synctera-hidden');
        }
    }
});

cardActivationSubmit.addEventListener('click', function () {
    if (!cardActivationValid) return;
    // Disable the submit button
    cardActivationSubmit.disabled = true;
    try {
        cardActivation.submit();
    } catch (e) {
        console.error('Card failed to activate', e);
    }
});

cardActivation.addEventListener('success', function () {
    // Hide the card activation form
    document.getElementById('card-activation-container').classList.add('synctera-hidden');
    // Show the success messsage
    document.getElementById('synctera-success').classList.remove('synctera-hidden');

    setTimeout(() => {
        // hide the success messsage
        document.getElementById('synctera-success').classList.add('synctera-hidden');
        // Show the set pin form
        document.getElementById('set-pin-container').classList.remove('synctera-hidden');
    }, 2000);
});

// SET PIN
let setPin = document.getElementById('set-pin-controller');
let setPinConfirmInput = document.getElementById('set-pin-confirm');
let setPinError = document.getElementById('set-pin-error')
let setPinConfirmError = document.getElementById('set-pin-confirm-error')
let setPinSubmit = document.getElementById('set-pin-submit-button');
let setPinCancel = document.getElementById('set-pin-cancel-button');
let setPinValid = false;

getCardToken(setPin, 'SET-PIN', 'card-guid');
setPin.addEventListener('load', function () {
    console.log('Set Pin Widget Loaded');
});

setPin.addEventListener('validity', function (e) {
    setPinValid = e.target.isValid;
    setPinSubmit.disabled = !setPinValid;

    // Update validation warnings
    if (setPinValid) {
        setPinError.classList.add('synctera-hidden')
        setPinConfirmError.classList.add('synctera-hidden')
    } else {
        if (setPinConfirmInput.hasAttribute('_user-invalid')) {
            setPinConfirmError.classList.remove('synctera-hidden')
        } else {
            setPinConfirmError.classList.add('synctera-hidden')
        }
        if (setPin.hasAttribute('_user-invalid')) {
            setPinError.classList.remove('synctera-hidden')
        } else {
            setPinError.classList.add('synctera-hidden')
        }
    }
});

setPinSubmit.addEventListener('click', function () {
    try {
        setPin.submit();
    } catch (e) {
        console.error('Pin failed to submit', e);
    }
});

setPin.addEventListener('success', function () {
    console.log('Pin set successfully');
});

setPin.addEventListener('failure', function (e) {
    loader.style.display = 'none';
    console.error('Pin failed to submit', e);
});

<!doctype html>

<html>

<head>
    <meta charset="utf-8" />
    <title>Activate Card & Set Pin</title>
    <link rel="shortcut icon" href="data:image/x-icon;," type="image/x-icon" />
    <!-- Import Scripts -->
    <script type="module" src="../build/src/activate/index.js"></script>
    <script type="module" src="../build/src/set-pin/index.js"></script>
    <style>
        .synctera-container {
            display: flex;
            flex-direction: column;
            align-items: center;
        }

        .synctera-form-container {
            min-width: 320px;
            display: flex;
            flex-direction: column;
            align-items: center;
            gap: 1rem;
            border: 1px solid #ddd;
            border-radius: 4px;
            padding: 1rem;
        }

        .synctera-header {
            display: flex;
            flex-direction: column;
            align-items: center;
            gap: 0.5rem;
        }

        .synctera-header-title {
            font-size: 2rem;
            font-weight: 700;
        }

        .synctera-header-subtitle {
            font-size: 1rem;
        }

        .synctera-input-container {
            position: relative;
            display: flex;
            flex-direction: column;
            align-items: flex-start;
        }

        .synctera-label {
            font-weight: bold;
            margin-bottom: 5px;
            /* These fonts will automatically be sent to the iframe (after sanitization) */
            font-family: 'system-ui', '-apple-system', 'BlinkMacSystemFont', 'Segoe UI', 'Roboto',
                'Helvetica Neue', 'Arial', sans-serif;
            font-weight: 500;
        }

        .synctera-input-error {
            color: #e31b0c;
            font-size: 0.8rem;
        }

        .synctera-custom-styles {
            /* Set on the web component tag */
            box-sizing: border-box;
            border: 1px solid #ddd;
            min-width: 240px;
            height: 40px;
            border-radius: 4px;
            padding: 0 8px;
        }

        .synctera-custom-styles[_hover] {
            border: 1px solid #616161;
        }

        .synctera-custom-styles[_focus] {
            border: 2px solid #2564eb;
            padding: 0 7px;
        }

        .synctera-custom-styles[_disabled] {
            background: #d3d3d3;
        }

        .synctera-custom-styles[_user-invalid] {
            border-color: #e31b0c;
        }

        .synctera-custom-styles,
        .synctera-placeholder {
            /* These fonts will automatically be sent to the iframe (after sanitization) */
            font-family: 'system-ui', '-apple-system', 'BlinkMacSystemFont', 'Segoe UI', 'Roboto',
                'Helvetica Neue', 'Arial', sans-serif;
            font-size: 1rem;
            line-height: 1.625em;
            font-weight: 400;
            color: rgba(0, 0, 0, 0.87);
        }

        .synctera-placeholder {
            position: absolute;
            display: none;
            top: 30px;
            left: 10px;
            color: rgba(0, 0, 0, 0.2);
            z-index: -1;
        }

        .synctera-custom-styles[_blank]+.synctera-placeholder {
            display: block;
        }

        .synctera-custom-styles[_focus]+.synctera-placeholder {
            display: none;
        }

        .synctera-button-container {
            display: flex;
            justify-content: center;
            align-items: center;
            width: 100%;
            gap: 1rem;
        }

        .synctera-submit-button {
            background-color: #1976d2;
            color: white;
            padding: 10px 20px;
            border: none;
            border-radius: 4px;
            font-size: 1rem;
            cursor: pointer;
            transition:
                background-color 0.3s,
                transform 0.3s;
            width: 100%;
        }

        .synctera-submit-button:hover {
            background-color: #155fa9;
        }

        .synctera-submit-button:active {
            transform: scale(0.97);
            transition: transform 0.1s ease-in-out;
        }

        .synctera-submit-button:disabled {
            background-color: #d3d3d3;
            cursor: not-allowed;
        }

        .synctera-cancel-button {
            background-color: #fff;
            color: #333;
            padding: 10px 20px;
            border: 1px solid #ddd;
            border-radius: 4px;
            font-size: 1rem;
            cursor: pointer;
            transition:
                background-color 0.3s,
                transform 0.3s;
            width: 100%;
        }

        .synctera-cancel-button:hover {
            background-color: #e0e0e0;
        }

        .synctera-cancel-button:active {
            transform: scale(0.97);
            transition: transform 0.1s ease-in-out;
        }

        .synctera-cancel-button:disabled {
            background-color: #d3d3d3;
            cursor: not-allowed;
        }

        .synctera-hidden {
            display: none;
        }
    </style>
</head>

<body>
    <div id="synctera-success" class="synctera-container synctera-hidden">
        <div class="synctera-form-container">Card activation was successful.</div>
    </div>

    <div id="card-activation-container" class="synctera-container">
        <div class="synctera-form-container">
            <div class="synctera-header">
                <h2 class="synctera-header-title">Activate Card</h2>
                <h4 class="synctera-header-subtitle">Enter your card details to activate</h4>
            </div>
            <div class="synctera-input-container">
                <div class="synctera-label">Card Number</div>
                <card-pan id="card-pan" token="hidden-token" class="synctera-custom-styles"
                    environment="SANDBOX"></card-pan>
                <div class="synctera-placeholder">4111 1111 1111 1111</div>
                <div id="card-pan-error" class="synctera-input-error synctera-hidden">
                    Card must be 16 digits
                </div>
            </div>
            <div class="synctera-input-container">
                <div class="synctera-label">Security Code</div>
                <card-cvv id="card-cvv" class="synctera-custom-styles"></card-cvv>
                <div class="synctera-placeholder">123</div>
                <div id="card-cvv-error" class="synctera-input-error synctera-hidden">
                    Security code must be 3 digits
                </div>
            </div>
            <div class="synctera-button-container">
                <button id="card-activation-cancel-button" class="synctera-cancel-button">Cancel</button>
                <button id="card-activation-submit-button" class="synctera-submit-button" disabled>
                    Activate
                </button>
            </div>
        </div>
    </div>

    <div id="set-pin-container" class="synctera-container synctera-hidden">
        <div class="synctera-form-container">
            <div class="synctera-header">
                <h2 class="synctera-header-title">Set Pin</h2>
                <h4 class="synctera-header-subtitle">Enter your 4-digit card PIN</h4>
            </div>
            <div class="synctera-input-container">
                <div class="synctera-label">New PIN</div>
                <set-pin id="set-pin-controller" class="synctera-custom-styles" token="hidden-token"
                    environment="SANDBOX"></set-pin>
                <div class="synctera-placeholder">1234</div>
                <div id="set-pin-error" class="synctera-input-error synctera-hidden">PIN must be 4 digits</div>
            </div>
            <div class="synctera-input-container">
                <div class="synctera-label">Confirm new PIN</div>
                <set-pin id="set-pin-confirm" class="synctera-custom-styles" isConfirm></set-pin>
                <div class="synctera-placeholder">1234</div>
                <div id="set-pin-confirm-error" class="synctera-input-error synctera-hidden">PINs must Match</div>
            </div>
            <div class="synctera-button-container">
                <button id="set-pin-cancel-button" class="synctera-cancel-button">Cancel</button>
                <button id="set-pin-submit-button" class="synctera-submit-button" disabled>Submit</button>
            </div>
        </div>
    </div>

    <script>
        const BASE_URL = 'http://your-server-url.com';
        // Helpers
        async function getCardToken(input, type = 'ACTIVATE', cardId) {
            // Make an api call to your server to get the card token
            const response = await fetch(
                `${BASE_URL}/api/cardToken?widgetType=${type}&cardId=${cardId}`
            );
            const data = await response.json();
            if (!data.widget_token) // update a error field 

                input.token = data.widget_token;
        }
        
        // Card Activation
        let cardActivation = document.getElementById('card-pan');
        let cardCvvInput = document.getElementById('card-cvv');
        let cardPanError = document.getElementById('card-pan-error');
        let cardCvvError = document.getElementById('card-cvv-error');
        let cardActivationSubmit = document.getElementById('card-activation-submit-button');
        let cardActivationCancel = document.getElementById('card-activation-cancel-button');
        let cardActivationValid = false;
        
        getCardToken(cardActivation, 'ACTIVATE', 'card-guid');

        cardActivation.addEventListener('load', function () {
            console.log('Card Activation Widget Loaded');
        });

        cardActivation.addEventListener('validity', function (e) {
            // Check if the form is valid
            cardActivationValid = e.target.isValid;
            cardActivationSubmit.disabled = !cardActivationValid;

            // Update validation warnings
            if (cardActivationValid) {
                cardPanError.classList.add('synctera-hidden');
                cardCvvError.classList.add('synctera-hidden');
            } else {
                if (cardCvvInput.hasAttribute('_user-invalid')) {
                    cardCvvError.classList.remove('synctera-hidden');
                } else {
                    cardCvvError.classList.add('synctera-hidden');
                }
                if (cardActivation.hasAttribute('_user-invalid')) {
                    cardPanError.classList.remove('synctera-hidden');
                } else {
                    cardPanError.classList.add('synctera-hidden');
                }
            }
        });

        cardActivationSubmit.addEventListener('click', function () {
            if (!cardActivationValid) return;
            // Disable the submit button
            cardActivationSubmit.disabled = true;
            try {
                cardActivation.submit();
            } catch (e) {
                console.error('Card failed to activate', e);
            }
        });

        cardActivation.addEventListener('success', function () {
            // Hide the card activation form
            document.getElementById('card-activation-container').classList.add('synctera-hidden');
            // Show the success messsage
            document.getElementById('synctera-success').classList.remove('synctera-hidden');

            setTimeout(() => {
                // hide the success messsage
                document.getElementById('synctera-success').classList.add('synctera-hidden');
                // Show the set pin form
                document.getElementById('set-pin-container').classList.remove('synctera-hidden');
            }, 2000);
        });

        // SET PIN
        let setPin = document.getElementById('set-pin-controller');
        let setPinConfirmInput = document.getElementById('set-pin-confirm');
        let setPinError = document.getElementById('set-pin-error')
        let setPinConfirmError = document.getElementById('set-pin-confirm-error')
        let setPinSubmit = document.getElementById('set-pin-submit-button');
        let setPinCancel = document.getElementById('set-pin-cancel-button');
        let setPinValid = false;

        getCardToken(setPin, 'SET-PIN', 'card-guid');
        setPin.addEventListener('load', function () {
            console.log('Set Pin Widget Loaded');
        });

        setPin.addEventListener('validity', function (e) {
            setPinValid = e.target.isValid;
            setPinSubmit.disabled = !setPinValid;

            // Update validation warnings
            if (setPinValid) {
                setPinError.classList.add('synctera-hidden')
                setPinConfirmError.classList.add('synctera-hidden')
            } else {
                if (setPinConfirmInput.hasAttribute('_user-invalid')) {
                    setPinConfirmError.classList.remove('synctera-hidden')
                } else {
                    setPinConfirmError.classList.add('synctera-hidden')
                }
                if (setPin.hasAttribute('_user-invalid')) {
                    setPinError.classList.remove('synctera-hidden')
                } else {
                    setPinError.classList.add('synctera-hidden')
                }
            }
        });

        setPinSubmit.addEventListener('click', function () {
            try {
                setPin.submit();
            } catch (e) {
                console.error('Pin failed to submit', e);
            }
        });

        setPin.addEventListener('success', function () {
            console.log('Pin set successfully');
        });

        setPin.addEventListener('failure', function (e) {
            loader.style.display = 'none';
            console.error('Pin failed to submit', e);
        });
    </script>
</body>

</html>