From c5564150b1835d5364605ef0338d01b025b3d4ad Mon Sep 17 00:00:00 2001 From: SirStendec Date: Sun, 8 Apr 2018 15:00:16 -0400 Subject: [PATCH] Clean up featured follow. Try to make the UX a bit nicer. Localize strings that weren't being localized. Add error handling. --- .../modules/featured-follow.vue | 94 +++++++---- .../modules/featured_follow.js | 156 ++++++++++-------- .../styles/featured_follow.scss | 7 +- 3 files changed, 151 insertions(+), 106 deletions(-) diff --git a/src/sites/twitch-twilight/modules/featured-follow.vue b/src/sites/twitch-twilight/modules/featured-follow.vue index 3e574acc..96f6588c 100644 --- a/src/sites/twitch-twilight/modules/featured-follow.vue +++ b/src/sites/twitch-twilight/modules/featured-follow.vue @@ -25,40 +25,48 @@

{{ user.displayName }}

- - - +
+ {{ t('featured-follow.error', 'An error occured.') }} +
+
@@ -72,6 +80,24 @@ export default { data() { return this.$vnode.data; + }, + + methods: { + clickWithTip(event, fn, ...args) { + const el = event.target, + tip = el && el._ffz_tooltip$0, + visible = tip && tip.visible; + + visible && tip.hide(); + fn.call(this, ...args); + visible && setTimeout(() => document.contains(el) && tip.show(), 0) + }, + + notifyTip(state) { + return state ? + this.t('featured-follow.notify.off', 'Notifications are currently disabled. Click to enable.') : + this.t('featured-follow.notify.on', 'Notifications are currently enabled. Click to disable.'); + } } } diff --git a/src/sites/twitch-twilight/modules/featured_follow.js b/src/sites/twitch-twilight/modules/featured_follow.js index dd2cd103..cb9bf2ea 100644 --- a/src/sites/twitch-twilight/modules/featured_follow.js +++ b/src/sites/twitch-twilight/modules/featured_follow.js @@ -5,14 +5,14 @@ // ============================================================================ import Module from 'utilities/module'; -import {createElement as e} from 'utilities/dom'; +import {createElement} from 'utilities/dom'; +import {has} from 'utilities/object'; import FEATURED_QUERY from './featured_follow_query.gql'; import FEATURED_FOLLOW from './featured_follow_follow.gql'; import FEATURED_UNFOLLOW from './featured_follow_unfollow.gql'; -const TWITCH_URL = /^(?:https?:\/\/)?(?:www\.)?twitch\.tv\/([A-Za-z0-9_]+)/i; export default class FeaturedFollow extends Module { constructor(...args) { @@ -84,31 +84,37 @@ export default class FeaturedFollow extends Module { this.follow_data = {}; this.socket.on(':command:follow_buttons', data => { - for(const channel_login in data) { - if (!data.hasOwnProperty(channel_login)) continue; + for(const channel_login in data) + if ( has(data, channel_login) ) + this.follow_data[channel_login] = data[channel_login]; - this.follow_data[channel_login] = data[channel_login]; - } - - if (this.vueFeaturedFollow) { + if ( this.vueFeaturedFollow ) this.vueFeaturedFollow.data.hasUpdate = true; - } this.metadata.updateMetadata('following'); }); - - // ffz.resolve('site.featured_follow').updateFeaturedChannels({ login: 'lordmau5' }, ['sirstendec','jugachi']); } async getFollowsForLogin(login) { const follow_data = this.follow_data && this.follow_data[login]; - if (!follow_data || follow_data.length === 0) return []; + if ( ! follow_data || ! follow_data.length ) + return []; - const ap_data = await this.apollo.client.query({ query: FEATURED_QUERY, variables: { logins: follow_data }}); + const ap_data = await this.apollo.client.query({ + query: FEATURED_QUERY, + variables: { + logins: follow_data + } + }), + follows = {}; - const follows = {}; for (const user of ap_data.data.users) { + if ( ! user.id ) + continue; + follows[user.id] = { + loading: false, + error: false, id: user.id, login: user.login, displayName: user.displayName, @@ -117,12 +123,13 @@ export default class FeaturedFollow extends Module { disableNotifications: user.self.follower.disableNotifications }; } + return follows; } buildFeaturedFollowMenu(vue, login, follows) { const vueEl = new vue.Vue({ - el: e('div'), + el: createElement('div'), render: h => this.vueFeaturedFollow = h('featured-follow', { login, follows, @@ -147,67 +154,82 @@ export default class FeaturedFollow extends Module { return vueEl.$el; } - updateFeaturedChannels(room, args) { - args = args.join(' ').trim().toLowerCase().split(/[ ,]+/); - - const out = []; - - for (let i = 0; i < args.length; i++) { - let arg = args[i]; - const match = arg.match(TWITCH_URL); - - if (match) - arg = match[1]; - - if (arg !== '' && out.indexOf(arg) === -1) - out.push(arg); - } - - this.socket.call('update_follow_buttons', room.login, out) - .then(() => { - // this.log.info('Success!', data); - }) - .catch(() => 'There was an error communicating with the server.'); - // , (success, data) => { - // if (!success) { - // this.log.warn('Not a Success: ', data); - // // f.room_message(room, data); - // return; - // } - - // this.log.info('Success!', data); - - // // this.room.message(`The following buttons have been ${data ? 'updated' : 'disabled'}.`); - // }) ) - - } - async followUser(follows, id) { - const ap_data = await this.apollo.client.mutate({ mutation: FEATURED_FOLLOW, variables: { targetID: id, disableNotifications: false }}); - - const follow = ap_data.data.followUser.follow; - - follows[id].following = follow.followedAt != null; - follows[id].disableNotifications = follow.disableNotifications; + const f = follows[id]; + f.loading = true; + + try { + const ap_data = await this.apollo.client.mutate({ + mutation: FEATURED_FOLLOW, + variables: { + targetID: id, + disableNotifications: false + } + }); + + const update = ap_data.data.followUser.follow; + + f.loading = false; + f.following = update.followedAt != null; + f.disableNotifications = update.disableNotifications; + + } catch(err) { + this.log.warn('There was a problem following.', err); + f.error = true; + } } async updateNotificationStatus(follows, id, oldStatus) { - const ap_data = await this.apollo.client.mutate({ mutation: FEATURED_FOLLOW, variables: { targetID: id, disableNotifications: !oldStatus }}); - - const follow = ap_data.data.followUser.follow; - - follows[id].following = follow.followedAt != null; - follows[id].disableNotifications = follow.disableNotifications; + const f = follows[id]; + f.loading = true; + + // Immediate Feedback + f.disableNotifications = ! oldStatus; + + try { + const ap_data = await this.apollo.client.mutate({ + mutation: FEATURED_FOLLOW, + variables: { + targetID: id, + disableNotifications: !oldStatus + } + }); + + const update = ap_data.data.followUser.follow; + + f.loading = false; + f.following = update.followedAt != null; + f.disableNotifications = update.disableNotifications; + + } catch(err) { + this.log.warn('There was a problem updating notification status.', err); + f.error = true; + } } async unfollowUser(follows, id) { - await this.apollo.client.mutate({ mutation: FEATURED_UNFOLLOW, variables: { targetID: id }}); - - follows[id].following = false; - follows[id].disableNotifications = false; + const f = follows[id]; + f.loading = true; + + try { + await this.apollo.client.mutate({ + mutation: FEATURED_UNFOLLOW, + variables: { + targetID: id + } + }); + + f.loading = false; + f.following = false; + f.disableNotifications = false; + + } catch(err) { + this.log.warn('There was a problem unfollowing.', err); + f.error = true; + } } route(channel) { this.router.navigate('user', { userName: channel }); } -} +} \ No newline at end of file diff --git a/src/sites/twitch-twilight/styles/featured_follow.scss b/src/sites/twitch-twilight/styles/featured_follow.scss index a616c056..25d3a068 100644 --- a/src/sites/twitch-twilight/styles/featured_follow.scss +++ b/src/sites/twitch-twilight/styles/featured_follow.scss @@ -4,15 +4,12 @@ } .ffz--featured-button-unfollow { - &:hover &:before { + &:hover figure:before { content: '\e813'; } - - > * { - pointer-events: none; - } } + .ffz--featured-button-unfollow, .ffz--featured-button-notification { > * { pointer-events: none;