[IMP] website_*: improve profile view
*= forum, profile, slides, slides_survey Purpose ======= Give users a better experience when browsing website profiles looking for courses, certifications, forum questions, ... Specifications ============= Add search bars for Questions, Answers and Upvotes, small UI changes here and there. Task-2676848 Based on #79372 Co-authored by: Fabio Barbero <faba@odoo.com> Part-of: odoo/odoo#129123
This commit is contained in:
@@ -122,6 +122,7 @@ class WebsiteForum(WebsiteProfile):
|
||||
my=my,
|
||||
create_uid=author.id,
|
||||
include_answers=include_answers,
|
||||
my_profile=request.env.user == author,
|
||||
**post
|
||||
)
|
||||
question_count, details, fuzzy_search_term = request.website._search_with_fuzzy(
|
||||
|
||||
@@ -35,9 +35,9 @@
|
||||
|
||||
<!-- Toggle Tags on click -->
|
||||
<t t-if="tag and tag.name == question_tag.name" t-set="click_action"
|
||||
t-value="'/forum/' + slug(question_tag.forum_id) + '?' + keep_query( 'search', 'sorting', 'my', 'author',)"/>
|
||||
t-value="'/forum/' + slug(question_tag.forum_id) + '?' + keep_query( 'search', 'sorting', 'my', 'create_uid',)"/>
|
||||
<t t-else="" t-set="click_action"
|
||||
t-value="'/forum/' + slug(question_tag.forum_id) + '/tag/' + slug(question_tag) + '/questions?' + keep_query( 'search', 'sorting', 'my', 'author', filters='tag')"/>
|
||||
t-value="'/forum/' + slug(question_tag.forum_id) + '/tag/' + slug(question_tag) + '/questions?' + keep_query( 'search', 'sorting', 'my', 'create_uid', filters='tag')"/>
|
||||
|
||||
<a t-att-href="click_action"
|
||||
t-attf-class="badge position-relative z-index-1 #{ 'text-bg-secondary' if tag and tag.name == question_tag.name else 'text-bg-light' } fw-normal"
|
||||
|
||||
@@ -57,10 +57,23 @@
|
||||
<t t-set="is_profile" t-value="true"/>
|
||||
<div role="tabpanel" class="o_wforum_profile_tab tab-pane" id="questions">
|
||||
<div class="mb-4">
|
||||
<h5 class="border-bottom pb-1">
|
||||
<h5 class="border-bottom pb-1 d-flex align-items-center justify-content-between">
|
||||
Questions
|
||||
<t t-call="website_forum.forum_filter_tag"/>
|
||||
<t t-if="count_questions > 0" class="float-end" t-call="website.website_search_box_input">
|
||||
<t t-set="_form_classes" t-valuef="d-flex flex-row align-items-center flex-wrap float-end"/>
|
||||
<t t-set="search_type" t-valuef="forums"/>
|
||||
<t t-if="forum_id" t-set="action" t-value="'/forum/%s%s' % (forum_id, ('/tag/%s/questions' % slug(tag)) if tag else '')"/>
|
||||
<t t-else="" t-set="action" t-value="'/forum/all%s' % (('/tag/%s/questions' % slug(tag)) if tag else '')"/>
|
||||
<t t-set="display_description" t-value="true"/>
|
||||
<t t-set="display_detail" t-valuef="false"/>
|
||||
<t t-set="placeholder" t-valuef="Search Questions..."/>
|
||||
<input type="hidden" name="create_uid" t-att-value="user.id"/>
|
||||
<input t-if="filters" type="hidden" name="filters" t-att-value="filters"/>
|
||||
<input t-if="my_profile" type="hidden" name="my" t-att-value="mine"/>
|
||||
<input t-if="sorting" type="hidden" name="sorting" t-att-value="sorting"/>
|
||||
</t>
|
||||
</h5>
|
||||
<t t-call="website_forum.forum_filter_tag"/>
|
||||
<t t-if="questions">
|
||||
<div class="mb-1" t-foreach="questions" t-as="question">
|
||||
<t t-call="website_forum.display_post"/>
|
||||
@@ -101,10 +114,24 @@
|
||||
</div>
|
||||
<div role="tabpanel" class="o_wforum_profile_tab tab-pane" id="answers">
|
||||
<div class="mb-4">
|
||||
<h5 class="border-bottom pb-1">
|
||||
<h5 class="border-bottom pb-1 d-flex align-items-center justify-content-between">
|
||||
Answers
|
||||
<t t-call="website_forum.forum_filter_tag"/>
|
||||
<t t-if="count_questions > 0" class="float-end" t-call="website.website_search_box_input">
|
||||
<t t-set="_form_classes" t-valuef="d-flex flex-row align-items-center flex-wrap float-end"/>
|
||||
<t t-set="search_type" t-valuef="forums"/>
|
||||
<t t-if="forum_id" t-set="action" t-value="'/forum/%s%s' % (forum_id, '/tag/%s/questions' % slug(tag)) if tag else ''"/>
|
||||
<t t-else="" t-set="action" t-value="'/forum/all%s' % (('/tag/%s/questions' % slug(tag)) if tag else '')"/>
|
||||
<t t-set="display_description" t-value="true"/>
|
||||
<t t-set="display_detail" t-valuef="false"/>
|
||||
<t t-set="placeholder" t-valuef="Search Answers..."/>
|
||||
<input type="hidden" name="author" t-att-value="user.id"/>
|
||||
<input t-if="filters" type="hidden" name="filters" t-att-value="filters"/>
|
||||
<input t-if="my_profile" type="hidden" name="my" t-att-value="mine"/>
|
||||
<input t-if="sorting" type="hidden" name="sorting" t-att-value="sorting"/>
|
||||
<input type="hidden" name="include_answers" t-att-value="True"/>
|
||||
</t>
|
||||
</h5>
|
||||
<t t-call="website_forum.forum_filter_tag"/>
|
||||
|
||||
<t t-if="answers">
|
||||
<div class="mb-1" t-foreach="answers" t-as="answer">
|
||||
@@ -127,16 +154,31 @@
|
||||
</div>
|
||||
<div role="tabpanel" class="o_wforum_profile_tab tab-pane" id="votes" t-if="uid == user.id">
|
||||
<div class="mb-4">
|
||||
<h5 class="border-bottom pb-1">Votes</h5>
|
||||
<h5 class="border-bottom pb-1 flex align-items-center justify-content-between" style="height:43px;">
|
||||
Votes
|
||||
<t t-if="my_profile" class="float-end" t-call="website.website_search_box_input">
|
||||
<t t-set="_form_classes" t-valuef="d-flex flex-row align-items-center flex-wrap float-end"/>
|
||||
<t t-set="search_type" t-valuef="forums"/>
|
||||
<t t-set="action" t-value="'/forum/%s%s' % (forum_id or 'all', '/tag/%s/questions' % slug(tag) if tag else '')"/>
|
||||
<t t-set="display_description" t-value="true"/>
|
||||
<t t-set="display_detail" t-valuef="false"/>
|
||||
<t t-set="placeholder" t-valuef="Search Posts..."/>
|
||||
<input type="hidden" name="my" value="upvoted"/>
|
||||
<input t-if="filters" type="hidden" name="filters" t-att-value="filters"/>
|
||||
<input t-if="sorting" type="hidden" name="sorting" t-att-value="sorting"/>
|
||||
<input type="hidden" name="include_answers" t-att-value="True"/>
|
||||
</t>
|
||||
</h5>
|
||||
<t t-call="website_forum.forum_filter_tag"/>
|
||||
<t t-call="website_forum.user_votes"/>
|
||||
</div>
|
||||
</div>
|
||||
<div role="tabpanel" class="o_wforum_profile_tab tab-pane" id="activity" t-if="uid == user.id">
|
||||
<div class="mb-4">
|
||||
<h5 class="border-bottom pb-1">
|
||||
<h5 class="border-bottom pb-1 d-flex align-items-center justify-content-between" style="height:43px;">
|
||||
Activities
|
||||
<t t-call="website_forum.forum_filter_tag"/>
|
||||
</h5>
|
||||
<t t-call="website_forum.forum_filter_tag"/>
|
||||
<t t-call="website_forum.display_activities"/>
|
||||
</div>
|
||||
</div>
|
||||
@@ -182,17 +224,21 @@
|
||||
<template id="user_votes" name="Forum User Votes">
|
||||
<div t-foreach="vote_post" t-as="vote" class="card mb-2">
|
||||
<div class="card-body">
|
||||
<span t-if="vote.vote == '1'" class="fa fa-thumbs-up text-success me-2" role="img" aria-label="Positive vote" title="Positive vote"/>
|
||||
<span t-if="vote.vote == '-1'" class="fa fa-thumbs-down text-warning me-2" role="img" aria-label="Negative vote" title="Negative vote"/>
|
||||
<span t-field="vote.post_id.create_date"/>
|
||||
<span t-if="vote.vote == '1'" class="fa fa-thumbs-up text-success" style="margin-left:30px" role="img" aria-label="Positive vote" title="Positive vote"/>
|
||||
<span t-if="vote.vote == '-1'" class="fa fa-thumbs-down text-warning" style="margin-left:30px" role="img" aria-label="Negative vote" title="Negative vote"/>
|
||||
<a t-if="vote.post_id.parent_id" class="ms-2" t-attf-href="/forum/#{ slug(vote.post_id.forum_id) }/#{ vote.post_id.parent_id.id }/#answer-#{ vote.post_id.id }"
|
||||
t-out="vote.post_id.parent_id.name"/>
|
||||
<a t-else="" class="ms-2 text-black" t-attf-href="/forum/#{ slug(vote.post_id.forum_id) }/#{ vote.post_id.id }"
|
||||
t-out="vote.post_id.name"/>
|
||||
<a t-if="vote.post_id.parent_id" class="ms-2" t-attf-href="/forum/#{ slug(vote.post_id.forum_id) }/#{ vote.post_id.parent_id.id }/#answer-#{ vote.post_id.id }" t-out="vote.post_id.parent_id.name"/>
|
||||
<a t-else="" class="text-black ms-2" t-attf-href="/forum/#{ slug(vote.post_id.forum_id) }/#{ vote.post_id.id }" t-out="vote.post_id.name"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mb16" t-if="not vote_post">
|
||||
<p class="text-muted">You haven't given any votes yet.</p>
|
||||
<div t-if="my_profile" class="text-muted">
|
||||
Help moderating the forums by upvoting and downvoting posts. <br />
|
||||
<a href="/forum/" class="btn-link">
|
||||
<i class="fa fa-arrow-right"></i> Go To Forums
|
||||
</a>
|
||||
</div>
|
||||
<p t-else="" class="text-muted">You haven't given any votes yet.</p>
|
||||
</div>
|
||||
</template>
|
||||
</data></odoo>
|
||||
|
||||
@@ -46,28 +46,36 @@ publicWidget.registry.websiteProfileEditor = publicWidget.Widget.extend({
|
||||
'click .o_forum_profile_pic_edit': '_onEditProfilePicClick',
|
||||
'change .o_forum_file_upload': '_onFileUploadChange',
|
||||
'click .o_forum_profile_pic_clear': '_onProfilePicClearClick',
|
||||
'click .o_forum_profile_bio_edit': '_onProfileBioEditClick',
|
||||
'click .o_forum_profile_bio_cancel_edit': '_onProfileBioCancelEditClick',
|
||||
},
|
||||
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
start: async function () {
|
||||
var def = this._super.apply(this, arguments);
|
||||
const def = this._super.apply(this, arguments);
|
||||
if (this.editableMode) {
|
||||
return def;
|
||||
}
|
||||
|
||||
var $textarea = this.$('textarea.o_wysiwyg_loader');
|
||||
const $textarea = this.$("textarea.o_wysiwyg_loader");
|
||||
|
||||
this._wysiwyg = await loadWysiwygFromTextarea(this, $textarea[0], {
|
||||
const options = {
|
||||
recordInfo: {
|
||||
context: this._getContext(),
|
||||
res_model: 'res.users',
|
||||
res_id: parseInt(this.$('input[name=user_id]').val()),
|
||||
res_model: "res.users",
|
||||
res_id: parseInt(this.$("input[name=user_id]").val()),
|
||||
},
|
||||
resizable: true,
|
||||
userGeneratedContent: true,
|
||||
});
|
||||
};
|
||||
|
||||
if ($textarea[0].attributes.placeholder) {
|
||||
options.placeholder = $textarea[0].attributes.placeholder.value;
|
||||
}
|
||||
|
||||
this._wysiwyg = await loadWysiwygFromTextarea(this, $textarea[0], options);
|
||||
|
||||
return Promise.all([def]);
|
||||
},
|
||||
@@ -113,6 +121,30 @@ publicWidget.registry.websiteProfileEditor = publicWidget.Widget.extend({
|
||||
type: 'hidden',
|
||||
}));
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {Event} ev
|
||||
*/
|
||||
_onProfileBioEditClick: function (ev) {
|
||||
ev.preventDefault();
|
||||
ev.currentTarget.classList.add("d-none");
|
||||
document.querySelector(".o_forum_profile_bio_cancel_edit").classList.remove("d-none");
|
||||
document.querySelector(".o_forum_profile_bio").classList.add("d-none");
|
||||
document.querySelector(".o_forum_profile_bio_form").classList.remove("d-none");
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {Event} ev
|
||||
*/
|
||||
_onProfileBioCancelEditClick: function (ev) {
|
||||
ev.preventDefault();
|
||||
ev.currentTarget.classList.add("d-none");
|
||||
document.querySelector(".o_forum_profile_bio_edit").classList.remove("d-none");
|
||||
document.querySelector(".o_forum_profile_bio_form").classList.add("d-none");
|
||||
document.querySelector(".o_forum_profile_bio").classList.remove("d-none");
|
||||
},
|
||||
});
|
||||
|
||||
publicWidget.registry.websiteProfileNextRankCard = publicWidget.Widget.extend({
|
||||
|
||||
@@ -99,7 +99,7 @@
|
||||
</a>
|
||||
</div>
|
||||
<div class="my-3 mb-0 pt-2 border-top">
|
||||
<label class="text-primary" for="user_website_published" t-if="user.id == uid"><span class="fw-bold">Public profile</span></label>
|
||||
<label class="text-primary" for="user_website_published" t-if="user.id == uid"><span class="fw-bold">Public Profile</span></label>
|
||||
<div class=" mb-0 float-end" t-if="user.id == uid">
|
||||
<input type="checkbox" class="mt8" name="website_published" id="user_website_published" value="True" t-if="not user.website_published"/>
|
||||
<input type="checkbox" class="mt8" name="website_published" id="user_website_published" value="True" checked="checked" t-if="user.website_published"/>
|
||||
@@ -156,7 +156,7 @@
|
||||
<div class="mb-3 col-12">
|
||||
<label class="mb-1 text-primary" for="description"><span class="fw-bold">Biography</span></label>
|
||||
<textarea name="description" id="description" style="min-height: 120px"
|
||||
class="form-control o_wysiwyg_loader"><t t-esc="user.partner_id.website_description"/></textarea>
|
||||
class="form-control o_wysiwyg_loader" placeholder="Write a few words about yourself..."><t t-out="user.partner_id.website_description"/></textarea>
|
||||
</div>
|
||||
<div class="col">
|
||||
<button type="submit" class="btn btn-primary o_wprofile_submit_btn">Update</button>
|
||||
@@ -257,10 +257,9 @@
|
||||
<th><small class="fw-bold">Joined</small></th>
|
||||
<td><span t-field="user.create_date" t-options='{"format": "d MMM Y"}'/></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<tr t-if="user.badge_ids">
|
||||
<th><small class="fw-bold">Badges</small></th>
|
||||
<td t-if="user.badge_ids" t-esc="len(user.badge_ids.filtered(lambda b: b.badge_id.website_published))"/>
|
||||
<td t-else="">0</td>
|
||||
<td t-esc="len(user.badge_ids.filtered(lambda b: b.badge_id.website_published))"/>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
@@ -277,7 +276,7 @@
|
||||
</ul>
|
||||
<div class="tab-content py-4 o_wprofile_tabs_content mb-4" id="profile_extra_info_tabcontent">
|
||||
<div role="tabpanel" t-attf-class="tab-pane #{ 'show active' if not active_tab or active_tab == 'about' else '' }" id="profile_tab_content_about">
|
||||
<div class="o_wprofile_email_validation_container mb16 mt16">
|
||||
<div class="o_wprofile_email_validation_container">
|
||||
<t t-call="website_profile.email_validation_banner">
|
||||
<t t-set="redirect_url" t-value="'/profile/user/%s' % user.id"/>
|
||||
<t t-set="additional_validation_email_message"/>
|
||||
@@ -287,9 +286,18 @@
|
||||
<h5 class="border-bottom pb-1">Badges</h5>
|
||||
<t t-call="website_profile.user_badges"></t>
|
||||
</div>
|
||||
<div t-if="user.partner_id.website_description" class="mb32">
|
||||
<div t-if="user.partner_id.website_description" class="o_wprofile_editor_form mb32">
|
||||
<t t-if="request.env.user == user and user.karma != 0 or request.env.user._is_admin()">
|
||||
<a href="#" class="o_forum_profile_bio_edit btn btn-link float-end">
|
||||
<i class="fa fa-pencil me-1"/>Edit
|
||||
</a>
|
||||
<a href="#" class="o_forum_profile_bio_cancel_edit btn btn-link float-end d-none">
|
||||
<i class="fa fa-close me-1"/>Cancel
|
||||
</a>
|
||||
</t>
|
||||
<h5 class="border-bottom pb-1">Biography</h5>
|
||||
<span t-field="user.partner_id.website_description"/>
|
||||
<span class="o_forum_profile_bio text-break" t-field="user.partner_id.website_description"/>
|
||||
<t t-call="website_profile.user_biography_editor"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -298,6 +306,29 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template id="user_biography_editor" name="Edit User Biography">
|
||||
<form t-attf-action="/profile/user/save" method="post" role="form" class="o_forum_profile_bio_form js_website_submit_form row d-none">
|
||||
<input type="hidden" name="csrf_token" t-att-value="request.csrf_token()"/>
|
||||
<input name="user_id" t-att-value="user.id" type="hidden"/>
|
||||
<input name="name" t-att-value="user.name" type="hidden"/>
|
||||
<input name="website" t-att-value="user.partner_id.website" type="hidden"/>
|
||||
<input name="email" t-att-value="user.partner_id.email" type="hidden"/>
|
||||
<input name="city" t-att-value="user.partner_id.city" type="hidden"/>
|
||||
<input name="country" t-att-value="user.partner_id.country_id.id" type="hidden"/>
|
||||
<div class="row">
|
||||
<div class="mb-1 col-12">
|
||||
<textarea name="description" id="description" style="min-height: 120px"
|
||||
class="form-control o_wysiwyg_loader" placeholder="Write a few words about yourself...">
|
||||
<t t-out="user.partner_id.website_description"/>
|
||||
</textarea>
|
||||
</div>
|
||||
<div class="col">
|
||||
<button type="submit" class="btn btn-primary o_wprofile_submit_btn">Update</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</template>
|
||||
|
||||
<template id="profile_next_rank_card" name="Profile Next Rank Card">
|
||||
<div class="o_wprofile_progress_circle">
|
||||
<svg viewBox="0 0 36 36" class="o_pc_circular_chart">
|
||||
@@ -375,14 +406,21 @@
|
||||
</t>
|
||||
</t>
|
||||
</div>
|
||||
<div class="mb-3 d-inline-block" t-if="not user.badge_ids">
|
||||
<div class="mb-3" t-elif="request.env.user == user">
|
||||
Badges are your collection of achievements. Wear them proudly! <br />
|
||||
<a t-if="not user.badge_ids and badge_category" t-attf-href="/profile/ranks_badges?badge_category=#{badge_category}&url_origin=#{request.httprequest.path}&name_origin=#{user.name}"
|
||||
class="btn-link"><i class="fa fa-arrow-right"/> Get Badges</a>
|
||||
<a t-else="" t-attf-href="/profile/ranks_badges?url_origin=#{request.httprequest.path}&name_origin=#{user.name}"
|
||||
class="btn-link"><i class="fa fa-arrow-right"/> Get Badges</a>
|
||||
</div>
|
||||
<div t-else="" class="mb-3 d-inline-block">
|
||||
<p class="text-muted">No badges yet!</p>
|
||||
</div>
|
||||
<div class="text-end d-inline-block pull-right">
|
||||
<div t-if="request.env.user.id != user.id" class="text-end d-inline-block pull-right">
|
||||
<a t-if="not user.badge_ids and badge_category" t-attf-href="/profile/ranks_badges?badge_category=#{badge_category}&url_origin=#{request.httprequest.path}&name_origin=#{user.name}"
|
||||
class="btn btn-link btn-sm"><i class="oi oi-arrow-right"/> All Badges</a>
|
||||
class="btn-link btn-sm"><i class="oi oi-arrow-right"/> All Badges</a>
|
||||
<a t-else="" t-attf-href="/profile/ranks_badges?url_origin=#{request.httprequest.path}&name_origin=#{user.name}"
|
||||
class="btn btn-link btn-sm"><i class="oi oi-arrow-right me-1"/>All Badges</a>
|
||||
class="btn-link btn-sm"><i class="oi oi-arrow-right me-1"/>All Badges</a>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -1574,6 +1574,7 @@ class WebsiteSlides(WebsiteProfile):
|
||||
'courses_ongoing': courses_ongoing,
|
||||
'is_profile_page': True,
|
||||
'badge_category': 'slides',
|
||||
'my_profile': request.env.user.id == user.id,
|
||||
}
|
||||
return values
|
||||
|
||||
|
||||
@@ -17,8 +17,14 @@
|
||||
<t t-if="courses_completed" t-call="website_slides.display_course">
|
||||
<t t-set="courses" t-value="courses_completed"></t>
|
||||
</t>
|
||||
<div t-elif="request.env.user == user" class="text-muted d-inline-block">
|
||||
Go through all its content to see a Course in this section. <br />
|
||||
<a href="/slides/" class="btn-link">
|
||||
<i class="fa fa-arrow-right"></i> Start Learning
|
||||
</a>
|
||||
</div>
|
||||
<div t-else="" class="text-muted d-inline-block">No completed courses yet!</div>
|
||||
<div class="text-end d-inline-block pull-right">
|
||||
<div t-if="request.env.user != user" class="text-end d-inline-block pull-right">
|
||||
<a href="/slides/all" class="btn btn-link btn-sm"><i class="oi oi-arrow-right me-1"/>All Courses</a>
|
||||
</div>
|
||||
</div>
|
||||
@@ -27,6 +33,12 @@
|
||||
<t t-if="courses_ongoing" t-call="website_slides.display_course">
|
||||
<t t-set="courses" t-value="courses_ongoing"></t>
|
||||
</t>
|
||||
<p t-elif="request.env.user == user" class="text-muted">
|
||||
All the courses you attend will appear here. <br />
|
||||
<a href="/slides/" class="btn-link">
|
||||
<i class="fa fa-arrow-right"></i> Start Learning
|
||||
</a>
|
||||
</p>
|
||||
<p t-else="" class="text-muted">No ongoing courses yet!</p>
|
||||
</div>
|
||||
</t>
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
</template>
|
||||
<template name="Replace Breadcrumb Root" id="website_slides_forum_breadcrumb" inherit_id="website_forum.forum_model_nav" active="True">
|
||||
<xpath expr="//nav[@id='o_wforum_nav']" position="before">
|
||||
<t t-if="forum.slide_channel_id" t-set="breadcrumb_kind" t-value="'slides'"/>
|
||||
<t t-if="forum and forum.slide_channel_id" t-set="breadcrumb_kind" t-value="'slides'"/>
|
||||
</xpath>
|
||||
<xpath expr="//div[hasclass('o_wforum_breadcrumb_root_single')]" postition="inside">
|
||||
<ol t-if="breadcrumb_kind == 'slides'" class="breadcrumb col-10 col-lg-6 mb-0 p-0">
|
||||
|
||||
Reference in New Issue
Block a user