Skip to end of banner
Go to start of banner

Example of perfect component

Skip to end of metadata
Go to start of metadata

You are viewing an old version of this page. View the current version.

Compare with Current View Page History

« Previous Version 3 Next »

import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { get } from 'lodash';


import jobPropTypes from '../Jobs/components/Job/jobPropTypes';
import jobLogPropTypes from '../JobLogs/jobLogPropTypes';
import {
  PROCESSING_IN_PROGRESS,
  PROCESSING_FINISHED,
  PARSING_IN_PROGRESS,
} from '../Jobs/jobStatuses';
import { DataFetcherContextProvider } from './DataFetcherContext';

const DEFAULT_UPDATE_INTERVAL = 5000;

class DataFetcher extends Component {
  static propTypes = {
    children: PropTypes.oneOfType([
      PropTypes.arrayOf(PropTypes.node),
      PropTypes.node,
    ]).isRequired,
    mutator: PropTypes.shape({
      jobs: PropTypes.shape({
        GET: PropTypes.func.isRequired,
      }).isRequired,
      logs: PropTypes.shape({
        GET: PropTypes.func.isRequired,
      }).isRequired,
    }).isRequired,
    resources: PropTypes.shape({
      jobs: PropTypes.shape({
        records: PropTypes.arrayOf(
          PropTypes.shape({
            jobExecutionDtos: PropTypes.arrayOf(jobPropTypes).isRequired,
          }),
        ).isRequired,
      }),
      logs: PropTypes.shape({
        records: PropTypes.arrayOf(
          PropTypes.shape({
            logs: PropTypes.arrayOf(jobLogPropTypes).isRequired,
          }),
        ).isRequired,
      }),
    }).isRequired,
    updateInterval: PropTypes.number, // milliseconds
  };

  static defaultProps = {
    updateInterval: DEFAULT_UPDATE_INTERVAL,
  };

  static manifest = Object.freeze({
    jobs: {
      type: 'okapi',
      path: `metadata-provider/jobExecutions?query=(status=("${PROCESSING_IN_PROGRESS}" OR "${PROCESSING_FINISHED}" OR "${PARSING_IN_PROGRESS}"))`,
      accumulate: true,
      throwErrors: false,
    },
    logs: {
      type: 'okapi',
      path: 'metadata-provider/logs?landingPage=true',
      accumulate: true,
      throwErrors: false,
    },
  });

  state = {
    contextData: {},
  };

  componentDidMount() {
    this.setInitialState();
    this.getResourcesData();
    this.updateResourcesData();
  }

  componentWillUnmount() {
    clearInterval(this.intervalId);
  }

  render() {
    const { children } = this.props;
    const { contextData } = this.state;

    return (
      <DataFetcherContextProvider value={contextData}>
        {children}
      </DataFetcherContextProvider>
    );
  }

  updateResourcesData() {
    const { updateInterval } = this.props;

    this.intervalId = setInterval(this.getResourcesData, updateInterval);
  }

  setInitialState() {
    const { mutator } = this.props;
    const initialContextData = {};

    Object.keys(mutator)
      .forEach(resourceName => {
        initialContextData[resourceName] = {
          hasLoaded: false,
        };
      });

    this.setState({
      contextData: initialContextData,
    });
  }

  getResourcesData = async () => {
    const { mutator } = this.props;

    const fetchResourcesPromises = Object.values(mutator)
      .reduce((res, resourceMutator) => {
        return res.concat(this.getResourceData(resourceMutator));
      }, []);

    try {
      await Promise.all(fetchResourcesPromises);

      this.mapResourcesToState();
    } catch (e) {
      // TODO: should be described in UIDATIMP-53
    }
  };

  async getResourceData({ GET, reset }) {
    // accumulate: true in manifest saves the results of all requests
    // because of that it is required to clear old data by invoking reset method before each request
    reset();
    await GET();
  }

  mapResourcesToState() {
    const { resources } = this.props;
    const contextData = {};

    Object.entries(resources)
      .forEach(([resourceName, resourceValue]) => {
        contextData[resourceName] = {
          hasLoaded: true,
          itemsObject: get(resourceValue, ['records', 0], {}),
        };
      });

    this.setState({
      contextData,
    });
  }
}

export default DataFetcher;
  • No labels