Skip to content

Commit

Permalink
Add followers page and share details modal for follow (WIP)
Browse files Browse the repository at this point in the history
  • Loading branch information
vidya-ram committed Dec 28, 2023
1 parent 48ccb8d commit a6b2f6d
Show file tree
Hide file tree
Showing 6 changed files with 228 additions and 0 deletions.
16 changes: 16 additions & 0 deletions funnel/assets/js/profile_followers.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import TableSearch from './utils/tablesearch';

$(() => {
window.Hasgeek.profileFollowersInit = (search) => {
if (search) {
const tableSearch = new TableSearch(search.tableId);
const inputId = `#${search.inputId}`;
const tableRow = `#${search.tableId} tbody tr`;
$(inputId).keyup(function doTableSearch() {
$(tableRow).addClass('mui--hide');
const hits = tableSearch.searchRows($(this).val());
$(hits.join(',')).removeClass('mui--hide');
});
}
};
});
84 changes: 84 additions & 0 deletions funnel/templates/follow_share_details_modal.html.jinja2
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
{% from "macros.html.jinja2" import faicon, csrf_tag %}

<link rel="stylesheet" type="text/css" href="{{ manifest('css/form.css') }}" />

<div class="modal__header">
<a class="modal__close mui--text-dark" href="#" onclick="return false;" data-target="close modal" aria-label="{% trans %}Close{% endtrans %}" rel="modal:close" data-cy="close-modal" role="button" tabindex="0">{{ faicon(icon='times', baseline=false, icon_size='title') }}</a>
<p class="mui--text-title text-bold mui--text-dark" id="confirm-rsvp">{{ faicon(icon='info-circle', baseline=true, icon_size='subhead') }} {% trans profile=account %}Share contact info with {{ profile }}{% endtrans %}</p>
</div>
<div class="modal__body">
<form action="" method="post" class="mui-form form-inline" id="rsvp-form">
{{ form.hidden_tag() }}
{{ csrf_tag() }}

<div class="mui-form__fields listwidget">
<div class="mui-form__controls">
{% if current_auth.user.views.emails_sorted()|length < 3 %}
<div class="mui-textfield">
<label class="mui-form__label">{% trans %}Email address{% endtrans %}</label>
<ul>
{% for useremail in current_auth.user.views.emails_sorted() %}
<li>
<input id="useremail-{{ loop.index }}" name="email" type="radio" value="{{ useremail }}">
<label for="useremail-{{ loop.index }}">{{ useremail }}</label>
</li>
{% endfor %}
<li>
<input id="useremail-last" name="email" type="radio" value="no">
<label for="useremail-last">{% trans %}Do not share{% endtrans %}</label>
</li>
</ul>
</div>
{%- else %}
<div class="mui-select">
<select name="email" id="shared-email">
{% for useremail in current_auth.user.views.emails_sorted() %}
<option value="{{ useremail }}">{{ useremail }}</option>
{% endfor %}
<option value="no">{% trans %}Do not share{% endtrans %}</option>
</select>
<label for="shared-email">{% trans %}Email address{% endtrans %}</label>
</div>
{%- endif %}
</div>
</div>

<div class="mui-form__fields listwidget">
<div class="mui-form__controls">
{% if current_auth.user.views.phones_sorted()|length < 3 %}
<div class="mui-textfield">
<label class="mui-form__label">{% trans %}Phone number{% endtrans %}</label>
<ul>
{% for userphone in current_auth.user.views.phones_sorted() %}
<li>
<input id="userphone-{{ loop.index }}" name="email" type="radio" value="{{ userphone }}">
<label for="userphone-{{ loop.index }}">{{ userphone }}</label>
</li>
{% endfor %}
<li>
<input id="userphone-last" name="email" type="radio" value="no">
<label for="userphone-last">{% trans %}Do not share{% endtrans %}</label>
</li>
</ul>
</div>
{%- else %}
<div class="mui-select">
<select name="email" id="shared-email">
{% for userphone in current_auth.user.views.phones_sorted() %}
<option value="{{ userphone }}">{{ userphone }}</option>
{% endfor %}
<option value="no">{% trans %}Do not share{% endtrans %}</option>
</select>
<label for="shared-email">{% trans %}Phone number{% endtrans %}</label>
</div>
{%- endif %}
</div>
</div>

