Skip to content

Commit e0b196e

Browse files
authored
Merge pull request #1 from KoolTheba/dev
Feat: deploy app in main
2 parents 637be5d + a347b0e commit e0b196e

File tree

22 files changed

+28228
-0
lines changed

22 files changed

+28228
-0
lines changed

.gitignore

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,3 +102,27 @@ dist
102102

103103
# TernJS port file
104104
.tern-port
105+
106+
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
107+
108+
# dependencies
109+
/node_modules
110+
/.pnp
111+
.pnp.js
112+
113+
# testing
114+
/coverage
115+
116+
# production
117+
/build
118+
119+
# misc
120+
.DS_Store
121+
.env.local
122+
.env.development.local
123+
.env.test.local
124+
.env.production.local
125+
126+
npm-debug.log*
127+
yarn-debug.log*
128+
yarn-error.log*

package-lock.json

Lines changed: 15611 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
{
2+
"name": "post-github-battle-react-project",
3+
"version": "0.1.0",
4+
"private": true,
5+
"dependencies": {
6+
"@testing-library/jest-dom": "^5.11.4",
7+
"@testing-library/react": "^11.1.0",
8+
"@testing-library/user-event": "^12.1.10",
9+
"query-string": "^7.1.1",
10+
"react": "^17.0.2",
11+
"react-dom": "^17.0.2",
12+
"react-icons": "^4.2.0",
13+
"react-router-dom": "^4.3.1",
14+
"react-scripts": "4.0.3",
15+
"web-vitals": "^1.0.1"
16+
},
17+
"scripts": {
18+
"start": "react-scripts start",
19+
"build": "react-scripts build",
20+
"test": "react-scripts test",
21+
"eject": "react-scripts eject"
22+
},
23+
"eslintConfig": {
24+
"extends": [
25+
"react-app",
26+
"react-app/jest"
27+
]
28+
},
29+
"browserslist": {
30+
"production": [
31+
">0.2%",
32+
"not dead",
33+
"not op_mini all"
34+
],
35+
"development": [
36+
"last 1 chrome version",
37+
"last 1 firefox version",
38+
"last 1 safari version"
39+
]
40+
}
41+
}

public/index.html

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="utf-8" />
5+
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
6+
<meta name="viewport" content="width=device-width, initial-scale=1" />
7+
<meta name="theme-color" content="#000000" />
8+
<meta
9+
name="description"
10+
content="Web site created using create-react-app"
11+
/>
12+
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
13+
<title>React App</title>
14+
</head>
15+
<body>
16+
<noscript>You need to enable JavaScript to run this app.</noscript>
17+
<div id="root"></div>
18+
<!--
19+
This HTML file is a template.
20+
If you open it directly in the browser, you will see an empty page.
21+
22+
You can add webfonts, meta tags, or analytics to this file.
23+
The build step will place the bundled scripts into the <body> tag.
24+
25+
To begin the development, run `npm start` or `yarn start`.
26+
To create a production bundle, use `npm run build` or `yarn build`.
27+
-->
28+
</body>
29+
</html>

src/App.js

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import React from 'react'
2+
import {
3+
BrowserRouter as Router,
4+
Route,
5+
Switch
6+
} from 'react-router-dom'
7+
8+
import { ThemeProvider } from './contexts/theme'
9+
10+
import Loading from './components/Loading'
11+
import Nav from './components/Nav'
12+
import './index.css'
13+
14+
const Popular = React.lazy(() => import('./components/Popular'))
15+
const Battle = React.lazy(() => import('./components/Battle'))
16+
const Result = React.lazy(() => import('./components/Results'))
17+
18+
class App extends React.Component {
19+
state = {
20+
theme: 'light',
21+
toggleTheme: () => {
22+
this.setState(({ theme }) => ({
23+
theme: theme === 'light' ? 'dark': 'light'
24+
}))
25+
}
26+
}
27+
28+
render(){
29+
return (
30+
<Router>
31+
<ThemeProvider value={this.state}>
32+
<div className={this.state.theme}>
33+
<div className='container'>
34+
<Nav />
35+
<React.Suspense fallback={<Loading />}>
36+
<Switch>
37+
<Route exact path={'/'} component={Popular} />
38+
<Route exact path={'/battle'} component={Battle} />
39+
<Route path={'/battle/results'} component={Result} />
40+
<Route render={() => <h1>404</h1>}/>
41+
</Switch>
42+
</React.Suspense>
43+
</div>
44+
</div>
45+
</ThemeProvider>
46+
</Router>
47+
)
48+
}
49+
}
50+
51+
export default App;

