Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
martin-helmich committed Apr 2, 2017
0 parents commit b513bd5
Show file tree
Hide file tree
Showing 15 changed files with 460 additions and 0 deletions.
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
18 changes: 18 additions & 0 deletions index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>MyEvents</title>

<!--<link rel="stylesheet" href="./node_modules/bootstrap/dist/css/bootstrap.min.css" />-->
</head>
<body>
<div id="myevents-app"></div>

<script src="./node_modules/react/dist/react.js"></script>
<script src="./node_modules/react-dom/dist/react-dom.js"></script>
<script src="./node_modules/promise-polyfill/promise.min.js"></script>
<script src="./node_modules/whatwg-fetch/fetch.js"></script>
<script src="./dist/bundle.js"></script>
</body>
</html>
36 changes: 36 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
{
"name": "myevents-ui",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"dependencies": {
"@types/react": "^15.0.16",
"@types/react-dom": "^0.14.23",
"@types/react-router-dom": "^4.0.1",
"@types/whatwg-fetch": "0.0.33",
"bootstrap": "^3.3.7",
"promise-polyfill": "^6.0.2",
"react": "^15.4.2",
"react-dom": "^15.4.2",
"react-router-dom": "^4.0.0",
"whatwg-fetch": "^2.0.3"
},
"devDependencies": {
"awesome-typescript-loader": "^3.1.2",
"babel-core": "^6.24.0",
"babel-loader": "^6.4.1",
"babel-preset-es2015": "^6.24.0",
"css-loader": "^0.27.3",
"file-loader": "^0.10.1",
"source-map-loader": "^0.2.0",
"style-loader": "^0.16.0",
"ts-loader": "^2.0.3",
"typescript": "^2.2.1",
"url-loader": "^0.5.8"
}
}
55 changes: 55 additions & 0 deletions src/components/event_booking_form.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import * as React from "react";
import {Event} from "../model/event";
import {FormRow} from "./form_row";

export interface EventBookingFormProps {
event: Event;
onSubmit: (seats: number) => any
}

export interface EventBookingFormState {
selectedAmount: number;
}

export class EventBookingForm extends React.Component<EventBookingFormProps, EventBookingFormState> {
constructor(p: EventBookingFormProps) {
super(p);

this.state = {
selectedAmount: 1
}
}

private handleNewAmount(n: number) {
const newState: EventBookingFormState = {
selectedAmount: n
};

this.setState(newState);
}

render() {
return <div>
<h2>Book tickets for {this.props.event.Name}!</h2>
<form className="form-horizontal">
<FormRow label="Event">
<p className="form-control-static">{this.props.event.Name}</p>
</FormRow>
<FormRow label="Number of tickets">
<select className="form-control" value={this.state.selectedAmount} onChange={e => this.handleNewAmount(parseInt(e.target.value))}>
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
<option value="4">4</option>
</select>
</FormRow>
<FormRow label="Price">
<p className="form-control-static">{this.state.selectedAmount * 99}</p>
</FormRow>
<FormRow>
<button className="btn btn-primary" onClick={() => this.props.onSubmit(this.state.selectedAmount)}>Submit order</button>
</FormRow>
</form>
</div>
}
}
49 changes: 49 additions & 0 deletions src/components/event_booking_form_container.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import * as React from "react";
import {EventBookingForm} from "./event_booking_form";
import {Event} from "../model/event";

export interface EventBookingFormContainerProps {
eventID: string;
eventServiceURL: string;
bookingServiceURL: string;
}

export interface EventBookingFormState {
loading: boolean;
event?: Event;
}

export class EventBookingFormContainer extends React.Component<EventBookingFormContainerProps, EventBookingFormState> {
constructor(p: EventBookingFormContainerProps) {
super(p);

this.state = {
loading: true
};

fetch(p.eventServiceURL + "/events/" + p.eventID)
.then<Event>(resp => resp.json())
.then(event => {
this.setState({
loading: false,
event: event
});
})
}

render() {
if (this.state.loading) {
return <div>Loading...</div>;
}

if (!this.state.event) {
return <div>Unknown error</div>;
}

return <EventBookingForm event={this.state.event} onSubmit={amount => this.handleSubmit(amount)}/>
}

private handleSubmit(amount: number) {

}
}
30 changes: 30 additions & 0 deletions src/components/event_list.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import * as React from "react";
import {EventListItem} from "./event_list_item";
import {Event} from "../model/event";

export interface EventListProps {
events: Event[]
onEventBooked: (e: Event) => any
}

export class EventList extends React.Component<EventListProps, {}> {
public render() {
const items = this.props.events.map(event =>
<EventListItem key={event.ID} event={event} onBooked={() => this.props.onEventBooked(event)}/>
);

return <table className="table">
<thead>
<tr>
<th>Name</th>
<th>Where</th>
<th colSpan={2}>When (start/end)</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
{items}
</tbody>
</table>;
}
}
43 changes: 43 additions & 0 deletions src/components/event_list_container.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import * as React from "react";
import {EventList} from "./event_list";
import {Loader} from "./loader";
import {Event} from "../model/event";

