feat(gifts): allow gifting from balance

This commit is contained in:
Tyler Renelle 2014-11-25 14:53:52 -07:00
parent 57bfee02cf
commit 7e9b92fcad
6 changed files with 134 additions and 20 deletions

View file

@ -29,4 +29,7 @@
// Hide visually and from screenreaders, but maintain layout
.invisible
visibility: hidden
visibility: hidden
.transparent
opacity: 0.5

View file

@ -2,6 +2,11 @@
habitrpg.controller("GroupsCtrl", ['$scope', '$rootScope', 'Shared', 'Groups', '$http', '$q', 'User', 'Members', '$state', 'Notification',
function($scope, $rootScope, Shared, Groups, $http, $q, User, Members, $state, Notification) {
Members.selectMember('9', function(){
$rootScope.openModal('send-gift',{controller:'MemberModalCtrl'})
});
$scope.isMemberOfPendingQuest = function(userid, group) {
if (!group.quest || !group.quest.members) return false;
if (group.quest.active) return false; // quest is started, not pending
@ -125,6 +130,18 @@ habitrpg.controller("GroupsCtrl", ['$scope', '$rootScope', 'Shared', 'Groups', '
$scope.$close();
});
}
$scope.gift = {
type: 'gems',
gems: {amount:0, fromBalance:true},
subscription: {},
message:''
};
$scope.sendGift = function(uuid, gift){
$http.post('/api/v2/members/'+uuid+'/gift', gift).success(function(){
Notification.text('Gift sent!')
$rootScope.User.sync();
})
}
}
])

View file