src/App.test.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import { render, screen } from '@testing-library/react';
2+
import App from './App';
3+
4+
test('renders learn react link', () => {
5+
render(<App />);
6+
const linkElement = screen.getByText(/learn react/i);
7+
expect(linkElement).toBeInTheDocument();
8+
});

src/Components/Battle.js

Lines changed: 181 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,181 @@
1+
import React from 'react'
2+
import PropTypes from 'prop-types'
3+
import { ThemeConsumer } from '../contexts/theme'
4+
import { Link } from 'react-router-dom'
5+
6+
import { FaUserFriends, FaFighterJet, FaTrophy, FaTimesCircle } from 'react-icons/fa'
7+
8+
function Instructions(){
9+
return (
10+
<ThemeConsumer>
11+
{({ theme }) => (
12+
<div className='instructions-container'>
13+
<h1 className='center-text header-lg'>
14+
Instructions
15+
</h1>
16+
<ol className='container-sm grid center-text battle-instructions'>
17+
<li>
18+
<h3 className='header-sm'>Enter two Github users</h3>
19+
<FaUserFriends className={`bg-${theme}`} color='rgb(255, 191, 116)' size={140} />
20+
</li>
21+
<li>
22+
<h3 className='header-sm'>Battle</h3>
23+
<FaFighterJet className={`bg-${theme}`} color='#727272' size={140} />
24+
</li>
25+
<li>
26+
<h3 className='header-sm'>See the winners</h3>
27+
<FaTrophy className={`bg-${theme}`} color='rgb(255, 215, 0)' size={140} />
28+
</li>
29+
</ol>
30+
</div>
31+
)}
32+
</ThemeConsumer>
33+
)
34+
}
35+
36+
class PlayerInput extends React.Component {
37+
state = {
38+
username: ''
39+
}
40+
41+
handleSubmit = (e) => {
42+
e.preventDefault()
43+
this.props.onSubmit(this.state.username)
44+
}
45+
46+
handleChange = (e) => {
47+
this.setState({
48+
username: e.target.value
49+
})
50+
}
51+
52+
render(){
53+
return (
54+
<ThemeConsumer>
55+
{({ theme }) => (
56+
<form className='column player' onSubmit={this.handleSubmit}>
57+
<label htmlFor='username' className='player-label'>
58+
{this.props.label}
59+
</label>
60+
<div className='row player-inputs'>
61+
<input
62+
type='text'
63+
id='username'
64+
className={`input-${theme}`}
65+
placeholder='github username'
66+
autoComplete='off'
67+
value={this.state.username}
68+
onChange={this.handleChange}
69+
/>
70+
<button
71+
className={`btn ${theme} === 'dark' ? light-btn : dark-btn`}
72+
type='submit'
73+
disabled={!this.state.username}
74+
>Submit</button>
75+
</div>
76+
</form>
77+
)}
78+
</ThemeConsumer>
79+
)
80+
}
81+
}
82+
83+
PlayerInput.propTypes = {
84+
onSubmit: PropTypes.func.isRequired,
85+
label: PropTypes.string.isRequired
86+
}
87+
88+
function PlayerPreview({username, onReset, label}){
89+
return (
90+
<ThemeConsumer>
91+
{({ theme }) => (
92+
<div className='column player'>
93+
<h3 className='player-label'>{label}</h3>
94+
<div className={`row bg-${theme}`}>
95+
<div className='player-info'>
96+
<img
97+
className='avatar-small'
98+
src={`https://github.com/${username}.png?size=200`}
99+
alt={`Avatar for ${username}`}
100+
/>
101+
<a
102+
href={`https://github.com/${username}`}
103+
className='link'>
104+
{username}
105+
</a>
106+
</div>
107+
<button className='btn-clear flex-center' onClick={onReset}>
108+
<FaTimesCircle color='rgb(194, 57, 42)' size={26} />
109+
</button>
110+
</div>
111+
</div>
112+
)}
113+
</ThemeConsumer>
114+
)
115+
}
116+
117+
PlayerPreview.propTypes = {
118+
username: PropTypes.string.isRequired,
119+
onReset: PropTypes.func.isRequired,
120+
label: PropTypes.string.isRequired
121+
}
122+
123+
// BATTLE COMPONENT
124+
export default class Battle extends React.Component {
125+
state = {
126+
playerOne: null,
127+
playerTwo: null,
128+
}
129+
130+
handleSubmit = (id, player) => {
131+
this.setState({
132+
[id]: player
133+
})
134+
}
135+
136+
handleReset = (id) => {
137+
this.setState({
138+
[id]: null
139+
})
140+
}
141+
142+
render(){
143+
const { playerOne, playerTwo } = this.state
144+
145+
return (
146+
<React.Fragment>
147+
<Instructions />
148+
<div className='players-container'>
149+
<h1 className='center-text header-lg'>Players</h1>
150+
<div className='row space-around'>
151+
{playerOne === null
152+
? <PlayerInput
153+
label='Player One'
154+
onSubmit={(player) => this.handleSubmit('playerOne', player)}
155+
/>
156+
: <PlayerPreview username={playerOne} label='Player One' onReset={() => this.handleReset('playerOne')} />
157+
158+
}
159+
{playerTwo === null
160+
? <PlayerInput
161+
label='Player Two'
162+
onSubmit={(player) => this.handleSubmit('playerTwo', player)}
163+
/>
164+
: <PlayerPreview username={playerTwo} label='Player Two' onReset={() => this.handleReset('playerTwo')} />
165+
}
166+
</div>
167+
{playerOne && playerTwo && (
168+
<Link
169+
className='btn dark-btn btn-space'
170+
to={{
171+
pathname: '/battle/results',
172+
search: `playerOne=${playerOne}&playerTwo=${playerTwo}`
173+
}}
174+
>Battle
175+
</Link>
176+
)}
177+
</div>
178+
</React.Fragment>
179+
)
180+
}
181+
}

