Skip to content

Attachments Guide

This attachments guide assumes that you have already completed the TheM>Getting Started>Quick Start guide and are familiar with TheM class, TheM submodule initialization, and creating/listening for custom events. This guide also assumes that you have already installed the amplifi_mobile_sdk package into your project and placed the following minified libraries in the /lib folder of your project: axios.min.js (Optional - fetch will be used if axios is not present), crypto-js.min.js, lz-string.min.js, moment.min.js, and socket.io.min.js. In addition, you should have completed:

  • the Onboarding Guide tutorial in order to create and onboard a user which can be logged into your ampliFi instance,
  • the Users Guide tutorial and the Accounts Guide tutorial so that you are familiar with logging a user in and working with accounts,
  • the Beneficiaries Guide tutorial in order to create a beneficiary to whom payment transactions can be remitted, and
  • the Remittances Guide tutorial in order to create transactions that may be referenced in this tutorial.

This tutorial will demonstrate how images (and thumbnail images) can be attached to existing transactions in base 64 string format and then managed using TheM.attachments submodule.

1. In the src folder of your project (from the Quick Start guide of the TheM Getting Started section), create a new file called attachments.js with the following code.

attachments.js

import ClassTheM from "../node_modules/@PayGearsCorp/amplifi_mobile_sdk/TheM/them.mjs";

import { thisDevice } from "./android-demo-device.js"; //android device emulator for testing

const AMPLIFI_BASE_URL = "PUT_YOUR_INSTANCE_URL_HERE"; //Speak to a support representative to be issued a sandbox instance URL
const AMPLIFI_CORE_URL = `${AMPLIFI_BASE_URL}core/`;
const DEVICE_TAG = "PUT_YOUR_DEVICE_TAG_HERE"; //Use deviceTag obtained from onboarding tutorial for this device

/*
For this tutorial, you will need a previously created account and transaction. If you have not already, it is recommended that you complete the tutorials for TheM.onboarding, TheM.user, TheM.accounts, TheM.beneficiaries, and TheM.remittance prior to completing this tutorial.
*/

const AFIACCOUNTID = "PUT_AFiAccountId_HERE"; //Use the AFiAccountId of a previously created account
const TRANSACTIONID = "PUT_transactionId_HERE"; //Use a transactionId of a previously created transaction for the account corresponding to AFIACCOUNTID

const subClassesToInit = [
    "accounts",
    "attachments",
    //"beneficiaries",
    //"cards",
    //"cheques",
    "common",
    //"externalAccounts",
    //"fdrs",
    //"fundstransfer",
    //"fxrates",
    //"genericRequests",
    //"ious",
    //"onboarding",
    //"payees",
    //"remittance",
    //"restrictions",
    //"statics",
    "user"
];


export const attachmentsTutorial = async (subClasses = "") => {
    TheM = new ClassTheM({
        config: {
            AFiInstanceId: "test",
            modulesFolder: "",
            modulesFolderOnboarding: "",
            webworkerFolder: "../TheM/",
            baseLibURL: "../demo/lib/",
            backEndURL: AMPLIFI_CORE_URL,
            socketURL: AMPLIFI_BASE_URL,
        },
        libs: {
        }
    });

    //Emulate user device before initializing TheM submodules
    TheM.thisDevice = {
        ...thisDevice,
        TheM,
        deviceTag: DEVICE_TAG,
    };

    //Initialize desired submodules
    //Some modules depend on others so must be initialized together
    //For instance, most submodules require the "common" subclass to be initialized
    await TheM.doInit(subClasses);

    //attachments workflow to try
    //Uncomment to run the whole workflow or follow the instructions in the browser
    /*
    //Prepare for logging in
    //Log in using the instructions in the browser or use the doAuthenticate method from the device emulator we created during onboarding
    await TheM.thisDevice.doAuthenticate(DEVICE_TAG);

    //Pull fresh accounts data from the server if necessary
    await TheM.accounts.doUpdate();

    //Check if the attachments submodule is ready and set if necessary
    if (!TheM.attachments.isReady) {
        TheM.attachments.isReady = true;
    };

    if (TheM.accounts && TheM.accounts[AFIACCOUNTID] && TheM.accounts[AFIACCOUNTID].transactions) {
        //Option 1 to create attachment
        //await TheM.attachments.doAttach({ imageB64: AMPLIFI_IMAGE_B64, thumbnailB64: AMPLIFI_IMAGE_B64, transaction: { transactionId: TRANSACTIONID, AFiAccountId: AFIACCOUNTID } });
        //Option 2 to create attachment
        await TheM.attachments.doAttach({ imageB64: AMPLIFI_IMAGE_B64, thumbnailB64: AMPLIFI_IMAGE_B64, transactionId: TRANSACTIONID, AFiAccountId: AFIACCOUNTID });
    } else {
        console.log("The specified account does not contain any transactions yet.")
    }

    //Fetch the most recently added attachment
    const id = TheM.attachments[TheM.attachments.length - 1].AFiAttachmentId;
    const attachmentEntity = await TheM.attachments.doFetch({ AFiAttachmentId: id, AFiAccountId: AFIACCOUNTID, transactionId: TRANSACTIONID });
    console.log(`The most recently added attachment is: ${JSON.stringify(attachmentEntity)}`)

    //Delete the attachment
    await TheM.attachments.doDelete({ AFiAttachmentId: id, AFiAccountId: AFIACCOUNTID, transactionId: TRANSACTIONID });

    if (TheM.attachments[id]) {
        console.log(`The attachment (${id}) failed to delete.`);
    } else {
        console.log(`The attachment (${id}) was deleted successfully.`);
    }

    //Logout when finished
    //await TheM.user.doLogout();
    */
};

