Merge branch 'BerkeleyTrue-fix/theme-flash' into staging
This commit is contained in:
@ -64,7 +64,6 @@ body.top-and-bottom-margins {
|
|||||||
}
|
}
|
||||||
|
|
||||||
body.no-top-and-bottom-margins {
|
body.no-top-and-bottom-margins {
|
||||||
display: none;
|
|
||||||
margin: 75px 20px 0px 20px;
|
margin: 75px 20px 0px 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -165,6 +165,7 @@ main.setMapShare = function setMapShare(id) {
|
|||||||
|
|
||||||
$(document).ready(function() {
|
$(document).ready(function() {
|
||||||
|
|
||||||
|
const { Observable } = window.Rx;
|
||||||
var CSRF_HEADER = 'X-CSRF-Token';
|
var CSRF_HEADER = 'X-CSRF-Token';
|
||||||
|
|
||||||
var setCSRFToken = function(securityToken) {
|
var setCSRFToken = function(securityToken) {
|
||||||
@ -548,51 +549,68 @@ $(document).ready(function() {
|
|||||||
// keyboard shortcuts: open map
|
// keyboard shortcuts: open map
|
||||||
window.Mousetrap.bind('g m', toggleMap);
|
window.Mousetrap.bind('g m', toggleMap);
|
||||||
|
|
||||||
// Night Mode
|
function addAlert(message = '', type = 'alert-info') {
|
||||||
function changeMode() {
|
return $('.flashMessage').append($(`
|
||||||
var newValue = false;
|
<div class='alert ${type}'>
|
||||||
try {
|
<button class='close' type='button', data-dismiss='alert'>
|
||||||
newValue = !JSON.parse(localStorage.getItem('nightMode'));
|
<span class='ion-close-circled' />
|
||||||
} catch (e) {
|
</Button>
|
||||||
console.error('Error parsing value form local storage:', 'nightMode', e);
|
<div>${message}</div>
|
||||||
}
|
</div>
|
||||||
localStorage.setItem('nightMode', String(newValue));
|
`));
|
||||||
toggleNightMode(newValue);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function toggleNightMode(nightModeEnabled) {
|
function toggleNightMode() {
|
||||||
var iframe = document.getElementById('map-aside-frame');
|
if (!main.userId) {
|
||||||
if (iframe) {
|
return addAlert('You must be logged in to use our themes.');
|
||||||
iframe.src = iframe.src;
|
|
||||||
}
|
}
|
||||||
var body = $('body');
|
const iframe$ = document.getElementById('map-aside-frame');
|
||||||
body.hide();
|
const body$ = $('body');
|
||||||
if (nightModeEnabled) {
|
if (iframe$) {
|
||||||
body.addClass('night');
|
iframe$.src = iframe$.src;
|
||||||
|
}
|
||||||
|
body$.hide();
|
||||||
|
let updateThemeTo;
|
||||||
|
if (body$.hasClass('night')) {
|
||||||
|
body$.removeClass('night');
|
||||||
|
updateThemeTo = 'default';
|
||||||
} else {
|
} else {
|
||||||
body.removeClass('night');
|
body$.addClass('night');
|
||||||
|
updateThemeTo = 'night';
|
||||||
}
|
}
|
||||||
body.fadeIn('100');
|
body$.fadeIn('100');
|
||||||
|
const options = {
|
||||||
|
url: `/api/users/${main.userId}/update-theme`,
|
||||||
|
type: 'POST',
|
||||||
|
data: { theme: updateThemeTo },
|
||||||
|
dataType: 'json'
|
||||||
|
};
|
||||||
|
return $.ajax(options)
|
||||||
|
.success(() => console.log('theme updated successfully'))
|
||||||
|
.fail(err => {
|
||||||
|
let message;
|
||||||
|
try {
|
||||||
|
message = JSON.parse(err.responseText).error.message;
|
||||||
|
} catch (error) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (!message) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return addAlert(message);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeof localStorage.getItem('nightMode') !== 'undefined') {
|
Observable.merge(
|
||||||
var oldVal = false;
|
Observable.fromEvent($('#night-mode'), 'click'),
|
||||||
try {
|
Observable.create(observer => {
|
||||||
oldVal = JSON.parse(localStorage.getItem('nightMode'));
|
window.Mousetrap.bind('g t n', () => observer.onNext());
|
||||||
} catch (e) {
|
})
|
||||||
console.error('Error parsing value form local storage:', 'nightMode', e);
|
)
|
||||||
}
|
.debounce(500)
|
||||||
toggleNightMode(oldVal);
|
.subscribe(toggleNightMode, err => console.error(err));
|
||||||
$('.nightMode-btn').on('click', function() {
|
|
||||||
changeMode();
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
localStorage.setItem('nightMode', 'false');
|
|
||||||
toggleNightMode('false');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Hot Keys
|
// Hot Keys
|
||||||
window.Mousetrap.bind('g t n', changeMode);
|
|
||||||
window.Mousetrap.bind('g n n', () => {
|
window.Mousetrap.bind('g n n', () => {
|
||||||
// Next Challenge
|
// Next Challenge
|
||||||
window.location = '/challenges/next-challenge';
|
window.location = '/challenges/next-challenge';
|
||||||
|
@ -486,6 +486,91 @@ module.exports = function(User) {
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
User.prototype.updateEmail = function updateEmail(email) {
|
||||||
|
if (this.email && this.email === email) {
|
||||||
|
return Promise.reject(new Error(
|
||||||
|
`${email} is already associated with this account.`
|
||||||
|
));
|
||||||
|
}
|
||||||
|
return User.doesExist(null, email)
|
||||||
|
.then(exists => {
|
||||||
|
if (exists) {
|
||||||
|
return Promise.reject(
|
||||||
|
new Error(`${email} is already associated with another account.`)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return this.update$({ email }).toPromise();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
User.remoteMethod(
|
||||||
|
'updateEmail',
|
||||||
|
{
|
||||||
|
isStatic: false,
|
||||||
|
description: 'updates the email of the user object',
|
||||||
|
accepts: [
|
||||||
|
{
|
||||||
|
arg: 'email',
|
||||||
|
type: 'string',
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
returns: [
|
||||||
|
{
|
||||||
|
arg: 'status',
|
||||||
|
type: 'object'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
http: {
|
||||||
|
path: '/update-email',
|
||||||
|
verb: 'POST'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
User.themes = {
|
||||||
|
night: true,
|
||||||
|
default: true
|
||||||
|
};
|
||||||
|
User.prototype.updateTheme = function updateTheme(theme) {
|
||||||
|
if (!this.constructor.themes[theme]) {
|
||||||
|
const err = new Error(
|
||||||
|
'Theme is not valid.'
|
||||||
|
);
|
||||||
|
err.messageType = 'info';
|
||||||
|
err.userMessage = err.message;
|
||||||
|
return Promise.reject(err);
|
||||||
|
}
|
||||||
|
return this.update$({ theme })
|
||||||
|
.map({ updatedTo: theme })
|
||||||
|
.toPromise();
|
||||||
|
};
|
||||||
|
|
||||||
|
User.remoteMethod(
|
||||||
|
'updateTheme',
|
||||||
|
{
|
||||||
|
isStatic: false,
|
||||||
|
description: 'updates the users chosen theme',
|
||||||
|
accepts: [
|
||||||
|
{
|
||||||
|
arg: 'theme',
|
||||||
|
type: 'string',
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
returns: [
|
||||||
|
{
|
||||||
|
arg: 'status',
|
||||||
|
type: 'object'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
http: {
|
||||||
|
path: '/update-theme',
|
||||||
|
verb: 'POST'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
// user.updateTo$(updateData: Object) => Observable[Number]
|
// user.updateTo$(updateData: Object) => Observable[Number]
|
||||||
User.prototype.update$ = function update$(updateData) {
|
User.prototype.update$ = function update$(updateData) {
|
||||||
const id = this.getId();
|
const id = this.getId();
|
||||||
|
@ -188,6 +188,10 @@
|
|||||||
},
|
},
|
||||||
"timezone": {
|
"timezone": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
|
},
|
||||||
|
"theme": {
|
||||||
|
"type": "string",
|
||||||
|
"default": "default"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"validations": [],
|
"validations": [],
|
||||||
@ -242,6 +246,13 @@
|
|||||||
"principalId": "$owner",
|
"principalId": "$owner",
|
||||||
"permission": "ALLOW",
|
"permission": "ALLOW",
|
||||||
"property": "updateEmail"
|
"property": "updateEmail"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"accessType": "EXECUTE",
|
||||||
|
"principalType": "ROLE",
|
||||||
|
"principalId": "$owner",
|
||||||
|
"permission": "ALLOW",
|
||||||
|
"property": "updateTheme"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"methods": []
|
"methods": []
|
||||||
|
@ -6,6 +6,10 @@ export default function globalLocals() {
|
|||||||
if (req.csrfToken) {
|
if (req.csrfToken) {
|
||||||
res.expose({ token: res.locals._csrf }, 'csrf');
|
res.expose({ token: res.locals._csrf }, 'csrf');
|
||||||
}
|
}
|
||||||
|
res.locals.theme = req.user && req.user.theme ||
|
||||||
|
req.cookies.theme ||
|
||||||
|
'default';
|
||||||
|
|
||||||
next();
|
next();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,7 @@ export function ifNoUserRedirectTo(url, message, type = 'errors') {
|
|||||||
}
|
}
|
||||||
|
|
||||||
req.flash(type, {
|
req.flash(type, {
|
||||||
msg: message || `You must be signed to go to ${path}`
|
msg: message || `You must be signed in to access ${path}`
|
||||||
});
|
});
|
||||||
|
|
||||||
return res.redirect(url);
|
return res.redirect(url);
|
||||||
|
@ -5,7 +5,7 @@ block content
|
|||||||
h2.text-center Actions
|
h2.text-center Actions
|
||||||
.row
|
.row
|
||||||
.col-xs-12
|
.col-xs-12
|
||||||
a.btn.btn-lg.btn-block.btn-primary.btn-link-social(class = "nightMode-btn") Night Mode
|
a#night-mode.btn.btn-lg.btn-block.btn-primary.btn-link-social Night Mode
|
||||||
.row
|
.row
|
||||||
.col-xs-12
|
.col-xs-12
|
||||||
if (!user.isGithubCool)
|
if (!user.isGithubCool)
|
||||||
@ -133,4 +133,4 @@ block content
|
|||||||
form(action='/account/delete', method='POST')
|
form(action='/account/delete', method='POST')
|
||||||
input(type='hidden', name='_csrf', value=_csrf)
|
input(type='hidden', name='_csrf', value=_csrf)
|
||||||
button.btn.btn-danger.btn-block(type='submit')
|
button.btn.btn-danger.btn-block(type='submit')
|
||||||
| I am 100% sure I want to delete my account and all of my progress
|
| I am 100% sure I want to delete my account and all of my progress
|
||||||
|
@ -8,9 +8,9 @@ html(lang='en')
|
|||||||
include partials/scripts
|
include partials/scripts
|
||||||
block content
|
block content
|
||||||
else
|
else
|
||||||
body.no-top-and-bottom-margins
|
body.no-top-and-bottom-margins(class=theme !== 'default' ? theme : '')
|
||||||
include partials/scripts
|
include partials/scripts
|
||||||
include partials/navbar
|
include partials/navbar
|
||||||
include partials/flash
|
include partials/flash
|
||||||
block content
|
block content
|
||||||
include partials/footer
|
include partials/footer
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
extends ../layout-wide
|
extends ../layout-wide
|
||||||
block content
|
block content
|
||||||
.mapWrapper
|
.mapWrapper
|
||||||
.text-center.map-fixed-header
|
.text-center.map-fixed-header
|
||||||
p Challenges required for certifications are marked with a *
|
p Challenges required for certifications are marked with a *
|
||||||
.row.map-buttons
|
.row.map-buttons
|
||||||
@ -9,7 +9,7 @@ block content
|
|||||||
.input-group
|
.input-group
|
||||||
input#map-filter.form-control(type="text" placeholder="Type a challenge name" autocomplete="off" value="")
|
input#map-filter.form-control(type="text" placeholder="Type a challenge name" autocomplete="off" value="")
|
||||||
span.input-group-addon
|
span.input-group-addon
|
||||||
i.fa.fa-search
|
i.fa.fa-search
|
||||||
hr
|
hr
|
||||||
include ../partials/flash
|
include ../partials/flash
|
||||||
#accordion.map-accordion
|
#accordion.map-accordion
|
||||||
@ -122,3 +122,4 @@ block content
|
|||||||
p.challenge-title.disabled.text-primary.ion-locked.padded-ionic-icon.negative-15(name="Mock Interview #2") Mock Interview #2
|
p.challenge-title.disabled.text-primary.ion-locked.padded-ionic-icon.negative-15(name="Mock Interview #2") Mock Interview #2
|
||||||
p.challenge-title.disabled.text-primary.ion-locked.padded-ionic-icon.negative-15(name="Mock Interview #3") Mock Interview #3
|
p.challenge-title.disabled.text-primary.ion-locked.padded-ionic-icon.negative-15(name="Mock Interview #3") Mock Interview #3
|
||||||
.spacer
|
.spacer
|
||||||
|
include ../partials/flash
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
.container
|
.container
|
||||||
.row.flashMessage.negative-30
|
.row.flashMessage.negative-30
|
||||||
.col-xs-12
|
.col-xs-12.col-sm-8.col-sm-offset-2.col-md-6.col-md-offset-3
|
||||||
if (messages.errors || messages.error)
|
if (messages.errors || messages.error)
|
||||||
.alert.alert-danger.fade.in
|
.alert.alert-danger.fade.in
|
||||||
button.close(type='button', data-dismiss='alert')
|
button.close(type='button', data-dismiss='alert')
|
||||||
|
@ -7,5 +7,11 @@ script.
|
|||||||
ga('require', 'displayfeatures');
|
ga('require', 'displayfeatures');
|
||||||
ga('send', 'pageview');
|
ga('send', 'pageview');
|
||||||
// Leave the below lines alone!
|
// Leave the below lines alone!
|
||||||
|
script.
|
||||||
|
(function(global) {
|
||||||
|
global.main = global.main || {};
|
||||||
|
global.main.isLoggedIn = !{JSON.stringify(!!user)};
|
||||||
|
global.main.userId = !{JSON.stringify(user && user.id || false)};
|
||||||
|
}(window))
|
||||||
script(src=rev('/js', 'vendor-main.js'))
|
script(src=rev('/js', 'vendor-main.js'))
|
||||||
script(src=rev('/js', 'main.js'))
|
script(src=rev('/js', 'main.js'))
|
||||||
|
Reference in New Issue
Block a user