# Density Reports

A collection of reports used to display data across all of our digital products.

## Getting started
```sh
git clone git@github.com:densityco/reports.git
cd reports/
npm install
npm start
```

## Rendering a report
This package exports by default a React component (originally from the dashboard) that can be used
to render a report:
```javascript
import Report from '@density/reports';

<Report
  report={{
    id: "rpt_xxx",
    type: "DAILY_PEAKS",
    creator_email: "engineering@density.io",
    name: "Custom report name",
    settings: {
      hello: "world"
    },
  }}
  reportData={{
    state: "COMPLETE",
    data: {
      calculationResults: "go here"
    },
  }}

  // Props to control exactly how this report looks when rendered:

  // Render this report in "expanded mode", optimizing graphics for a large format
  expanded={false}
  // Set to true when a report is being rendered in a digest email
  email={false}

  // Optionally hide the border of the report if it's being rendered in a context that provides a
  // border already
  hideBorder={true}

  // Hide the csv action on the action bar at the bottom of the report
  hideCsvAction={true}
  // Hide the expand action on the action bar if it should be hidden in a specific context
  hideExpandAction={true}

  // Props that allow the report to interact with the application it is within:
  onOpenReportExpandedModal={report => {
    console.log('Called when "expand" button is clicked on a report.');
    console.log('If report cannot be expanded, this callback is never called.');
  }}
  onCsvExportError={error => {
    console.error('An error occured while exporting a csv from a report:', error);
    console.error('A toast or other sort of error alert should be shown in the application.');
  }}
/>
```

## Creating a new report
There are two ways to go about this, the easy way, and the hard way

### The Easy Way
Use a nifty script:

`npm run make-report`

### The Hard Way
1. Make a copy of an existing report, such as `TotalVisits`:
```sh
cp -R src/reports/TotalVisits src/reports/MyReport
```

2. Add the new report to the central reports list, located at `src/reports.js`:
```javascript

/* ... */
import MyReport from './reports/MyReport/index';

/* ... */
import myReport from './reports/MyReport/calculations';

/* ... */

const REPORTS = {
  /* ... */

  MY_REPORT: { // `MY_REPORT` is the enum value defined in the Core API's `Report` type field
    component: MyReport,
    calculations: myReport,
    /* there are other keys too, look at the other reports for details */
  },

  /* ... */
};
```

3. Finally, update the interactive story in `src/MyReport/story.js` to point to the new report:
```javascript
.add('Interactive', () => (
  <ReportTester
    name="My Report Example"
    type="MY_REPORT"
  />
))
```

## Report Calculation Schema
A report calculation function accepts two parameters and must return a promise that resolves to an
object.

```typescript
type ReportCalculationFunction = (report: DensityReport, opts: DensityReportOptions) => Promise<object>;

type DensityReport = {
  id: string;
  name: string;
  settings: string;
  /* ... */
}

type DensityReportOptions = {
  date: Moment; // A moment representing "now", in utc. This permits reports to be run for any time period, including in the past!
  week_start: string; // A weekday for the report week to start on. Default is "Sunday".
  client: any; // An axios client used to make AJAX requests.
  slow: boolean; // A flag representing if the report calculations should run specifying the "?slow=true" flag, which bypasses the new reporting database.
}

// CSV calculation function schema
type DensityCalculatedCsv = {
  fileName: string,
  contents: string,
};
type DensityCsvCalculationFunction = (report: DensityReport, calculationResult: ReturnType<ReportCalculationFunction>) => Promise<DensityCalculatedCsv>
```
