<commit_before>import React from 'react';
import PropTypes from 'prop-types';

import { connect } from 'react-redux';

import { PageHeader, Well, Alert, Row, Col } from 'react-bootstrap';
import { ButtonToolbar, Button, ButtonGroup, Glyphicon } from 'react-bootstrap';

import _ from 'lodash';
import Moment from 'moment';
import { formatDateTime, toZuluTime } from '../utils/date';
import Promise from 'bluebird';

import * as Action from '../actionTypes';
import * as Api from '../api';
import * as Constant from '../constants';
import store from '../store';

import CheckboxControl from '../components/CheckboxControl.jsx';
import DateControl from '../components/DateControl.jsx';
import Favourites from '../components/Favourites.jsx';
import KeySearchControl from '../components/KeySearchControl.jsx';
import MultiDropdown from '../components/MultiDropdown.jsx';
import SortTable from '../components/SortTable.jsx';
import Markdown from 'react-markdown';
import Spinner from '../components/Spinner.jsx';
import Unimplemented from '../components/Unimplemented.jsx';
import Tooltips from '../components/Tooltips.jsx';
import Authorize from '../components/Authorize';
import UpdateButton from '../components/UpdateButton.jsx';
import DeleteButton from '../components/DeleteButton.jsx';

class CCWNotifications extends React.Component {
  static propTypes = {
    currentUser: PropTypes.object,
    districts: PropTypes.object,
    inspectors: PropTypes.object,
    ccwnotifications: PropTypes.object,
    favourites: PropTypes.object,
    search: PropTypes.object,
    ui: PropTypes.object,
    router: PropTypes.object,
  };

  constructor(props) {
    super(props);
    var defaultSelectedInspectors = props.currentUser.isInspector ? [props.currentUser.id] : [];

    var defaultSelectedDistricts =
      props.currentUser.isInspector || !props.currentUser.districtId ? [] : [props.currentUser.districtId];

    var defaultDateFrom = toZuluTime(new Date('2020-09-01'));
    var defaultDateTo = toZuluTime(Moment());

    this.state = {
      loading: true,
      selectAll: false,
      searched: false,

      search: {
        selectedDistrictsIds: props.search.selectedDistrictsIds || defaultSelectedDistricts,
        selectedInspectorsIds: props.search.selectedInspectorsIds || defaultSelectedInspectors,
        keySearchField: props.search.keySearchField,
        keySearchText: props.search.keySearchText,
        keySearchParams: props.search.keySearchParams,
        hideRead: props.search.hideRead || true,
        dateFrom: props.search.dateFrom || defaultDateFrom,
        dateTo: props.search.dateTo || defaultDateTo,
        loaded: props.search.loaded || true,
      },

      ui: {
        sortField: props.ui.sortField || 'dateDetected',
        sortDesc: props.ui.sortDesc === true,
      },
    };
  }

  buildSearchParams = () => {
    var searchParams = {
      hideRead: this.state.search.hideRead,
    };

    var dateFrom = Moment(this.state.search.dateFrom);
    if (dateFrom && dateFrom.isValid()) {
      searchParams.dateFrom = toZuluTime(dateFrom.startOf('day'));
    }

    var dateTo = Moment(this.state.search.dateTo);
    if (dateTo && dateTo.isValid()) {
      searchParams.dateTo = toZuluTime(dateTo.startOf('day'));
    }

    if (this.state.search.keySearchParams) {
      // Use key search control params if there
      return { ...this.state.search.keySearchParams, ...searchParams };
    }

    if (
      this.state.search.selectedDistrictsIds.length > 0 &&
      this.state.search.selectedDistrictsIds.length !== _.size(this.props.districts)
    ) {
      searchParams.districts = this.state.search.selectedDistrictsIds;
    }

    if (
      this.state.search.selectedInspectorsIds.length > 0 &&
      this.state.search.selectedInspectorsIds.length !== _.size(this.props.inspectors)
    ) {
      searchParams.inspectors = this.state.search.selectedInspectorsIds;
    }

    return searchParams;
  };

