initial commit

This commit is contained in:
Senad Uka
2017-10-16 09:10:30 +02:00
commit 8b938120ca
17 changed files with 2397 additions and 0 deletions

21
.gitignore vendored Normal file
View File

@@ -0,0 +1,21 @@
# See https://help.github.com/ignore-files/ for more about ignoring files.
# dependencies
/node_modules
# testing
/coverage
# production
/build
# misc
.DS_Store
.env.local
.env.development.local
.env.test.local
.env.production.local
npm-debug.log*
yarn-debug.log*
yarn-error.log*

1901
README.md Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,28 @@
import React, { Component } from 'react';
export default class SelectablePersonComponent extends Component{
constructor(props) {
super(props);
this.state = {personName: this.props.person.personName, isSelected: this.props.person.isSelected};
this.personSelectedChangedEventHandler = this.personSelectedChangedEventHandler.bind(this);
}
personSelectedChangedEventHandler(event) {
this.setState(prevState => ({
isSelected: !prevState.isSelected
}));
this.props.personsSelectionChanged(this.props.index);
}
render(){
return (
<div>
<div className = "horizontalDiv">
<input type = "checkbox" checked = {this.state.isSelected} onChange = {this.personSelectedChangedEventHandler}></input>
<div>{this.state.personName}</div>
</div>
</div>
)
}
}

18
package.json Normal file
View File

@@ -0,0 +1,18 @@
{
"name": "meetup-app",
"version": "0.1.0",
"private": true,
"dependencies": {
"react": "^15.6.1",
"react-dom": "^15.6.1"
},
"devDependencies": {
"react-scripts": "1.0.7"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test --env=jsdom",
"eject": "react-scripts eject"
}
}

BIN
public/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

40
public/index.html Normal file
View File

