<repo_name>mrVanboy/zonky-api-example<file_sep>/Makefile
DEVELOP_CONTAINER_NAME=zonky_docker_node_dev
DEVELOP_IMAGE=node:latest

.PHONY: help
# HELP
# This will output the help for each task
# thanks to https://marmelab.com/blog/2016/02/29/auto-documented-makefile.html


help: ## This help.
	@awk 'BEGIN {FS = ":.*?## "} /^[a-zA-Z_-]+:.*?## / {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' $(MAKEFILE_LIST)

.DEFAULT_GOAL := help

docker-develop:  ## Start docker container with development environment
	@ docker run \
		--name $(DEVELOP_CONTAINER_NAME) \
		-p 4200:4200 \
		-v $(PWD):/app \
		-ti \
		--entrypoint bash \
		$(DEVELOP_IMAGE)

docker-stop: ## Stop docker environment container and remove it
	@ docker rm $(DEVELOP_CONTAINER_NAME)

up: ## Up docker compose with builded aplication
	@ docker-compose up

down: ## Down docker-compose containers with app
	@ docker-compose down

build: ## Build docker-compose images
	@ docker-compose build

build-up: build up ## Build and up docker-compose containers<file_sep>/Dockerfile
FROM node:10.3-alpine as build-env

COPY ./package.json ./package-lock.json /

RUN npm set progress=false && npm config set depth 0 && npm cache clean --force

## Storing node modules on a separate layer will prevent unnecessary npm installs at each build
RUN npm i && mkdir /app && cp -R ./node_modules ./app

COPY . /app
WORKDIR /app

RUN $(npm bin)/ng build --prod --build-optimizer --output-path /app/dist

# ++++++++++++++++++++++++++++
FROM nginx:1.14-alpine
MAINTAINER <NAME> <<EMAIL>>
COPY --from=build-env /app/dist /usr/share/nginx/html

<file_sep>/README.md
# Zonky Api Example
Example project that using [Zonky API](https://zonky.docs.apiary.io/#).
> **YOU MUST DISABLE CROSS-ORIGIN SECURITY IN BROWSER**
> Ex. Chrome must be lauched with parameters: `google-chrome --disable-web-security --user-data-dir`

## Development server
You can use classic way of the development with local instance of node or
here is prepared *Makefile* with dockerized environment.

```bash
make docker-develop

# Next commands must be runned inside docker container
cd /app
npm start -- --host=0.0.0.0
```

After that just open `localhost:400` in your browser.

## Build
Resulted image is builded with *docker-compose* and *Makefile* contain
prepared tasks.

Run `make up`, wait until container will be prepared and open
[localhost:8080](http://localhost:8080).

<file_sep>/docker-compose.yml
version: "3"
services:

  zonky-api-example:
    build: .
    ports:
      - 8080:80
<file_sep>/src/app/app.component.ts
import {Component} from '@angular/core';
import {HttpClient, HttpHeaders} from "@angular/common/http";
import {HttpObserve} from "@angular/common/http/src/client";
import {isArray} from "util";

@Component({
    selector: 'app-root',
    templateUrl: './app.component.html',
    styleUrls: ['./app.component.scss']
})

export class AppComponent {
    constructor(private http: HttpClient) {
    }

    result: string = 'Select the rating';

    ratingArray = [
        new Rating('A**', 'AAAAA'),
        new Rating('A*', 'AAAA'),
        new Rating('A++', 'AAA'),
        new Rating('A+', 'AA'),
        new Rating('A', 'A'),
        new Rating('B', 'B'),
        new Rating('C', 'C'),
        new Rating('D', 'D'),
    ];

    onSelectChange(newValue: string) {
        this.sendRequest(newValue);
        this.result = 'Loading...'
    }

    private static url = 'https://api.zonky.cz/loans/marketplace?fields=id,amount&&rating__eq=';

    private loadAllItems(v: string, totalNumber: number) {
        const options = {
            headers: new HttpHeaders().set('X-Size', totalNumber.toString()),
        };
        this.http.get(AppComponent.url + v, options).subscribe(res => {
            this.calculateAverage(res)
        });
    }

    private calculateAverage(res: any) {
        let sum = 0;
        let q = 0;
        if (isArray(res)) {
            res.forEach(value => {
                if (value.hasOwnProperty('amount')) {
                    sum += value.amount;
                    q++;
                } else {
                    console.warn('Can\'t parse loan object: ', value)
                }
            });

            let avg = sum / q;
            this.result = 'Average amount: ' + avg.toFixed(2)
        }
        else {
            this.result = 'No loans available'
        }
    }

    private sendRequest(v: string) {
        let httpObserve: HttpObserve = 'response';
        const options = {
            headers: new HttpHeaders().set('X-Size', '1'),
            observe: httpObserve,
        };
        this.http.head(AppComponent.url + v, options).subscribe(res => {
            let sNumber = res.headers.get('X-Total');
            let number = parseInt(sNumber);
            this.loadAllItems(v, number)
        });

    }

}

class Rating {
    name: string;
    value: string;

    constructor(name, value: string) {
        this.name = name;
        this.value = value;
    }
}
