ao-helper

arthur online helper

2020-02-19 기준 버전입니다. 최신 버전을 확인하세요.

// ==UserScript==
// @name         ao-helper
// @description  arthur online helper
// @version      1.0.9
// @author       yuze
// @namespace    yuze
// @match        https://system.arthuronline.co.uk/*
// @connect      arthuronline.co.uk
// @connect      ea-api.yuze.now.sh
// @grant        GM.getValue
// @grant        GM.setValue
// @grant        GM.xmlHttpRequest
// @require      https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.24.0/moment.min.js
// ==/UserScript==

/* eslint-env jquery */ 
/* globals moment, GM */

let id;
let icons = {}
let storage = {}
let targets = {}

let local = false
let letter_endpoint

init()
function init() {
    $(window).on('load focus mousedown', checkLocation)
    $(window).on('load', loadActions)
    $(window).on('mousedown', mousedownActions)
    $(window).on('hashchange', checkTab)

    appendCSS()
    loadIcons()

    id = $('.text-logo span').text().toLowerCase()

    if (local) {
        letter_endpoint = 'https://localhost:3000/api/gen-letter'
        console.log('using localhost endpoint')
    } else {
        letter_endpoint = 'https://ea-api.yuze.now.sh/api/gen-letter'
    }

    targets = {
        addTransaction: {
            btn: '.box-header .actions ul > :nth-child(3)',
            date: 'input#TransactionDate',
            desc: 'input#TransactionDescription',
            amount: 'input#TransactionAmount',
        },
        documents: {
            checkboxes: 'table.attachments input[type="checkbox"]'
        }
    }
}

function loadActions() {
    //quickAccess()
    quickNotes()
}

function mousedownActions(e) {
    if ( event.which == 2 || event.which == 3  ) return;

    copyOnClick(e)
    addTransactionBtn(e)
}

async function wait(ms) {
    return new Promise(resolve => {
        setTimeout( () => { resolve() }, ms);
    });
}

async function waitForExistance(elem, resolve) {

    if ( $(elem).length ) {
        resolve()
    }

    let interval;
    if ( !$(elem).length ) {
        interval = setInterval( () => checkExistance(), 256)
    }
    function checkExistance() {
        if ( $(elem).length ) {
            clearInterval(interval)
            resolve()
        }
    }
}

async function waitForIframeExistance(iframe, elem, resolve) {
    if ( $(iframe).contents().find(elem).length ) {
        resolve()
    }
    let interval;
    if ( !$(iframe).contents().find(elem).length ) {
        interval = setInterval( () => checkExistance(), 128)
    }
    function checkExistance() {
        if ( $(iframe).contents().find(elem).length ) {
            clearInterval(interval)
            resolve()
        }
    }
}

async function checkLocation() {
    $(window).trigger('hashchange')
    await wait(256)
    if( /tenancies\/view\/\d{6}/.test(window.location.href) ) {
        viewTenancies()
    }
    if( /\/\w+\/(page|filter|index)/.test(window.location.href) ) {
        viewSearch()
    }
}

async function checkTab() {
    await wait(64)
    if( !location.hash.includes('tab-transactions') ) {
        tabTransactions(true)
    }
    if( !location.hash.includes('tab-recurrings') ) {
        tabRecurrings(true)
    }   
    if( !location.hash.includes('tab-attachments') ) {
        tabAttachments(true)
    }   

    if( location.hash.includes('tab-transactions') ) {
        tabTransactions(false)
    }
    if( location.hash.includes('tab-recurrings') ) {
        tabRecurrings(false)
    }
    if( location.hash.includes('tab-attachments') ) {
        tabAttachments(false)
    }
    
}

function viewTenancies() {
    new Promise( function(resolve) {
        waitForExistance('.identifier', resolve)
    }).then( () => {
        appendTenantToolbox()
        appendReadableDateRange()
    } )
}

function viewSearch() {
    $('#_q').off('paste', querySeperator)
    $('#_q').on('paste', querySeperator)
}

function appendTenantToolbox() {

    if ( $('#tenantToolbox').length ) return;

    const option = {
        bfc: `  <div class="option" id="tenantToolbox_bfc">
                    <div class="icon red">${icons.percent}</div><span class="red">Breaking Fee Calculator</span>
                </div>`,
        letter: `<div class="option" id="tenantToolbox_letter">
                    <div class="icon red">${icons.letter}</div><span class="red">Overdue Rent Letter</span>
                </div>`
    }

    const html = `  <div id="tenantToolbox" class="element-container">
                        <div class="element-header">
                            <div class="title">${id[0].toUpperCase() + id.slice(1)} tools</div>
                            <div style="height: 4px"></div>
                            ${option.bfc}
                            ${option.letter}
                        </div>
                    </div>`

    $('.left-side-detail').append(html)

    $('#tenantToolbox').on('click', tenantToolboxActions)
}

function tenantToolboxActions(e) { 
    if( e.target.id == 'tenantToolbox' ) return;
    if( e.target.closest('.option').id == 'tenantToolbox_bfc') {
        prepareModal('bfc')
        return;
    }
    if( e.target.id == 'tenantToolbox' ) return;
    if( e.target.closest('.option').id == 'tenantToolbox_letter') {
        genLetter()
        return;
    }
}

