mirror of
https://github.com/sudoxnym/habitica.git
synced 2026-08-03 08:21:07 +00:00
feat(gifts): allow gifting from balance
This commit is contained in:
parent
57bfee02cf
commit
7e9b92fcad
6 changed files with 134 additions and 20 deletions
|
|
@ -29,4 +29,7 @@
|
|||
|
||||
// Hide visually and from screenreaders, but maintain layout
|
||||
.invisible
|
||||
visibility: hidden
|
||||
visibility: hidden
|
||||
|
||||
.transparent
|
||||
opacity: 0.5
|
||||
|
|
@ -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();
|
||||
})
|
||||
}
|
||||
}
|
||||
])
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
});
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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')
|
||||
Loading…
Reference in a new issue