Skip to content

Commit

Permalink
Fetch office listing with search and display the results
Browse files Browse the repository at this point in the history
  • Loading branch information
victorchabbert committed Oct 22, 2020
1 parent a0eb277 commit da48076
Show file tree
Hide file tree
Showing 5 changed files with 176 additions and 2 deletions.
43 changes: 41 additions & 2 deletions src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,25 @@ import "./styles/global.scss";
import styles from "./app.module.scss";
import Header from "./templates/header";
import { Office } from "./models/offices";
import { OfficeSearch } from "./models/offices";
import OfficeList from "./templates/office-list/OfficeList";
import { getStats } from "./services/offices";
import { getOffices } from "./services/offices";
import StatsBar from "./templates/stats-bar/StatsBar";
import { Stat } from "./models/stats";

type State = {
sort: "asc" | "desc";
offices?: OfficeSearch;
query?: any;
stats?: Stat;
};
class App extends React.Component<{}, State> {
state: State = {
sort: "asc"
sort: "asc",
offices: undefined,
query: undefined,
stats: undefined
};

handleSortToggle = () => {
Expand All @@ -24,14 +36,41 @@ class App extends React.Component<{}, State> {
}
};

componentDidMount() {
getOffices().then(offices =>
this.setState(state => ({ ...state, offices }))
);
getStats().then(stats => this.setState({ stats }));
}

componentWillUpdate(_nextProps: any, nextState: State) {
if (nextState.query !== this.state.query && nextState.query !== undefined) {
this.handleOfficeSearch(nextState.query);
}
}

handleOfficeSearch = (query: string) => {
getOffices(query).then(offices =>
this.setState(state => ({ ...state, offices }))
);
};

render() {
return (
<div className={styles.app}>
<Header
sort={this.state.sort}
onSortToggle={this.handleSortToggle}
onSearchSubmit={console.log}
onSearchSubmit={query => this.setState({ query })}
/>
{this.state.stats && <StatsBar stats={this.state.stats} />}
{this.state.offices ? (
<OfficeList
offices={this.state.offices.data.sort(this.sortOffices)}
/>
) : (
false
)}
</div>
);
}
Expand Down
6 changes: 6 additions & 0 deletions src/models/stats.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export type Stat = {
office_count: number;
employee_avg: number;
continent_count: number;
spoken_languages: Array<string>;
};
51 changes: 51 additions & 0 deletions src/services/offices.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { fetch } from "../fake-fetch";
import { OfficeSearch } from "../models/offices";
import { Stat } from "../models/stats";

export function getOffices(query: string = ""): Promise<OfficeSearch> {
return fetch(
`http://fake.fabernovel.com/api/offices?query=${query}`
).then(r => r.json());
}

export function getStats(query?: string): Promise<Stat> {
const initialStat: Stat = {
office_count: 0,
employee_avg: 0,
continent_count: 0,
spoken_languages: []
};
const continents: Array<string> = [];
const languages: Array<Array<string>> = [];

return getOffices(query)
.then(offices => {
return [
offices,
offices.data.reduce(function(stats, office) {
continents.push(office.location.continent.label);
languages.push(office.location.language);

const stat: Stat = {
...stats,
employee_avg: stats.employee_avg + office.employees_count,
office_count: stats.office_count + 1
};
return stat;
}, initialStat)
] as [OfficeSearch, Stat];
})
.then(data => {
const [offices, stats] = data;
return {
...stats,
employee_avg: Math.round(stats.employee_avg / offices.data.length),
continent_count: continents.filter(
(value, i) => continents.indexOf(value) === i
).length,
spoken_languages: ([] as Array<string>)
.concat(...languages)
.filter((value, i, langs) => langs.indexOf(value) === i)
};
});
}
27 changes: 27 additions & 0 deletions src/templates/stats-bar/StatsBar.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import React from "react";
import { Stat } from "../../models/stats";
import styles from "./stats-bar.module.scss";

const StatsBar = ({ stats }: { stats: Stat }) => {
return (
<div className={styles.statBar}>
<StatItem label="offices" value={`${stats.office_count}`} />
<StatItem
label="avg employees per location"
value={`${stats.employee_avg}`}
/>
<StatItem label="continents" value={`${stats.continent_count}`} />
<StatItem label="languages" value={`${stats.spoken_languages.length}`} />
</div>
);
};

const StatItem = ({ label, value }: { label: string; value: string }) => (
<div>
<h1>
{value} <span>{label}</span>
</h1>
</div>
);

export default StatsBar;
51 changes: 51 additions & 0 deletions src/templates/stats-bar/stats-bar.module.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
.statBar {
max-width: 1280px;
margin: 0 auto;
padding: 0 16px 23px;

&::after {
content: "";
display: table;
clear: both;
}

div {
margin: 0;
float: left;
padding-right: 16px;
margin-right: 16px;
position: relative;

&:not(:last-of-type)::after {
content: "";
width: 1px;
position: absolute;
top: 50%;
bottom: 20%;
right: 1px;
background: #ccc;
}

&:nth-child(3n + 0) {
color: #E05A4F;
}

&:nth-child(3n + 1) {
color: #00BD9D;
}

&:nth-child(3n + 2) {
color: #008AFD;
}

h1 {
display: inline-block;
vertical-align: baseline;

span {
font-size: 12px;
color: #321000;
}
}
}
}

0 comments on commit da48076

Please sign in to comment.