Client-side trade using Firebase
This demonstrates trading items in Firebase using only client-side code and audit records.
by Firebase
HTML
<script src="http://cdn.firebase.com/js/client/1.0.11/firebase.js"></script>
<script src="https://cdn.firebase.com/js/simple-login/1.3.2/firebase-simple-login.js"></script>
<script src="https://rawgit.com/firebase/firebase-util/master/firebase-util.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.6/angular.min.js"></script>
<script src="https://cdn.firebase.com/libs/angularfire/0.7.1/angularfire.min.js"></script>
<p> <a href="#" ng-click="login('user1')">join as Chuck</a> | <a href="#" ng-click="login('user2')">join as Bruce</a> |
<a href="https://gist.github.com/katowulf/d858d9809670dce4ab31" target="_blank">check out the security rules</a> |
<a href="https://kato-game.firebaseio.com/.json?print=pretty" target="_blank">check out the data</a>
(Open <a href="http://jsfiddle.net/katowulf/J4kay/embedded/result/" target="_blank">two windows</a> for great justice!)</p>
<p>How this works: Both users suggest an item to trade. One both have accepted, the items trade places and no changes can be made.</p>
<div class="require-login">
<h1>I am logged in as: {{profile.name}} ({{uid}})</h1>
<div class="col">
<h2>{{users[selectedUser].name}}'s Offer</h2>
<div ng-show="!offeredItem">Nothing yet; offer a trade!</div>
<div ng-show="!!offeredItem">{{offeredItem.name}} (${{offeredItem.value}})
<button ng-click="accept()" ng-class="{active: isAccepted===true}">accept</button>
<button ng-click="decline()" ng-class="{active: isAccepted===false}">decline</button>
</div>
</div>
<div class="col require-login">
<h2>My Items</h2>
<ul>
<li ng-repeat="(key,item) in myItems">{{item.name}} (${{item.value}})
<button ng-click="setOffer(key)" ng-class="{active: myOffer === key}">trade this</button> <span ng-show="myOffer === key" class="{{responseMessage()}}">{{responseMessage()}}</span>
</li>
</ul>
</div>
</div>
CSS
.col {
width: 45%;
float: left;
}
body.not-initialized .require-login {
display: none;
}
.declined, .accepted, .pending {
background-color: yellow;
}
.error, .declined {
color: red;
}
.accepted: {
color: green;
}
.pending {
color: blue;
}
button.active {
background-color: green;
}
JavaScript
var fb = new Firebase('https://kato-game.firebaseio.com/');
var app = angular.module('app', ['firebase']);
app.controller('ctrl', function ($scope, myItems, $firebase, tradeQueue, loginManager, $timeout) {
// we just load all the data because it's easier; yay demo!
$scope.users = $firebase(fb.child('users'));
$scope.items = $firebase(fb.child('items'));
// we only have one offer for simplicity; yay mocks!
$scope.offer = $firebase(fb.child('offers/singleton'));
$scope.offer.$on('change', checkOfferStatus);
loginManager.setCallback(loadProfile);
var myRole, otherRole;
// A key point in the trade! When I change or set my offered item
// I must revoke the accepted status for the other user; this is
// forced by security rules so that each time I change what I offer
// his acceptance is automagically cancelled. Also note that I set it
// to null (pendng) rather than false (declined)
$scope.setOffer = function (key) {
var data = {};
data[myRole + '_offer'] = key;
data['accepted_by_' + otherRole] = null;
console.log('update', data);
$scope.offer.$update(data);
};
$scope.accept = function () {
// we can't just set value on offer and call $scope.offer.$save() here
// because we're not actually allowed to write to the whole offer, just
// the accepted_* fields and *_item fields
$scope.offer.$getRef().child('accepted_by_' + myRole).set(true);
};
$scope.decline = function () {
$scope.offer.$getRef().child('accepted_by_' + myRole).set(false);
}
function checkOfferStatus() {
var offer = $scope.offer;
updateOfferedItem();
if( !$scope.uid ) { return; }
// another key point in the trade! When both parties have accepted the trade agreement
// then the items cannot be changed and the booleans cannot be changed. Then I take my
// item. Once both parties have...