-
-
Notifications
You must be signed in to change notification settings - Fork 775
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Following section #6301
Following section #6301
Changes from 16 commits
0ca2ca3
13e854f
6c2780e
e22d9f6
c0dcaee
39f5a34
8648841
cb8bafc
edda50d
7517420
a0efb30
398f1f6
fa26429
bc5ae0c
14ca76b
0a98720
ab54f3d
1dccfb9
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -83,3 +83,59 @@ const tribeLeader = () => { | |
}; | ||
|
||
tribeLeader(); | ||
|
||
const newManageTribe = () => { | ||
$('[data-tribe]').each(function(index, elem) { | ||
$(elem).mouseenter(function(e) { | ||
if ($(elem).hasClass('btn-outline-gc-green')) { | ||
$(elem).addClass('btn-gc-outline-red').text('Unfollow'); | ||
$(elem).removeClass('btn-outline-gc-green'); | ||
} | ||
}).mouseleave(function(e) { | ||
if ($(elem).hasClass('btn-gc-outline-red')) { | ||
$(elem).removeClass('btn-gc-outline-red'); | ||
$(elem).addClass('btn-outline-gc-green').text('Following'); | ||
} | ||
}); | ||
|
||
$(elem).focus(function(e) { | ||
if ($(elem).hasClass('btn-outline-gc-green')) { | ||
$(elem).addClass('btn-gc-outline-red').text('Unfollow'); | ||
$(elem).removeClass('btn-outline-gc-green'); | ||
} | ||
}).focusout(function(e) { | ||
if ($(elem).hasClass('btn-gc-outline-red')) { | ||
$(elem).removeClass('btn-gc-outline-red'); | ||
$(elem).addClass('btn-outline-gc-green').text('Following'); | ||
} | ||
}); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. you should use multiple event to be more DRY There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done |
||
|
||
$(elem).on('click', function(e) { | ||
if (!document.contxt.github_handle) { | ||
e.preventDefault(); | ||
_alert('Please login first.', 'error'); | ||
return; | ||
} | ||
|
||
$(elem).attr('disabled', true); | ||
e.preventDefault(); | ||
const tribe = $(elem).data('tribe'); | ||
const url = `/tribe/${tribe}/join/`; | ||
const sendJoin = fetchData (url, 'POST', {}, {'X-CSRFToken': $("input[name='csrfmiddlewaretoken']").val()}); | ||
|
||
$.when(sendJoin).then(function(response) { | ||
$(elem).attr('disabled', false); | ||
$(elem).attr('member', response.is_member); | ||
if (response.is_member) { | ||
$(elem).addClass('btn-outline-gc-green').removeClass([ 'btn-gc-blue', 'btn-gc-outline-red' ]).text('Following'); | ||
} else { | ||
$(elem).removeClass([ 'btn-outline-gc-green', 'btn-gc-outline-red' ]).addClass('btn-gc-blue').text('Follow'); | ||
} | ||
}).fail(function(error) { | ||
$(elem).attr('disabled', false); | ||
}); | ||
}); | ||
}); | ||
}; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. if you rebase this then you will see this file now have There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done :) |
||
|
||
newManageTribe(); |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4896,3 +4896,18 @@ class TribeMember(SuperModel): | |
max_length=20, | ||
blank=True | ||
) | ||
|
||
@property | ||
def mutual_follow(self): | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. tribesmembers is used for users following but also for orgs tribes seems this will show tribes orgs as following There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is a handy method for Tribe Members, this method will be used as predicate to know if the current pair (org, profile) follow mutually. |
||
return TribeMember.objects.filter(profile=self.org, org=self.profile).exists() | ||
|
||
@property | ||
def mutual_follower(self): | ||
tribe_following = TribeMember.objects.filter(profile=self.profile).values('org') | ||
return TribeMember.objects.filter(org=self.org, profile__in=tribe_following).exclude(profile=self.profile) | ||
|
||
@property | ||
def mutual_following(self): | ||
tribe_following = TribeMember.objects.filter(org=self.profile).values('profile') | ||
print(tribe_following) | ||
return TribeMember.objects.filter(org__in=tribe_following, profile=self.org) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. not sure about this logic, if you already have those who already following you why not better cross both and have the result to avoid many queries? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Whats the missing print? Is there a rule for printing objects here we have to follow? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done, only one query is executed on each of these methods using a subquery |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,145 @@ | ||
{% load i18n static %} | ||
|
||
{% if not hidden %} | ||
<div id="profile-tabs" class="tab-container font-body mt-3 mb-4"> | ||
<button type="button" id="nav-description" href="{{profile.url}}/follow?sub=followers" class="text-center section-tab {% if foltab == "followers" %} active {% endif %}"> | ||
{% trans "FOLLOWERS" %} <span class="nav-badge">({{followers.count}})</span> | ||
</button> | ||
<button type="button" id="nav-description" href="{{profile.url}}/follow?sub=following" class="text-center section-tab {% if foltab == "following" %} active {% endif %}"> | ||
{% trans "FOLLOWING" %} <span class="nav-badge">({{following.count}})</span> | ||
</button> | ||
</div> | ||
{% endif %} | ||
|
||
<div class="tab-projects d-flex flex-column"> | ||
{% if foltab == 'followers' %} | ||
<!-- Show This users followers--> | ||
{% for user in followers %} | ||
<div class="tab-projects__item d-flex mb-0 pt-1 pb-1 bounty_row"> | ||
<div class="avatar-container col-1 justify-content-center hide_min_viewport"> | ||
<img class="profile-header__avatar mr-3" src="/dynamic/avatar/{{ user.profile.handle }}" alt=""> | ||
</div> | ||
<div class="tab-projects__item-details col-3 d-flex flex-column bounty-detail"> | ||
<div class="d-flex flex-column"> | ||
<div class="font-weight-semibold font-header">{{user.profile.name}}</div> | ||
<div class="text-highlight-gc-blue font-smaller-1">{{user.profile.handle}}</div> | ||
</div> | ||
</div> | ||
<div class="mb-0 mt-1 col-5 d-flex flex-row align-items-center"> | ||
<div class="mr-5" style="height: fit-content"> | ||
<button class="btn btn-outline-gc-blue btn-sm flex-grow-1 font-smaller-5 position-relative quick-link" data-openchat="{{user.profile}}"> | ||
<i class="fas fa-comment-dots" data-placement="bottom" data-toggle="tooltip" data-html="true" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. lets move the tooltip to the button to show it on all the button hover not just the icon There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done |
||
title="Chat @{{ user.profile.handle }}"> | ||
</i> | ||
</button> | ||
</div> | ||
<div style="height: fit-content"> | ||
<a class="btn btn-outline-gc-blue btn-sm flex-grow-1 mr-5 font-smaller-5 position-relative quick-link btn-outline-gc-blue" href="https://gitcoin.co/users?invite={{user.profile.handle}}" data-placement="bottom" data-toggle="tooltip" data-html="true" title="Invite {{ user.profile.handle }} to Bounty"> | ||
<i class="fas fa-envelope-open-text"></i> | ||
</a> | ||
</div> | ||
<div class="d-flex align-items-center" style="height: fit-content"> | ||
{% with followers=user.mutual_following %} | ||
{% if followers|length == 1 %} | ||
<div style="width: 60px"> | ||
<img class="rounded-circle" style="height: 25px; width: 25px;" src="/dynamic/avatar/{{ followers.0.org.handle }}" alt=""> | ||
</div> | ||
<p class="text-muted font-smaller-4 my-0">Followed by {{ followers.0.org.handle }}</p> | ||
{% endif %} | ||
{% if followers|length == 2 %} | ||
<div style="width: 60px" class="d-flex flex-row align-items-center"> | ||
<img class="rounded-circle" style="height: 25px; width: 25px; margin-right: -12px " src="/dynamic/avatar/{{ followers.0.org.handle }}" alt=""> | ||
<img class="rounded-circle" style="height: 25px; width: 25px;" src="/dynamic/avatar/{{ followers.1.org.handle }}" alt=""> | ||
</div> | ||
<p class="text-muted font-smaller-4 my-0">Followed by {{ followers.0.org.handle }} and {{ followers.1.org.handle }}</p> | ||
{% endif %} | ||
{% if followers|length >= 3 %} | ||
<div style="width: 60px" class="d-flex flex-row align-items-center"> | ||
<img class="rounded-circle" style="height: 25px; width: 25px; margin-right: -12px" src="/dynamic/avatar/{{ followers.0.org.handle }}" alt=""> | ||
<img class="rounded-circle" style="height: 25px; width: 25px; margin-right: -12px" src="/dynamic/avatar/{{ followers.1.org.handle }}" alt=""> | ||
<img class="rounded-circle" style="height: 25px; width: 25px;" src="/dynamic/avatar/{{ followers.2.org.handle }}" alt=""> | ||
</div> | ||
<p class="text-muted font-smaller-4 my-0">Followed by {{ followers.0.org.handle }}, {{ followers.1.org.handle }} and {{ followers|length|add:-2}} others you follow</p> | ||
{% endif %} | ||
{% endwith %} | ||
</div> | ||
</div> | ||
<div class="col-12 col-md-4 col-lg-3 font-caption my-auto text-right"> | ||
{% if user.mutual_follow %} | ||
<button class="btn btn-sm m-2 px-4 font-caption py-1 font-weight-bold btn-outline-gc-green" style="border-width: 2px !important;" data-tribe="{{user.profile.handle}}">Following</button> | ||
{% else %} | ||
<button class="btn btn-gc-blue btn-sm m-2 px-2 font-caption" data-jointribe="{{user.profile.handle}}">Follow<i class="fas fa-user-plus font-smaller-4 ml-2"></i></button> | ||
{% endif %} | ||
</div> | ||
</div> | ||
{% endfor %} | ||
|
||
{% elif foltab == 'following' %} | ||
<!-- Show which users this one is following--> | ||
{% for user in following %} | ||
<div class="tab-projects__item d-flex mb-0 pt-1 pb-1 bounty_row"> | ||
<div class="avatar-container col-1 justify-content-center hide_min_viewport"> | ||
<img class="profile-header__avatar mr-3" src="/dynamic/avatar/{{ user.org.handle }}" alt=""> | ||
</div> | ||
<div class="tab-projects__item-details col-3 d-flex flex-column bounty-detail"> | ||
<div class="d-flex flex-column"> | ||
<div class="font-weight-semibold font-header">{{user.org.name}}</div> | ||
<div class="text-highlight-gc-blue font-smaller-1">{{user.org.handle}}</div> | ||
</div> | ||
</div> | ||
<div class="mb-0 mt-1 col-5 d-flex flex-row align-items-center"> | ||
<div class="mr-5" style="height: fit-content"> | ||
<button class="btn btn-outline-gc-blue btn-sm flex-grow-1 font-smaller-5 position-relative quick-link" data-openchat="{{user.org}}"> | ||
<i class="fas fa-comment-dots" data-p lacement="bottom" data-toggle="tooltip" data-html="true" | ||
title="Chat @{{ user.org.handle }}"> | ||
</i> | ||
</button> | ||
</div> | ||
<div style="height: fit-content"> | ||
<a class="btn btn-sm flex-grow-1 mr-5 font-smaller-5 position-relative quick-link btn-outline-gc-blue" {% if not user.org.email %} hidden {% endif %} href="mailto:{{user.org.email}}" data-placement="bottom" data-toggle="tooltip" data-html="true" title="@{{ user.org.handle }}'s Email"> | ||
<i class="far fa-envelope"></i> | ||
</a> | ||
</div> | ||
<div class="d-flex align-items-center" style="height: fit-content"> | ||
{% with followers=user.mutual_follower %} | ||
{% if followers|length == 1 %} | ||
<div style="width: 60px"> | ||
<img class="rounded-circle" style="height: 25px; width: 25px;" src="/dynamic/avatar/{{ followers.0.profile.handle }}" alt=""> | ||
</div> | ||
<p class="text-muted font-smaller-4 my-0">Followed by {{ followers.0.profile.handle }}</p> | ||
{% endif %} | ||
{% if followers|length == 2 %} | ||
<div style="width: 60px" class="d-flex flex-row align-items-center"> | ||
<img class="rounded-circle" style="height: 25px; width: 25px; margin-right: -12px " src="/dynamic/avatar/{{ followers.0.profile.handle }}" alt=""> | ||
<img class="rounded-circle" style="height: 25px; width: 25px;" src="/dynamic/avatar/{{ followers.1.profile.handle }}" alt=""> | ||
</div> | ||
<p class="text-muted font-smaller-4 my-0">Followed by {{ followers.0.profile.handle }} and {{ followers.1.profile.handle }}</p> | ||
{% endif %} | ||
{% if followers|length >= 3 %} | ||
<div style="width: 60px" class="d-flex flex-row align-items-center"> | ||
<img class="rounded-circle" style="height: 25px; width: 25px; margin-right: -12px" src="/dynamic/avatar/{{ followers.0.profile.handle }}" alt=""> | ||
<img class="rounded-circle" style="height: 25px; width: 25px; margin-right: -12px" src="/dynamic/avatar/{{ followers.1.profile.handle }}" alt=""> | ||
<img class="rounded-circle" style="height: 25px; width: 25px;" src="/dynamic/avatar/{{ followers.2.profile.handle }}" alt=""> | ||
</div> | ||
<p class="text-muted font-smaller-4 my-0">Followed by {{ followers.0.profile.handle }}, {{ followers.1.profile.handle }} and {{ followers|length|add:-2}} others you follow</p> | ||
{% endif %} | ||
{% endwith %} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. lets move this logic to a loop instead and limit the looping to be more DRY There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not sure this would be better as a loop There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done |
||
</div> | ||
|
||
</div> | ||
<div class="col-12 col-md-3 col-lg-3 font-caption my-auto text-right"> | ||
<button class="btn btn-sm m-4 px-4 font-caption py-1 font-weight-bold btn-outline-gc-green" style="border-width: 2px !important;" data-tribe="{{user.org.handle}}">Following</button> | ||
</div> | ||
</div> | ||
{% endfor %} | ||
</div> | ||
|
||
|
||
<script> | ||
setInterval(function(){ | ||
if($ && $('.load-more').length && $(".load-more").isInViewport()){ | ||
$('.load-more').click(); | ||
} | ||
}, 1000); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. how this work? doesn't seems to be any ajax request handling this and if checking each second to click the button? Or I am missing something? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. borrowed from a different tab, I think tab_kudos.html. Possibly didn't connect it, will check that. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done |
||
</script> | ||
{% endif %} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2663,6 +2663,15 @@ def get_profile_tab(request, profile, tab, prev_context): | |
pass | ||
elif tab == 'tribe': | ||
context['team'] = profile.team_or_none_if_timeout | ||
elif tab == 'follow': | ||
context['org_kudos'] = profile.get_org_kudos | ||
owned_kudos = profile.get_my_kudos.order_by('id', order_by) | ||
sent_kudos = profile.get_sent_kudos.order_by('id', order_by) | ||
kudos_limit = 8 | ||
context['kudos'] = owned_kudos[0:kudos_limit] | ||
context['sent_kudos'] = sent_kudos[0:kudos_limit] | ||
context['kudos_count'] = owned_kudos.count() | ||
context['sent_kudos_count'] = sent_kudos.count() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. why this context here instead on the general context? shouldn't be here the follow data you need only for that tab? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done |
||
elif tab == 'people': | ||
if profile.is_org: | ||
context['team'] = profile.team_or_none_if_timeout | ||
|
@@ -2783,7 +2792,7 @@ def profile(request, handle, tab=None): | |
disable_cache = False | ||
|
||
# make sure tab param is correct | ||
all_tabs = ['active', 'ratings', 'portfolio', 'viewers', 'activity', 'resume', 'kudos', 'earnings', 'spent', 'orgs', 'people', 'grants', 'quests', 'tribe', 'hackathons'] | ||
all_tabs = ['active', 'ratings', 'follow', 'portfolio', 'viewers', 'activity', 'resume', 'kudos', 'earnings', 'spent', 'orgs', 'people', 'grants', 'quests', 'tribe', 'hackathons'] | ||
tab = default_tab if tab not in all_tabs else tab | ||
if handle in all_tabs and request.user.is_authenticated: | ||
# someone trying to go to their own profile? | ||
|
@@ -2817,6 +2826,7 @@ def profile(request, handle, tab=None): | |
context = { | ||
'hidden': True, | ||
'ratings': range(0,5), | ||
'followers': TribeMember.objects.filter(org=request.user.profile), | ||
'profile': { | ||
'handle': handle, | ||
'avatar_url': f"/dynamic/avatar/Self", | ||
|
@@ -2852,6 +2862,7 @@ def profile(request, handle, tab=None): | |
|
||
context['is_my_profile'] = is_my_profile | ||
context['show_resume_tab'] = profile.show_job_status or context['is_my_profile'] | ||
context['show_follow_tab'] = True | ||
context['is_editable'] = context['is_my_profile'] # or context['is_my_org'] | ||
context['tab'] = tab | ||
context['show_activity'] = request.GET.get('p', False) != False | ||
|
@@ -2864,7 +2875,11 @@ def profile(request, handle, tab=None): | |
context['feedbacks_got'] = [fb.pk for fb in profile.feedbacks_got.all() if fb.visible_to(request.user)] | ||
context['all_feedbacks'] = context['feedbacks_got'] + context['feedbacks_sent'] | ||
context['tags'] = [('#announce','bullhorn'), ('#mentor','terminal'), ('#jobs','code'), ('#help','laptop-code'), ('#other','briefcase'), ] | ||
context['followers'] = TribeMember.objects.filter(org=request.user.profile) | ||
context['following'] = TribeMember.objects.filter(profile=request.user.profile) | ||
context['foltab'] = request.GET.get('sub', 'followers') | ||
|
||
print(f'===== TRIBES COUNT: {TribeMember.objects.filter(org=request.user.profile)}') | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. missing print There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done |
||
tab = get_profile_tab(request, profile, tab, context) | ||
if type(tab) == dict: | ||
context.update(tab) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this file is loaded in many pleases probably is better to move it to his own file or even loaded on that page only.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
could we omit this at this moment? i'll move this in another PR due i'll be working this weeks on tribes functionality.