await attachmentsTutorial(subClassesToInit.join(" "));

2. The attachments module expects the user to be using some type of device so make sure the android-demo-device.js file used during onboarding is still in your /src folder.

3. Create a new file in the /demo folder of your project called attachments.html with the following code.

attachments.html

<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no" />

    <title>ampliFi</title>

    <script>
        var TheM;
        var TheM_config;
    </script>

    <script src="../lib/socket.io.min.js"></script>
    <script src="../lib/lz-string.min.js"></script>
    <script src="../lib/moment.min.js"></script>
    <script src="../lib/axios.min.js"></script>
    <script src="../lib/crypto-js.min.js"></script>
    <script type="module" src="/../src/attachments.js"></script>

    <style>
        html {
            color: white;
            background-color: black;
        }
    </style>
</head>


<body>
    <div>
        Hit F12 to open the browser console.
        Start working with TheM by typing "TheM" into the browser console.
    </div>
    <br />
    <br />
    <div>
        1. In order to log a user in, we will need to prepare the user credentials using the encryptedServerSecret
        stored locally during onboarding. Type the following to retrieve the encryptedServerSecret. (Or skip steps 1-5
        by using the doAuthenticate method in the device emulator like so, `await
        TheM.thisDevice.doAuthenticate(DEVICE_TAG);`.)
        <br /><br />
        <code>let { encryptedServerSecret } = await TheM.thisDevice.retrieveLocally("encryptedServerSecret", true);</code>
        <br /><br />
        Type <code>encryptedServerSecret</code> into the browser console and hit enter to view the encryptedServerSecret
        value.
        <br /><br />
        2. Since we are using an emulated android device to log in, we need to get the cryptotext value like so.
        <br /><br />
        <code>
            let _SUPER_SECRET = "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000";<br />
            let _dtsValueString = (new Date()).valueOf().toString();<br />
            let serverSecret = CryptoJS.AES.decrypt(encryptedServerSecret, _SUPER_SECRET).toString(CryptoJS.enc.Utf8);<br />
            let cryptotext = CryptoJS.AES.encrypt((TheM.thisDevice.deviceTag) + _dtsValueString, serverSecret).toString(); 
        </code>
        <br /><br />
        3. Set a socket connection for bidirectional communication.
        <br /><br />
        <pre><code>TheM.thisDevice.halfRef = TheM.common.GetRandomSTR(40);<br />let manager = new TheM.io.Manager(TheM.config.socketURL + "?halfRef=" + TheM.thisDevice.halfRef, {<br />  autoConnect: false<br />});<br />let socket = manager.socket("/");</code></pre>
        <br />
        4. Open the socket connection.
        <br /><br />
        <pre><code>manager.connect(function (data) {<br />  console.log("established real-time comm channel for onboarding");<br />  TheM.thisDevice.isRealTimeCommAvailable = true;<br />});</code></pre>
        <br />
        5. Log the user in using the deviceTag obtained during onboarding and the newly created cryptotext.
        <br /><br />
        <pre><code>const credentials = {<br />  "dtsValueString": _dtsValueString,<br />  "deviceTag": "PUT_DEVICE_TAG_HERE",<br />  "deviceData": TheM.thisDevice.data,<br />  "channel": TheM.thisDevice.platform,<br />  "dynamicScreensVersion": TheM.thisDevice.dynamicScreensVersion,<br />  "socket": {<br />    halfRef: TheM.thisDevice.halfRef<br />  },<br />  "pushMessToken": TheM.thisDevice.pushMessToken,<br />  "cryptotext": cryptotext<br />};<br />await TheM.user.doLogin(credentials);</code></pre>
        <br />
        6. After authentication, pull fresh accounts data from the server if necessary. We need to be able to reference
        previously created account transactions.
        <br /><br />
        <code>
            await TheM.accounts.doUpdate();
        </code>
        <br /><br />
        7. Check if the attachments submodule is ready and set if necessary.
        <br /><br />
        <pre><code>if (!TheM.attachments.isReady) {<br />  TheM.attachments.isReady = true;<br />};</code></pre>
        <br /><br />
        8. Create an attachment for an existing transaction.
        <br /><br />
        <code>await TheM.attachments.doAttach({ imageB64: "VeryLongBase64ImageString", thumbnailB64: "VeryLongBase64ImageString", transactionId: "PUT_transactionId_HERE", AFiAccountId: "PUT_AFiAccountId_HERE" });</code>
        <br /><br />
        9. Fetch the most recently added attachment.
        <br /><br />
        <code>const id = TheM.attachments[TheM.attachments.length - 1].AFiAttachmentId;<br />const attachmentEntity = await TheM.attachments.doFetch({ AFiAttachmentId: id, AFiAccountId: "PUT_AFiAccountId_HERE", transactionId: "PUT_transactionId_HERE" });<br />console.log(`The most recently added attachment is: ${JSON.stringify(attachmentEntity)}`)
        </code>
        <br /><br />
        10. Delete the attachment.
        <br /><br />
        <code>await TheM.attachments.doDelete({ AFiAttachmentId: id, AFiAccountId: "PUT_AFiAccountId_HERE", transactionId: "PUT_transactionId_HERE" });
        </code>
        <br /><br />
        11. Keep exploring TheM.attachments properties and methods and log out when finished.
        <br /><br />
        <code>
            await TheM.user.doLogout();
        </code>
        <br /><br />
    </div>
</body>

</html>

4. Start a server in the root folder of your project.

py -m http.server 8000

5. Open a browser and enter the following URL: http://localhost:8000/demo/

6. Click on the link for "attachments.html" and follow the instructions to log in, add a new attachment, fetch an attachment, delete an attachment, and log out.