Skip to content
This repository has been archived by the owner on Feb 8, 2018. It is now read-only.

Commit

Permalink
Merge pull request #4077 from gratipay/preen-takes
Browse files Browse the repository at this point in the history
bring back the takes UI
  • Loading branch information
chadwhitacre authored Aug 9, 2016
2 parents 7db4d94 + 14a5f24 commit 2d22820
Show file tree
Hide file tree
Showing 22 changed files with 433 additions and 233 deletions.
4 changes: 2 additions & 2 deletions gratipay/models/team/mixins/membership.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,10 +59,10 @@ def get_memberships(self, current_participant=None):
member['balance'] = take['balance']
member['percentage'] = take['percentage']

member['removal_allowed'] = current_participant == self
member['editing_allowed'] = False
member['is_current_user'] = False
if current_participant is not None:
if current_participant:
member['removal_allowed'] = current_participant.username == self.owner
if member['username'] == current_participant.username:
member['is_current_user'] = True
if take['ctime'] is not None:
Expand Down
21 changes: 12 additions & 9 deletions gratipay/models/team/mixins/takes.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
from collections import OrderedDict
from decimal import Decimal as D


ZERO = D('0.00')
PENNY = D('0.01')

Expand Down Expand Up @@ -55,7 +54,7 @@ def set_take_for(self, participant, take, recorder, cursor=None):
"""Set the amount a participant wants to take from this team during payday.
:param Participant participant: the participant to set the take for
:param int take: the amount the participant wants to take
:param Decimal take: the amount the participant wants to take
:param Participant recorder: the participant making the change
:return: the new take as a py:class:`~decimal.Decimal`
Expand All @@ -71,19 +70,23 @@ def set_take_for(self, participant, take, recorder, cursor=None):
"""
def vet(p):
assert not p.is_suspicious, p.id
assert p.is_claimed, p.id
assert p.email_address, p.id
assert p.has_verified_identity, p.id
if p.is_suspicious:
raise NotAllowed("user must not be flagged as suspicious")
elif not p.has_verified_identity:
raise NotAllowed("user must have verified his identity")
elif not p.email_address:
raise NotAllowed("user must have added at least one email address")
elif not p.is_claimed:
raise NotAllowed("user must have claimed the account")

vet(participant)
vet(recorder)

if recorder.username == self.owner:
if take not in (ZERO, PENNY):
raise NotAllowed('owner can only add and remove members, not otherwise set takes')
raise NotAllowed("owner can only add and remove members, not otherwise set takes")
elif recorder != participant:
raise NotAllowed('can only set own take')
raise NotAllowed("can only set own take")

with self.db.get_cursor(cursor) as cursor:
cursor.run("LOCK TABLE takes IN EXCLUSIVE MODE") # avoid race conditions
Expand All @@ -93,7 +96,7 @@ def vet(p):

if recorder.username != self.owner:
if recorder == participant and participant.id not in old_takes:
raise NotAllowed('can only set take if already a member of the team')
raise NotAllowed("can only set take if already a member of the team")

