add subnavigation, minor cleanup

This commit is contained in:
Christian Cueni 2019-04-08 17:11:08 +02:00
parent 13685b082e
commit f3289ba881
11 changed files with 98 additions and 55 deletions

View File

@ -12,7 +12,7 @@ describe('Change Password Page', () => {
it('shows an empty form', () => { it('shows an empty form', () => {
cy.login('rahel.cueni', 'test'); cy.login('rahel.cueni', 'test');
cy.visit('/password-change'); cy.visit('/me/password-change');
cy.get('[data-cy=password-change-success]').should('not.exist'); cy.get('[data-cy=password-change-success]').should('not.exist');
cy.get('[data-cy=old-password]').should('have.value', ''); cy.get('[data-cy=old-password]').should('have.value', '');
@ -21,15 +21,15 @@ describe('Change Password Page', () => {
it('shows errors if old password is not entered', () => { it('shows errors if old password is not entered', () => {
cy.login('rahel.cueni', 'test'); cy.login('rahel.cueni', 'test');
cy.visit('/password-change'); cy.visit('/me/password-change');
cy.changePassword('', validNewPassword); cy.changePassword('', validNewPassword);
cy.get('[data-cy=old-password-local-errors]').should('contain', 'Dein aktuelles Passwort fehlt') cy.get('[data-cy=old-password-local-errors]').should('contain', 'Dein aktuelles Passwort fehlt')
}); });
it('shows errors if old password is not entered', () => { it('shows errors if new password is not entered', () => {
cy.login('rahel.cueni', 'test'); cy.login('rahel.cueni', 'test');
cy.visit('/password-change'); cy.visit('/me/password-change');
cy.changePassword(validOldPassword, ''); cy.changePassword(validOldPassword, '');
cy.get('[data-cy=new-password-local-errors]').should('contain', 'Dein neues Passwort fehlt') cy.get('[data-cy=new-password-local-errors]').should('contain', 'Dein neues Passwort fehlt')
@ -37,7 +37,7 @@ describe('Change Password Page', () => {
it('shows errors if new password is too short', () => { it('shows errors if new password is too short', () => {
cy.login('rahel.cueni', 'test'); cy.login('rahel.cueni', 'test');
cy.visit('/password-change'); cy.visit('/me/password-change');
cy.changePassword(validOldPassword, 'Abc1!'); cy.changePassword(validOldPassword, 'Abc1!');
cy.get('[data-cy=new-password-local-errors]').should('contain', validationTooShort) cy.get('[data-cy=new-password-local-errors]').should('contain', validationTooShort)
@ -45,7 +45,7 @@ describe('Change Password Page', () => {
it('shows errors if new password has no uppercase letter', () => { it('shows errors if new password has no uppercase letter', () => {
cy.login('rahel.cueni', 'test'); cy.login('rahel.cueni', 'test');
cy.visit('/password-change'); cy.visit('/me/password-change');
cy.changePassword(validOldPassword, 'aabdddedddbc1!'); cy.changePassword(validOldPassword, 'aabdddedddbc1!');
cy.get('[data-cy=new-password-local-errors]').should('contain', validationErrorMsg) cy.get('[data-cy=new-password-local-errors]').should('contain', validationErrorMsg)
@ -53,7 +53,7 @@ describe('Change Password Page', () => {
it('shows errors if new password has no lowercase letter', () => { it('shows errors if new password has no lowercase letter', () => {
cy.login('rahel.cueni', 'test'); cy.login('rahel.cueni', 'test');
cy.visit('/password-change'); cy.visit('/me/password-change');
cy.changePassword(validOldPassword, 'ABCDDD334551!'); cy.changePassword(validOldPassword, 'ABCDDD334551!');
cy.get('[data-cy=new-password-local-errors]').should('contain', validationErrorMsg) cy.get('[data-cy=new-password-local-errors]').should('contain', validationErrorMsg)
@ -61,7 +61,7 @@ describe('Change Password Page', () => {
it('shows errors if new password has no digit', () => { it('shows errors if new password has no digit', () => {
cy.login('rahel.cueni', 'test'); cy.login('rahel.cueni', 'test');
cy.visit('/password-change'); cy.visit('/me/password-change');
cy.changePassword(validOldPassword, 'AbcdEEDE!'); cy.changePassword(validOldPassword, 'AbcdEEDE!');
cy.get('[data-cy=new-password-local-errors]').should('contain', validationErrorMsg) cy.get('[data-cy=new-password-local-errors]').should('contain', validationErrorMsg)
@ -69,7 +69,7 @@ describe('Change Password Page', () => {
it('shows errors if new password has no special character', () => { it('shows errors if new password has no special character', () => {
cy.login('rahel.cueni', 'test'); cy.login('rahel.cueni', 'test');
cy.visit('/password-change'); cy.visit('/me/password-change');
cy.changePassword(validOldPassword, 'AbcdEEDE09877'); cy.changePassword(validOldPassword, 'AbcdEEDE09877');
cy.get('[data-cy=new-password-local-errors]').should('contain', validationErrorMsg) cy.get('[data-cy=new-password-local-errors]').should('contain', validationErrorMsg)
@ -77,7 +77,7 @@ describe('Change Password Page', () => {
it('shows errors if old password does not match', () => { it('shows errors if old password does not match', () => {
cy.login('rahel.cueni', 'test'); cy.login('rahel.cueni', 'test');
cy.visit('/password-change'); cy.visit('/me/password-change');
cy.changePassword('test12345', validNewPassword); cy.changePassword('test12345', validNewPassword);
cy.get('[data-cy=old-password-remote-errors]').should('contain', validationOldWrongMsg) cy.get('[data-cy=old-password-remote-errors]').should('contain', validationOldWrongMsg)
@ -85,9 +85,9 @@ describe('Change Password Page', () => {
it('shows success if change was successful', () => { it('shows success if change was successful', () => {
cy.login('rahel.cueni', 'test'); cy.login('rahel.cueni', 'test');
cy.visit('/password-change'); cy.visit('/me/password-change');
cy.changePassword('test', validNewPassword); cy.changePassword(validOldPassword, validNewPassword);
cy.get('[data-cy=password-change-success]').should('contain', 'Dein Password wurde erfolgreich geändert.'); cy.get('[data-cy=password-change-success]').should('contain', 'Dein Password wurde erfolgreich geändert.');
cy.get('[data-cy=old-password]').should('have.value', ''); cy.get('[data-cy=old-password]').should('have.value', '');
cy.get('[data-cy=new-password]').should('have.value', ''); cy.get('[data-cy=new-password]').should('have.value', '');

View File

@ -2,7 +2,7 @@
<div class="pw-change"> <div class="pw-change">
<form class="pw-change__form change-form" novalidate @submit.prevent="validateBeforeSubmit"> <form class="pw-change__form change-form" novalidate @submit.prevent="validateBeforeSubmit">
<div class="change-form__field sbform-input"> <div class="change-form__field sbform-input">
<label for="old-pw" class="sbform-input__label">Aktuells Passwort</label> <label for="old-pw" class="sbform-input__label">Aktuelles Passwort</label>
<input id="old-pw" <input id="old-pw"
name="oldPassword" name="oldPassword"
type="text" type="text"
@ -29,7 +29,7 @@
<small v-if="errors.has('newPassword') && submitted" class=" sbform-input__error" data-cy="new-password-local-errors">{{ errors.first('newPassword') }}</small> <small v-if="errors.has('newPassword') && submitted" class=" sbform-input__error" data-cy="new-password-local-errors">{{ errors.first('newPassword') }}</small>
<small v-for="error in newPasswordErrors" :key="error" class=" sbform-input__error" data-cy="new-password-remote-errors">{{ error }}</small> <small v-for="error in newPasswordErrors" :key="error" class=" sbform-input__error" data-cy="new-password-remote-errors">{{ error }}</small>
</div> </div>
<button class="button button--primary change-form__submit" data-cy="change-password-button">Zurücksetzen</button> <button class="button button--primary change-form__submit" data-cy="change-password-button">Speichern</button>
</form> </form>
</div> </div>
</template> </template>

View File

@ -22,21 +22,4 @@
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">
@import "@/styles/_variables.scss";
.top-navigation {
display: flex;
&__link {
font-size: 1.0625rem;
padding: 0 24px;
font-family: $sans-serif-font-family;
font-weight: $font-weight-regular;
color: $color-grey;
&--active {
color: $color-brand;
}
}
}
</style> </style>

View File

@ -1,16 +1,18 @@
<template> <template>
<div class="user-widget"> <router-link to="/me">
<user-icon class="user-widget__avatar" :src="avatar"></user-icon> <div class="user-widget" :class="{'user-widget--is-profile': isProfile}">
<span class="user-widget__name">{{firstName}} {{lastName}}</span> <user-icon class="user-widget__avatar" :src="avatar"></user-icon>
<span class="user-widget__date" v-if="date">{{date}}</span> <span class="user-widget__name">{{firstName}} {{lastName}}</span>
</div> <span class="user-widget__date" v-if="date">{{date}}</span>
</div>
</router-link>
</template> </template>
<script> <script>
import UserIcon from '@/components/icons/UserIcon'; import UserIcon from '@/components/icons/UserIcon';
export default { export default {
props: ['firstName', 'lastName', 'avatar', 'date'], props: ['firstName', 'lastName', 'avatar', 'date', 'isProfile'],
components: { components: {
UserIcon UserIcon
@ -42,5 +44,15 @@
border-radius: 15px; border-radius: 15px;
fill: $color-grey; fill: $color-grey;
} }
&--is-profile {
& > svg {
fill: $color-brand;
}
& > span {
color: $color-brand;
}
}
} }
</style> </style>

View File

@ -4,7 +4,7 @@
<top-navigation></top-navigation> <top-navigation></top-navigation>
<router-link to="/" class="skillbox__header-logo">skillbox</router-link> <router-link to="/" class="skillbox__header-logo">skillbox</router-link>
<div class="user-header"> <div class="user-header">
<user-widget v-bind="me"></user-widget> <user-widget v-bind="me" :isProfile="isProfile"></user-widget>
<logout-widget></logout-widget> <logout-widget></logout-widget>
</div> </div>
<book-navigation v-if="showSubnavigation"> <book-navigation v-if="showSubnavigation">
@ -45,7 +45,10 @@
specialContainerClass() { specialContainerClass() {
let cls = this.$store.state.specialContainerClass; let cls = this.$store.state.specialContainerClass;
return [cls ? `skillbox--${cls}` : '', {'skillbox--show-filter': this.showFilter}] return [cls ? `skillbox--${cls}` : '', {'skillbox--show-filter': this.showFilter}]
} },
isProfile() {
return this.$route.meta.isProfile;
},
}, },
data() { data() {

View File

@ -79,17 +79,7 @@
<style scoped lang="scss"> <style scoped lang="scss">
@import "@/styles/_variables.scss"; @import "@/styles/_variables.scss";
.password-reset {
padding: $medium-spacing;
@media screen and (max-width: 1024px) {
max-width: 640px;
margin: 0 auto;
}
}
.success-message { .success-message {
margin-bottom: 20px; margin-bottom: 20px;
&__msg { &__msg {

View File

@ -1,6 +1,17 @@
<template> <template>
<div class="profile"> <div class="profile">
<h1 class="profile__heading">Profile</h1> <nav class="top-navigation profile-submenu profile__submenu">
<router-link to="/me/activity" active-class="top-navigation__link--active"
class="top-navigation__link profile-submenu__item submenu-item">Aktivität
</router-link>
<router-link to="/me/classlist" active-class="top-navigation__link--active"
class="top-navigation__link profile-submenu__item submenu-item">Klassenliste
</router-link>
<router-link to="password-change" active-class="top-navigation__link--active"
class="top-navigation__link profile-submenu__item submenu-item">Passwort ändern
</router-link>
</nav>
<router-view></router-view>
</div> </div>
</template> </template>
@ -20,5 +31,27 @@
<style scoped lang="scss"> <style scoped lang="scss">
@import "@/styles/_variables.scss"; @import "@/styles/_variables.scss";
@import "@/styles/_functions.scss";
.profile {
padding: $medium-spacing;
@media screen and (max-width: 1024px) {
max-width: 640px;
margin: 0 auto;
}
&__submenu {
margin-bottom: $medium-spacing;
margin-left: -$medium-spacing;
}
}
.profile-submenu {
&__item {
font-family: $sans-serif-font-family;
font-size: toRem(14px);
}
}
</style> </style>

View File

@ -64,8 +64,17 @@ const routes = [
{path: 'topic/:topicSlug', component: topic, meta: {subnavigation: true}} {path: 'topic/:topicSlug', component: topic, meta: {subnavigation: true}}
] ]
}, },
{path: '/me', name: 'profile', component: profilePage}, {
{path: '/password-change', name: 'pw-change', component: passwordChange}, path: '/me',
name: 'profile',
component: profilePage,
meta: {
isProfile: true
},
children: [
{path: 'password-change', name: 'pw-change', component: passwordChange, meta: {isProfile: true}}
]
},
{path: '*', component: p404} {path: '*', component: p404}
]; ];

View File

@ -0,0 +1,15 @@
.top-navigation {
display: flex;
&__link {
font-size: 1.0625rem;
padding: 0 24px;
font-family: $sans-serif-font-family;
font-weight: $font-weight-regular;
color: $color-grey;
&--active {
color: $color-brand;
}
}
}

View File

@ -13,3 +13,4 @@
@import "objective-group"; @import "objective-group";
@import "article"; @import "article";
@import "actions"; @import "actions";
@import "top-navigation";

View File

@ -40,9 +40,6 @@ def validate_old_new_password(value):
def validate_strong_email(password): def validate_strong_email(password):
if len(password) == 0:
return password
has_number = re.search('\d', password) has_number = re.search('\d', password)
has_upper = re.search('[A-Z]', password) has_upper = re.search('[A-Z]', password)
has_lower = re.search('[a-z]', password) has_lower = re.search('[a-z]', password)