Gitter migration: Point people to app.gitter.im (rollout pt. 1)
[gitter.git] / public / js / views / profile-menu / profile-menu-view.js
blob63f1bc31c2cb9eea4c97193963bfc6391c0a3d6e
1 'use strict';
3 var Marionette = require('backbone.marionette');
4 var Backbone = require('backbone');
5 var _ = require('lodash');
6 var log = require('../../utils/log');
7 var appEvents = require('../../utils/appevents');
8 const clientEnv = require('gitter-client-env');
9 var template = require('./profile-menu-view.hbs');
10 var itemTemplate = require('./profile-menu-item-view.hbs');
11 var toggleClass = require('../../utils/toggle-class');
12 var logout = require('../../utils/logout');
13 var isNative = require('../../utils/is-native');
14 var context = require('gitter-web-client-context');
15 var toggleDarkTheme = require('../../utils/toggle-dark-theme');
16 var autoModelSave = require('../../utils/auto-model-save');
17 var showDesktopNotification = require('../../utils/show-desktop-notification');
18 var apiClient = require('../../components/api-client');
20 require('@gitterhq/styleguide/css/components/dropdowns.css');
22 function getProfileCollection() {
23   var result = new Backbone.Collection([{ name: 'Home', stub: '/home' }]);
25   var isWebApp = !isNative();
27   var user = context.user();
29   // This is more fragile than i'd like it to be
30   function showHideRepoAccess() {
31     var scopes = user.get('scopes');
32     var existing = result.find(function(f) {
33       return f.get('upgradeItem');
34     });
36     if (!user.id || !scopes || scopes.private_repo) {
37       // Hide the scope
38       if (!existing) return;
39       result.remove(existing);
40     } else {
41       // Show the scope
42       if (existing) return;
43       var appsItem = result.find(function(f) {
44         return f.get('stub') === '/apps';
45       });
47       result.add(
48         {
49           name: 'Allow Private Repo Access',
50           stub: '/login/upgrade?scopes=repo',
51           upgradeItem: true
52         },
53         {
54           at: result.indexOf(appsItem) + 1
55         }
56       );
57     }
58   }
60   showHideRepoAccess();
61   user.on('change:id', showHideRepoAccess);
62   user.on('change:scopes', showHideRepoAccess);
64   var currentTheme = hasDarkTheme() ? 'gitter-dark' : '';
65   result.add({
66     name: 'Toggle Dark Theme',
67     stub: '#dark-theme',
68     onClick(e) {
69       e.preventDefault();
71       var newTheme = currentTheme === 'gitter-dark' ? '' : 'gitter-dark';
73       toggleDarkTheme(!!newTheme.length);
75       apiClient.user.put('/settings/userTheme', { theme: newTheme }).catch(err => {
76         showDesktopNotification({
77           title: 'Problem persisting /settings/userTheme',
78           text: '(see devtools console for details)'
79         });
80         log.error('Problem persisting /settings/userTheme', { exception: err });
81       });
83       currentTheme = newTheme;
84     }
85   });
87   result.add({
88     name: 'Terms of Service',
89     stub: 'https://element.io/terms-of-service',
90     target: '_blank'
91   });
93   result.add({
94     name: 'Contribute to Gitter',
95     stub: 'https://gitlab.com/gitterHQ/webapp',
96     target: '_blank'
97   });
99   result.add({
100     name: 'Help (Documentation)',
101     stub: 'https://gitlab.com/gitterHQ/webapp/tree/develop/docs#documentation',
102     target: '_blank'
103   });
105   result.add({
106     name: "What's new?",
107     stub: 'https://gitlab.com/gitterHQ/webapp/blob/develop/CHANGELOG.md',
108     target: '_blank'
109   });
111   if (clientEnv.exportEnabled) {
112     result.add({
113       name: 'Export user data',
114       onClick: e => {
115         e.preventDefault();
116         appEvents.trigger('route', 'export-user-data');
117       }
118     });
119   }
121   result.add({
122     name: 'Delete Account',
123     onClick: e => {
124       e.preventDefault();
125       appEvents.trigger('route', 'delete-account');
126     }
127   });
129   if (isWebApp) {
130     result.add({
131       name: 'Sign Out',
132       stub: '/logout',
133       onClick: e => {
134         e.preventDefault();
135         logout();
136       }
137     });
138   }
140   return result;
143 function hasDarkTheme() {
144   var r = document.getElementById('gitter-dark');
145   return !!r;
148 var ProfileMenuModel = Backbone.Model.extend({
149   initialize: function() {
150     autoModelSave(this, ['theme'], this.autoPersist);
151   }
154 var ItemView = Marionette.ItemView.extend({
155   tagName: 'li',
156   className: 'dropdown__item--positive profile-menu__item',
157   template: itemTemplate,
158   events: {
159     'click a': 'onItemClicked'
160   },
162   onItemClicked: function(e) {
163     const cb = this.model.get('onClick');
164     if (cb) {
165       cb(e);
166     }
167   }
170 module.exports = Marionette.CompositeView.extend({
171   template: template,
172   childView: ItemView,
173   childViewContainer: '#profile-menu-items',
175   constructor: function() {
176     this.collection = getProfileCollection();
178     this.model = new ProfileMenuModel();
180     //Super
181     Marionette.CollectionView.prototype.constructor.apply(this, arguments);
182   },
184   ui: {
185     menu: '#profile-menu-items',
186     menuBackdrop: '#profile-menu-items-backdrop'
187   },
189   events: {
190     'click #profile-menu-avatar': 'onAvatarClicked',
191     'mouseleave @ui.menu': 'onMouseLeave',
192     'click @ui.menuBackdrop': 'onBackdropClicked'
193   },
195   modelEvents: {
196     'change:active': 'onActiveStateChange'
197   },
199   serializeData: function() {
200     var data = this.model.toJSON();
201     var user = context.user();
202     return _.extend({}, data, {
203       avatarUrl: user.get('avatarUrl'),
204       username: user.get('username')
205     });
206   },
208   onMouseLeave() {
209     this.model.set('active', false);
210   },
212   onBackdropClicked() {
213     this.model.set('active', false);
214   },
216   onAvatarClicked: function(e) {
217     e.preventDefault();
218     this.model.set({ active: true });
219   },
221   onActiveStateChange: function() {
222     var state = this.model.get('active');
223     toggleClass(this.ui.menu[0], 'hidden', !state);
224     toggleClass(this.ui.menuBackdrop[0], 'hidden', !state);
225   }