new_take = cursor.one( """
Expand Down
2 changes: 1 addition & 1 deletion gratipay/testing/browser.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
"""
from __future__ import absolute_import, division, print_function, unicode_literals

import os
import atexit
import os

from splinter.browser import _DRIVERS

Expand Down
11 changes: 11 additions & 0 deletions js/gratipay/confirm.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
Gratipay.confirm = function(message, yes, no) {
var $m = $('.modal');
$m.show();
$('.confirmation-message', $m).html(message);
$('.yes', $m).off('click').click(function() { yes(); Gratipay.confirm.close(); });
$('.no', $m).off('click').click(function() { no(); Gratipay.confirm.close(); });
};

Gratipay.confirm.close = function() {
$('.modal').hide();
};
166 changes: 84 additions & 82 deletions js/gratipay/team.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
Gratipay.team = (function() {

var $t = function(selector) { return selector ? $(selector, 'table.team') : $('table.team'); };

function init() {
$('#lookup-container form').submit(add);
$('#lookup-results').on('click', 'li', selectLookupResult);
$('#query').focus().keyup(lookup);
$t('.lookup-container form').submit(add);
$t('.lookup-results').on('click', 'li', selectLookupResult);
$t('.query').focus().keyup(lookup);

jQuery.get("index.json").success(function(members) {
jQuery.get("index.json").success(function(d) {
$('.loading-indicator').remove();
drawRows(members);
drawRows(d.available, d.members);
});
}

Expand All @@ -21,35 +24,27 @@ Gratipay.team = (function() {
var take = num(member.take);

if (member.editing_allowed)
return [ 'form', {'id': 'take'}
, ['input', { 'value': take
, 'data-username': member.username
, 'data-take': take // useful to reset form
, 'tabindex': '1'
}]
];
return [ 'form'
, {'class': 'edit knob'}
, [ 'input'
, { 'value': take
, 'data-id': member.participant_id
, 'data-take': take // useful to reset form
, 'tabindex': '1'
}
]
];

if (member.removal_allowed)
return [ 'span', { 'class': 'remove'
, 'data-username': member.username
}, take];
return ['span', {'class': 'remove knob', 'data-id': member.participant_id}, take];

return take;
}

function drawRows(members) {
nmembers = members.length - 1; // includes the Team itself, which we don't
// want to enumerate
function drawRows(available, members) {
var nmembers = members.length;
var rows = [];

if (nmembers === 0) {
rows.push(Gratipay.jsonml(
[ 'tr'
, ['td', {'colspan': '6', 'class': 'no-members'}, "No members"]
]
));
}

for (var i=0, len=members.length; i<len; i++) {
var member = members[i];
var increase = '';
Expand All @@ -61,43 +56,50 @@ Gratipay.team = (function() {
if (member.take === member.max_this_week)
increase = 'max';

if (i < nmembers)
rows.push(Gratipay.jsonml(
[ 'tr'
, ['td', {'class': 'n'}, (i === nmembers ? '' : nmembers - i)]
, ['td', ['a', {'href': '/'+member.username+'/'}, member.username]]
, ['td', {'class': 'figure last_week'}, num(member.last_week)]
, ['td', {'class': 'figure take ' + increase}, drawMemberTake(member)]
, ['td', {'class': 'figure balance'}, num(member.balance)]
, ['td', {'class': 'figure percentage'}, perc(member.percentage)]
]
));
else if (nmembers > 0)
rows.push(Gratipay.jsonml(
[ 'tr'
, ['td']
, ['td']
, ['td']
, ['td', {'class': 'figure take'}, num(member.take)]
, ['td', {'class': 'figure balance'}, num(member.balance)]
, ['td', {'class': 'figure percentage'}, perc(member.percentage)]
]
));
rows.push(Gratipay.jsonml(
[ 'tr'
, ['td', {'class': 'n'}, (i === nmembers ? '' : nmembers - i)]
, ['td', ['a', {'href': '/~'+member.username+'/'}, member.username]]
, ['td', {'class': 'figure last_week'}, num(member.last_week)]
, ['td', {'class': 'figure take ' + increase}, drawMemberTake(member)]
, ['td', {'class': 'figure balance'}, num(member.balance)]
, ['td', {'class': 'figure percentage'}, perc(member.percentage)]
]
));
}

if (nmembers === 0) {
rows.push(Gratipay.jsonml(
['tr', ['td', {'colspan': '6', 'class': 'no-members'}, "No members"]]
));
} else {
rows.push(Gratipay.jsonml(
[ 'tr'
, {'class': 'totals'}
, ['td']
, ['td']
, ['td']
, ['td', {'class': 'figure take'}, num(available - member.balance)]
, ['td', {'class': 'figure balance'}, num(member.balance)]
, ['td', {'class': 'figure percentage'}, perc(member.balance / available)]
]
));
}
$('#team-members').html(rows);
$('#take').submit(doTake);
$('#take input').focus().keyup(maybeCancelTake);
$('#team-members .remove').click(remove);

$t('.team-members').html(rows);
$t('.team-members .edit').submit(doTake);
$t('.team-members .edit input').focus().keyup(maybeCancelTake);
$t('.team-members .remove').click(remove);
}


// Add
// ===

function lookup() {
var query = $('#query').val();
var query = $t('.query').val();
if (query === '')
$('#lookup-results').empty();
$t('.lookup-results').empty();
else
jQuery.get("/lookup.json", {query: query}).success(drawLookupResults);
}
Expand All @@ -110,29 +112,32 @@ Gratipay.team = (function() {
['li', {"data-id": result.id}, result.username]
));
}
$('#lookup-results').html(items);
$t('.lookup-results').html(items);
if (items.length === 1)
selectLookupResult.call($t('.lookup-results li'));
}

function selectLookupResult() {
$('#query').val($(this).html());
$('#lookup-results').empty();
$li = $(this);
$t('.query').val($li.html()).data('id', $li.data('id'));
$t('.lookup-results').empty();
}

function add(e) {
e.preventDefault();
e.stopPropagation();
var query = $('#query').val();
setTake(query, '0.01');
$('#lookup-results').empty();
$('#query').val('').focus();
var participantId = $t('.query').data('id');
setTake(participantId, '0.01');
$t('.lookup-results').empty();
$t('.query').val('').focus();
return false;
}

function remove(e) {
e.preventDefault();
e.stopPropagation();
var membername = $(e.target).attr('data-username');
setTake(membername, '0.00');
var participantId = $(e.target).data('id');
setTake(participantId, '0.00');
return false;
}

Expand All @@ -147,47 +152,44 @@ Gratipay.team = (function() {
}

function resetTake() {
$('#take').show().parent().find('.updating').remove();
var _ = $('#take input');
$t('.take .knob').show().parent().find('.updating').remove();
var _ = $t('.take input');
_.val(_.attr('data-take')).blur();
}

function doTake(e) {
e.preventDefault();
e.stopPropagation();
var frm = $('#take'), _ = $('input', frm);
var username = _.attr('data-username'),
take = _.val();
setTake(username, take);
var input = $t('.take input');
var participantId = input.data('id'), take = input.val();
setTake(participantId, take);
return false;
}

function setTake(username, take, confirmed) {
if ($('#take').parent().find('.updating').length === 0) {
function setTake(participantId, take, confirmed) {
if ($t('.take').find('.updating').length === 0) {
var $updating = $('<span class="updating"></span>');
$updating.text($('#team').data('updating'));
$('#take').hide().parent().append($updating);
$updating.text($t().data('updating'));
$t('.take .knob').hide().parent().append($updating);
}

var data = {take: take};
if (confirmed) data.confirmed = true;

jQuery.ajax(
{ type: 'POST'
, url: username + ".json"
, url: participantId + ".json"
, data: data
, success: function(d) {
if (d.confirm) {
if (confirm(d.confirm)) {
return setTake(username, take, true)
} else {
return resetTake()
function proceed() { setTake(participantId, take, true); }
Gratipay.confirm(d.confirm, proceed, resetTake);
} else {
if(d.success) {
Gratipay.notification(d.success, 'success');
}
drawRows(d.available, d.members);
}
if(d.success) {
Gratipay.notification(d.success, 'success');
}
drawRows(d.members);
}
, error: [resetTake, Gratipay.error]
});
Expand Down
20 changes: 20 additions & 0 deletions scss/components/modal.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
.modal {
display: none;
position: fixed;
left: 50%;
top: 30%;
margin-top: 24px;
margin-left: -144px;
width: 288px;
font: normal 14px/18px $Ideal;
padding: 24px;
background: $white;
border: 2px solid $black;
@include border-radius(5px);
box-shadow: 0px 0px 32px 16px rgba($black, 0.5);
z-index: 3;

.continue {
text-align: right;
}
}
20 changes: 0 additions & 20 deletions scss/pages/homepage.scss
Original file line number Diff line number Diff line change
@@ -1,24 +1,4 @@
#homepage {
.welcome {
position: fixed;
left: 50%;
top: 30%;
margin-top: 24px;
margin-left: -144px;
width: 288px;
font: normal 14px/18px $Ideal;
padding: 24px;
background: $white;
border: 2px solid $black;
@include border-radius(5px);
box-shadow: 0px 0px 32px 16px rgba($black, 0.5);
z-index: 3;

.continue {
text-align: right;
}
}

#main {
position: relative;
.nav {
Expand Down
Loading

0 comments on commit 2d22820

Please sign in to comment.