Merge pull request #7344 from surajshetty3416/fix-social-ui
feat(social): Add period filter and user search option for leaderboard and edit profile dialog
This commit is contained in:
commit
d87b900f7e
7 changed files with 228 additions and 151 deletions
|
|
@ -12,6 +12,8 @@ from frappe.utils.user import get_system_managers
|
|||
import frappe.permissions
|
||||
import frappe.share
|
||||
import re
|
||||
import json
|
||||
|
||||
from frappe.limits import get_limits
|
||||
from frappe.website.utils import is_signup_enabled
|
||||
from frappe.utils.background_jobs import enqueue
|
||||
|
|
@ -1086,4 +1088,12 @@ def generate_keys(user):
|
|||
user_details.save()
|
||||
|
||||
return {"api_secret": api_secret}
|
||||
frappe.throw(frappe._("Not Permitted"), frappe.PermissionError)
|
||||
frappe.throw(frappe._("Not Permitted"), frappe.PermissionError)
|
||||
|
||||
@frappe.whitelist()
|
||||
def update_profile_info(profile_info):
|
||||
profile_info = json.loads(profile_info)
|
||||
user = frappe.get_doc('User', frappe.session.user)
|
||||
user.update(profile_info)
|
||||
user.save()
|
||||
return user
|
||||
|
|
@ -60,10 +60,6 @@ export default {
|
|||
this.show_preview = false;
|
||||
})
|
||||
|
||||
frappe.app_updates.on('user_image_updated', () => {
|
||||
this.$root.$emit('user_image_updated')
|
||||
})
|
||||
|
||||
this.update_primary_action(frappe.get_route()[1])
|
||||
},
|
||||
mounted() {
|
||||
|
|
|
|||
|
|
@ -22,13 +22,13 @@
|
|||
</template>
|
||||
<script>
|
||||
export default {
|
||||
props: ['user'],
|
||||
props: ['user', 'from_date'],
|
||||
data() {
|
||||
return {
|
||||
history_logs: [],
|
||||
fetching: false,
|
||||
has_more_logs: true
|
||||
}
|
||||
};
|
||||
},
|
||||
created() {
|
||||
this.get_logs();
|
||||
|
|
@ -37,34 +37,37 @@ export default {
|
|||
get_logs() {
|
||||
this.fetching = true;
|
||||
const pull_limit = 10;
|
||||
frappe.db.get_list('Energy Point Log', {
|
||||
filters: {
|
||||
user: this.user,
|
||||
type: ['!=', 'Review']
|
||||
},
|
||||
fields: ['*'],
|
||||
limit: pull_limit,
|
||||
limit_start: this.history_logs.length
|
||||
}).then(data => {
|
||||
this.history_logs = this.history_logs.concat(data);
|
||||
this.has_more_logs = data.length === pull_limit;
|
||||
}).finally(() => {
|
||||
this.fetching = false;
|
||||
})
|
||||
frappe.db
|
||||
.get_list('Energy Point Log', {
|
||||
filters: {
|
||||
user: this.user,
|
||||
type: ['!=', 'Review'],
|
||||
creation: ['>=', this.from_date]
|
||||
},
|
||||
fields: ['*'],
|
||||
limit: pull_limit,
|
||||
limit_start: this.history_logs.length
|
||||
})
|
||||
.then(data => {
|
||||
this.history_logs = this.history_logs.concat(data);
|
||||
this.has_more_logs = data.length === pull_limit;
|
||||
})
|
||||
.finally(() => {
|
||||
this.fetching = false;
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<style lang="less">
|
||||
@import "frappe/public/less/common";
|
||||
@import 'frappe/public/less/common';
|
||||
.log-list {
|
||||
padding: 15px;
|
||||
padding-left: 0px;
|
||||
position: relative;
|
||||
}
|
||||
.log-list:before {
|
||||
content: " ";
|
||||
content: ' ';
|
||||
border-left: 1px solid @border-color;
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
|
|
@ -82,7 +85,7 @@ export default {
|
|||
position: relative;
|
||||
}
|
||||
.history-log:before {
|
||||
content: " ";
|
||||
content: ' ';
|
||||
width: 7px;
|
||||
height: 7px;
|
||||
background-color: @border-color;
|
||||
|
|
|
|||
|
|
@ -2,8 +2,6 @@
|
|||
<div ref="banner" class="banner" :style="background_style">
|
||||
<div
|
||||
class="user-avatar container"
|
||||
:class="{'editable-image': is_own_profile}"
|
||||
@click="update_image"
|
||||
v-html="user_avatar">
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -13,29 +11,23 @@ export default {
|
|||
props: ['user_id'],
|
||||
data() {
|
||||
return {
|
||||
is_own_profile: this.user_id === frappe.session.user,
|
||||
user_avatar: frappe.avatar(this.user_id, 'avatar-xl'),
|
||||
background_style: {
|
||||
'background': '#262626'
|
||||
}
|
||||
user_banner: frappe.user_info(this.user_id).banner_image
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.$root.$on('user_image_updated', () => {
|
||||
this.user_avatar = frappe.avatar(this.user_id, 'avatar-xl')
|
||||
this.user_banner = frappe.user_info(this.user_id).banner_image
|
||||
})
|
||||
const user_banner = frappe.user_info(this.user_id).banner_image;
|
||||
if (user_banner) {
|
||||
this.background_style = {
|
||||
'background-image': `url('${user_banner}')`
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
update_image() {
|
||||
if (this.is_own_profile) {
|
||||
frappe.social.update_user_image.show()
|
||||
computed: {
|
||||
background_style() {
|
||||
const style = {}
|
||||
if (this.user_banner) {
|
||||
style['background-image'] = `url('${this.user_banner}')`
|
||||
}
|
||||
return style;
|
||||
}
|
||||
},
|
||||
}
|
||||
|
|
@ -51,6 +43,7 @@ export default {
|
|||
background-size: cover;
|
||||
background-position: center;
|
||||
background-repeat: no-repeat;
|
||||
background-color: '#262626';
|
||||
.user-avatar {
|
||||
position: relative;
|
||||
/deep/ .avatar {
|
||||
|
|
|
|||
|
|
@ -4,62 +4,126 @@
|
|||
<h3>{{ user.fullname }}</h3>
|
||||
<p>{{ user.bio }}</p>
|
||||
<div class="location" v-if="user.location">
|
||||
<span class="text-muted"><i class="fa fa-map-marker"> </i>{{ user.location }}</span>
|
||||
<span class="text-muted">
|
||||
<i class="fa fa-map-marker"> </i>
|
||||
{{ user.location }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="interest" v-if="user.interest">
|
||||
<span class="text-muted"><i class="fa fa-puzzle-piece"> </i>{{ user.interest }}</span>
|
||||
<span class="text-muted">
|
||||
<i class="fa fa-puzzle-piece"> </i>
|
||||
{{ user.interest }}
|
||||
</span>
|
||||
</div>
|
||||
<a v-if="show_add_info_link" @click="go_to_user_settings">{{ __('Add your information') }}</a>
|
||||
</div>
|
||||
<a class="home-link" @click="go_to_home()"> ← {{ __('Back To Home') }}</a>
|
||||
<a
|
||||
class="edit-profile-link"
|
||||
v-if="can_edit_profile"
|
||||
@click="edit_profile()"
|
||||
>{{ __('Edit Profile') }}</a>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
'user_id': String,
|
||||
user_id: String
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
'user': frappe.user_info(this.user_id),
|
||||
'show_add_info_link': false
|
||||
}
|
||||
},
|
||||
created() {
|
||||
if (frappe.social.is_session_user_page() && this.is_info_missing()) {
|
||||
this.show_add_info_link = true;
|
||||
}
|
||||
user: frappe.user_info(this.user_id),
|
||||
can_edit_profile: frappe.social.is_session_user_page()
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
is_info_missing() {
|
||||
return !this.user.location || !this.user.interest || !this.user.bio;
|
||||
},
|
||||
go_to_home() {
|
||||
frappe.set_route('social', 'home');
|
||||
},
|
||||
go_to_user_settings() {
|
||||
frappe.set_route('Form', 'User', this.user_id).then(()=> {
|
||||
frappe.dom.scroll_to_section('More Information');
|
||||
})
|
||||
edit_profile() {
|
||||
const edit_profile_dialog = new frappe.ui.Dialog({
|
||||
title: __('Edit Profile'),
|
||||
fields: [
|
||||
{
|
||||
fieldtype: 'Attach Image',
|
||||
fieldname: 'user_image',
|
||||
label: 'Profile Image',
|
||||
reqd: 1
|
||||
},
|
||||
{
|
||||
fieldtype: 'Data',
|
||||
fieldname: 'interest',
|
||||
label: 'Interests',
|
||||
reqd: 1
|
||||
},
|
||||
{
|
||||
fieldtype: 'Column Break'
|
||||
},
|
||||
{
|
||||
fieldtype: 'Attach Image',
|
||||
fieldname: 'banner_image',
|
||||
label: 'Banner Image',
|
||||
reqd: 1
|
||||
},
|
||||
{
|
||||
fieldtype: 'Data',
|
||||
fieldname: 'location',
|
||||
label: 'Location',
|
||||
reqd: 1
|
||||
},
|
||||
{
|
||||
fieldtype: 'Section Break',
|
||||
fieldname: 'Interest'
|
||||
},
|
||||
{
|
||||
fieldtype: 'Small Text',
|
||||
fieldname: 'bio',
|
||||
label: 'Bio',
|
||||
reqd: 1
|
||||
}
|
||||
],
|
||||
primary_action: values => {
|
||||
edit_profile_dialog.disable_primary_action();
|
||||
frappe
|
||||
.xcall('frappe.core.doctype.user.user.update_profile_info', {
|
||||
profile_info: values
|
||||
})
|
||||
.then(user => {
|
||||
user.image = user.user_image;
|
||||
let user_info = frappe.user_info(this.user_id);
|
||||
this.user = Object.assign(user_info, user);
|
||||
this.$root.$emit('user_image_updated');
|
||||
edit_profile_dialog.hide();
|
||||
})
|
||||
.finally(() => {
|
||||
edit_profile_dialog.enable_primary_action();
|
||||
});
|
||||
},
|
||||
primary_action_label: __('Save')
|
||||
});
|
||||
edit_profile_dialog.set_values({
|
||||
user_image: this.user.image,
|
||||
banner_image: this.user.banner_image,
|
||||
location: this.user.location,
|
||||
interest: this.user.interest,
|
||||
bio: this.user.bio
|
||||
});
|
||||
edit_profile_dialog.show();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.profile-sidebar {
|
||||
padding: 10px 10px 0 0
|
||||
padding: 10px 10px 0 0;
|
||||
}
|
||||
.user-details {
|
||||
min-height: 150px;
|
||||
.location, .interest {
|
||||
.location,
|
||||
.interest {
|
||||
margin-bottom: 10px;
|
||||
i {
|
||||
width: 15px;
|
||||
}
|
||||
}
|
||||
.home-link {
|
||||
margin-top: 15px;
|
||||
}
|
||||
}
|
||||
.edit-profile-link {
|
||||
margin-top: 15px;
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -3,47 +3,53 @@
|
|||
<ul class="list-unstyled user-list">
|
||||
<li class="user-card user-list-header text-medium">
|
||||
<span class="user-details text-muted">
|
||||
{{ __('User') }}
|
||||
<input
|
||||
class="form-control"
|
||||
type="search"
|
||||
placeholder="Search User"
|
||||
v-model="filter_users_by"
|
||||
>
|
||||
</span>
|
||||
<span class="user-points text-muted">
|
||||
{{ __('Energy Points') }}
|
||||
</span>
|
||||
<span class="user-points text-muted">
|
||||
{{ __('Review Points') }}
|
||||
</span>
|
||||
<span class="user-points text-muted">
|
||||
{{ __('Points Given') }}
|
||||
<span class="flex-40"></span>
|
||||
<span class="flex-20 text-muted">
|
||||
<select class="form-control" data-toggle="tooltip" title="Period" v-model="period">
|
||||
<option v-for="value in period_options" :key="value" :value="value">{{ value }}</option>
|
||||
</select>
|
||||
</span>
|
||||
</li>
|
||||
<li
|
||||
v-for="user in filtered_users"
|
||||
:key="user.name">
|
||||
<li class="user-card user-list-header text-medium">
|
||||
<span class="user-details text-muted">{{ __('User') }}</span>
|
||||
<span
|
||||
class="flex-20 text-muted"
|
||||
v-for="title in ['Energy Points', 'Review Points', 'Points Given']"
|
||||
:key="title"
|
||||
>{{ __(title) }}</span>
|
||||
</li>
|
||||
<li v-for="user in filtered_users" :key="user.name">
|
||||
<div class="user-card" @click="toggle_log(user.name)">
|
||||
<div class="user-details flex">
|
||||
<span class="user-details flex">
|
||||
<span v-html="get_avatar(user.name)"></span>
|
||||
<span>
|
||||
<a @click="go_to_profile_page(user.name)">{{ user.fullname }}</a>
|
||||
<div class="text-muted text-medium" :class="{'italic': !user.bio}">
|
||||
{{ frappe.ellipsis(user.bio, 100) || 'No Bio'}}
|
||||
</div>
|
||||
<div
|
||||
class="text-muted text-medium"
|
||||
:class="{'italic': !user.bio}"
|
||||
>{{ frappe.ellipsis(user.bio, 100) || 'No Bio'}}</div>
|
||||
</span>
|
||||
</div>
|
||||
<span class="text-muted text-nowrap user-points">
|
||||
{{ user.energy_points }}
|
||||
</span>
|
||||
<span class="text-muted text-nowrap user-points">
|
||||
{{ user.review_points }}
|
||||
</span>
|
||||
<span class="text-muted text-nowrap user-points">
|
||||
{{ user.given_points }}
|
||||
</span>
|
||||
<span
|
||||
class="text-muted text-nowrap flex-20"
|
||||
v-for="key in ['energy_points', 'review_points', 'given_points']"
|
||||
:key="key"
|
||||
>{{ user[key] }}</span>
|
||||
</div>
|
||||
<energy-point-history
|
||||
v-show="show_log_for===user.name"
|
||||
class="energy-point-history"
|
||||
:user="user.name"
|
||||
:key="user.name + user.energy_points">
|
||||
</energy-point-history>
|
||||
:from_date="from_date"
|
||||
:key="user.name + user.energy_points"
|
||||
></energy-point-history>
|
||||
</li>
|
||||
<li class="user-card text-muted" v-if="!filtered_users.length">{{__('No user found')}}</li>
|
||||
</ul>
|
||||
|
|
@ -61,17 +67,33 @@ export default {
|
|||
filter_users_by: null,
|
||||
sort_users_by: 'energy_points',
|
||||
sort_order: 'desc',
|
||||
show_log_for: null
|
||||
}
|
||||
show_log_for: null,
|
||||
period_options: ['Lifetime', 'Last Month', 'Last Week', 'Today'],
|
||||
period: 'Lifetime'
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
from_date() {
|
||||
const days_to_deduct = {
|
||||
'Last Week': 7,
|
||||
'Last Month': 30
|
||||
};
|
||||
if (this.period === 'Lifetime') {
|
||||
return null;
|
||||
}
|
||||
if (this.period === 'Today') {
|
||||
return frappe.datetime.get_today();
|
||||
}
|
||||
return frappe.datetime.add_days(moment(), -days_to_deduct[this.period]);
|
||||
},
|
||||
filtered_users() {
|
||||
let filtered = this.users.slice();
|
||||
|
||||
if (this.filter_users_by) {
|
||||
filtered = filtered.filter(user =>
|
||||
user.fullname.toLowerCase().includes(this.filter_users_by.toLowerCase())
|
||||
)
|
||||
user.fullname
|
||||
.toLowerCase()
|
||||
.includes(this.filter_users_by.toLowerCase())
|
||||
);
|
||||
}
|
||||
|
||||
if (this.sort_users_by) {
|
||||
|
|
@ -89,15 +111,23 @@ export default {
|
|||
}
|
||||
|
||||
if (this.sort_order === 'desc') {
|
||||
return_value = -return_value
|
||||
return_value = -return_value;
|
||||
}
|
||||
|
||||
return return_value
|
||||
return return_value;
|
||||
});
|
||||
}
|
||||
return filtered;
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
period() {
|
||||
this.fetch_users_energy_points_and_update_users();
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
$('[data-toggle="tooltip"]').tooltip();
|
||||
},
|
||||
created() {
|
||||
const standard_users = ['Administrator', 'Guest', 'guest@example.com'];
|
||||
this.users = frappe.boot.user_info;
|
||||
|
|
@ -111,37 +141,42 @@ export default {
|
|||
},
|
||||
methods: {
|
||||
get_avatar(user) {
|
||||
return frappe.avatar(user, 'avatar-medium')
|
||||
return frappe.avatar(user, 'avatar-medium');
|
||||
},
|
||||
go_to_profile_page(user) {
|
||||
frappe.set_route('social', 'profile', user)
|
||||
frappe.set_route('social', 'profile', user);
|
||||
},
|
||||
fetch_users_energy_points_and_update_users() {
|
||||
frappe.xcall(
|
||||
'frappe.social.doctype.energy_point_log.energy_point_log.get_user_energy_and_review_points'
|
||||
).then(data => {
|
||||
let users = this.users.slice();
|
||||
this.users = users.map(user => {
|
||||
const points = data[user.name] || {};
|
||||
user.energy_points = points.energy_points || 0;
|
||||
user.review_points = points.review_points || 0;
|
||||
user.given_points = points.given_points || 0;
|
||||
return user;
|
||||
frappe
|
||||
.xcall(
|
||||
'frappe.social.doctype.energy_point_log.energy_point_log.get_user_energy_and_review_points',
|
||||
{
|
||||
from_date: this.from_date
|
||||
}
|
||||
)
|
||||
.then(data => {
|
||||
let users = this.users.slice();
|
||||
this.users = users.map(user => {
|
||||
const points = data[user.name] || {};
|
||||
user.energy_points = points.energy_points || 0;
|
||||
user.review_points = points.review_points || 0;
|
||||
user.given_points = points.given_points || 0;
|
||||
return user;
|
||||
});
|
||||
});
|
||||
});
|
||||
},
|
||||
toggle_log(user) {
|
||||
if (this.show_log_for === user) {
|
||||
this.show_log_for = null
|
||||
this.show_log_for = null;
|
||||
} else {
|
||||
this.show_log_for = user
|
||||
this.show_log_for = user;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
@import "frappe/public/less/variables";
|
||||
@import 'frappe/public/less/variables';
|
||||
.user-list {
|
||||
border-left: 1px solid @border-color;
|
||||
border-right: 1px solid @border-color;
|
||||
|
|
@ -158,11 +193,14 @@ export default {
|
|||
}
|
||||
}
|
||||
}
|
||||
.user-points {
|
||||
.flex-20 {
|
||||
flex: 0 0 20%;
|
||||
text-align: right;
|
||||
align-self: center;
|
||||
}
|
||||
.flex-40 {
|
||||
flex: 0 0 40%;
|
||||
}
|
||||
.user-list-header {
|
||||
background-color: @light-bg;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -48,33 +48,6 @@ frappe.social.post_dialog = new frappe.ui.Dialog({
|
|||
}
|
||||
});
|
||||
|
||||
frappe.social.update_user_image = new frappe.ui.Dialog({
|
||||
title: __("User Image"),
|
||||
fields: [
|
||||
{
|
||||
fieldtype: "Attach Image",
|
||||
fieldname: "image",
|
||||
label: __("Image"),
|
||||
reqd: 1,
|
||||
default: frappe.user.image()
|
||||
},
|
||||
],
|
||||
primary_action_label: __('Set Image'),
|
||||
primary_action: (values) => {
|
||||
const user = frappe.session.user;
|
||||
frappe.db.set_value('User', user, 'user_image', values.image)
|
||||
.then((resp) => {
|
||||
frappe.boot.user_info[user].image = resp.message.user_image;
|
||||
frappe.app_updates.trigger('user_image_updated');
|
||||
frappe.social.update_user_image.clear();
|
||||
frappe.social.update_user_image.hide();
|
||||
})
|
||||
.fail((err) => {
|
||||
frappe.msgprint(err);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
frappe.social.is_home_page = () => {
|
||||
return frappe.get_route()[0] === 'social' && frappe.get_route()[1] === 'home';
|
||||
};
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue