<commit_before>import React from 'react';
import Container from 'components/Container';
import Overview from 'components/Accounts/Overview';
import Transactions from 'components/Accounts/Transactions';
import TransactionOverview from 'components/Accounts/Transactions/Transaction/Overview';
import { intToAmount, once } from 'lib/utils';
import localForage from 'localforage';

export default class Accounts extends React.Component {

  constructor() {
    super();

    // Lazy init sidebar & date
    this.initSideMenu = once(this.initSideMenu);

    // TODO Add Redux
    this.state = {
      ui: {
        selectedTransaction: 0
      },
      transactionOverview: {
        empty: true,
        loading: false,
        data: {}
      },
      account: {
        id: undefined,
        name: '',
        transactions: [],
        filterActive: false,
        filteredTransactions: [],
        balance: '',
        currency: '',
        spentToday: ''
      }
    };
  }

  componentWillMount() {

    // Retrieve inital data
    this.retrieveAccount().then(() => {
      this.retrieveBalance();
      this.retrieveTransactions();
    });
  }

  componentDidMount() {
    this.initSideMenu();
  }

  initSideMenu() {
    $('.button-collapse').sideNav({
      edge: 'right',
      closeOnClick: true
    });
  }

  // Updates the state with the latest balance
  retrieveBalance() {
    $.ajax({
      url: `https://api.getmondo.co.uk/balance?account_id=${this.state.account.id}`,
      headers: {
        'Authorization': `Bearer ${localStorage.mondo_access_token}`
      }
    })
    .done(account => {
      const { currency, balance, spend_today: spentToday} = account;
      this.setState({
        account: Object.assign({}, this.state.account, {
          balance, spentToday, currency
        })
      });
    })
    .fail(err => swal('Error', err.responseJSON ? `${err.responseJSON.message} try logging out and in again` : false
      || 'Internal error, check your network connection, contact me in the menu if this keeps happening', 'error'));
  }

  // Updates the state with the account name (only first account supported atm)
  retrieveAccount() {
    return new Promise(resolve => {
      $.ajax({
        url: 'https://api.getmondo.co.uk/accounts',
        headers: {
          'Authorization': `Bearer ${localStorage.mondo_access_token}`
        }
      })
      .done(response => {
        this.setState({
          account: Object.assign({}, this.state.account, {
            name: response.accounts[0].description,
            id: response.accounts[0].id
          })
        });
        resolve();
      })
      .fail(err => swal('Error', err.responseJSON ? `${err.responseJSON.message} try logging out and in again` : false
        || 'Internal error, check your network connection, contact me in the menu if this keeps happening', 'error'));
    });
  }

  // Params is a query string starting with '&'
  retrieveTransactions(params = '') {
    $.ajax({
      url: `https://api.getmondo.co.uk/transactions?expand[]=merchant&account_id=${this.state.account.id}${params}`,
      headers: {
        'Authorization': `Bearer ${localStorage.mondo_access_token}`
      }
    })
    .done(account => {
      this.setState({
        account: Object.assign({}, this.state.account, {
          transactions: account.transactions
        })
      });
    })
    .fail(err => swal('Error', err.responseJSON ? `${err.responseJSON.message} try logging out and in again` : false
      || 'Internal error, check your network connection, contact me in the menu if this keeps happening', 'error'));
  }

  transactionSelect(event) {
    event.preventDefault();
    let target = event.target;
    while (target.parentElement) {
      target = target.parentElement;
      if (target.dataset.tid) {
        break;
      }
    }

    // Happens when user clicks an odd bit of the collection item
    if (!target.dataset.tid) {
      return false;
    }

    let transactionId = atob(target.dataset.tid);

    this.setState({
      transactionOverview: {
        empty: false,
        loading: true,
        data: {}
      }
    });

    $.ajax({
      url: `https://api.getmondo.co.uk/transactions/${transactionId}?expand[]=merchant`,
      headers: {
        'Authorization': `Bearer ${localStorage.mondo_access_token}`
      }
    })
    .done(result => {
      const transaction = result.transaction;
      this.setState({
        ui: {
          selectedTransaction: btoa(transaction.id)
        },
        transactionOverview: {
          empty: false,
          loading: false,
          data: {
            lat: transaction.merchant ? transaction.merchant.address.latitude : '50.1477307',
            long: transaction.merchant ? transaction.merchant.address.longitude : '0.7332003',
            zoom: transaction.merchant ? transaction.merchant.address.zoom_level : '4.6',
            logo: transaction.merchant ? transaction.merchant.logo : false,
            merchant: transaction.merchant ? transaction.merchant.name : transaction.is_load ? 'Mondo' : '',
            address: transaction.merchant ? transaction.merchant.address.short_formatted : 'In the clouds',
            tags: transaction.merchant ? transaction.merchant.metadata.suggested_tags.split(' ') : [],
            amount: intToAmount(transaction.amount, transaction.currency),
            online: transaction.merchant ? transaction.merchant.online : false,
            notes: transaction.notes,
            created: transaction.created
          }
        }
      });
    })
    .fail(err => swal('Error', err.responseJSON ? `${err.responseJSON.message} try logging out and in again` : false
      || 'Internal error, check your network connection, contact me in the menu if this keeps happening', 'error'));
  }