src/Components/Card.js

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import React from "react";
2+
import PropTypes from "prop-types";
3+
import { ThemeConsumer } from "../contexts/theme";
4+
5+
export default function Card ({
6+
header,
7+
subheader,
8+
avatar,
9+
href,
10+
name,
11+
children
12+
}) {
13+
return (
14+
<ThemeConsumer>
15+
{({ theme }) => (
16+
<div className={`card bg-${theme}`}>
17+
<h4 className='header-lg center-text'>
18+
{header}
19+
</h4>
20+
<img
21+
className='avatar'
22+
src={avatar}
23+
alt={`Avatar for ${name}`}
24+
/>
25+
{subheader && (
26+
<h4 className='center-text'>
27+
{subheader}
28+
</h4>
29+
)}
30+
<h2 className='center-text'>
31+
<a className='link' href={href}>
32+
{name}
33+
</a>
34+
</h2>
35+
{children}
36+
</div>
37+
)}
38+
</ThemeConsumer>
39+
)
40+
}
41+
42+
Card.propTypes = {
43+
header: PropTypes.string.isRequired,
44+
subheader: PropTypes.string,
45+
avatar: PropTypes.string.isRequired,
46+
href: PropTypes.string.isRequired,
47+
name: PropTypes.string.isRequired
48+
}

0 commit comments

Comments
 (0)