@ -29,33 +29,67 @@ api.getMember = function(req, res, next) {
})
}
api.sendPrivateMessage = function(req,res,next){
var sendMessage = function(user, member, msg){
var message = groups.chatDefaults(msg, user);
shared.refPush(member.inbox.messages, message);
member.inbox.newMessages++;
member._v++;
member.markModified('inbox.messages');
var message = groups.chatDefaults(msg, member);
shared.refPush(user.inbox.messages, _.defaults({sent:true},message));
user.markModified('inbox.messages');
}
api.sendPrivateMessage = function(req, res, next){
async.waterfall([
fetchMember(req.params.uuid),
function(member, cb){
function(member, cb) {
if (~member.inbox.blocks.indexOf(res.locals.user._id) // can't send message if that user blocked me
|| ~res.locals.user.inbox.blocks.indexOf(member._id) // or if I blocked them
|| member.inbox.optOut) { // or if they've opted out of messaging
return cb({code:401, err: "Can't send message to this user."});
return cb({code: 401, err: "Can't send message to this user."});
}
var message = groups.chatDefaults(req.body.message, res.locals.user);
shared.refPush(member.inbox.messages, message);
member.inbox.newMessages++;
member._v++;
member.markModified('inbox.messages');
var message = groups.chatDefaults(req.body.message, member);
shared.refPush(res.locals.user.inbox.messages, _.defaults({sent:true},message));
res.locals.user.markModified('inbox.messages');
member.save(cb);
},
function(a,b,cb){
res.locals.user.save(cb);
sendMessage(res.locals.user, member, req.body.message);
async.parallel([
function (cb2) { member.save(cb2) },
function (cb2) { res.locals.user.save(cb2) }
], cb);
}
], function(err){
if (err) return sendErr(err, res, next);
res.send(200);
})
}
api.sendGift = function(req, res, next){
async.waterfall([
fetchMember(req.params.uuid),
function(member, cb) {
// Gems
switch (req.body.type) {
case "gems":
var amt = req.body.gems.amount / 4,
user = res.locals.user;
if (amt < 1 || user.balance < amt)
return cb({code: 401, err: "Amount must be within 0 and your current number of gems."});
member.balance += amt;
user.balance -= amt;
var msg = "`Hello "+member.profile.name+", "+user.profile.name+" has sent you "+amt+" gems!` ";
if (req.body.message) msg += req.body.message;
sendMessage(user, member, msg);
return async.parallel([
function (cb2) { member.save(cb2) },
function (cb2) { res.locals.user.save(cb2) }
], cb);
case "subscription":
return cb();
default:
return cb({code:400, err:"Body must contain a gems:{amount,fromBalance} or subscription:{months} object"});
}
}
], function(err) {
if (err) return sendErr(err, res, next);
res.send(200);
});
}

View file

@ -602,6 +602,16 @@ module.exports = (swagger, v2) ->
]
middleware: [auth.auth]
action: user.blockUser
"/members/{uuid}/gift":
spec:
method: 'POST'
description: 'Send a gift to a member'
parameters: [
path 'uuid', 'The UUID of the member', 'string'
body '', '{gems:{amount:Number, fromBalance:Boolean}, subscription:{months:Number}}', 'object'
]
middleware: [auth.auth]
action: members.sendGift
# ---------------------------------
# Hall of Heroes / Patrons

View file

@ -20,7 +20,6 @@ script(id='modals/buyGems.html', type='text/ng-template')
td
p
small.muted=env.t('paymentMethods')
//.btn.btn-primary(ng-click='showStripe()')=env.t('payWithCard')
.btn.btn-primary(ng-click='showStripe()')=env.t('card')
a.btn.btn-warning(href='/paypal/checkout?_id={{user._id}}&apiToken={{user.apiToken}}') PayPal

View file

@ -38,6 +38,8 @@ script(type='text/ng-template', id='modals/member.html')
span.glyphicon.glyphicon-ban-circle
button.btn.btn-md.btn-default(tooltip=env.t('sendPM'), ng-click="openModal('private-message',{controller:'MemberModalCtrl'})", tooltip-placement='right')
span.glyphicon.glyphicon-envelope
button.btn.btn-md.btn-default(tooltip="Send Gift", ng-click="openModal('send-gift',{controller:'MemberModalCtrl'})", tooltip-placement='right')
span.glyphicon.glyphicon-gift
button.btn.btn-default(ng-click='$close()')=env.t('close')
script(type='text/ng-template', id='modals/private-message.html')
@ -48,3 +50,52 @@ script(type='text/ng-template', id='modals/private-message.html')
.modal-footer
button.btn.btn-primary(ng-click='sendPrivateMessage(profile._id, _message)')=env.t("send")
button.btn.btn-default(ng-click='$close()')=env.t('cancel')
script(type='text/ng-template', id='modals/send-gift.html')
.modal-header
h4 Send Gift to {{::profile.profile.name}}
.modal-body
.panel.panel-default(class="{{gift.type=='gems' ? 'panel-primary' : 'transparent'}}", ng-click='gift.type="gems"')
.panel-heading
.pull-right
span(ng-show='gift.gems.fromBalance') From {{user.balance*4}} Gems
span(ng-hide='gift.gems.fromBalance') Total: ${{gift.gems.amount/4}} USD
| Gems
.panel-body
.row
.col-md-6
.form-group
input.form-control(type='number', placeholder='Number of Gems', min='0', max='{{gift.gems.fromBalance ? user.balance*4 : ""}}', ng-model='gift.gems.amount')
.col-md-6
.btn-group
a.btn.btn-default(ng-class="{active:gift.gems.fromBalance}", ng-click="gift.gems.fromBalance=true") From Balance
a.btn.btn-default(ng-class="{active:!gift.gems.fromBalance}", ng-click="gift.gems.fromBalance=false") Purchase
.panel.panel-default(class="{{gift.type=='subscription' ? 'panel-primary' : 'transparent'}}", ng-click='gift.type="subscription"')
.panel-heading Subscription
.panel-body
.form-group
.radio
label
input(type="radio", name="subRadio", value="1", ng-model='gift.subscription.months')
| 1 Month ($5)
.radio
label
input(type="radio", name="subRadio", value="3", ng-model='gift.subscription.months')
| 3 Months ($15)
.radio
label
input(type="radio", name="subRadio", value="6", ng-model='gift.subscription.months')
| 6 Months ($30)
.radio
label
input(type="radio", name="subRadio", value="12", ng-model='gift.subscription.months')
| 1 Year ($48)
textarea.form-control(rows='3', ng-model='gift.message', placeholder='Personal message (optional)')
.modal-footer
- var fromBal = "gift.type=='gems' && gift.gems.fromBalance"
button.btn.btn-primary(ng-show=fromBal, ng-click='sendGift(profile._id, gift)')=env.t("send")
a.btn.btn-primary(ng-hide=fromBal, ng-click='showStripe({uuid:profile._id})')=env.t('card')
a.btn.btn-warning(ng-hide=fromBal, href='/paypal/checkout?uuid={{profile._id}}') PayPal
button.btn.btn-default(ng-click='$close()')=env.t('cancel')