  transactionSearch(event) {
    event.preventDefault();
    const search = event.target.value;

    if (search.length < 3) {
      return this.setState({
        account: Object.assign({}, this.state.account, {
          filterActive: false,
          filteredTransactions: []
        })
      });
    }

    // TODO Move to search all trans (fetch) when pagination is implemented
    let transactions = this.state.account.transactions;

    // Search merchant name, address category and notes
    transactions = transactions.filter(transaction => (
      (transaction.merchant ? transaction.merchant.name.toLowerCase().includes(search.toLowerCase()) : false) ||
      (transaction.merchant ? transaction.merchant.address.formatted.toLowerCase().includes(search.toLowerCase()) : false) ||
      (transaction.merchant ? transaction.merchant.category.toLowerCase().includes(search.toLowerCase()) : false) ||
      (transaction.notes ? transaction.notes.toLowerCase().includes(search.toLowerCase()) : false)
    ));

    this.setState({
      account: Object.assign({}, this.state.account, {
        filterActive: true,
        filteredTransactions: transactions
      })
    });
  }

  render() {
    const { account, transactionOverview, ui } = this.state;

    return (
      <Container>
        <Overview
          name={account.name}
          balance={account.balance}
          spentToday={account.spentToday}
        />
        <div className='row'>
          <div className='col s12 m12 l3'>
            <div className='border-box'>
              <input onKeyUp={this.transactionSearch.bind(this)} placeholder='Search' autoFocus type='text' /><commit_msg>Redirect if no access token<commit_after>import React from 'react';
import Container from 'components/Container';
import Overview from 'components/Accounts/Overview';
import Transactions from 'components/Accounts/Transactions';
import TransactionOverview from 'components/Accounts/Transactions/Transaction/Overview';
import { intToAmount, once } from 'lib/utils';
import localForage from 'localforage';

export default class Accounts extends React.Component {

  constructor() {
    super();

    // Lazy init sidebar & date
    this.initSideMenu = once(this.initSideMenu);

    // TODO Add Redux
    this.state = {
      ui: {
        selectedTransaction: 0
      },
      transactionOverview: {
        empty: true,
        loading: false,
        data: {}
      },
      account: {
        id: undefined,
        name: '',
        transactions: [],
        filterActive: false,
        filteredTransactions: [],
        balance: '',
        currency: '',
        spentToday: ''
      }
    };
  }

  componentWillMount() {

    // Retrieve inital data
    this.retrieveAccount().then(() => {
      this.retrieveBalance();
      this.retrieveTransactions();
    });
  }

  componentDidMount() {
    this.initSideMenu();
  }

  initSideMenu() {
    $('.button-collapse').sideNav({
      edge: 'right',
      closeOnClick: true
    });
  }

  // Updates the state with the latest balance
  retrieveBalance() {
    $.ajax({
      url: `https://api.getmondo.co.uk/balance?account_id=${this.state.account.id}`,
      headers: {
        'Authorization': `Bearer ${localStorage.mondo_access_token}`
      }
    })
    .done(account => {
      const { currency, balance, spend_today: spentToday} = account;
      this.setState({
        account: Object.assign({}, this.state.account, {
          balance, spentToday, currency
        })
      });
    })
    .fail(err => swal('Error', err.responseJSON ? `${err.responseJSON.message} try logging out and in again` : false
      || 'Internal error, check your network connection, contact me in the menu if this keeps happening', 'error'));
  }

  // Updates the state with the account name (only first account supported atm)
  retrieveAccount() {
    return new Promise(resolve => {
      $.ajax({
        url: 'https://api.getmondo.co.uk/accounts',
        headers: {
          'Authorization': `Bearer ${localStorage.mondo_access_token}`
        }
      })
      .done(response => {
        this.setState({
          account: Object.assign({}, this.state.account, {
            name: response.accounts[0].description,
            id: response.accounts[0].id
          })
        });
        resolve();
      })
      .fail(err => swal('Error', err.responseJSON ? `${err.responseJSON.message} try logging out and in again` : false
        || 'Internal error, check your network connection, contact me in the menu if this keeps happening', 'error'));
    });
  }

  // Params is a query string starting with '&'
  retrieveTransactions(params = '') {
    $.ajax({
      url: `https://api.getmondo.co.uk/transactions?expand[]=merchant&account_id=${this.state.account.id}${params}`,
      headers: {
        'Authorization': `Bearer ${localStorage.mondo_access_token}`
      }
    })
    .done(account => {
      this.setState({
        account: Object.assign({}, this.state.account, {
          transactions: account.transactions
        })
      });
    })
    .fail(err => swal('Error', err.responseJSON ? `${err.responseJSON.message} try logging out and in again` : false
      || 'Internal error, check your network connection, contact me in the menu if this keeps happening', 'error'));
  }

  transactionSelect(event) {
    event.preventDefault();
    let target = event.target;
    while (target.parentElement) {
      target = target.parentElement;
      if (target.dataset.tid) {
        break;
      }
    }

    // Happens when user clicks an odd bit of the collection item
    if (!target.dataset.tid) {
      return false;
    }

    let transactionId = atob(target.dataset.tid);

    this.setState({
      transactionOverview: {
        empty: false,
        loading: true,
        data: {}
      }
    });

    $.ajax({
      url: `https://api.getmondo.co.uk/transactions/${transactionId}?expand[]=merchant`,
      headers: {
        'Authorization': `Bearer ${localStorage.mondo_access_token}`
      }
    })
    .done(result => {
      const transaction = result.transaction;
      this.setState({
        ui: {
          selectedTransaction: btoa(transaction.id)
        },
        transactionOverview: {
          empty: false,
          loading: false,
          data: {
            lat: transaction.merchant ? transaction.merchant.address.latitude : '50.1477307',
            long: transaction.merchant ? transaction.merchant.address.longitude : '0.7332003',
            zoom: transaction.merchant ? transaction.merchant.address.zoom_level : '4.6',
            logo: transaction.merchant ? transaction.merchant.logo : false,
            merchant: transaction.merchant ? transaction.merchant.name : transaction.is_load ? 'Mondo' : '',
            address: transaction.merchant ? transaction.merchant.address.short_formatted : 'In the clouds',
            tags: transaction.merchant ? transaction.merchant.metadata.suggested_tags.split(' ') : [],
            amount: intToAmount(transaction.amount, transaction.currency),
            online: transaction.merchant ? transaction.merchant.online : false,
            notes: transaction.notes,
            created: transaction.created
          }
        }
      });
    })
    .fail(err => swal('Error', err.responseJSON ? `${err.responseJSON.message} try logging out and in again` : false
      || 'Internal error, check your network connection, contact me in the menu if this keeps happening', 'error'));
  }

  transactionSearch(event) {
    event.preventDefault();
    const search = event.target.value;

    if (search.length < 3) {
      return this.setState({
        account: Object.assign({}, this.state.account, {
          filterActive: false,
          filteredTransactions: []
        })
      });
    }

    // TODO Move to search all trans (fetch) when pagination is implemented
    let transactions = this.state.account.transactions;

    // Search merchant name, address category and notes
    transactions = transactions.filter(transaction => (
      (transaction.merchant ? transaction.merchant.name.toLowerCase().includes(search.toLowerCase()) : false) ||
      (transaction.merchant ? transaction.merchant.address.formatted.toLowerCase().includes(search.toLowerCase()) : false) ||
      (transaction.merchant ? transaction.merchant.category.toLowerCase().includes(search.toLowerCase()) : false) ||
      (transaction.notes ? transaction.notes.toLowerCase().includes(search.toLowerCase()) : false)
    ));

    this.setState({
      account: Object.assign({}, this.state.account, {
        filterActive: true,
        filteredTransactions: transactions
      })
    });
  }

  render() {
    const { account, transactionOverview, ui } = this.state;

    if (!localStorage.mondo_access_token) {
      window.location.href = '/';
      return false;
    }

    return (
      <Container>
        <Overview
          name={account.name}
          balance={account.balance}
          spentToday={account.spentToday}
        />
        <div className='row'>
          <div className='col s12 m12 l3'>
            <div className='border-box'>
              <input onKeyUp={this.transactionSearch.bind(this)} placeholder='Search' autoFocus type='text' />
{'fraction_non_alphanumeric': 0.12976642044320225, 'fraction_numerical': 0.003726625407599654, 'mean_word_length': 2.538497763126913, 'pattern_counts': {'":': 0, '<': 17, '<?xml version=': 0, '>': 37, 'https://': 8, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4989786', 'n_tokens_mistral': 4137, 'n_tokens_neox': 4116, 'n_words': 925}