@@ -0,0 +1,40 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="theme-color" content="#000000">
<!--
manifest.json provides metadata used when your web app is added to the
homescreen on Android. See https://developers.google.com/web/fundamentals/engage-and-retain/web-app-manifest/
-->
<link rel="manifest" href="%PUBLIC_URL%/manifest.json">
<link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico">
<!--
Notice the use of %PUBLIC_URL% in the tags above.
It will be replaced with the URL of the `public` folder during the build.
Only files inside the `public` folder can be referenced from the HTML.
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`.
-->
<title>React App</title>
</head>
<body>
<noscript>
You need to enable JavaScript to run this app.
</noscript>
<div id="root"></div>
<!--
This HTML file is a template.
If you open it directly in the browser, you will see an empty page.
You can add webfonts, meta tags, or analytics to this file.
The build step will place the bundled scripts into the <body> tag.
To begin the development, run `npm start` or `yarn start`.
To create a production bundle, use `npm run build` or `yarn build`.
-->
</body>
</html>

15
public/manifest.json Normal file
View File

@@ -0,0 +1,15 @@
{
"short_name": "React App",
"name": "Create React App Sample",
"icons": [
{
"src": "favicon.ico",
"sizes": "192x192",
"type": "image/png"
}
],
"start_url": "./index.html",
"display": "standalone",
"theme_color": "#000000",
"background_color": "#ffffff"
}

35
src/App.css Normal file
View File

@@ -0,0 +1,35 @@
.App {
text-align: center;
}
.App-logo {
animation: App-logo-spin infinite 20s linear;
height: 80px;
}
.App-header {
background-color: #222;
height: 150px;
padding: 20px;
color: white;
}
.App-intro {
font-size: large;
}
.horizontalDiv div{
display: inline-block;
}
#outerDiv{
width: 50%;
margin-top: 12.5px;
margin-right: auto;
margin-left: auto;
}
@keyframes App-logo-spin {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}

130
src/App.js Normal file
View File

@@ -0,0 +1,130 @@
import React, { Component } from 'react';
import './App.css';
import PersonsListComponent from './PersonsListComponent.js';
class App extends Component {
constructor(props){
super(props);
this.state = {renderPersonsList: false, persons: [], currentPairsText: ""};
this.getNamesEventHandler = this.getNamesEventHandler.bind(this);
this.createTableEventHandler = this.createTableEventHandler.bind(this);
this.addAndSaveEventHandler = this.addAndSaveEventHandler.bind(this);
this.pairsTextChangedEventHandler = this.pairsTextChangedEventHandler.bind(this);
this.personsSelectionChangedEventHandler = this.personsSelectionChangedEventHandler.bind(this);
}
componentDidMount(){
this.currentPairs = JSON.parse(localStorage.getItem("currentPairs") || "[]");
this.currentPersons = JSON.parse(localStorage.getItem("currentPersons") || "[]");
// Load textarea text from local storage
this.setState({currentPairsText: JSON.parse(localStorage.getItem("currentPairsText")) || ""});
}
pairsTextChangedEventHandler(event) {
this.setState({currentPairsText: event.target.value});
}
getNamesEventHandler(event) {
if(this.state.currentPairsText.trim() === "")
return;
let allNames = this.state.currentPairsText.trim().replace(/\n\s*\n/g, '\n').replace(/(\r\n|\n|\r)/gm, "|").split("|");
allNames = allNames.map(name => name.trim());
console.log(allNames);
let names = [...new Set(allNames)];
if(this.currentPersons.length === 0)
this.currentPersons = names;
else{
// Check if there are some new names
let newNames = names.filter(name => !this.currentPersons.includes(name));
for(const newName of newNames)
this.currentPersons.push(newName);
}
let matrix = new Array(this.currentPersons.length);
for (let i = 0; i < matrix.length; ++i) {
matrix[i] = [];
}
for(let i = 0; i < allNames.length; i = i + 2){
const idx1 = this.currentPersons.indexOf(allNames[i]);
const idx2 = this.currentPersons.indexOf(allNames[i + 1]);
matrix[idx1].push(idx2);
matrix[idx2].push(idx1);
}
this.currentPairs = matrix;
this.setState({persons: names.map(name => ({personName: name, isSelected: true})), renderPersonsList: true});
}
createTableEventHandler(event) {
const selectedPersonNames = this.state.persons.filter(person => person.isSelected).map(person => person.personName);
let selectedPersonIndices = selectedPersonNames.map(name => this.currentPersons.indexOf(name));
let newPairs = "";
while(selectedPersonIndices.length > 1){
const firstIdx = selectedPersonIndices[0];
const pairIndices = this.currentPairs[firstIdx];
const missingPairIndices = Array.from(Array(this.currentPersons.length).keys()).filter(
(idx) => (idx !== firstIdx && !pairIndices.includes(idx) && selectedPersonIndices.includes(idx)));
// Person has had meetup with everyone
if(missingPairIndices.length === 0)
selectedPersonIndices.splice(0, 1);
else{
let pairsMatrix = this.currentPairs;
pairsMatrix[firstIdx].push(missingPairIndices[0]);
pairsMatrix[missingPairIndices[0]].push(firstIdx);
this.currentPairs = pairsMatrix;
newPairs += this.currentPersons[firstIdx] + " | " + this.currentPersons[missingPairIndices[0]] + "\n";
selectedPersonIndices.splice(0, 1);
selectedPersonIndices.splice(selectedPersonIndices.indexOf(missingPairIndices[0]), 1);
}
}
console.log(newPairs);
if(newPairs === "")
alert("Everyone (from the list of selected persons) had meetup with everyone else!");
else{
this.setState((prevState, props) => ({
currentPairsText: prevState.currentPairsText.trim() + "\n\n" + newPairs.trim()
}));
}
}
addAndSaveEventHandler(event) {
// Save textarea text to local storage
localStorage.setItem("currentPairsText", JSON.stringify(this.state.currentPairsText));
// Save current persons to local storage
localStorage.setItem("currentPersons", JSON.stringify(this.currentPersons));
// Save pairs matrix to local storage
localStorage.setItem("currentPairs", JSON.stringify(this.currentPairs));
}
personsSelectionChangedEventHandler(index){
let personsList = this.state.persons;
personsList[index].isSelected = !personsList[index].isSelected;
this.setState({
persons: personsList
});
}
render() {
return (
<div className = "App">
<div>
<h2>Meetup app</h2>
</div>
<textarea rows = "20" cols = "50" value = {this.state.currentPairsText} onChange = {this.pairsTextChangedEventHandler}></textarea>
<div className = "horizontalDiv">
<button onClick = {this.getNamesEventHandler}>GET NAMES</button>
<button onClick = {this.createTableEventHandler}>CREATE TABLE</button>
<button onClick = {this.addAndSaveEventHandler}>ADD AND SAVE</button>
</div>
{
this.state.renderPersonsList &&
<PersonsListComponent persons = {this.state.persons} personsSelectionChanged = {this.personsSelectionChangedEventHandler}/>
}
</div>
);
}
}
export default App;

8
src/App.test.js Normal file
View File

@@ -0,0 +1,8 @@
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
it('renders without crashing', () => {
const div = document.createElement('div');
ReactDOM.render(<App />, div);
});

View File

@@ -0,0 +1,15 @@
import React, { Component } from 'react';
import SelectablePersonComponent from './SelectablePersonComponent.js';
export default class PersonsListComponent extends Component{
render(){
return(
<div id = "outerDiv">
{
this.props.persons.map((person, index) =>
(<SelectablePersonComponent key = {index} index = {index} personsSelectionChanged = {this.props.personsSelectionChanged} person = {person}/>))
}
</div>
)
}
}

View File

@@ -0,0 +1,27 @@
import React, { Component } from 'react';
export default class SelectablePersonComponent extends Component{
constructor(props) {
super(props);
this.state = {personName: this.props.person.personName, isSelected: this.props.person.isSelected};
this.personSelectedChangedEventHandler = this.personSelectedChangedEventHandler.bind(this);
}
personSelectedChangedEventHandler(event) {
this.setState(prevState => ({
isSelected: !prevState.isSelected
}));
this.props.personsSelectionChanged(this.props.index);
}
render(){
return (
<div>
<div className = "horizontalDiv">
<input type = "checkbox" checked = {this.state.isSelected} onChange = {this.personSelectedChangedEventHandler}></input>
<div>{this.state.personName}</div>
</div>
</div>
)
}
}

5
src/index.css Normal file
View File

@@ -0,0 +1,5 @@
body {
margin: 0;
padding: 0;
font-family: sans-serif;
}

8
src/index.js Normal file
View File

@@ -0,0 +1,8 @@
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import registerServiceWorker from './registerServiceWorker';
import './index.css';
ReactDOM.render(<App />, document.getElementById('root'));
registerServiceWorker();

7
src/logo.svg Normal file
View File

@@ -0,0 +1,7 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 841.9 595.3">
<g fill="#61DAFB">
<path d="M666.3 296.5c0-32.5-40.7-63.3-103.1-82.4 14.4-63.6 8-114.2-20.2-130.4-6.5-3.8-14.1-5.6-22.4-5.6v22.3c4.6 0 8.3.9 11.4 2.6 13.6 7.8 19.5 37.5 14.9 75.7-1.1 9.4-2.9 19.3-5.1 29.4-19.6-4.8-41-8.5-63.5-10.9-13.5-18.5-27.5-35.3-41.6-50 32.6-30.3 63.2-46.9 84-46.9V78c-27.5 0-63.5 19.6-99.9 53.6-36.4-33.8-72.4-53.2-99.9-53.2v22.3c20.7 0 51.4 16.5 84 46.6-14 14.7-28 31.4-41.3 49.9-22.6 2.4-44 6.1-63.6 11-2.3-10-4-19.7-5.2-29-4.7-38.2 1.1-67.9 14.6-75.8 3-1.8 6.9-2.6 11.5-2.6V78.5c-8.4 0-16 1.8-22.6 5.6-28.1 16.2-34.4 66.7-19.9 130.1-62.2 19.2-102.7 49.9-102.7 82.3 0 32.5 40.7 63.3 103.1 82.4-14.4 63.6-8 114.2 20.2 130.4 6.5 3.8 14.1 5.6 22.5 5.6 27.5 0 63.5-19.6 99.9-53.6 36.4 33.8 72.4 53.2 99.9 53.2 8.4 0 16-1.8 22.6-5.6 28.1-16.2 34.4-66.7 19.9-130.1 62-19.1 102.5-49.9 102.5-82.3zm-130.2-66.7c-3.7 12.9-8.3 26.2-13.5 39.5-4.1-8-8.4-16-13.1-24-4.6-8-9.5-15.8-14.4-23.4 14.2 2.1 27.9 4.7 41 7.9zm-45.8 106.5c-7.8 13.5-15.8 26.3-24.1 38.2-14.9 1.3-30 2-45.2 2-15.1 0-30.2-.7-45-1.9-8.3-11.9-16.4-24.6-24.2-38-7.6-13.1-14.5-26.4-20.8-39.8 6.2-13.4 13.2-26.8 20.7-39.9 7.8-13.5 15.8-26.3 24.1-38.2 14.9-1.3 30-2 45.2-2 15.1 0 30.2.7 45 1.9 8.3 11.9 16.4 24.6 24.2 38 7.6 13.1 14.5 26.4 20.8 39.8-6.3 13.4-13.2 26.8-20.7 39.9zm32.3-13c5.4 13.4 10 26.8 13.8 39.8-13.1 3.2-26.9 5.9-41.2 8 4.9-7.7 9.8-15.6 14.4-23.7 4.6-8 8.9-16.1 13-24.1zM421.2 430c-9.3-9.6-18.6-20.3-27.8-32 9 .4 18.2.7 27.5.7 9.4 0 18.7-.2 27.8-.7-9 11.7-18.3 22.4-27.5 32zm-74.4-58.9c-14.2-2.1-27.9-4.7-41-7.9 3.7-12.9 8.3-26.2 13.5-39.5 4.1 8 8.4 16 13.1 24 4.7 8 9.5 15.8 14.4 23.4zM420.7 163c9.3 9.6 18.6 20.3 27.8 32-9-.4-18.2-.7-27.5-.7-9.4 0-18.7.2-27.8.7 9-11.7 18.3-22.4 27.5-32zm-74 58.9c-4.9 7.7-9.8 15.6-14.4 23.7-4.6 8-8.9 16-13 24-5.4-13.4-10-26.8-13.8-39.8 13.1-3.1 26.9-5.8 41.2-7.9zm-90.5 125.2c-35.4-15.1-58.3-34.9-58.3-50.6 0-15.7 22.9-35.6 58.3-50.6 8.6-3.7 18-7 27.7-10.1 5.7 19.6 13.2 40 22.5 60.9-9.2 20.8-16.6 41.1-22.2 60.6-9.9-3.1-19.3-6.5-28-10.2zM310 490c-13.6-7.8-19.5-37.5-14.9-75.7 1.1-9.4 2.9-19.3 5.1-29.4 19.6 4.8 41 8.5 63.5 10.9 13.5 18.5 27.5 35.3 41.6 50-32.6 30.3-63.2 46.9-84 46.9-4.5-.1-8.3-1-11.3-2.7zm237.2-76.2c4.7 38.2-1.1 67.9-14.6 75.8-3 1.8-6.9 2.6-11.5 2.6-20.7 0-51.4-16.5-84-46.6 14-14.7 28-31.4 41.3-49.9 22.6-2.4 44-6.1 63.6-11 2.3 10.1 4.1 19.8 5.2 29.1zm38.5-66.7c-8.6 3.7-18 7-27.7 10.1-5.7-19.6-13.2-40-22.5-60.9 9.2-20.8 16.6-41.1 22.2-60.6 9.9 3.1 19.3 6.5 28.1 10.2 35.4 15.1 58.3 34.9 58.3 50.6-.1 15.7-23 35.6-58.4 50.6zM320.8 78.4z"/>
<circle cx="420.9" cy="296.5" r="45.7"/>
<path d="M520.5 78.1z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.6 KiB

View File

@@ -0,0 +1,51 @@
// In production, we register a service worker to serve assets from local cache.
// This lets the app load faster on subsequent visits in production, and gives
// it offline capabilities. However, it also means that developers (and users)
// will only see deployed updates on the "N+1" visit to a page, since previously
// cached resources are updated in the background.
// To learn more about the benefits of this model, read https://goo.gl/KwvDNy.
// This link also includes instructions on opting out of this behavior.
export default function register() {
if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) {
window.addEventListener('load', () => {
const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`;
navigator.serviceWorker
.register(swUrl)
.then(registration => {
registration.onupdatefound = () => {
const installingWorker = registration.installing;
installingWorker.onstatechange = () => {
if (installingWorker.state === 'installed') {
if (navigator.serviceWorker.controller) {
// At this point, the old content will have been purged and
// the fresh content will have been added to the cache.
// It's the perfect time to display a "New content is
// available; please refresh." message in your web app.
console.log('New content is available; please refresh.');
} else {
// At this point, everything has been precached.
// It's the perfect time to display a
// "Content is cached for offline use." message.
console.log('Content is cached for offline use.');
}
}
};
};
})
.catch(error => {
console.error('Error during service worker registration:', error);
});
});
}
}
export function unregister() {
if ('serviceWorker' in navigator) {
navigator.serviceWorker.ready.then(registration => {
registration.unregister();
});
}
}