export interface EventListContainerProps {
eventServiceURL: string;
}

export interface EventListContainerState {
loading: boolean;
events: Event[];
}

export class EventListContainer extends React.Component<EventListContainerProps, EventListContainerState> {
constructor(p: EventListContainerProps) {
super(p);

this.state = {
loading: true,
events: []
};

fetch(p.eventServiceURL + "/events", {method: "GET"})
.then<Event[]>(response => response.json())
.then(events => {
this.setState({
loading: false,
events: events
})
})
}

private handleEventBooked(e: Event) {
console.log("booking event...");
}

render() {
return <Loader loading={this.state.loading} message="Loading events...">
<EventList events={this.state.events} onEventBooked={e => this.handleEventBooked(e)}/>
</Loader>
}
}
29 changes: 29 additions & 0 deletions src/components/event_list_item.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import * as React from "react";
import {Link} from "react-router-dom";
import {Event} from "../model/event";

export interface EventListItemProps {
event: Event;
selected?: boolean;

onBooked: () => any;
}

export class EventListItem extends React.Component<EventListItemProps, {}> {
render() {
const start = new Date(this.props.event.StartDate * 1000);
const end = new Date(this.props.event.EndDate * 1000);

const locationName = this.props.event.Location ? this.props.event.Location.Name : "unknown";

console.log(this.props.event);

return <tr>
<td>{this.props.event.Name}</td>
<td>{locationName}</td>
<td>{start.toLocaleDateString()}</td>
<td>{end.toLocaleDateString()}</td>
<td><Link to={`/events/${this.props.event.ID}/book`} className="btn btn-primary">Book now!</Link></td>
</tr>
}
}
19 changes: 19 additions & 0 deletions src/components/form_row.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import * as React from "react";

export interface FormRowProps {
label?: string;
}

export class FormRow extends React.Component<FormRowProps, {}> {
render() {
const label = this.props.label ? <label className="col-sm-2 control-label">{this.props.label}</label> : undefined;
const cls = "col-sm-10" + (this.props.label ? "" : " col-sm-offset-2");

return <div className="form-group">
{label}
<div className={cls}>
{this.props.children}
</div>
</div>
}
}
20 changes: 20 additions & 0 deletions src/components/loader.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import * as React from "react";

export interface LoaderProps {
loading: boolean;
message?: string;
}

export class Loader extends React.Component<LoaderProps, {}> {
render() {
const msg = this.props.message || "Loading. Please wait...";

if (this.props.loading) {
return <div>{msg}</div>
}

return <div>
{this.props.children}
</div>;
}
}
30 changes: 30 additions & 0 deletions src/components/navigation.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import * as React from "react";
import {Link} from "react-router-dom";

export interface NavigationProps {
brandName: string;
}

export class Navigation extends React.Component<NavigationProps, {}> {
render() {
return <nav className="navbar navbar-default">
<div className="container">
<div className="navbar-header">
{/*<button type="button" className="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1" aria-expanded="false">
<span className="sr-only">Toggle navigation</span>
<span className="icon-bar"></span>
<span className="icon-bar"></span>
<span className="icon-bar"></span>
</button>*/}
<Link to="/" className="navbar-brand">{this.props.brandName}</Link>
</div>

{/*<div className="collapse navbar-collapse" id="bs-example-navbar-collapse-1">*/}
<ul className="nav navbar-nav">
<li className="active"><Link to="/">Events</Link></li>
</ul>
{/*</div>*/}
</div>
</nav>
}
}
36 changes: 36 additions & 0 deletions src/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import * as React from "react";
import * as ReactDOM from "react-dom";
import {HashRouter as Router, Route} from "react-router-dom";
import {EventListContainer} from "./components/event_list_container";
import {Navigation} from "./components/navigation";
import {EventBookingFormContainer} from "./components/event_booking_form_container";

declare function require(n: string): any;

const bs = require("bootstrap/dist/css/bootstrap.css");

class App extends React.Component<{}, {}> {
render() {
const eventList = () => <EventListContainer eventServiceURL="http://localhost:8181"/>;
const eventBooking = ({match}:any) => <EventBookingFormContainer eventID={match.params.id}
eventServiceURL="http://localhost:8181"
bookingServiceURL="http://localhost:8282"/>;

return <Router>
<div>
<Navigation brandName="MyEvents"/>
<div className="container">
<h1>My Events</h1>

<Route exact path="/" component={eventList}/>
<Route path="/events/:id/book" component={eventBooking}/>
</div>
</div>
</Router>
}
}

ReactDOM.render(
<App/>,
document.getElementById("myevents-app")
);
Loading

0 comments on commit b513bd5

Please sign in to comment.