IN THIS ARTICLE
In this tutorial, we’ll show you how to build an online realtime auction system in React using PubNub Realtime Messaging and React-Bootstrap. The auction application will have a gallery of artwork and you can join the bidding event to place bids on the art. While placing your bids, you can simultaneously check the bids placed by other users in realtime. Your app will also have a dashboard that can be used by the admin to track the viewers and their bids.
What and Why React?
React is a JavaScript library for building user interfaces. React gives you a template language and some function hooks to render HTML. Your bundles of HTML/JavaScript are called “components”. Components are similar to JavaScript functions. They accept arbitrary inputs called props and return React elements. These elements describe what should appear on the screen.
Developers love ReactJS because it is highly performant and render changes almost instantly. The best part about ReactJS is that it is a relatively small framework and does not take too much time to learn!
Getting Started
The full GitHub code repository can be found here.
You’ll first have to sign up for a PubNub account to get your unique publish/subscribe keys. Then, install PubNub package using the following command in your terminal.
npm install --save pubnub pubnub-react
Import the required libraries.
import PubNubReact from 'pubnub-react'; import React, { Component } from 'react'; import { Route } from 'react-router-dom'; import PropTypes from 'prop-types'
PubNub React is a wrapper of PubNub Javascript. It adds a few extra features to simplify the integration with React. In order to get the integration between your React’s Component and PubNub, PubNubReact
will be the way to get this without any kind of difficulty or extra job when you need to render data in your UI.
Here’s how you can initialize PubNub in your application.
constructor(props) { super(props); this.pubnub = new PubNubReact({ publishKey: 'YOUR PUBLISH KEY', subscribeKey: 'YOUR SUBSCRIBE KEY' }); this.pubnub.init(this); }
Let’s divide the application into Bidding Portal and Admin Dashboard. The bidding portal would be used by customers to bid prices during an auction. And the dashboard can be used by the admins to track values of the auction.
Bidding Portal
Registration
Let’s have a registration modal to register the user. Make the registration mandatory. This way, you can keep track of every bid that comes in.
Inside render()
:
<form onSubmit={this.handleSubmit}> <ModalHeader>Live Bidding Registration</ModalHeader> <ModalBody> <label>Name:</label> <input type="text" value={this.state.name} onChange={this.handleChangeName} className="form-control" /> </ModalBody> <ModalFooter> <Button type="submit" onClick={this.handleSubmit} color="success" className="btn btn-success">Register</Button> <Button color="danger" onClick={this.toggle}>Cancel</Button> </ModalFooter> </form>
Homepage
Routing helps us build a single page application in React. To use routing, we have to pull down React Router and React DOM:
npm install react-router-dom --save
This is how you can build a single page application using routers by switching between the tabs.
<main> <Switch> <Route exact path='/' component={Home}/> <Route path='/products' component={Products}/> <Route path='/contact' component={Contact}/> <Route path='/art' component={Art}/> <Route path='/about' component={About}/> <Route path='/user' component={User}/> <Route path='/dashboard' component={Dashboard}/> </Switch> </main>
Products – PubNub Channels
Products here represent different channels of PubNub. You can re-use React components in such a way that the buttons on different art products lead you to different channels.
The Cardholder component receives values passed by the <Cardholder/> tag in the products page.
<Cardholder name="Art 1" description="Description of Art 1" image={image9}/>
Here’s a small code snippet of Cardholder, which can be used to build n number of products by passing different product names and their associated subtitles and description.
Additionally, you can make the buttons lead you to different PubNub channels based on the product.
<Card> <CardImg top width="10%" src={this.props.image} alt="Card image cap" /> <CardBody> <CardTitle><h1>{this.props.name}</h1></CardTitle> <CardSubtitle>Card subtitle</CardSubtitle> <CardText>{this.props.description}</CardText> <Route render={({ history}) => ( <Button className="btn btn-info" onClick={() => { history.push(channelName) }}> Join the event </Button> )} /> </CardBody> </Card>
Placing a Bid
The most interesting part of your application is the page where you place the bid. The buttons on the products page lead you to their corresponding PubNub channels, which in turn lead you to the corresponding bidding pages, where you can submit the amount.
<form onSubmit={this.handleSubmit} style={{marginLeft: 10 + 'em'}}> <h2> Starting bid: $30 </h2> <label> <FormControl type="number" pattern="[0-9]*" inputMode="numeric" value={this.state.value} onChange={this.handleChange} /> </label> <Button className="btn btn-info btn-lg" type="submit" value="Submit" style={{marginLeft: 10 + 'px'}}>Place Bid</Button> </form>
PubNub Realtime Messaging
Once you submit your price into the input form, PubNub publishes the message to the hosts of the auction through the art’s channel with 1/4th the second latency. If you subscribe to the same channel, you can view the bids of various users who are currently participating in the bid.
handleSubmit(event) { var startingBid = 30; var data = localStorage.getItem('Username'); var message = data +" : "+ this.state.value; if(data != null) { if(this.state.value > startingBid && this.state.value < 1000000) { this.pubnub.publish({ message: message, channel: 'art' }); } else { alert("Enter value between Starting Bid and 1000000!"); } }else { alert("Enter username!"); } event.preventDefault(); } componentWillMount() { this.pubnub.subscribe({ channels: ['art'], withPresence: false }); this.pubnub.getMessage('art1', (msg) => { var data = localStorage.getItem('username'); this.last_message = msg.message; }); }
Dashboard
PubNub Realtime Messaging
You can find out the size of the map by using {message.length}
and also find out the highest bid from the map and display it on the dashboard as follows:
export default class Dashboard extends Component { constructor(props) { super(props); this.state = {highest: 0, people: 0}; this.pubnub = new PubNubReact({ publishKey: 'ENTER YOUR PUBLISH KEY', subscribeKey: 'ENTER YOUR SUBSCRIBE KEY' }); this.pubnub.init(this); } componentWillMount() { this.pubnub.subscribe({ channels: ['art'], withPresence: true }); this.pubnub.getMessage('art', (msg) => { this.setState ({ highest: msg.message }); }); } render() { const messages = this.pubnub.getMessage('art'); return ( <div> <Cards data={messages.length} highest={this.state.highest} people={this.state.people}/> <ListGroup flush>{messages.map((m, index) => <ListGroupItem><h1 key={'message' + index}>{m.message}</h1></ListGroupItem>)}</ListGroup> </div> ); } }
Presence
Presence delivers the status of users and devices connected to PubNub’s channels at any point under a millisecond. PubNub requires you to enable Presence on their PubNub Dashboard. Here’s how to enable Presence. Now you can execute this piece of code to find out how many users/devices are connected to PubNub’s channel at the moment.
this.pubnub.hereNow({ channels: ["art"], includeState: true },(status,response)=> { this.setState ({ people: response.totalOccupancy }); });
const presence = this.pubnub.hereNow('art');
Here’s how you can design the Admin Dashboard cards to display the number of bids, highest bid, and the number of viewers. You can also implement graphs and charts to represent these values graphically.
class Cards extends Component { constructor(props) { super(props); this.toggle = this.toggle.bind(this); this.toggleFade = this.toggleFade.bind(this); this.state = { collapse: true, fadeIn: true, timeout: 300 }; } toggle() { this.setState({ collapse: !this.state.collapse }); } toggleFade() { this.setState((prevState) => { return { fadeIn: !prevState }}); } render() { return ( <div className="animated fadeIn"> <Row> <Col xs="12" sm="6" md="4"> <Card className="text-white bg-info card text-center"> <CardBody> <blockquote className="card-bodyquote"> <header>Number of Bids</header> <h1>{this.props.data}</h1> </blockquote> </CardBody> </Card> </Col> <Col xs="12" sm="6" md="4"> <Card className="text-white bg-warning card text-center"> <CardBody> <blockquote className="card-bodyquote"> <header>Highest bid</header> <h1>{this.props.highest}</h1> </blockquote> </CardBody> </Card> </Col> <Col xs="12" sm="6" md="4"> <Card className="text-white bg-success card text-center"> <CardBody> <blockquote className="card-bodyquote"> <header>Users online</header> <h1>{this.props.people}</h1> </blockquote> </CardBody> </Card> </Col> </Row> </div> ); } } Cards.propTypes = { data: PropTypes.string, highest: PropTypes.string, people: PropTypes.string }; export default Cards;
Ideas for Implementation
Congratulations! Now you have your own small bidding portal. You can have OAuth 2.0 for login instead of username modal and you can design the dashboard to display statistics of multiple artwork. You can also grant access to admin for bid-calling like “Going once.. Going twice…” and then pick the winner in the admin dashboard.