  componentDidMount() {
    this.setState({ loading: true });

    var inspectorsPromise = Api.getInspectors();
    var favouritesPromise = Api.getFavourites('ccwnotification');

    Promise.all([inspectorsPromise, favouritesPromise])
      .then(() => {
        if (this.props.location.search) {
          // Check for specific school bus query
          var state = {
            selectedDistrictsIds: [],
            selectedInspectorsIds: this.props.currentUser.isInspector ? [this.props.currentUser.id] : [],
            keySearchField: this.props.search.keySearchField,
            keySearchText: '',
            keySearchParams: null,
            startDate: '',
            endDate: '',
            hideRead: true,
            selectAll: false,
          };

          if (this.props.location.query[Constant.CCWNOTIRICATION_INSPECTORS_QUERY]) {
            state.selectedInspectorsIds = this.props.currentUser.isInspector ? [this.props.currentUser.id] : [];
          }

          this.updateSearchState(state, this.initialFetch);
        } else {
          if (!this.props.search.loaded) {
            // This is the first load so look for a default favourite
            var favourite = _.find(this.props.favourites, (favourite) => {
              return favourite.isDefault;
            });
            if (favourite) {
              this.loadFavourite(favourite);
            }
          }
          return this.initialFetch();
        }
      })
      .finally(() => {
        this.setState({ loading: false });
      });
  }

  initialFetch = () => {
    if (!this.props.currentUser.isInspector) return { loading: false };
    return this.fetch();
  };

  fetch = () => {
    this.setState({ loading: true });
    return Api.getCCWNotifications(this.buildSearchParams()).finally(() => {
      this.setState({ loading: false, searched: true });
    });
  };

  updateSearchState = (state, callback) => {
    this.setState({ search: { ...this.state.search, ...state, ...{ loaded: true } } }, () => {
      store.dispatch({
        type: Action.UPDATE_CCWNOTIFICATIONS_SEARCH,
        ccwnotifications: this.state.search,
      });
      if (callback) {
        callback();
      }
    });
  };

  updateUIState = (state, callback) => {
    this.setState({ ui: { ...this.state.ui, ...state } }, () => {
      store.dispatch({ type: Action.UPDATE_CCWNOTIFICATION_UI, ccwnotifications: this.state.ui });
      if (callback) {
        callback();
      }
    });
  };

  loadFavourite = (favourite) => {
    this.updateSearchState(JSON.parse(favourite.value), this.fetch);
  };

  updateCCWNotifications = (ccwnotifications) => {
    const notifications = _.pickBy(
      ccwnotifications,
      (ccwnotification) =>
        this.props.currentUser.isSystemAdmin || ccwnotification.inspectorId === this.props.currentUser.id
    );

    const notificationArray = Object.values(notifications);

    if (notificationArray.length === 0) return;

    Api.updateCCWNotifications(notificationArray).then(() => {
      this.fetch();
    });
  };

  deleteCCWNotifications = (ccwnotifications) => {
    const notifications = _.pickBy(
      ccwnotifications,
      (ccwnotification) =>
        this.props.currentUser.isSystemAdmin ||
        (ccwnotification.inspectorId === this.props.currentUser.id && ccwnotification.hasBeenViewed)
    );

    const notificationArray = Object.values(notifications);

    if (notificationArray.length === 0) return;

    Api.deleteCCWNotifications(notificationArray).then(() => {
      this.fetch();
    });
  };

  togleHasBeenViewedAll = (toggle) => {
    var ccwnotifications = { ...this.props.ccwnotifications };

    _.values(ccwnotifications).forEach((ccwnotification) => {
      if (this.props.currentUser.isSystemAdmin || ccwnotification.inspectorId === this.props.currentUser.id) {
        ccwnotification.hasBeenViewed = toggle.selectAll;
      }
    });
    store.dispatch({ type: Action.UPDATE_CCWNOTIFICATIONS, ccwnotifications: ccwnotifications });
  };