88
uptonow.txt Normal file
View File

@@ -0,0 +1,88 @@
Reuben Montehermoso | Senad Uka
Eric Hulburd | Katarzyna Frey
Kamil Grabowski | James Marvin
Krzysiek Herod | Luca Del Bianco
Krzysztof Wawer | Ben Jacobs
Adam Florczak | Daniel Mihalyi
Damian Aruj | Steven Joseph
Mary Grace Andrade | Fernando Catacora
Grzegorz Biziel | Monika Glier
Jess Jacobs | Jacque Presas
Attila Aros | Gabriele Favalessa
Cezary Kopacz | Carlo Liwanag
Fernando Catacora | Krzysztof Wawer
Steven Joseph | Cezary Kopacz
Adam Florczak | Grzegorz Biziel
Eric Hulburd | Kamil Grabowski
Carlo Liwanag | Damian Aruj
Krzysiek Herod | James Marvin
Mary Grace Andrade | Nick Allen
Gabriele Favalessa | Monika Glier
Jess Jacobs | Luca Del Bianco
Reuben Montehermoso | Katarzyna Frey
Senad Uka | Daniel Mihalyi
Piotr Szotkowski | Ben Jacobs
Cezary Kopacz | James Marvin
Jess Jacobs | Grzegorz Biziel
Eric Hulburd | Krzysztof Wawer
Mary Grace Andrade | Piotr Szotkowski
Kamil Grabowski | Nick Allen
Senad Uka | Luca Del Bianco
Monika Glier | Reuben Montehermoso
Adam Florczak | Krzysiek Herod
Fernando Catacora | Carlo Liwanag
Gabriele Favalessa | Katarzyna Frey
Damian Aruj | Steven Joseph
Fernando Catacora | Grzegorz Biziel
Damian Aruj | Eric Hulburd
Krzysiek Herod | James Marvin
Ric Szopa | Steven Joseph
Senad Uka | Monika Glier
Nick Allen | Karen Bevis
Katarzyna Frey | Gabriele Favalessa
Jess Jacobs | Kamil Grabowski
Dusan Pantelic | Piotr Szotkowski
Fernando Catacora | Piotr Szotkowski
Damian Aruj | Grzegorz Biziel
Krzysiek Herod | Eric Hulburd
Ric Szopa | James Marvin
Senad Uka | Steven Joseph
Nick Allen | Monika Glier
Katarzyna Frey | Karen Bevis
Jess Jacobs | Gabriele Favalessa
Dusan Pantelic | Kamil Grabowski1
Fernando Catacora | Gabriele Favalessa
Damian Aruj | Kamil Grabowski
Krzysiek Herod | Piotr Szotkowski
Ric Szopa | Grzegorz Biziel
Senad Uka | Eric Hulburd
Nick Allen | Monika Glier
Jess Jacobs | Steven Joseph
Dusan Pantelic | James Marvin
Fernando Catacora | James Marvin
Damian Aruj | Gabriele Favalessa
Krzysiek Herod | Kamil Grabowski
Ric Szopa | Piotr Szotkowski
Senad Uka | Grzegorz Biziel
Nick Allen | Eric Hulburd
Jess Jacobs | Monika Glier
Dusan Pantelic | Steven Joseph
Grzegorz Biziel | Jess Jacobs
Kamil Grabowski | James Marvin
Katarzyna Frey | Krzysiek Herod
Senad Uka | Jorge Vazquez
Gabriele Favalessa | Mary Grace Andrade
Adam Florczak | Nick Allen
Reuben Montehermoso | Steven Joseph
Damian Aruj | Krzysztof Wawer
Patrick Downing | Fernando Catacora
Carlo Liwanag | Eric Hulburd