Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
dc8d765
Push branch with codebase for code review
eddubbs Oct 19, 2018
c8d3f7d
Changed transpilation onto ES2015. It removed all let/const that coul…
eddubbs Oct 19, 2018
792646d
'User image in history block is not aligned properly',
eddubbs Oct 19, 2018
8d67fb6
Added validation of user name,
eddubbs Oct 19, 2018
0e04d50
Done updateGithubHistory();
eddubbs Oct 23, 2018
b3e39c5
Added GithubUser class and covered constructor with mocha test
eddubbs Oct 23, 2018
a431452
Created Profile component
eddubbs Oct 23, 2018
78d36d5
Tests for Profile, GithubUser
eddubbs Oct 23, 2018
1ca9fc4
Moved GithubUser onto entity dir
eddubbs Oct 23, 2018
286d525
moved GithubUserTest onto new dir
eddubbs Oct 23, 2018
9653081
Added GithubEvent and GithubEventTest
eddubbs Oct 23, 2018
cfd8529
Test collection of github events,
eddubbs Oct 23, 2018
3b0a520
Created timelineComponent,
eddubbs Oct 23, 2018
bc6fb82
Added static constructor for response from Event
eddubbs Oct 23, 2018
d72d6df
added static getPayloadActionName for handling the key-nesting over r…
eddubbs Oct 23, 2018
864411b
getFilledNode tested over even/uneven is-primary,
eddubbs Oct 23, 2018
7e14ee1
Added proper nesting within timeline
eddubbs Oct 23, 2018
c4e1acc
State management added to GithubInput,
eddubbs Oct 23, 2018
ef30b82
Added static constructor for GithubUser with proper regexp, and cover…
eddubbs Oct 24, 2018
0c150ae
Profile is filled on proper request
eddubbs Oct 24, 2018
9dc4a91
Working app with new features
eddubbs Oct 24, 2018
dd205da
Fast lookout over code
eddubbs Oct 24, 2018
5e6a63c
Added spinner and message, where no public data was found
eddubbs Oct 24, 2018
5bdc428
Changed bulma classes to fit:
eddubbs Oct 24, 2018
95a1709
I assume that size reduced from almost 500KB onto 4.0KB is enough?
eddubbs Oct 24, 2018
fe8eea7
Resolved issue with wrong check over githubUser,
eddubbs Oct 24, 2018
da6383d
added .gitignore
eddubbs Oct 24, 2018
8603323
removed redundant usage of require
eddubbs Oct 24, 2018
998c25b
Merge branch 'bug-hunt' of https://github.com/eddubbs/tsh into new-fe…
eddubbs Oct 24, 2018
0f27662
Added handler for user not found response,
eddubbs Oct 24, 2018
bd35407
Added even/uneven color changes in timeline,
eddubbs Oct 24, 2018
9395df8
Added (no information) or bio onto profile component,
eddubbs Oct 24, 2018
ac28b60
Added nickname styling over even/uneven
eddubbs Oct 24, 2018
98263bc
Removed source map to reduce size into <150KB
eddubbs Oct 25, 2018
bbc8997
changed let to const in GithubEvent
eddubbs Oct 25, 2018
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.idea
dist
node_modules
43 changes: 41 additions & 2 deletions README.md
100644 → 100755
Original file line number Diff line number Diff line change
@@ -1,2 +1,41 @@
# tsh_github
github tsh app
# GH-Browser

A browser for Github users. Entering github username will display user's details and history of his public events.

## Installation

Install npm packages:
```
yarn
```


## Develop locally

1. Run:

```
yarn start
```