  togleHasBeenViewed = (toggle, ccwnotification) => {
    var notification = { ...ccwnotification };
    notification.hasBeenViewed = toggle.hasBeenViewed;

    var ccwnotifications = { ...this.props.ccwnotifications, [notification.id]: notification };

    store.dispatch({ type: Action.UPDATE_CCWNOTIFICATIONS, ccwnotifications: ccwnotifications });
  };

  email = () => {};
  print = () => {};

  render() {
    var districts = _.sortBy(this.props.districts, 'name');
    var inspectors = _.sortBy(this.props.inspectors, 'name');
    var ccwnotificationArray = _.values(this.props.ccwnotifications);

    var isEditable =
      this.props.currentUser.isSystemAdmin ||
      ccwnotificationArray.filter((x) => x.inspectorId === this.props.currentUser.id).length > 0;

    var numCCWNotifications = this.state.loading ? '...' : ccwnotificationArray.length;

    return (
      <div id="ccwnotifications">
        <PageHeader>
          CCW Notifications ({numCCWNotifications})
          <ButtonGroup id="ccwnotifications-buttons">
            <Unimplemented>
              <Button onClick={this.email}>
                <Glyphicon glyph="envelope" title="E-mail" />
              </Button>
            </Unimplemented>
            <Unimplemented>
              <Button onClick={this.print}>
                <Glyphicon glyph="print" title="Print" />
              </Button>
            </Unimplemented>
          </ButtonGroup>
        </PageHeader>
        <div>
          <Well id="ccwnotifications-bar" bsSize="small" className="clearfix">
            <Row>
              <Col md={10}>
                <Row>
                  <ButtonToolbar id="ccwnotifications-search">
                    <MultiDropdown
                      id="selectedDistrictsIds"
                      placeholder="Districts"<commit_msg>export button<commit_after>import React from 'react';
import PropTypes from 'prop-types';

import { connect } from 'react-redux';

import { PageHeader, Well, Alert, Row, Col } from 'react-bootstrap';
import { ButtonToolbar, Button, ButtonGroup, Glyphicon } from 'react-bootstrap';

import _ from 'lodash';
import Moment from 'moment';
import { formatDateTime, toZuluTime } from '../utils/date';
import Promise from 'bluebird';

import * as Action from '../actionTypes';
import * as Api from '../api';
import * as Constant from '../constants';
import store from '../store';

import CheckboxControl from '../components/CheckboxControl.jsx';
import DateControl from '../components/DateControl.jsx';
import Favourites from '../components/Favourites.jsx';
import KeySearchControl from '../components/KeySearchControl.jsx';
import MultiDropdown from '../components/MultiDropdown.jsx';
import SortTable from '../components/SortTable.jsx';
import Markdown from 'react-markdown';
import Spinner from '../components/Spinner.jsx';
import Unimplemented from '../components/Unimplemented.jsx';
import Tooltips from '../components/Tooltips.jsx';
import Authorize from '../components/Authorize';
import UpdateButton from '../components/UpdateButton.jsx';
import DeleteButton from '../components/DeleteButton.jsx';

class CCWNotifications extends React.Component {
  static propTypes = {
    currentUser: PropTypes.object,
    districts: PropTypes.object,
    inspectors: PropTypes.object,
    ccwnotifications: PropTypes.object,
    favourites: PropTypes.object,
    search: PropTypes.object,
    ui: PropTypes.object,
    router: PropTypes.object,
  };

  constructor(props) {
    super(props);
    var defaultSelectedInspectors = props.currentUser.isInspector ? [props.currentUser.id] : [];

    var defaultSelectedDistricts =
      props.currentUser.isInspector || !props.currentUser.districtId ? [] : [props.currentUser.districtId];

    var defaultDateFrom = toZuluTime(new Date('2020-09-01'));
    var defaultDateTo = toZuluTime(Moment());

    this.state = {
      loading: true,
      selectAll: false,
      searched: false,

      search: {
        selectedDistrictsIds: props.search.selectedDistrictsIds || defaultSelectedDistricts,
        selectedInspectorsIds: props.search.selectedInspectorsIds || defaultSelectedInspectors,
        keySearchField: props.search.keySearchField,
        keySearchText: props.search.keySearchText,
        keySearchParams: props.search.keySearchParams,
        hideRead: props.search.hideRead || true,
        dateFrom: props.search.dateFrom || defaultDateFrom,
        dateTo: props.search.dateTo || defaultDateTo,
        loaded: props.search.loaded || true,
      },

      ui: {
        sortField: props.ui.sortField || 'dateDetected',
        sortDesc: props.ui.sortDesc === true,
      },
    };
  }

  buildSearchParams = () => {
    var searchParams = {
      hideRead: this.state.search.hideRead,
    };

    var dateFrom = Moment(this.state.search.dateFrom);
    if (dateFrom && dateFrom.isValid()) {
      searchParams.dateFrom = toZuluTime(dateFrom.startOf('day'));
    }

    var dateTo = Moment(this.state.search.dateTo);
    if (dateTo && dateTo.isValid()) {
      searchParams.dateTo = toZuluTime(dateTo.startOf('day'));
    }

    if (this.state.search.keySearchParams) {
      // Use key search control params if there
      return { ...this.state.search.keySearchParams, ...searchParams };
    }

    if (
      this.state.search.selectedDistrictsIds.length > 0 &&
      this.state.search.selectedDistrictsIds.length !== _.size(this.props.districts)
    ) {
      searchParams.districts = this.state.search.selectedDistrictsIds;
    }

    if (
      this.state.search.selectedInspectorsIds.length > 0 &&
      this.state.search.selectedInspectorsIds.length !== _.size(this.props.inspectors)
    ) {
      searchParams.inspectors = this.state.search.selectedInspectorsIds;
    }

    return searchParams;
  };

  componentDidMount() {
    this.setState({ loading: true });

    var inspectorsPromise = Api.getInspectors();
    var favouritesPromise = Api.getFavourites('ccwnotification');

    Promise.all([inspectorsPromise, favouritesPromise])
      .then(() => {
        if (this.props.location.search) {
          // Check for specific school bus query
          var state = {
            selectedDistrictsIds: [],
            selectedInspectorsIds: this.props.currentUser.isInspector ? [this.props.currentUser.id] : [],
            keySearchField: this.props.search.keySearchField,
            keySearchText: '',
            keySearchParams: null,
            startDate: '',
            endDate: '',
            hideRead: true,
            selectAll: false,
          };

          if (this.props.location.query[Constant.CCWNOTIRICATION_INSPECTORS_QUERY]) {
            state.selectedInspectorsIds = this.props.currentUser.isInspector ? [this.props.currentUser.id] : [];
          }

          this.updateSearchState(state, this.initialFetch);
        } else {
          if (!this.props.search.loaded) {
            // This is the first load so look for a default favourite
            var favourite = _.find(this.props.favourites, (favourite) => {
              return favourite.isDefault;
            });
            if (favourite) {
              this.loadFavourite(favourite);
            }
          }
          return this.initialFetch();
        }
      })
      .finally(() => {
        this.setState({ loading: false });
      });
  }

  initialFetch = () => {
    if (!this.props.currentUser.isInspector) return { loading: false };
    return this.fetch();
  };

  fetch = () => {
    this.setState({ loading: true });
    return Api.getCCWNotifications(this.buildSearchParams()).finally(() => {
      this.setState({ loading: false, searched: true });
    });
  };

  updateSearchState = (state, callback) => {
    this.setState({ search: { ...this.state.search, ...state, ...{ loaded: true } } }, () => {
      store.dispatch({
        type: Action.UPDATE_CCWNOTIFICATIONS_SEARCH,
        ccwnotifications: this.state.search,
      });
      if (callback) {
        callback();
      }
    });
  };

  updateUIState = (state, callback) => {
    this.setState({ ui: { ...this.state.ui, ...state } }, () => {
      store.dispatch({ type: Action.UPDATE_CCWNOTIFICATION_UI, ccwnotifications: this.state.ui });
      if (callback) {
        callback();
      }
    });
  };

  loadFavourite = (favourite) => {
    this.updateSearchState(JSON.parse(favourite.value), this.fetch);
  };

  updateCCWNotifications = (ccwnotifications) => {
    const notifications = _.pickBy(
      ccwnotifications,
      (ccwnotification) =>
        this.props.currentUser.isSystemAdmin || ccwnotification.inspectorId === this.props.currentUser.id
    );

    const notificationArray = Object.values(notifications);

    if (notificationArray.length === 0) return;

    Api.updateCCWNotifications(notificationArray).then(() => {
      this.fetch();
    });
  };

  deleteCCWNotifications = (ccwnotifications) => {
    const notifications = _.pickBy(
      ccwnotifications,
      (ccwnotification) =>
        this.props.currentUser.isSystemAdmin ||
        (ccwnotification.inspectorId === this.props.currentUser.id && ccwnotification.hasBeenViewed)
    );

    const notificationArray = Object.values(notifications);

    if (notificationArray.length === 0) return;

    Api.deleteCCWNotifications(notificationArray).then(() => {
      this.fetch();
    });
  };

  togleHasBeenViewedAll = (toggle) => {
    var ccwnotifications = { ...this.props.ccwnotifications };

    _.values(ccwnotifications).forEach((ccwnotification) => {
      if (this.props.currentUser.isSystemAdmin || ccwnotification.inspectorId === this.props.currentUser.id) {
        ccwnotification.hasBeenViewed = toggle.selectAll;
      }
    });
    store.dispatch({ type: Action.UPDATE_CCWNOTIFICATIONS, ccwnotifications: ccwnotifications });
  };

  togleHasBeenViewed = (toggle, ccwnotification) => {
    var notification = { ...ccwnotification };
    notification.hasBeenViewed = toggle.hasBeenViewed;

    var ccwnotifications = { ...this.props.ccwnotifications, [notification.id]: notification };

    store.dispatch({ type: Action.UPDATE_CCWNOTIFICATIONS, ccwnotifications: ccwnotifications });
  };

  export = () => {};

  render() {
    var districts = _.sortBy(this.props.districts, 'name');
    var inspectors = _.sortBy(this.props.inspectors, 'name');
    var ccwnotificationArray = _.values(this.props.ccwnotifications);

    var isEditable =
      this.props.currentUser.isSystemAdmin ||
      ccwnotificationArray.filter((x) => x.inspectorId === this.props.currentUser.id).length > 0;

    var numCCWNotifications = this.state.loading ? '...' : ccwnotificationArray.length;

    return (
      <div id="ccwnotifications">
        <PageHeader>
          CCW Notifications ({numCCWNotifications})
          <ButtonGroup id="ccwnotifications-buttons">
            <Unimplemented>
              <Button onClick={this.print}>
                <Glyphicon glyph="download-alt" title="Export" />
              </Button>
            </Unimplemented>
          </ButtonGroup>
        </PageHeader>
        <div>
          <Well id="ccwnotifications-bar" bsSize="small" className="clearfix">
            <Row>
              <Col md={10}>
                <Row>
                  <ButtonToolbar id="ccwnotifications-search">
                    <MultiDropdown
                      id="selectedDistrictsIds"
                      placeholder="Districts"
{'fraction_non_alphanumeric': 0.13111616840798593, 'fraction_numerical': 0.0015516706320471707, 'mean_word_length': 2.8046044864226682, 'pattern_counts': {'":': 0, '<': 42, '<?xml version=': 0, '>': 93, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 1, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1200713', 'n_tokens_mistral': 5686, 'n_tokens_neox': 5543, 'n_words': 1013}