async function genLetter() {

    let savedLoc = window.location.href;
    
    let property = function() {
        let arr = $('.identifier-detail .sub-title a:nth-of-type(1)').text().split(',')
        arr.splice(1, 1)
        return arr.join(',')
    }()

    let ref = $('.identifier-detail .title').text().match(/TE\d{4,5}/)[0]
    let total = $('.financial-transaction .overdue .number').text()

    let arrears;
    let dueDate;

    getArrears()
    function getArrears() {
        $('.nav.nav-tabs [href^="#tab-transactions"]')[0].click()

        new Promise( function(resolve) {
            waitForExistance('.transactions tbody', resolve)
        }).then(() => {

            // arrears data
            $('#genOverdueBtn')[0].click()
            arrears =  $('#genOverdueText')[0].value.split('\n\n')[0]
            $('#genOverdueText').css('display', 'none')

            // extract due date
            dueDate = arrears.split('\n')

            for (let i = 0; i <= dueDate.length; i++) {
                
                if ( !dueDate[i] && i === 0 ) {
                    break;
                } else if ( i == dueDate.length - 1 ) {

                    try {
                        dueDate = dueDate[0].match(/\((\d.+)-/)[1].trim()
                        break;
                    } catch(err) {
                        dueDate = dueDate[0].match(/\((\d.+)\)/)[1].trim()
                        break;
                    }
                    
                } else if ( dueDate[i].includes('Outstanding') ) {
                    dueDate = dueDate[i].match(/\((.+)-/)[1].trim()
                    break;
                }

            }
            getNames()
        })
    }

    let names = []
    let namesFirst = []
    let fullName;
    let firstName;

    function getNames() {
        $('.nav.nav-tabs [href^="#tab-summary"]')[0].click()

        new Promise( function(resolve) {
            waitForExistance('.title .name h3', resolve)
        }).then(() => {
            for(let i = 0; i < $('.title .name h3').length; i++) {
                names.push( $('.title .name h3')[i].textContent )
            }

            for (let i = 0; i < names.length; i++) {    
                fullName = names.join(', ')
            }
        
            for (let i = 0; i < names.length; i++) {
                namesFirst.push( names[i].split(' ')[0] )
            }

            if( names.length > 2) {
                firstName = namesFirst.join(', ').replace(/(,)(?!.+\1)/, ' and')
            } else {
                firstName = namesFirst.join(' and ')
            }
            returnToSavedLocation()
            sendRequest()
        })
    }

    function sendRequest() {

        GM.xmlHttpRequest({
            method: "POST",
            url: letter_endpoint,
            data: `for=${id}&name=${names[0]}&full_name=${fullName}&first_name=${firstName}&property=${property}&ref=${ref}&arrears=${arrears}&due_date=${dueDate}&total=${total}`,
            headers: {
                "Content-Type": "application/x-www-form-urlencoded"
            },
            onload: function(res) {
                console.log(res.response)
                window.open(`${letter_endpoint}/${names[0]}/${property}/`)
            }
        })

    }

    function returnToSavedLocation() {
        if( /tenancies\/view\/\d{6}\/ident:Datatable.{5}$/.test(savedLoc) ){
            setTimeout( async () => {
                $(`.nav.nav-tabs [href^="#tab-summary"]`)[0].click()
                await wait(512)
                checkLocation()
            }, 1)
        } else if ( /tenancies\/view\/\d{6}\/ident:Datatable.{5}#tab-.+-/.test(savedLoc) ) {
            let match = savedLoc.match(/tab-.+(?=-)/)[0]
            setTimeout( async () => {
                $(`.nav.nav-tabs [href^="#${match}"]`)[0].click()
                await wait(512)
                checkLocation()
            }, 1)
        }
    }
}

async function prepareModal(mode) {

    let template = {}

    if ( mode == 'bfc') {
        prepareDataBfc('bfc')
    }

    async function prepareDataBfc(mode) {
        let data = {}

        data.today = currentDate()
        data.endOfTenancy = storage.tenancyEndDate
        data.monthly = ''

        if ( $('.summary-data-container div:nth-child(2) p').length ) {
            data.monthly = $('.summary-data-container div:nth-child(2) p').text().trim().replace(' monthly', '')
            makeTemplateBfc(data, mode)
        } else {
            $('.nav.nav-tabs [href^="#tab-summary"]')[0].click()
            new Promise( function(resolve) {
                waitForExistance('.summary-data-container div:nth-child(2) p', resolve)
            }).then( () => {
                data.monthly = $('.summary-data-container div:nth-child(2) p').text().trim().replace(' monthly', '')
                makeTemplateBfc(data, mode)
            } )
        }
    }

    function makeTemplateBfc(data, mode) {    

        template.postLaunchActions = true
        template.title = 'Breaking Fee Calculator'
        template.close = 'Understood'
        template.color = 'red'
        template.body = `One month's rent is&ensp;<input class="monthly red" type="text" value="£0.00" style="width: 7.5ch"><br>
                    <hr>
                    <input class="from red" type="date" value="2020-01-01" style="width: 12.25ch">&ensp;to&ensp;<input class="to red" type="date" value="2020-01-01" style="width: 12.25ch">&ensp;is <b><span class="days">0</span> days</b><br>
                    That's <span class="daysBetweenReadable"><b>0 months, 0 weeks</b> and <b>0 days</b></span>
                    <hr>
                    Weekly rent is <b>£<span class="weekly curr">0.00</span></b> which is <b>£<span class="daily curr">0.00</span></b> per day<br>
                    <b class="start">£<span class="daily curr">0.00</span></b> multiplied by <b><span class="days">0</span> days</b> is <b>£<span class="dailyByDays curr">0.00</span></b>
                    <hr>
                    <input type="text" value="0%" style="width: 2.75ch" class="percent red"">&ensp;of <b>£<span class="dailyByDays curr">0.00</span></b> is <b>£<span class="percentOfRemaining curr">0.00</span></b>`
        template.footer = `<span style="color: #d64a65">Total to be paid: <b class="totalStyle">£<span class="total">0.00</span></b></span>`
        
        createModal(template, data, mode)
    }
}

function createModal(template, data, mode) {

    if ( $('#fModal').length ) return;

    let { title, body, footer, close, color, postLaunchActions } = template;

    const html = `  <div id="fModal" class="${color}">
                        <div class="header ${color}">${title}</div>
                        <div class="body">${body}</div>
                        <div class="footer">
                            <div class="left">${footer}</div>
                            <div class="right"><div class="btn ${color}" id="fModalClose">${close}</div></div>
                        </div>
                    </div>`

    $('body').append(html)
    $('#fModal').hide().fadeIn(314)

    //CLOSE
    $('#fModalClose').on('click', removeModal)

    //MOVE
    $('#fModal .header').on('mousedown', moveModal)

    function moveModal(e) {
        let x = e.clientX - ( $('#fModal .header')[0].getBoundingClientRect().left + ( $('#fModal .header')[0].getBoundingClientRect().width / 2 ) )
        let y = e.clientY - $('#fModal .header')[0].getBoundingClientRect().top

        $('body').on('mousemove', beginDrag)
        function beginDrag(e) {
            $('#fModal').css('left', e.clientX - x + "px")
            $('#fModal').css('top', + e.clientY - y + "px")
        } 

        $('#fModal .header').on('mouseup', endDrag)
        function endDrag(){
            $('body').off('mousemove', beginDrag)
        }
    }

    if ( postLaunchActions ) {
        modalPostLaunch(data, mode)
    }
}

function modalPostLaunch(data, mode) {
    if ( mode == 'bfc') {
        postLaunchBfc(data)
    }

    function postLaunchBfc(data) {

        let { monthly, today, endOfTenancy } = data;

        initialise()
        function initialise() {
            $('#fModal .monthly')[0].value = monthly
            $('#fModal .from')[0].value = today
            $('#fModal .to')[0].value = endOfTenancy
            $('#fModal .percent')[0].value = 7

            console.log(endOfTenancy)
        }
        
        calc()
        function calc() {

            let monthly = $('#fModal .monthly')[0].value
            let percent = $('#fModal .percent')[0].value

            clearFormatting()
            function clearFormatting() {
                // monthly
                if ( $('#fModal .monthly')[0].value.includes('£') ) {
                    monthly = $('#fModal .monthly')[0].value.slice(1)
                }
                if ( monthly.includes(',') ) {
                    monthly = monthly.replace(',', '')
                }
                // percent
                if ( $('#fModal .percent')[0].value.includes('%') ) {
                    percent = $('#fModal .percent')[0].value.replace('%', '')
                }
            }

            let daysBetweenArray = differenceBetweenDates($('#fModal .from')[0].value, $('#fModal .to')[0].value)
            for(let i = 0; i < $('#fModal .days').length; i++ ) {
                if ( $('#fModal .days')[i].innerHTML == 'NaN' ) {
                    $('#fModal .days')[i].innerHTML = '0'
                    continue;
                }
                $('#fModal .days')[i].innerHTML = daysBetweenArray[0]
            }
            $('#fModal .daysBetweenReadable')[0].innerHTML = daysBetweenArray[1]

            $('#fModal .weekly')[0].innerHTML = function() {

                let weekly = String( (parseFloat(monthly) * 12 / 52).toFixed(3) ).slice(0, -1) ;

                if( weekly.match(/\.\d(\d)/)[1] == '9' ) {
                    weekly = +weekly + 0.01
                } else if ( weekly.match(/\.\d(\d)/)[1] == '1' ) {
                    weekly = +weekly - 0.01 
                } else {
                    weekly = +weekly
                }

                return String( weekly.toFixed(3) ).slice(0,-1)
            }() 

            for(let i = 0; i < $('#fModal .daily').length; i++ ) {
                $('#fModal .daily')[i].innerHTML = +String( +$('#fModal .weekly')[0].innerHTML / 7 ).match(/\d+(\.\d{2})?/)[0]
            }


            for(let i = 0; i <  $('#fModal .dailyByDays').length; i++ ) {
                $('#fModal .dailyByDays')[i].innerHTML = +String(+$('#fModal .daily')[0].innerHTML * +$('#fModal .days')[0].innerHTML).match(/\d+(\.\d{2})?/)[0]
            }

            $('#fModal .percentOfRemaining')[0].innerHTML = +String(+$('#fModal .dailyByDays')[0].innerHTML * ( percent / 100 ) ).match(/\d+(\.\d{2})?/)[0]

            let total = String(+monthly +  +$('#fModal .percentOfRemaining')[0].innerHTML)
            if ( !total.includes('.') ) {
                total = String(+monthly +  +$('#fModal .percentOfRemaining')[0].innerHTML) + '.00'
            }
            if ( total.match(/\.\d{1}(?!\d)/) ) {
                total = String(+monthly +  +$('#fModal .percentOfRemaining')[0].innerHTML) + '0'
            }
            total = total.match(/[0-9]+[.,]\d{2}/)[0]
            $('#fModal .total')[0].innerHTML = total.replace(/(\d{1})(\d{3}.\d{1,2})/, '$1,$2')
        }

        format()
        function format() {
            // currentcy input
            if ( !$('#fModal .monthly')[0].value.includes('£') ) {
                $('#fModal .monthly')[0].value = '£' + $('#fModal .monthly')[0].value
            }
            if ( !$('#fModal .monthly')[0].value.includes('.') ) {
                $('#fModal .monthly')[0].value = $('#fModal .monthly')[0].value + '.00'
            }
            if ( $('#fModal .monthly')[0].value.match(/(£\d{1})(\d{3}.\d{1,2})/) ) {
                $('#fModal .monthly')[0].value = $('#fModal .monthly')[0].value.replace(/(£\d{1})(\d{3}.\d{1,2})/, '$1,$2')
            }
            if( $(`#fModal .monthly`)[0].value.match(/\.\d{1}(?!\d)/g)  ){
                $(`#fModal .monthly`)[0].value = $(`#fModal .monthly`)[0].value + 0
            }   
            // query currencies
            for (let i = 0; i < $('#fModal .curr').length; i++) {
                if ( !$(`#fModal .curr`)[i].innerHTML.includes('.') ) {
                    $(`#fModal .curr`)[i].innerHTML = $(`#fModal .curr`)[i].innerHTML + '.00'
                }
                if ( $(`#fModal .curr`)[i].innerHTML.match(/(\d{1})(\d{3}.\d{1,2})/) ) {
                    $(`#fModal .curr`)[i].innerHTML = $(`#fModal .curr`)[i].innerHTML.replace(/(\d{1})(\d{3}.\d{1,2})/, '$1,$2')
                }
                if( $(`#fModal .curr`)[i].innerHTML.match(/\.\d{1}(?!\d)/g)  ){
                    $(`#fModal .curr`)[i].innerHTML = $(`#fModal .curr`)[i].innerHTML + 0
                }   
            }
            // percent
            if ( !$('#fModal .percent')[0].value.includes('%') ) {
                $('#fModal .percent')[0].value = $('#fModal .percent')[0].value + '%'
            }
        }

        resize()
        function resize() {
            // currency
            if ( $('#fModal .monthly')[0].value.includes(',') ) {
                $('#fModal .monthly').css('width',  $('#fModal .monthly')[0].value.length - 0.25 + 'ch')
            } else {
                $('#fModal .monthly').css('width',  $('#fModal .monthly')[0].value.length + 'ch')
            }
            // percent
            if ( $('#fModal .percent')[0].value.includes('.') ) {
                $('#fModal .percent').css('width',  $('#fModal .percent')[0].value.length + 0.25 + 'ch')
            } else {
                $('#fModal .percent').css('width',  $('#fModal .percent')[0].value.length + 0.75 + 'ch')
            }
        }

        listeners()
        function listeners() {
            $('#fModal .monthly, #fModal .from, #fModal .to').on('input', function() {
                calc()
                resize()
            })
            $('#fModal .percent').on('input', function() {
                calc()
                resize()
            })
            $('#fModal .monthly, #fModal .percent, #fModal .from, #fModal .to').on('change', function() {
                calc()
                format()
                resize()
            })
            $('#fModal .monthly, #fModal .percent').on('focus click', function(e) {
                e.target.select()
            })
            let timer;
            $('#fModal .monthly, #fModal .percent').on('keyup', function(e) {
                clearInterval(timer)
                timer = setTimeout( () => {
                            e.target.blur()
                        }, 1218)
            })
        }
    }

}

function removeModal() {
    $('#fModal').fadeOut(314, function () {
        $('#fModal').remove()
    })
}

function tabTransactions(remove) {
    if (remove) {
        $('#genOverdueBtn').remove()
        $('#genOverdueContainer').remove()
        $('.genCopyIcon').remove()
        return;
    }

    overdueGenReport()
    function overdueGenReport() {
        appendOverdueBtn()
        function appendOverdueBtn() {
            if ( $('#genOverdueBtn').length ) return;
    
            const html = `<button id="genOverdueBtn" class="btn btnPad btnSpecial">Generate Overdue Report</button>`
            $('body').append(html)
            $('#genOverdueBtn').on('click', appendOverdueDisplay)
        }
    
        function appendOverdueDisplay() {
            $('#genOverdueBtn').off('click', appendOverdueDisplay)
            const html = `<textarea id="genOverdueText" class="input textarea textareaSpecial"></textarea>${icons.copy}`
            $('body').append(html)
            $('#genOverdueText').hide().fadeIn(618)
            $('.genCopyIcon').hide().fadeIn(618)
    
            $('#genOverdueText').on('focusout', removeOverdueReport)
            $('#genOverdueText').focus()
    
            $('.genCopyIcon').on('mousedown', copyOverdueReport)
    
            getOverdueData()
        }
    
        function getOverdueData() {
    
            let overdueArray = [];
    
            // OLD FUCKED UP AO-HELPER LOGIC START
            let getTransactionLength = $('.transactions tbody').children().length
            for (let i = 0; i < getTransactionLength; i++) {
                if ( $('.transactions tbody').children().eq(i).children().eq(1).text().includes('Overdue') ) {
    
                    let getOutstanding = $('.transactions tbody').children().eq(i).children().eq(9).text().trim()
                    let getDesc = $('.transactions tbody').children().eq(i).children().eq(3).text().split('Tenancy:')[0].trim()
                    let getDate = $('.transactions tbody').children().eq(i).children().eq(1).text().split('Due')[0]
    
                    if ( getDesc.includes('Default tenancy rent charge transaction type') ) {
                        getDesc = 'Outstanding Rent'
                        getDate = $('.transactions tbody').children().eq(i).children().eq(3).text().split('Tenancy:')[0].trim().match(/\d{1,2}.{2} \w{3,4} \d{4} - \d{1,2}.{2} \w{3,4} \d{4}/)
                    } else {
                        getDesc = $('.transactions tbody').children().eq(i).children().eq(3).text().split('Tenancy:')[0].trim()
                        }
                    overdueArray.push([getOutstanding, getDesc, getDate])
                }
            }
            overdueArray.forEach( (i) => appendToGenReportTextbox(`${i[0]} — ${i[1]} (${i[2]})`, false) )
            let formattedOverdueValues = []
            for (let i = 0; i < overdueArray.length; i++) {
                formattedOverdueValues[i] = +overdueArray[i][0].replace(',', '').slice(1)
            }
            let sum = '£' + String(formattedOverdueValues.reduce( (a, b) => a + b, 0))
            appendToGenReportTextbox('Total to be paid: ' + `${sum.replace(/£(\d{1,4}$)/, '£$1.00').replace(/£(\d{1})(\d{3})/, '£$1,$2')}`, true)
            // OLD FUCKED UP AO-HELPER LOGIC START
    
            resizeOverdueReport()
        }
    
        function appendToGenReportTextbox(data, end) {
            if (!end) {
                $('#genOverdueText').val( $('#genOverdueText').val() + data + '\n' );
            } else {
                $('#genOverdueText').val( $('#genOverdueText').val() + '\n' + data );
            }
        }
    
        function resizeOverdueReport() {
            $('#genOverdueText').width(  $('#genOverdueText').prop('scrollWidth') + "px" )
            $('#genOverdueText').height( $('#genOverdueText').prop('scrollHeight') - 10 + "px" )
            $('.genCopyIcon').css('left', $('#genOverdueText')[0].getBoundingClientRect().right - 52 + "px")
    
        }
    
        function copyOverdueReport() {
            copyToClipboard($('#genOverdueText').val())
            copyToast('report')
        }
        
        function removeOverdueReport() {
            $('#genOverdueText').fadeOut(314, function() {
                $('#genOverdueText').remove()
                $('#genOverdueBtn').on('click', appendOverdueDisplay)
            })
            $('.genCopyIcon').fadeOut(314, function() {
                $('.genCopyIcon').remove()
            })
        }
    }
}

function tabRecurrings(remove) {

    if (remove) {
        $('#genNextMonthBtn').remove()
        return;
    }

    // genNextMonth()
    function genNextMonth() {
        
        appendGenNextMonthBtn()
        function appendGenNextMonthBtn() {
            const html = `<button id="genNextMonthBtn" class="btn btnPad">Generate Next Month Invoice?</button>`
            
            new Promise( function(resolve) {
                waitForExistance('.recurrings .box-header .actions', resolve)
            }).then( () => {
                if ( $('#genNextMonthBtn').length ) return;
                $('.recurrings .box-header .actions').prepend(html)
                $('#genNextMonthBtn').on('click', automation)
            } )
        }

        async function automation() {
            disableAccess('<b style="font-size: 1.5em;">Please wait 📅</b><br>Generating next month\'s invoice...')
            
            $('.recurrings .datatable-subactions ul > li:nth-child(3) a').click()
        
            new Promise( function(resolve) {
                waitForIframeExistance('#dialog iframe', 'input#RecurringDaysInAdvance', resolve)
            }).then( () => {
                let input = $('#dialog iframe').contents().find('input#RecurringDaysInAdvance')
                input.val(31)
                $('#dialog iframe').contents().find('input.submit-btn')[0].click()
            })
        
            await wait(2500)

            new Promise ( function(resolve) {
                $('.recurrings .datatable-subactions ul > li:nth-child(3) a').click()
                waitForIframeExistance('#dialog iframe', 'input#RecurringDaysInAdvance', resolve)
            }).then( () => {
                let input = $('#dialog iframe').contents().find('input#RecurringDaysInAdvance')
                input.val(7)
                $('#dialog iframe').contents().find('input.submit-btn')[0].click()
                disableAccess('', true)
            })            
        }


    }
}

function tabAttachments(remove) {
    if (remove) {
        return;
    }
}

function appendReadableDateRange() {
    if ( $('.readableDateRange').length ) return;

    let getDates = $('.identifier-detail .sub-title')[0].innerHTML.match(/(\d{1,2} \w{3,4} \d{4}) - (\d{1,2} \w{3,4} \d{4})/)

    let from = dateFormat( getDates[1].split(' ') )
    let to = dateFormat( getDates[2].split(' ') )

    storage.tenancyStartDate = from
    storage.tenancyEndDate = to

    function dateFormat(date) {
        let month = new Date(1900 + date[1] + 1).getMonth() + 1
        return date[2] + '-' + String(month).padStart(2, '0') + '-' + String(date[0]).padStart(2, '0')
    }
    
    let readable = differenceBetweenDates(from, to)[1]
                    .replace(/&ensp;/g, '')
                    .replace(/<b>/g, '')
                    .replace(/<\/b>/g, '')
                    .replace(/\s\s+/g, ' ')
                    .replace(/ and 0 days/g, '')
                    .replace(/, 0 weeks/g, '')
                    .trim()    
    
    let readableWrapped = `<span style="color: #8ba2af" class="readableDateRange">&ensp;▶&ensp;${readable}</span>`
    
    $('.identifier-detail .sub-title')[0].innerHTML = $('.identifier-detail .sub-title')[0].innerHTML
                                                        .replace(/(\d{1,2} \w{3,4} \d{4} - \d{1,2} \w{3,4} \d{4})/, '$1' + readableWrapped)
}

function currentTime(){
    let time = new Date();
    return time.toLocaleString('en-GB', { hour: 'numeric', minute: 'numeric', hour12: true });
}

function currentDate() {
    let date = new Date

    let dateYear = date.getFullYear()
    let dateMonth = String(date.getMonth() + 1).padStart(2, '0')
    let dateDate = String(date.getDate()).padStart(2, '0')

    let today = `${dateYear}-${dateMonth}-${dateDate}`

    return today
}

function currentDateLegacy(){
    let date = new Date();
    let dateString = `${date.getDate().toString().padStart(2, '0')}/${(date.getMonth() + 1).toString().padStart(2, "0")}`;
    return dateString;
}

function differenceBetweenDates(from, to) {
    let a = moment(from, 'YYYY-MM-DD');
    let b = moment(to, 'YYYY-MM-DD');

    let diffDays = b.diff(a, 'days') + 1;

    let diff = moment.duration(b.diff(a))
    diff.add(1, 'days')

    let years = diff.years()
    let months = diff.months()
    let weeks = diff.weeks()
    let days = diff.days()%7

    let diffFull = `<b> ${years == 1 ? years + ' year,&ensp;' : years > 1 ? years + ' years,&ensp;' : ''}
                    ${months == 1 ? months + ' month,&ensp;' : months > 1 ? months + ' months,&ensp;' : ''}
                    ${isNaN(weeks) ? '0 weeks' : weeks == 1 ? weeks + ' week' : weeks + ' weeks'}</b> and <b>
                    ${isNaN(days) ? '0 days' : days == 1 ? days + ' day' : days + ' days'}</b>`

    return [diffDays, diffFull];
}

function querySeperator() {
    setTimeout( () => delay(), 128)
    function delay() {
        let commaDelimited = $('#_q').val().trim().split(' ').join(', ')
        $('#_q').val( commaDelimited )
    }
}

function copyOnClick(e) {

    tenant()
    function tenant() {
        if ( $(e.target).closest('.identifier-detail').length ) {

            if ( e.ctrlKey && e.altKey ) {
                landingDetailFull()
                return;
            }

            landingDetail()
        }
        if ( $(e.target).closest('.financial-transaction').length ) {
            landingBalance()
        }
        if ( $(e.target).closest('.summary-group-container').length ) {
            landingSummary()
        }
        if ( $(e.target).closest('.notes tbody').length ) {
            landingNotes()
        }
        if ( $(e.target).closest('.transactions tbody').length ) {
            statement()
        }
        if ( $(e.target).closest('.attachments tbody').length ) {
            documents()
        }
    }

    tenantSearch()
    function tenantSearch() {
        if ( $(e.target).closest('.datatable-index-filters .tenancies tbody').length ) {
            tenantSearchTable()
        }
    }

    // further test
    function landingDetail() {

        if ( $(e.target).attr('class') == 'title' ) {
            copyToClipboard($(e.target).text().match(/TE\d{4,5}/)[0])
            copyToast('tenancy reference')
        }
        if ( $(e.target).attr('class') == 'name' ){
            let clone = $(e.target).clone()
            clone.find('.label').remove()
            copyToClipboard(clone.text().replace(/\+.+/, '').trim())
            copyToast('full name')
        }
        if ( $(e.target).closest('.sub-title').length ) {
            copyToClipboard($('.sub-title a')[0].innerHTML.split(',')[0].replace(' Room', ', Room'))
            copyToast('property + room')
        }
    }
    function landingDetailFull() {

        let clone = $('.identifier-detail .name').clone()
        clone.find('.label').remove()
        let getName = clone.text().replace(/\+.+/, '').trim()
        let getDate = $('.identifier-detail').children().eq(2).contents()[2].wholeText
        let getMonthly = $('.content-main .summary-data-container').children().eq(1).children().eq(1).text().trim()

        copyToClipboard(getName + "\n" + getDate + "\n" + getMonthly + "\n\n")
        copyToast('full information')
    }
    function landingBalance() {
        if ( $(e.target).attr('class').includes('number') ) {
            copyToClipboard($(e.target).text())
            copyToast('balance')
        }
    }
    function landingSummary() {
        if ( $(e.target).closest('.name').length ) {
            copyToClipboard($(e.target).text())
            copyToast('full name')
        }
        if ( $(e.target).closest('.detail > div:nth-child(2) div').length ) {
            copyToClipboard($(e.target).text())
            copyToast('phone')
        }
        if ( $(e.target).closest('.summary-group-container .detail > div:nth-child(3) div').length ) {
            copyToClipboard($(e.target).text())
            copyToast('email')
        }
    }
    function landingNotes() {
        if ( $(e.target).closest('.note').length ) {
            copyToClipboard($(e.target).text())
            copyToast('note')
        }
    }
    function statement() {
        if ( $(e.target).closest('.ref').length ) {
            copyToClipboard($(e.target).text())
            copyToast('ref')
        }
        if ( $(e.target).closest('.date').length ) {
            copyToClipboard($(e.target).text().split('Due')[0]  )
            copyToast('date')
        }
        if ( $(e.target).closest('.description').length ) {
            copyToClipboard($(e.target).closest('.description').text().replace(/ {3}.+/, '').trim() )
            copyToast('description')
        }
        if ( $(e.target).closest('.charge-made').length ) {
            copyToClipboard($(e.target).text().trim())
            copyToast('charge made')
        }
        if ( $(e.target).closest('.payments-received').length ) {
            copyToClipboard($(e.target).text().trim())
            copyToast('received')
        }
        if ( $(e.target).closest('.outstanding').length ) {
            copyToClipboard($(e.target).text().trim())
            copyToast('outstanding')
        }
    }
    function documents() {
        if ( $(e.target).closest('.name').length ) {
            let header = $(e.target).closest('.name').find('a').text()
            let body = $(e.target).closest('.name').find('.unimportant')[0].innerHTML.replace(/<br>/g, '\n')
            let compile = body ? header + '\n' + body : header;

            let headerLowerCase = header.toLowerCase()

            if ( headerLowerCase.includes('top') || headerLowerCase.includes('receipt') || headerLowerCase.includes('key') ) {

                let bodyArr = []

                for ( let i = 0; i < $(targets.documents.checkboxes).length - 1; i++ ) {

                    // if anything is checked , return
                    if ( $(targets.documents.checkboxes)[i].checked  ) {

                        // as something is checked, we want to loop over checked and push its data
                        for ( let i = 0; i < $(targets.documents.checkboxes).length; i++ ) {
                            if ( $(targets.documents.checkboxes)[i].checked  ) {
                                bodyArr.push( $($(targets.documents.checkboxes)[i].closest('tr')).find('.unimportant')[0].innerHTML.replace(/<br>/g, '\n') )
                            }
                        }

                        compile = header + '\n' + bodyArr.join('\n')

                        copyToClipboard( noteFormat_topup(compile) )
                        copyToast('multiple utility notes')
                        return;
                    }
                }
                copyToClipboard( noteFormat_topup(compile) )
                copyToast('utility note')
            } else {
                copyToClipboard(compile)
                copyToast('note')
            }   
        }
    }
    function tenantSearchTable() {
        if ( $(e.target).closest('.name').length ) {
            copyToClipboard($(e.target).text())
            copyToast(`ref`)
        }
        if ( $(e.target).closest('.tenant').length ) {
            copyToClipboard($(e.target).closest('.tenant').text().replace(/ {2}.+/, '').split('+')[0].trim())
            copyToast('name')
        }
        if ( $(e.target).closest('.unit-address').length ) {
            copyToClipboard($(e.target).text())
            copyToast('unit-address')
        }
    }


}

function noteFormat_topup( content ) {

    console.log(content)

    let split = content.split('\n')
    let header = split[0] + ' ― '
    let body = split.slice(1).join('; ')

    console.log( (header + body + ';').replace(/ ;/g, '') )

    return (header + body + ';').replace(/ ;/g, '') 
}

function copyToClipboard(text) {
    let temp = $("<textarea>");
    $('body').append(temp);
    temp.val(text).select();
    document.execCommand("copy");
    temp.remove();
}

function copyToast(text) {

    if ( $('.copyToast').length > 4 ) return;

    let x = event.pageX
    let y = event.pageY

	$(window).on('mouseup', calcMousePos)

	function calcMousePos(newMousePos) {

		if (Math.abs(x - newMousePos.pageX) > 1 || Math.abs(y - newMousePos.pageY) > 1) return;

        let elem = document.createElement('div')
        elem.innerHTML = icons.clipboard + ' ' + text
        elem.className = "copyToast"
        elem.style.backgroundColor = $('#main_nav').css('background-color')
        elem.style.left = event.pageX + "px"
        elem.style.top = event.pageY - 25 + "px"
        
        $('body').append(elem);
    
        $(elem).delay(618).animate({
            'opacity': 0,
            'top': event.pageY - 55 + "px",
        }, 618, function() {
            $(elem).remove()
        })

		$(window).off('mouseup', calcMousePos)
	}
}

function disableAccess(desc, remove) {

    if ( remove ) {
        removeDisableAccess()
        return;
    }
    if ( $('#disableAccess').length ) return;

    $('body').append(`  <div id="disableAccess">
                            <div id="disableDesc">${desc}</div>
                        </div>`)

    $('#disableAccess').hide().fadeIn(618)

    setTimeout( () => {
        if ( $('#disableAccess').length ) {
            $('#disableDesc').append('<br><div class="btn" style="transform: scale(1.75,1.75); margin-top: 48px" id="disableExit">This is taking too long! Get me out of here. 😠</div>')
            $('#disableExit').hide().fadeIn(1024)
            $('#disableExit').on('click', function() {
                removeDisableAccess()
            })
        }
    }, 5500)

    $('#disableClickCover').on('mousedown keydown', disableAccess)
    function disableAccess(e){
        e.preventDefault()
        return;
    }

    function removeDisableAccess() {
        $('#disableAccess').off('mousedown keydown scroll', disableAccess)
        $('#disableAccess').fadeOut(314, function() {
            $('#disableAccess').remove()
        })
    }

}

function quickAccess() {

    let html = `<div class="qaOption report" id="qaReport">
                    <div style="position: fixed; left: 27px">${icons.letter}</div>
                    Overdue Report</div>`

    $('#main_nav').append(html)

    $('.qaOption').on('click', qaActions)

    function qaActions(e) {
        if (e.target.id == 'qaReport'){
            qaGenOverdueReport()
        }
    }

    function qaGenOverdueReport() {
        disableAccess('<b style="font-size: 1.5em;">Please wait 📋</b><br>Generating overdue report...')

        let iframe = document.createElement('iframe')
        iframe.id = 'targetIframe'
        iframe.src = 'https://system.arthuronline.co.uk/flintonsprop/reports/edit/11441/'

        $('body').append(iframe)

        let interval;
        if ( !$(iframe).contents().find("body").length ) {
            interval = setInterval( () => findBody(), 25)
        }
        function findBody() {
            if ( $(iframe).contents().find("body").length ) {
                clearInterval(interval)
                iframeContents()
            }
        }

        setTimeout( () => iframeContents(), 3000)

        function iframeContents() {
            let contents = $(iframe).contents()
            contents.find('.daterangepicker .ranges ul li:nth-child(3)').click()
            contents.find('#runOutput')[0].selectedIndex = 4;
            contents.find('.save-and-run .btn').click()
            setTimeout( () => iframe.remove(), 5000 )
            disableAccess('', true)
        }
    }
}

function quickNotes() {
    let html = `<div id="quickNotes">
                    <div id="qnPhone" class="btnCirc">${icons.phone}</div>
                    <div id="qnVoicemail" class="btnCirc">${icons.vm}</div>
                    <div id="qnEmail" class="btnCirc">${icons.email}</div>
                    <div id="qnReceipt" class="btnCirc">${icons.receipt}</div>
                </div>`

    $('#content-wrapper').append(html)

    $('#quickNotes').on('mousedown', quickNoteActions)
    function quickNoteActions(e) {


        if ( e.target.closest('div').id == 'qnPhone') {
            copyToClipboard(`PHONED tenant at ${currentTime()} on ${currentDateLegacy()} regarding `)
        }
        if ( e.target.closest('div').id == 'qnVoicemail') {
            copyToClipboard(`Left VOICEMAIL at ${currentTime()} on ${currentDateLegacy()} regarding `)
        }
        if ( e.target.closest('div').id == 'qnEmail') {
            copyToClipboard(`EMAILED tenant at ${currentTime()} on ${currentDateLegacy()} regarding `)
        }
        if ( e.target.closest('div').id == 'qnReceipt') {
            let tenantPayDay = String(storage.tenancyStartDate.match(/\d{4}-\d{1,2}-(\d{1,2})/)[1]).padStart(2, '0')
            copyToClipboard(`Top-up receipts approved to be deducted from rent due ${tenantPayDay}/`)
        }
    }
}

function addTransactionBtn(e) {
    if ( e.target.closest( targets.addTransaction.btn ) ) {
        topupProcessing()
    }

    function topupProcessing() {
        let desc;
        let date;
        let amount;

        new Promise( function(resolve) {
            waitForIframeExistance('#dialog iframe', targets.addTransaction.amount , resolve)
        }).then( () => {
            //$('#dialog iframe').contents().find( targets.addTransaction.desc ).on('change', descChange)
            $('#dialog iframe').contents().find( targets.addTransaction.desc ).on('paste', function() {
                setTimeout( () => descChange(), 32)
            })

            desc = $('#dialog iframe').contents().find( targets.addTransaction.desc )
            date = $('#dialog iframe').contents().find( targets.addTransaction.date )
            amount = $('#dialog iframe').contents().find( targets.addTransaction.amount )
        } )

        function descChange() {
            let current = currentDate().split('-')
            let dayAndMonth = desc.val().match(/(?<=deduct).*?(\d{1,2})[/.-](\d{1,2})/)
            let day = dayAndMonth[1]
            let month = dayAndMonth[2]
            let year = current[0]
            if ( +current[1] == 12 && +month == 1 ) {
                year++
            }
            date.val(`${year}-${month}-${day}`)

            parseDesc()
        }
        function parseDesc() {

            let topUps = desc.val().split(' ― ')[1].split(';')
                topUps.splice(topUps.length - 1, 1)
            let arr = []

            for(let i = 0; i < topUps.length; i++) {
                console.log(topUps[i])

                if (topUps[i].includes('dup')) {
                    continue;
                } else if (topUps[i].includes('app') && topUps[i].includes('rej')) {

                    let match
                    try {
                        match = topUps[i].match(/(?<=app\w+) £?((\d+)(\.?(\d+))?)/)[1]
                    } catch(err) {
                        match = topUps[i].match(/((\d+)(\.?(\d+))?)(?= app)/)[1]
                    }
                    arr.push( +match )

                } else if (topUps[i].includes('rej')) {
                    continue;
                } else {
                    arr.push( +topUps[i].match(/£((\d*)\.?(\d*))/)[1] )
                }
            }

            // populate value field
            if ( arr.length == 1) {
                amount.val( -arr[0] )
            } else {
                amount.val( -arr.reduce( (prev, curr) => prev + curr ) )
            }            
        }
    }
}

function loadIcons() {
    icons.percent = `<img style="filter: invert(100%); height: 20px; width: 20px" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAABmJLR0QA/wD/AP+gvaeTAAAA9klEQVRIie2UOw6CQBRFj53f1sRVuAoLURtWopWfljXgWlyCn87EPRjssLFCi7lGVJCBUFB4EkLezHDfm5l3gT9VZQTsgaveTsq6BuAWEb8nPElJfM15eRIc9NEcaAELxbuPdRMgAm5AP0+CUIJtxR3FYWxNDwg0PssjDubM78BSSVa876AGbDS2UZyLAWbrn3cw1PxM8UU7KYSjiq/ANibex5x5hLmDUqkDR0z1ftniAGuJn4Bm2eJJLWlrxky6wBlT/VRjY+zN+JO0lrQ1YybPlgx4b0kbM2byqyWzzGiFR3pLOnyff8TLL9a4mF9yEmlm/FMxHpirXwLh4+GPAAAAAElFTkSuQmCC">`,
    icons.clipboard = `<img style=" width: 14px; height: 14px; margin-top: -2px" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAACXBIWXMAAAsSAAALEgHS3X78AAAAgUlEQVRIie2VQQqAIBBFn9ExovtE9+ji0z2mTYJKaE1Zi/wgunDmyf8wOlWlprqq3RPADKyAGtehXGCRAMONx7oSQHMXrXo1g1TWTASYfJOcRXcyEWAsAayZRHWfZtAADfAXQB+cH52iXp9atO675WeTM4AlgFyR7LVAPE2rqHoGG9+QR9qv/pARAAAAAElFTkSuQmCC">`,
    icons.copy = `<img class="genCopyIcon" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAAABHNCSVQICAgIfAhkiAAAAWBJREFUaIHtmKFOA0EQhv/ZrihJBRKBRFTUInB9BUjqEVUXDCEhQaArCgpNcr6iBolENEFgKnmAPsCFJg13g2pCZo+EvfRuuDCf29nkbr7M7k1uAMP431BZcJQkvXzdnRQFhkQ0aDKheXpfmtNPeBkYJUlv87H36oA+RT1KBycD+bo7cUBfI5kqBAJFgaFGIlUJjpA887FnsmmCCrQNE9AmuAO/ock+wcxLcrTw7G5n6XQl96MrsO0TzHTRRJMjogEY4w3yt7Px9aHcjxbQ6hMOdIDP/CGMR6LZJxjhu6PvQNN94vT8ir8t9+V+679CJqCNCWhjAtqYgDYmoI0JaGMC2piANiagTfBP/NdnoZLWV8AEtImfCzHemXC0XYu5Ta0wI5Ox+AoQXnaSTTUWMhAt0IG7KcDBlLhumJGRp0sZjxaYpdNVx/tjMJ7KSrprmJEx45k8ncwf75Z1v88w2sYX2olePMs5UyEAAAAASUVORK5CYII=">`,
    icons.letter = `<img style="width: 17px; height: 17px;margin-top: -1px" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAQAAAD8x0bcAAAAcElEQVR4AZ3KoRGAMBBE0YNuSBO0gsEhY2FSC5XQAS5DJ6hkITHczawA/rdPPoQOQT1wdODpBOAZ0m3whnEkgskwiu4wIltm0Y6+vgIW8f6gXG/UuczQouaIbVGqt+pUZmhWc8S2KIIVLXIIZCfvuwD++D9vDI3s3wAAAABJRU5ErkJggg==">`,
    icons.phone = `<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAkCAQAAABLCVATAAABA0lEQVR4Ae3UMSgFUBTH4SNPYWGhTDLJbBPCoIyCwV7CYLAYhDJaTRY2MSiSwURZpNjLCqO32PQx6d0yvHfv+r6z/+os/2hqhBW7f7elM/KYkzqIPDalHiKPVamXyGNJqhp5jCA1GDn0SLEceXxIHUYex1LrkceiWjfaIo8OXwCutEU+Z4ArlShhEjAQpTyC6yhlHDAbpRyBd31RRrd38Kwjyhj1DS6ilDXAmfaoocWOfRMqUS/bgCe9NZkTQNWdW7dO63jfHuDVQvzS6kQK1hob33vDzv1nN+phxqdEA6GUfpcFoZQZTwWhlDHHPrNDKRXTDrypNR/5dBkyZcmG1WhqwA+OqfZX7C8frQAAAABJRU5ErkJggg==">`,
    icons.vm = `<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAkCAQAAABLCVATAAABh0lEQVR4Ae3TM6CWURgA4DfbXLKnzKk127Ybs+227DlrryXXFsZsm0/+6r/hYonPuxz7xG/pv/8UMsR+Fz1x3HL14/tCQ8sd99hF+wxRIFLp75ZU25WKNJSyXaob+sYXFvieq6rGV1Rz1fcsiI8MAFzQS/YI5a31BpyTLF1B58Aba5WPkF0vFwADIkJZD8EauSOhsZtgcVKyFNzUOBLyWA0eKhtmg6OyRQotwXP54h35PAetIoVsDoPZ4SToEd9wFrSJd7QFZ7/Tqjs4Fe6Ast9pshKMjneMBau+06oMuBOeg/zfabIQjI93TASLvtMqH3gRLoK632myM7mRMAjs+k6rOuBi2Pb9uRT1FFSLd9QATxWNNCwC20JH8EitSGELOJjkj4LNkUJNj0CniHAA3DNM9vhAFXsBzZIuzQF7VYwP5DDSPZLplHYZcNYsM2zwAnDRDEm4BHhhgxlmOQu4kvxKFZ2RVWdUTL3E8S7JrEvGyxtpyaaRQaabkYGYZpCGssV///3l3gLdS5QBUjZf7QAAAABJRU5ErkJggg==">`,
    icons.email = `<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAkCAQAAABLCVATAAAA00lEQVR4Ae3QAQbCUBzH8X8FpBOkMwQdIoi6SZ0ghlSgblIIO0RhZ8hjAyEB1Tf+FP/ZHnvAsg/Y4/lu+0mdNYhIqSolomUzK0JtbcgR6mZDLwAmFYKOCaogJEKPnT77PdnTFSkPKYYk+CQMRZWGONHXU4c5D4rcWdDWO31O5SF7MSYvLnqRDb0LP32K4+vKzP66P2TG/I2fP+MPWY6xKEaMRDHGoSqE1FE3UQw4oPyhMjq+HTcopC6cUeEhqwn9bSglVGpDa0JtxGJJRlUZkTRq7ANaQCOJt++IMQAAAABJRU5ErkJggg==">`,
    icons.receipt = `<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAkCAQAAABLCVATAAAAgklEQVR4Ae2RAQaAQBBF9x6hPVrRETrAANCpooMUAUQ3eLEGaJkJonb/4I+HBz8UEHqa1IKkjswO0t1FwkaDADASWcFBJCeCEw2HtkWyoscpWCT2uUTBkXdFiH11tbpaXa2u9hXRiUY/m2RFK5FJd2vZwSY5UUdMPSGpWxYHGcL/cwGEQwsHbI/lEwAAAABJRU5ErkJggg==">`
}

function appendCSS() {

    const colors = {
        red: '#d64a65',
        blue: '#1facf0',
        green: '#8BC34A',
    }

    const copyToast = `.copyToast{
                            position: absolute;
                            color: white;
                            font-family: 'Open Sans', sans-serif;
                            text-transform: uppercase;
                            font-size: 0.75rem;
                            font-weight: 600;
                            padding: 4px 9px;
                            border-radius: 12px;
                            transform: translate(-50%, -50%);
                            z-index: 9999;
                            pointer-events: none;
                        }`

    const tenantHeaderTweaks = `.left-side-detail > :nth-child(3){
                                    margin-right: -40px;
                                }
                                .left-side-detail{
                                    width: calc(50% + 200px) !important;
                                }`

    const tenantToolbox = ` #tenantToolbox {
                                width: 240px;
                            }
                            #tenantToolbox .option{
                                display: flex;
                                cursor: pointer;
                                user-select: none;
                                margin-bottom: 7px;
                                transition: 314ms;
                            }
                            #tenantToolbox .option:hover{
                                filter: brightness(125%);
                            }
                            #tenantToolbox .option:active{
                                filter: brightness(70%) contrast(250%);
                                transition: 32ms;
                            }
                            #tenantToolbox .icon{
                                display: flex;
                                align-items: center;
                                justify-content: center;
                                width: 22px;
                                height: 22px;
                                border-radius: 4px;
                                margin-right: 10px;
                                background: dimgray;
                            }
                            #tenantToolbox span{
                                padding-top: 1px;
                                font-weight: 600;
                                font-size: 15px;
                                color: dimgray;
                            }

                            #tenantToolbox .icon.red{
                                background: #DA3C5A;
                            }
                            #tenantToolbox span.red{
                                color: #DA3C5A;
                            }`

    const tenantSummaryTweaks = `* {
                                    outline: 0px dashed rgba(0, 0, 256, 0.1);
                                }
                                
                                .retailspace-horizontal .header {
                                    display: none;
                                }
                                .summary-wrapper hr:nth-child(2) {
                                    display: none;
                                }
                                .summary-group-container .detail.detail div:first-child,
                                .summary-group-container .detail.detail div:nth-child(4),
                                .summary-group-container .detail.detail div:nth-child(5) {
                                    display: none;
                                }
                                .summary-group-container .detail div:nth-child(2) div {
                                    font-size: 2.3rem !important;
                                    letter-spacing: 0.1618rem;
                                    padding: 18px 0 16px 0;
                                    margin-left: -2px;
                                }
                                .summary-group-container .detail div:nth-child(3) div {
                                    font-size: 1.2rem !important;
                                    padding: 12px 0 0 0;
                                }
                                .summary-group-container .status-container div {
                                    display: none;
                                }`

    const tenantReadabilityTweaks = `.numeric {
                                        font-size: 1.218em;
                                        font-weight: 600;
                                    }`

    const statementReport = `.btnSpecial {
                                position: fixed;
                                z-index: 1001;
                                left: 240px;
                                bottom: 18px;
                                outline: 0;
                            }
                            .btnPad{
                                padding: 11px;
                            }
                            .textareaSpecial {
                                position: fixed;
                                font-family: 'Open Sans', sans-serif;
                                box-sizing: border-box;
                                font-size: 16px;
                                line-height: 2em;
                                bottom: 62px;
                                z-index: 1000;
                                left: 240px;
                                resize: none;
                                padding: 6px 10px;
                                color: #516073;
                                background: #f5f7fa;
                                white-space: nowrap;
                            }
                            .textareaSpecial:focus {
                                outline: 0;
                                box-shadow: -40px 70px 175px rgba(0,0,0,0.15), 0 8px 12px rgba(0,0,0,0.14) !important;
                                border: 1px solid #8ba2af;
                            }
                            .textareaSpecial::selection{
                                background: #8ba2af;
                                color: white;
                            }
                            .genCopyIcon {
                                position: fixed;
                                bottom: 78px;
                                z-index: 1001;
                                filter: brightness(170%);
                            }
                            .genCopyIcon:hover {
                                filter: hue-rotate(350deg) brightness(140%) contrast(300%);
                            }
                            .genCopyIcon:active {
                                filter: none;
                            }`

    const modal = ` #fModal{
                        font-family: 'Open Sans', sans-serif;
                        transform: translate(-50%, 0%);
                        position: fixed;
                        top: 15%;
                        left: 50%;
                        z-index: 2001;
                        width: 460px;
                    }
                    #fModal .header{
                        display: flex;
                        align-items: center;
                        background: dimgray;
                        height: 68px;
                        font-size: 20px;
                        font-weight: 400;
                        color: white;
                        padding-left: 24px;
                        border-radius: 6px 6px 0 0;
                        cursor: grab;
                        user-select: none;
                        box-shadow: 0 8px 24px rgba(0,0,0,0.05), 0 8px 4px rgba(0,0,0,0.1618);
                    }
                    #fModal .header:active{
                        cursor: grabbing;
                    }
                    #fModal .body{
                        border-bottom: 1px solid #ECECEC;
                        padding: 14px 24px;
                        font-size: 16px;
                        background: #fff;
                        line-height: 2.75rem;
                        letter-spacing: 0.314px;
                        box-shadow: 0 8px 24px rgba(0,0,0,0.05), 0 8px 4px rgba(0,0,0,0.1618);
                    }
                    #fModal .body hr{
                        margin: 16px -24px 10px -24px;
                        border: 0.5px solid #ececec;
                    }
                    #fModal .footer{
                        display: flex;
                        justify-content: space-between;
                        padding: 12px 24px;
                        height: 52px;
                        background: #fff;
                        border-radius: 0 0 6px 6px;
                        box-shadow: 0 8px 24px rgba(0,0,0,0.05), 0 4px 4px rgba(0,0,0,0.1618);
                    }
                    #fModal .left{
                        align-self: center;
                        font-size: 16px;
                        margin-top: -4px;
                    }
                    #fModal .right{
                        align-self: center;
                    }
                    #fModal .btn{
                        background: dimgray;
                        user-select: none;
                        border-radius: 3px;
                        padding: 11px 15px;
                        margin-left: 12px;
                    }
                    #fModal .btn:hover{
                        filter: brightness(115%);
                    }
                    #fModal .btn:active{
                        filter: brightness(80%) contrast(150%);
                        transition: 64ms;
                    }
                    #fModal b{
                        cursor: default;
                        letter-spacing: 0.618px;
                        border-bottom: 1px dashed gainsboro;
                        padding: 0 4px 4px 4px;
                    }
                    #fModal b.start{
                        padding: 0 4px 4px 0;
                    }`

    const modalInputs = `#fModal input::-webkit-inner-spin-button,
                        #fModal input::-webkit-outer-spin-button{
                            -webkit-appearance: none; 
                            margin: 0; 
                        }
                        #fModal input::-webkit-calendar-picker-indicator{
                            opacity: 0.75;
                            padding: 6px 0 6px 6px;
                            margin-left: -12px;
                        }
                        #fModal input::-webkit-clear-button{
                            display: none;
                        }
                        #fModal input[type="date"]::-webkit-calendar-picker-indicator {
                            width: 10px;
                            height: 10px;
                        }
                        #fModal input{
                            position: relative;
                            top: 6px;
                            font-size: inherit;
                            font-family: inherit;
                            font-weight: 700;
                            border: 0;
                            outline: 0;
                            border-radius: 0;
                            box-shadow: none;
                            border-bottom: 1px solid gray;
                            transition: 0.6s cubic-bezier(0.075, 0.82, 0.165, 1);
                            letter-spacing: 0.618px;
                            padding: 0 2px 4px 2px;
                            cursor: pointer;
                        }
                        #fModal input:hover{
                            top: 8px;
                            padding-bottom: 8px;
                        }
                        #fModal input:focus{
                            top: 8px;
                            color: dimgray;
                            border-bottom: 2px solid dimgray;
                            padding: 0 8px 7px 8px;
                        }
                        #fModal .percent{
                            margin-top: -1px;
                            padding-top: -1px;

                        }`

    const modalColorVariation = `   #fModal .header.red{
                                        background: ${colors.red};
                                    }
                                    #fModal .header.blue{
                                        background: ${colors.blue};
                                    }
                                    #fModal .header.green{
                                        background: ${colors.green};
                                    }
                                    #fModal .btn.red{
                                        background: ${colors.red};
                                    }
                                    #fModal .btn.blue{
                                        background: ${colors.blue};
                                    }
                                    #fModal .btn.green{
                                        background: ${colors.green};
                                    }
                                    #fModal.red *::selection{
                                        background: ${colors.red} !important;
                                        color: white;
                                    }
                                    #fModal.blue *::selection{
                                        background: ${colors.blue} !important;
                                        color: white;
                                    }
                                    #fModal.green *::selection{
                                        background: ${colors.green} !important;
                                        color: white;
                                    }
                                    #fModal input.red:focus{
                                        color: ${colors.red};
                                        border-bottom: 2px solid #d64a65;
                                    }
                                    #fModal input.blue:focus{
                                        color: ${colors.blue};
                                        border-bottom: 2px solid #d64a65;
                                    }
                                    #fModal input.green:focus{
                                        color: ${colors.green};
                                        border-bottom: 2px solid #d64a65;
                                    }
                                    #fModal .totalStyle{
                                        padding-bottom: 6px;
                                        border-bottom: 1px solid #d64a65;
                                    }`     
                                    
    const disableAccess = `#disableAccess {
                                display: flex;
                                position: fixed;
                                top: 0;
                                left: 0;
                                align-items: center;
                                justify-content: center;
                                color: lightgray;
                                background: rgba(0,6,12,0.65);
                                height: 100vh;
                                width: 100vw;
                                z-index: 9999;
                                cursor: wait;
                                user-select: none;
                                backdrop-filter: blur(4px);
                            }
                            #disableDesc {
                                transition: 314ms;
                                font-family: 'Open Sans', sans-serif;
                                font-size: 3.5em;
                                line-height: 1.5em;
                                text-align: center; 
                                margin-top: -128px;
                            }`

    const quickAccess = `.qaOption.report{
                            box-sizing: border-box;
                            position: absolute;
                            font-size: inherit;
                            transition: color 314ms;
                            background: #0693d7;
                            padding-left: 68px;
                            padding-bottom: 18px;
                            padding-top: 12px;
                            bottom: 0;
                            width: 220px;
                            cursor: pointer;
                        }
                        .qaOption:hover{
                            color: white;
                                padding-left: 63px;
                            border-left: 5px solid #ffffff;
                        }
                        .qaOption.report:active{
                            font-weight: bold;
                        }
                        nav div ul li a[title="Settings"]{
                            padding-bottom: 34px;
                        }
                        #targetIframe{
                            position: fixed;
                            left: 0;
                            top: 0;
                            height: 200px;
                            width: 200px;
                        }`

    const quickNotes = `#quickNotes {
                            pointer-events: none;
                            z-index: 9999;
                            display: flex;
                            position: fixed;
                            bottom: 0px;
                            right: 76px;
                            padding: 1.2rem;
                        }
                        .btnCirc {
                            pointer-events: visible;
                            background: #2392EC;
                            color: white;
                            border-radius: 100%;
                            margin-left: 0.75rem;
                            transition: 128ms;
                            height: 45px;
                            width: 45px;
                            box-shadow: 0px 0px 18px 0px rgba(0, 0, 0, 0.15);
                            cursor: pointer;
                        }
                        .btnCirc:hover {
                            filter: brightness(120%);
                            transform: scale(1.055, 1.055);
                        }
                        .btnCirc:active {
                            transition: 64ms;
                            filter: brightness(85%) saturate(75%) contrast(150%);
                            transform: scale(0.75, 0.75);
                        }
                        .btnCirc img{
                            pointer-events: visible;
                            padding: 8px;
                            -webkit-user-drag: none;
                            transition: 314ms;
                            width: 28px;
                            height: 28px;
                        }
                        .btnCirc img:hover{
                            transform: scale(1.1, 1.1);
                        }`

    const style = ` <style>
                        ${copyToast}
                        ${tenantHeaderTweaks}
                        ${tenantToolbox}
                        ${tenantSummaryTweaks}
                        ${tenantReadabilityTweaks}
                        ${statementReport}
                        ${modal}
                        ${modalInputs}
                        ${modalColorVariation}
                        ${disableAccess}
                        /* ${quickAccess} */
                        ${quickNotes}
                    </style>`

    $('head').append(style)
}