Example: TON plugin

Find below the code of the TON plugin

Component parameters

Component code

Init

function(instance, context, config) {
  
  	// prevent double-rendering
 	if(window.init && 1 == window.init[instance.id]) return;
 	if(window.init || (window.init={}),!instance.id) return;
  	window.init[instance.id] = !0;
  
    div = $(`
	<form id="tonСonnect"></form>
	`);
  
    instance.canvas.append(div);
}

Update

function(instance, properties, context, config) {  
    $form = $("#tonСonnect");

    // clear layout on update
    var layout = $('#tonСonnect')
    layout.empty();  

    var locale = config.locale || 'ENG'

    // local templating
    function template(input) {
        const templateData = _.get(context,"endpoint[0]") || {};
        _.templateSettings.interpolate = /{{([\s\S]+?)}}/g;
        if (!templateData) return ""
        const renderTemplate = (template) => {
            return _.template(template, {
                interpolate: /{{([\s\S]+?)}}/g
            })(templateData, {
                variable: '',
                evaluate: /<%([\s\S]+?)%>/g,
                escape: /<%-([\s\S]+?)%>/g
            });
        };
        try {
            const result = renderTemplate(input);
            return result;
        } catch (error) {
            console.error("template")
            console.error(input)
            console.error(templateData)
            console.error('Error rendering template:', error);
            return '';
        }
    }

    var dict = {
        ENG: {
            "disconnect": "Disconnect wallet",
            "confirm": "Confirm transaction",
            "connect": "Connect wallet",
            "successMessage": "Success! The transaction may take a few minutes.",
        },
        GER: {
            "disconnect": "Wallet trennen",
            "confirm": "Transaktion bestätigen",
            "connect": "Wallet verbinden",
            "successMessage": "Erfolg! Die Transaktion kann einige Minuten dauern.",
        },
        ESP: {
            "disconnect": "Desconectar cartera",
            "confirm": "Confirmar transacción",
            "connect": "Conectar cartera",
            "successMessage": "¡Éxito! La transacción puede tardar unos minutos.",
        },
        FRA: {
            "disconnect": "Déconnecter le portefeuille",
            "confirm": "Confirmer la transaction",
            "connect": "Connecter le portefeuille",
            "successMessage": "Succès ! La transaction peut prendre quelques minutes.",
        },
        RUS: {
            "disconnect": "Отключить кошелек",
            "confirm": "Подтвердить транзакцию",
            "connect": "Подключить кошелек",
            "successMessage": "Успех! Транзакция может занять несколько минут.",
        },
        JPN: {
            "disconnect": "ウォレットを切断",
            "confirm": "取引を確認する",
            "connect": "ウォレットを接続",
            "successMessage": "成功です!取引には数分かかる場合があります。",
        },
        POR: {
            "disconnect": "Desconectar carteira",
            "confirm": "Confirmar transação",
            "connect": "Conectar carteira",
            "successMessage": "Sucesso! A transação pode levar alguns minutos.",
        },
        IND: {
            "disconnect": "वॉलेट डिस्कनेक्ट करें",
            "confirm": "लेन-देन की पुष्टि करें",
            "connect": "वॉलेट कनेक्ट करें",
            "successMessage": "सफलता! लेन-देन में कुछ मिनट लग सकते हैं।"
        },
        KOR: {
            "disconnect": "지갑 연결 끊기",
            "confirm": "거래 확인",
            "connect": "지갑 연결",
            "successMessage": "성공! 거래가 몇 분 정도 걸릴 수 있습니다.",
        }
    }

    var svgData = `<g id="ton-logo" fill="#FFFFFF" fill-rule="nonzero">
<path d="M37.1153287,19 C38.7084887,19 40,20.2846058 40,21.8692473 L40,60.125878 
C40,63.0535566 36.1095077,64.1011762 34.6246277,61.5733414 C32.2779476,57.5783927 
32.2779476,57.5783927 25.2379073,45.5935466 C20.3312126,37.240472 18.8443354,34.7092373 
17.5679538,32.5319622 L17.2376495,31.9684115 C16.7979832,31.218129 16.3500203,30.4531462 
15.7587094,29.4433688 C15.2208728,28.3670775 14.9605279,27.179804 15.0048455,25.9969387 
C15.0433928,24.8019799 15.3833303,23.6308115 15.9880796,22.6050914 C16.5924637,21.5736398 
17.443754,20.7075471 18.4800157,20.0713338 C19.4987828,19.4520827 20.6548433,19.0879541 
22.0458062,19 L37.1153287,19 Z M23.0700308,24.0026041 L22.4228731,24 C22.1604706,24.0186412 
21.9105713,24.1008057 21.7049058,24.231268 C21.4909167,24.3684171 21.3177649,24.5523074 
21.1922318,24.7759213 C21.0751474,24.9832245 21.008859,25.2216226 21.0009575,25.4761216 
C20.9924828,25.7124407 21.042561,25.9508345 21.0607339,26.0035974 C21.6607738,27.0699046 
22.1019795,27.8539541 22.5525285,28.654607 L22.8561242,29.194115 C24.0393632,31.2968024 
25.5276974,33.9416626 30.1280032,42.116685 C31.7281095,44.9601711 32.9517202,47.1346016 
33.9169516,48.8498763 L34,49 L34,24.0028938 L23.2616773,24.0032932 C23.1986199,24.0030773 
23.1350331,24.0028478 23.0700308,24.0026041 Z" id="Path"></path>
<path d="M51.0418462,19.0032931 C51.1232812,19.0035127 51.2059707,19.0037469 51.2910421,19.0039966 
L52.1514281,19.0066926 C53.3455002,19.0879541 54.5015812,19.4520827 55.5313829,20.0780638 
C56.5566466,20.7075471 57.4079519,21.5736399 58.0084415,22.5984473 C58.6171068,23.6308116 
58.9570504,24.80198 58.9950845,25.9821942 C59.0401209,27.1852586 58.7771527,28.3769796 58.1455257,
29.6135309 C57.7314831,30.3185218 57.3905069,30.8991026 57.0710208,31.4430922 L56.7567879,31.9781372 
C55.4095976,34.2720005 54.1431145,36.4284435 48.7605616,45.5933259 C41.7218386,57.5781722 41.7218386,
57.5781722 39.3755976,61.573121 C37.8908494,64.1012045 34,63.0536927 34,60.1258786 L34,21.8692473 C34,
20.2846058 35.2915342,19 36.8847225,19 L51.0418462,19.0032931 Z M40,49 L40.0883486,48.8500819 C41.0529283,
47.1346086 42.275713,44.9599264 43.8747391,42.1161111 C48.8716956,33.2291885 50.1944193,30.8767678 
51.4119971,28.7158234 L51.7040243,28.1976254 C52.0466313,27.5897724 52.4033802,26.9571476 52.8526196,
26.1605091 C52.9585278,25.9417484 53.007886,25.7081133 52.9989778,25.4585291 C52.991576,25.2188698 
52.9253188,24.9804442 52.8045189,24.7664166 C52.6828154,24.5494772 52.509745,24.3655656 52.306493,
24.2351875 C52.0902878,24.0979233 51.8405061,24.0157492 51.7683482,24.0038551 L40,24 L40,49 Z" id="Path"></path>
<path d="M37.0000346,0 C57.4362074,0 74,16.5638158 74,37.0000346 C74,57.4361958 57.4361958,74 37.0000346,
74 C16.5638158,74 0,57.4362074 0,37.0000346 C0,16.5638042 16.5638042,0 37.0000346,0 Z M37.5000348,5 
C20.1013601,5 6,19.1013601 6,36.5000348 C6,53.8986497 20.10137,68 37.5000348,68 C54.8986399,68 69,53.8986399 69,
36.5000348 C69,19.10137 54.8986497,5 37.5000348,5 Z" id="Path"></path>
</g>`
    const accentTextColor = getComputedStyle(document.documentElement)
    .getPropertyValue('--button-accent-text').trim();
    svgData = svgData.replace(/fill="#FFFFFF"/g, `fill="${accentTextColor}"`);

    var connect = $(`
<button class='tonConnectPlugin_button'>
<svg transform="translate(-5 0)"  width="22px" height="22px" viewBox="0 0 74 74" 
version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">${svgData}</svg>&nbsp;
${dict[locale].connect}
</button>`);

    // add styling:
    var style = document.createElement('style');
    style.type = 'text/css';
    style.innerHTML = `
.tonConnectPlugin_button {
background-color: var(--button-accent-bgr);
color: var(--button-accent-text);
border: solid 1px var(--button-accent-border);
display: flex;
user-select: none;
justify-content: center;
align-items: center;
padding: 1px 18px;
text-decoration: none;
font-size: var(--text-font-size);
border-radius: var(--border-radius);
cursor: pointer;
outline: none;
transition: 0s;
white-space: nowrap;
font-weight: var(--text-font-weight);
margin: 1px;
height:42px;
}
.tonConnectPlugin_button:hover {
background-color: var(--button-accent-hover-bgr);
color: var(--button-accent-hover-text);
border-color: var(--button-accent-hover-border);
box-shadow: 0 0 0 1px var(--button-accent-hover-border);
}
.tonConnectPlugin_button:active {
background-color: var(--button-accent-active-bgr);
color: var(--button-accent-active-text);
border-color: var(--button-accent-active-border);
box-shadow: 0 0 0 1px var(--button-accent-active-border);
}
.tonConnectPlugin_icon {
width: 22px;
margin-right:5px;
}
.tonConnectPlugin_disconenct {
font-size: 14px;
color:var(--layout-accent);
text-decoration:none;
}
.tonConnectPlugin_disconenct:hover {
color:var(--layout-accent-hover);
}
.tonConnectPlugin_wallet {
display: flex;
gap: 0 16px;
background:var(--cards-bgr);
border-radius: 20px;
padding: 12px;
margin-bottom: 12px;
}
.tonConnectPlugin_wallet_info {
flex: 1;
overflow:hidden;
text-overflow: ellipsis;
}
.wallet_img {
width: 75px;
height: 75px;
overflow: hidden;
border-radius: 100%;
flex-shrink: 0;
}
.wallet_title {
font-weight: bold;
margin-bottom:5px;
}
.wallet_description {
opacity:.5;
overflow:hidden;
text-overflow: ellipsis;
margin-bottom:5px;
}
.tonConnectPlugin_pay {
display: flex;
gap: 0 16px;
align-items: center;
font-size: var(--h3-font-size);
cursor: pointer;
}
.tonConnectPlugin_success {
background-color: var(--hint-ok-light);
border-left: solid 5px var(--hint-ok);
color: var(--hint-text-color);
padding: 18px;
font-size: var(--text-font-size);
position: relative;
border-radius: 4px;
}
`;
    document.getElementsByTagName('head')[0].appendChild(style);

    connect.click((e) => {
        e.preventDefault()
        e.stopPropagation()
        config.tonConnectUI.openModal()
    })

    // success message
    var success = document.createElement('blockquote');
    success.className = 'tonConnectPlugin_success';
    success.innerHTML = dict[locale].successMessage;
    
    // Create the displayWallet container
    var displayWallet = document.createElement('div');
    displayWallet.className = 'tonConnectPlugin_wallet';

    var displayWalletInfo = document.createElement('div');
    displayWalletInfo.className = 'tonConnectPlugin_wallet_info';

    // Create the image element and set its src attribute
    var imgElement = document.createElement('img');
    imgElement.className = 'wallet_img';
    imgElement.src = _.get(config,"wallet.imageUrl");

    // Create the title div and set its innerHTML
    var titleElement = document.createElement('div');
    titleElement.className = 'wallet_title';
    titleElement.innerHTML = _.get(config,"wallet.name");

    // Create the description div and set its innerHTML
    var descriptionElement = document.createElement('div');
    descriptionElement.className = 'wallet_description';
    descriptionElement.innerHTML = _.get(config,"wallet.account.address");

    var disconnectButton =  document.createElement('a') //$(`<a class="tonConnectPlugin_disconenct">Disconnect wallet</a>`);
    disconnectButton.className = 'wallet_description';
    disconnectButton.innerHTML = dict[locale].disconnect
    disconnectButton.href = "#"; // Optionally, set the href attribute to '#' to make it clickable
    disconnectButton.addEventListener('click', function(e) {
        e.preventDefault(); // Prevent the default action if necessary
        config.tonConnectUI.disconnect(); // Call the disconnect function
    });

    // Append the elements to the displayWallet container
    displayWallet.appendChild(imgElement);
    displayWalletInfo.appendChild(titleElement);
    displayWalletInfo.appendChild(descriptionElement);
    displayWalletInfo.appendChild(disconnectButton);
    displayWallet.appendChild(displayWalletInfo);

    var tonMulti = 1000000000
    var amount = (template(_.get(context,"amount") || 0)/tonMulti).toFixed(2)

    var address = template(_.get(context,"address"))
    var orderNumber = template(_.get(context,"orderNumber")) || Math.floor(Math.random()*100000000)

    var send = $(`<div class="tonConnectPlugin_pay">
<div class="tonConnectPlugin_amount"><b>${amount}</b> TONs</div>
<button class='tonConnectPlugin_button'>${dict[locale].confirm}</button>
</div>`);

    const sendNotification = () => {
  
        var payload = {
            user: _.get(config,"auth.user"),
            addressFrom: _.get(config,"wallet.account.address"),
            addressTo: address,
            orderNumber: orderNumber,
            status: "success",
            amountTons: amount,
            amountNanoTons: amount * tonMulti
        }
        if (!_.get(context,"webhook")) {
            console.log("TON PLUGIN: no webhook")
            return;
        }
        fetch(_.get(context,"webhook"), {
            mode:  'cors', 
            method: 'POST',
            headers: {
                'Accept': 'application/json',
                'Content-Type': 'application/json'
            },
            body: JSON.stringify(payload)
        }).then(()=>{
            console.log("TON PLUGIN: message to the webhook is sent")
        })
    }


    send.click((e)=>{
        e.preventDefault()
        e.stopPropagation()
        if (!address) {
            alert('TON: no address to send');
            return;
        }
        if (!template(_.get(context,"amount"))) {
            alert('TON: transaction amount = 0');
            return;
        }
        var message = config.beginCell()
        .storeUint(0, 32) // write 32 zero bits to indicate that a text comment will follow
        .storeStringTail(`Order #${orderNumber}`) 
        .endCell();
        var tx = {
            // The transaction is valid for 10 minutes from now, in unix epoch seconds.
            validUntil: Math.floor(Date.now() / 1000) + 600,
            messages: [
                {
                    address: address,
                    // Amount to send in nanoTON. For example, 0.005 TON is 5000000 nanoTON.
                    amount: amount * tonMulti,
                    payload: message.toBoc().toString("base64"),
                    bounce:false
                },
            ],
        };
        console.log("TON PLUGIN: tx")
        console.log(tx)
        config.tonConnectUI.sendTransaction(tx)
            .then((res)=>{ 
                sendNotification();
            	layout.empty();  
             	$form.append(success)
            })
            .catch((err)=>{ alert('error') })
        e.preventDefault()
    })

    // adding the controls:
    if(config.wallet) { 
        $form.append(displayWallet);
        $form.append(send);
    } else {
        $form.append(connect);
    }
}

Destroy

function destroy(instance) {
  if(window.init && window.init[instance.id] == true){
		delete window.init[instance.id];
  }
}

Last updated