2. In your browser, navigate to: [http://localhost:2000/](http://localhost:2000/)

## Build production-ready app

```
yarn build
```

### Test the code

1. To test the code, run:
```
yarn test
```

# Technical details

* Bundler: [Webpack](https://webpack.js.org/)
* DOM Manipulation: [Cash-DOM](https://github.com/kenwheeler/cash)
* CSS styling: [Bulma CSS](https://bulma.io/)
* [Github API](https://api.github.com/)
71 changes: 71 additions & 0 deletions TASK.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
# TSH recruitment task

Hi there, stranger! I'm glad you can help us with our messy code.


## Step 1: Code Review

Create empty repository and make Pull Request with the whole codebase you've got from us. Then make a code review
for it. Don't hesitate to point out each concern - we want to make the code eventually perfect!
We'll be grateful for all your thoughts on it.


## Step 2: Bug hunt

1. For some reason the app doesn't fully load data. This happens on all major browsers: Chrome, Firefox, IE11.
When you resolve the issue, make sure it works on all mentioned browsers

2. The user image in the history block is not aligned properly. Can you do something about it?


## Step 3: New features

As you could probably see, the project lacks some more or less important features. Can you help us making it done?


1. The username field is missing validation. Prepare a simple validation for the input field:
* not-empty
* allow only characters: `a-z`, `0-9`, `-`, `_`

When the value is not valid, display a red border around the field.

2. The History block is just a mockup. Make it dynamic. After user data has been loaded, use the below URL:
`https://api.github.com/users/{username}/events/public`
to load user's latest events. Populate the history list with events gotten from the above step.

For now we want only 2 event types to be included:

* `PullRequestEvent` - both "opened" and "closed" Pull Requests
* `PullRequestReviewCommentEvent`

please take into account that other events will be implemented later.

Github documentation may become handy: https://developer.github.com/v3/


```
**Warning:** be aware that Github uses request limiting. When it occurs, try to mitigate it. Or just make
your code perfect at first time :)
```

3. Hide fake Profile and History fields until the data is being loaded.
We've prepare a spinner element (in HTML) to indicate loading data, but forgot to use it, Can you make it visible
when there are pending requests?

4. Currently the Profile column has width of 1/3 screen. Let's change it's size:
* below 768px: make it 100% (as it is now)
* 768-1280px: make it 50%
* 1280px and above: make it 30%

5. The production build is quite big: **556kB**. Can you optimize it to fit in less than 350kB? The less
the better.


# Rules

**Each Step should be in separate commit.**
That way you will first create a PR and then have at least 8 more commits:
* 1 containing whole code for Pull request
* 2 for bug fixes
* 5 for new features

50 changes: 50 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
{
"name": "calc",
"version": "0.1.0",
"description": "",
"main": "index.js",
"scripts": {
"start": "./node_modules/.bin/webpack-dev-server",
"build": "./node_modules/.bin/webpack -p",
"watch": "./node_modules/.bin/webpack --watch",
"test": "./node_modules/mocha/bin/mocha --compilers js:babel-core/register test/ --recursive --require test/plainJsTestHelper.js"
},
"babel": {
"presets": [
"stage-3",
"latest"
]
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"babel-core": "~6.26.0",
"babel-loader": "~7.1.2",
"babel-preset-env": "~1.6.0",
"babel-preset-latest": "^6.16.0",
"babel-preset-stage-3": "^6.17.0",
"clean-webpack-plugin": "~0.1.17",
"css-loader": "~0.28.7",
"extract-text-webpack-plugin": "^4.0.0-beta.0",
"file-loader": "~1.1.4",
"html-loader": "~0.5.1",
"html-webpack-plugin": "^4.0.0-beta.2",
"node-sass": "~4.5.3",
"sass-loader": "~6.0.6",
"style-loader": "~0.18.2",
"webpack": "^4.22.0",
"webpack-cli": "^3.1.2",
"webpack-dev-server": "^3.1.10"
},
"dependencies": {
"babel-polyfill": "^6.26.0",
"bulma": "^0.7.1",
"bulma-start": "^0.0.2",
"bulma-timeline": "^2.0.3",
"cash-dom": "^2.1.7",
"chai": "^4.2.0",
"jsdom": "^12.2.0",
"mocha": "^5.2.0"
}
}
64 changes: 64 additions & 0 deletions src/app.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import './assets/scss/app.scss';
import {GithubUser} from "./entity/GithubUser";
import {Profile} from "./components/Profile";
import {Timeline} from "./components/Timeline";
import {GithubClient} from "./client/GithubClient";
import {GithubInput} from "./components/GithubInput";

export class App {
constructor() {
const self = this;

Object.defineProperty(self, 'githubUser', {
enumerable: true,
writable: true,
});

self.initializeApp();
}

initializeApp() {
let self = this;
const githubInput = new GithubInput('github-user-fetch', self);
githubInput.initialize();
}

fetchProfile(githubUser) {
const self = this;
GithubInput.runSpinner();
GithubClient.fetchUserProfile(githubUser, self);
}

fetchTimeline(githubUser) {
const self = this;
GithubClient.fetchUserTimeline(githubUser, self);
}

updateGithubProfile(body) {
const self = this;
self.githubUser = new GithubUser(body);
const profile = new Profile(self.githubUser, 'githubProfile');
profile.appendHtml();
self.fetchTimeline(self.githubUser, self);
}

updateGithubTimeline(body) {
const timeline = new Timeline('user-timeline', body);
timeline.appendHtml();
GithubInput.hideSpinner();
}

handleInvalidFetchState(e) {
if (!(e instanceof Error)) {
throw new Error('invalid argument for function');
}

const rawProfile = document.getElementById('githubProfile');
const rawTimeline = document.getElementById('user-timeline');

rawProfile.innerHTML = '<h2 class="subtitle is-4">Profile</h2><span>user not found</span>';
rawTimeline.innerHTML = '<h2 class="subtitle is-4">History</h2>' +
'<img src="https://s3.eu-central-1.amazonaws.com/blazej.m8b.pl/tsh/images/2kvyb4.jpg">';
GithubInput.hideSpinner();
}
}
65 changes: 65 additions & 0 deletions src/assets/scss/app.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@

.navbar {
border-bottom: 1px solid #eee;
margin-bottom: 8px;
}

.gh-username {
display: grid;
grid-template-rows: auto auto;
display: -ms-grid;
-ms-grid-rows: auto auto;
}

.gh-username img {
width: 32px;
margin: 5px;
-ms-grid-row: 1;
}

.gh-username a {
color: #18d17d;
font-weight: 500;
font-size: 18px;
-ms-grid-row: 2;
}

.gh-username.grey a {
color: #dbdbdb;
}

.gh-username a:hover {
font-weight: 600;
cursor: pointer;
}

#profile-bio{
margin-top:10px;
word-wrap: break-word;
max-width: 20vw;
}

.timeline .timeline-item {
padding-bottom:1em;
}

.input--error {
border: solid 1px red;
}

.repo-name.grey a {
color: #dbdbdb;
font-weight: bold;
}

.repo-name.green a {
color: #18d17d;
font-weight: bold;
}

@media screen and (max-width: 1088px) {
// Added this padding, because it was looking awful. Really.
body .container {
padding: 20px;
}
}
45 changes: 45 additions & 0 deletions src/client/GithubClient.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import {GithubUser} from "../entity/GithubUser";
import {GithubInput} from "../components/GithubInput";

// Due to there are no credentials over calls by now, there is no need of constructor/credentials builder;

export class GithubClient {
static fetchUserProfile(githubUser, observerCallback) {
// observerCallback must have updateGithubProfile(body) method;
if (!(githubUser instanceof GithubUser)) {
throw new Error('githubUser is not instance of itself');
}

fetch('https://api.github.com/users/' + githubUser.name)
.then(response => { return GithubClient.handleResponse(response) })
.then(body => {observerCallback.updateGithubProfile(body)})
.catch(e => {observerCallback.handleInvalidFetchState(e)})
}

static fetchUserTimeline(githubUser, observerCallback) {
// observerCallback must have updateGithubProfile(body) method;
if (!(githubUser instanceof GithubUser)) {
throw new Error('githubUser is not instance of itself');
}

let endpoint = 'https://api.github.com/users/{username}/events/public';
endpoint = endpoint.replace('{username}', githubUser.login);

fetch(endpoint)
.then(response => {
return GithubClient.handleResponse(response) })
.then(body => observerCallback.updateGithubTimeline(body))
}

static handleResponse(response) {
if (200 === response.status) {
return response.json()
}

if (404 === response.status) {
throw new Error('Could not fetch username');
}

throw new Error('Could not fetch. Response status: ' + response.status);
}
}
Loading