<p class="mui--text-body2 top-padding zero-bottom-margin">{% trans profile=account, url=url_for('index', _external=true) %}This allows {{ profile }} to send direct updates. {{ profile }} may also choose to contact you outside of {{ url }}{% endtrans %}</p>
<div class="mui--text-right">
<button class="mui-btn mui-btn--raised mui-btn--primary" type="submit" name="submit" value="yes" data-cy="confirm">{% trans %}Share{% endtrans %}</button>
</div>
</form>
</div>
<script src="{{ manifest('form.js') }}" type="text/javascript"></script>
100 changes: 100 additions & 0 deletions funnel/templates/profile_followers.html.jinja2
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
{% extends "profile_layout.html.jinja2" %}
{%- from "macros.html.jinja2" import faicon, useravatar %}

{%- block pageheaders %}
<link rel="stylesheet" type="text/css" href="{{ manifest('css/profile.css') }}" />
<link rel="stylesheet" type="text/css" href="{{ manifest('css/membership.css') }}" />
<link rel="search" type="application/opensearchdescription+xml" href="{{ url_for('opensearch') }}" title="{{ config['SITE_TITLE'] }}" />
<script type="application/ld+json">
{
"@context" : "http://schema.org",
"@type" : "WebSite",
"name" : {{ config['SITE_TITLE']|tojson }},
"url" : {{ url_for('index', _external=true)|tojson }},
"potentialAction": {
"@type": "SearchAction",
"target": "{{ url_for('search', _external=true) }}?q={query}",
"query-input": "required name=query"
}
}
</script>
<script type="application/ld+json">
{
"@context" : "http://schema.org",
"@type" : "Organization",
"name" : {{ profile.title|tojson }},
{%- if profile.banner_image_url.url %}
"logo" : {{ profile.banner_image_url.url|tojson }},
{%- elif profile.logo_url.url %}
"logo" : {{ profile.logo_url.url|tojson }},
{% endif %}
"url" : {{ profile.url_for(_external=true)|tojson }}
}
</script>
{%- endblock pageheaders %}

{% block bodyattrs %}class="bg-primary mobile-header"{% endblock bodyattrs %}

{% block contenthead %}
{% endblock contenthead %}

{% block baseheadline %}
{{ profile_header(profile, class="mui--hidden-xs mui--hidden-sm", current_page="followers", title=_("Followers")) }}
{% endblock baseheadline %}

{% block basecontent %}
<div class="bg-accent top-padding">
<div class="mui-container">
<div class="page-content">
<div class="grid" id="crew">
<div class="grid__col-xs-12">
<a class="mui-btn mui-btn--raised mui-btn--primary" href="{{ profile.url_for('follow') }}" rel="modal:open">{% trans %}Follow{% endtrans %}</a>
<form class="display-inlineblock search search--small search--icon mui--z1">
<div class="textfield">
<input class="search-query" id="search" type="text" name="key" value="" placeholder="{% trans %}Search{% endtrans %}"/>{{ faicon(icon='search', css_class="search-form__icon")}}
</div>
</form>
<table id="js-followers-table">
<tbody class="membership-wrapper__members">
{%- for membership in followers %}
{%- if membership %}
<tr class="membership-wrapper__members__list user" id="p-{{ membership.member.username }}">
<td class="js-searchable mui--hide">{{ membership.member.fullname }}</td>
<td class="js-searchable mui--hide">{{ membership.member.username }}</td>
<td>
<div class="member mui--clearfix">
<div class="user__box mui--pull-left">
{{ useravatar(membership.member, add_profile_link=true, size='big') }}
<div class="user__box__header">
<h3 class="mui--text-body2 user__box__fullname">{{ membership.member.fullname }}<span>{% if membership.member.features.is_private() %}{{ faicon(icon='lock-alt', icon_size='caption', baseline=false, css_class="margin-left") }}{%- endif %}</span></h3>
<h3 v-if="membership.member.username" class="mui--text-caption user__box__userid"><span data-cy="member">@{{ membership.member.username }}</span></h3>
</div>
</div>
<div class="mui--pull-right">
</div>
</div>
</td>
</tr>
{%- endif %}
{%- endfor %}
</table>
</div>
</div>
</div>
</div>
</div>
</div>
{% endblock basecontent %}

{% block innerscripts %}
<script src="{{ manifest('profile_followers.js') }}" type="text/javascript"></script>
<script type="text/javascript">
$(function() {
search = {
tableId: 'js-followers-table',
inputId: 'search'
};
Hasgeek.profileFollowersInit(search);
});
</script>
{% endblock innerscripts %}
1 change: 1 addition & 0 deletions funnel/templates/profile_layout.html.jinja2
Original file line number Diff line number Diff line change
Expand Up @@ -426,6 +426,7 @@
{% if profile.is_organization_profile %}
<a class="sub-navbar__item mui--text-subhead mui--text-dark mui--hidden-xs mui--hidden-sm {% if current_page == 'profile' %}sub-navbar__item--active{%- endif %}" href="{%- if current_page != 'profile' -%}{{ profile.url_for() }}{%- endif %}" data-cy-navbar="profile">{% trans %}Home{% endtrans %}</a>
<a class="sub-navbar__item mui--text-subhead mui--text-dark {% if current_page == 'admins' %}sub-navbar__item--active{%- endif %}" href="{%- if current_page != 'admins' -%}{{ profile.urls['members'] }}{%- endif %}" data-cy-navbar="admins">{% trans %}Admins{% endtrans %} <span class="sub-navbar__item__icon mui--pull-right">{{ faicon(icon='chevron-right', icon_size='subhead') }}</span></a>
<a class="sub-navbar__item mui--text-subhead mui--text-dark {% if current_page == 'followers' %}sub-navbar__item--active{%- endif %}" href="{%- if current_page != 'followers' -%}{{ profile.url_for('followers') }}{%- endif %}" data-cy-navbar="admins">{% trans %}Followers{% endtrans %} <span class="sub-navbar__item__icon mui--pull-right">{{ faicon(icon='chevron-right', icon_size='subhead') }}</span></a>
{% elif not profile.features.is_private() %}
<a class="sub-navbar__item mui--text-subhead mui--text-dark mui--hidden-xs mui--hidden-sm {% if current_page == 'profile' %}sub-navbar__item--active{%- endif %}" href="{{ profile.url_for() }}">{% trans %}Sessions{% endtrans %}</a>
<a class="sub-navbar__item mui--text-subhead mui--text-dark {% if current_page == 'projects' %}sub-navbar__item--active{%- endif %}" href="{{ profile.url_for('user_participated_projects') }}">{% trans %}Projects{% endtrans %}<span class="sub-navbar__item__icon mui--pull-right">{{ faicon(icon='chevron-right', icon_size='subhead') }}</span></a>
Expand Down
26 changes: 26 additions & 0 deletions funnel/views/profile.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

from baseframe import _
from baseframe.filters import date_filter
from baseframe import forms
from baseframe.forms import render_form
from coaster.auth import current_auth
from coaster.views import (
Expand Down Expand Up @@ -277,6 +278,19 @@ def user_proposals(self) -> ReturnRenderWith:
],
}


@route('followers')
@render_with('profile_followers.html.jinja2', json=True)
def followers(self) -> ReturnRenderWith:
# Tobechanged: Return followers
return {
'profile': self.obj.current_access(datasets=('primary', 'related')),
'followers': [
membership.current_access(datasets=('without_parent', 'related'))
for membership in self.obj.active_admin_memberships
],
}

@route('past.projects')
@requestargs(('page', int), ('per_page', int))
@render_with('past_projects_section.html.jinja2')
Expand Down Expand Up @@ -468,4 +482,16 @@ def transition(self) -> ReturnView:
return render_redirect(get_next_url(referrer=True))


@route('follow', methods=['GET'])
@render_with('follow_share_details_modal.html.jinja2')
@requires_login
def follow(self) -> ReturnRenderWith:
"""Edit project banner."""
form = forms.Form()
return {
'profile': self.obj,
'form': form,
}


ProfileView.init_app(app)
1 change: 1 addition & 0 deletions webpack.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ module.exports = {
labels_form: path.resolve(__dirname, 'funnel/assets/js/labels_form.js'),
cfp_form: path.resolve(__dirname, 'funnel/assets/js/cfp_form.js'),
rsvp_form_modal: path.resolve(__dirname, 'funnel/assets/js/rsvp_form_modal.js'),
profile_followers: path.resolve(__dirname, 'funnel/assets/js/profile_followers.js'),
app_css: path.resolve(__dirname, 'funnel/assets/sass/app.scss'),
form_css: path.resolve(__dirname, 'funnel/assets/sass/form.scss'),
index_css: path.resolve(__dirname, 'funnel/assets/sass/pages/index.scss'),
Expand Down

0 comments on commit a6b2f6d

Please sign in to comment.