Add read-only banner

This commit is contained in:
Ramon Wenger 2021-08-03 15:12:09 +02:00
parent b6298710a0
commit 44f25bd113
11 changed files with 159 additions and 19 deletions

View File

@ -0,0 +1,67 @@
const getOperations = ({readOnly, classReadOnly = false}) => ({
MeQuery: {
me: {
onboardingVisited: true,
readOnly,
isTeacher: true,
selectedClass: {
id: 'selectedClassId',
readOnly: classReadOnly
}
},
},
NewsTeasers: {
newsTeasers: {
edges: []
}
}
});
const checkReadOnly = (shouldBannerExist, text) => {
cy.visit('/');
cy.getByDataCy('start-page-heading').should('exist');
if (shouldBannerExist) {
cy.getByDataCy('read-only-banner').should('exist').should('contain', text);
} else {
cy.getByDataCy('read-only-banner').should('not.exist');
}
};
describe('Read Only Banner', () => {
beforeEach(() => {
cy.setup();
});
it('is not shown', () => {
cy.mockGraphqlOps({
operations: getOperations({readOnly: false}),
});
checkReadOnly(false);
});
it('is shown for expired license', () => {
cy.mockGraphqlOps({
operations: getOperations({readOnly: true}),
});
checkReadOnly(true, 'Lizenz');
// cy.visit('/');
//
// cy.getByDataCy('start-page-heading').should('exist');
// cy.getByDataCy('read-only-banner').should('exist').should('contain', 'nicht mehr aktiv');
});
it('is shown for inactive school class', () => {
cy.mockGraphqlOps({
operations: getOperations({readOnly: false, classReadOnly: true}),
});
checkReadOnly(true, 'Klasse');
//
// cy.visit('/');
// cy.getByDataCy('start-page-heading').should('exist');
// cy.getByDataCy('read-only-banner').should('exist').should('contain', 'nicht mehr aktiv');
});
});

View File

@ -3,6 +3,7 @@
:class="{'no-scroll': showModal || showMobileNavigation}" :class="{'no-scroll': showModal || showMobileNavigation}"
class="app" class="app"
id="app"> id="app">
<read-only-banner/>
<scroll-up/> <scroll-up/>
<component <component
:is="showModalDeprecated" :is="showModalDeprecated"
@ -40,11 +41,13 @@
import SnapshotCreated from '@/components/modules/SnapshotCreated'; import SnapshotCreated from '@/components/modules/SnapshotCreated';
import {mapGetters} from 'vuex'; import {mapGetters} from 'vuex';
import ScrollUp from '@/components/ScrollUp'; import ScrollUp from '@/components/ScrollUp';
import ReadOnlyBanner from '@/components/ReadOnlyBanner';
export default { export default {
name: 'App', name: 'App',
components: { components: {
ReadOnlyBanner,
ScrollUp, ScrollUp,
DefaultLayout, DefaultLayout,
SimpleLayout, SimpleLayout,
@ -68,7 +71,7 @@
FullscreenInfographic, FullscreenInfographic,
FullscreenVideo, FullscreenVideo,
DeactivatePerson, DeactivatePerson,
SnapshotCreated SnapshotCreated,
}, },
computed: { computed: {
@ -77,17 +80,17 @@
}, },
...mapGetters({ ...mapGetters({
showModalDeprecated: 'showModal', // don't use this any more todo: remove this showModalDeprecated: 'showModal', // don't use this any more todo: remove this
showMobileNavigation: 'showMobileNavigation' showMobileNavigation: 'showMobileNavigation',
}), }),
showModal() { showModal() {
return this.$modal.state.component; return this.$modal.state.component;
} },
}, },
}; };
</script> </script>
<style lang="scss"> <style lang="scss">
@import "styles/main.scss"; @import "~styles/main.scss";
body { body {
overflow-y: auto; overflow-y: auto;
@ -100,6 +103,8 @@
min-height: 100vh; min-height: 100vh;
/*for IE10+*/ /*for IE10+*/
display: flex; display: flex;
flex-direction: column;
} }
.no-scroll { .no-scroll {

View File

@ -0,0 +1,41 @@
<template>
<div
class="read-only-banner"
data-cy="read-only-banner"
v-if="me.readOnly || me.selectedClass.readOnly">
<p class="read-only-banner__text">
{{ readOnlyText }} Sie können Inhalte lesen, aber nicht
bearbeiten.
</p>
</div>
</template>
<script>
import me from '@/mixins/me';
export default {
mixins: [me],
computed: {
readOnlyText() {
return this.me.readOnly ? 'Sie besitzen keine aktive Lizenz.' : 'Sie sind in dieser Klasse nicht mehr aktiv.';
}
}
};
</script>
<style scoped lang="scss">
@import '~styles/helpers';
.read-only-banner {
background-color: $color-brand-light;
display: flex;
justify-content: center;
&__text {
padding: $small-spacing 0;
@include regular-text;
max-width: $screen-width;
}
}
</style>

View File

@ -5,7 +5,7 @@ export default {
addSchoolClass(store, schoolClass) { addSchoolClass(store, schoolClass) {
const query = ME_QUERY; const query = ME_QUERY;
if (schoolClass) { if (schoolClass) {
console.log('updating school class'); this.$log.debug('updating school class', schoolClass);
const data = store.readQuery({query}); const data = store.readQuery({query});
if (data) { if (data) {
data.me.schoolClasses.edges = [ data.me.schoolClasses.edges = [

View File

@ -76,7 +76,7 @@
} }
&__title { &__title {
max-width: 1200px; max-width: $screen-width;
line-height: 1.2; line-height: 1.2;
margin-bottom: 0; margin-bottom: 0;
} }
@ -87,7 +87,7 @@
&__list { &__list {
padding: $large-spacing 0; padding: $large-spacing 0;
max-width: 1200px; max-width: $screen-width;
width: 100%; width: 100%;
display: flex; display: flex;
flex-direction: column; flex-direction: column;

View File

@ -34,7 +34,7 @@
this.error = ''; this.error = '';
}, },
joinClass(code) { joinClass(code) {
let self = this; this.$log.debug('joining class');
this.$apollo.mutate({ this.$apollo.mutate({
mutation: JOIN_CLASS_MUTATION, mutation: JOIN_CLASS_MUTATION,
variables: { variables: {
@ -42,9 +42,10 @@
code, code,
}, },
}, },
update(store, {data: {joinClass: {schoolClass}}}) { update: (store, {data: {joinClass: {schoolClass}}}) => {
self.addSchoolClass(store, schoolClass); this.addSchoolClass(store, schoolClass);
self.$router.push({name: 'my-class'}); this.$log.debug('added school class');
this.$router.push({name: 'my-class'});
}, },
refetchQueries: [{query: MY_SCHOOL_CLASS_QUERY}], refetchQueries: [{query: MY_SCHOOL_CLASS_QUERY}],
}) })

View File

@ -4,7 +4,9 @@
<div <div
class="start-page__modules start-sections" class="start-page__modules start-sections"
data-cy="start-modules-list"> data-cy="start-modules-list">
<h2 class="start-page__heading">Letzte Module</h2> <h2
class="start-page__heading"
data-cy="start-page-heading">Letzte Module</h2>
<h3 <h3
class="start-page__no-modules" class="start-page__no-modules"
data-cy="no-modules-yet" data-cy="no-modules-yet"
@ -109,9 +111,7 @@
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">
@import "~styles/helpers";
@import "@/styles/_variables.scss";
@import "@/styles/_mixins.scss";
.start-page { .start-page {
display: flex; display: flex;
@ -151,7 +151,7 @@
box-sizing: border-box; box-sizing: border-box;
max-width: 100%; max-width: 100%;
@include desktop { @include desktop {
max-width: 1200px; max-width: $screen-width;
margin: 0 auto; margin: 0 auto;
} }
} }

View File

@ -56,7 +56,7 @@
.submissions-page { .submissions-page {
display: grid; display: grid;
width: 100%; width: 100%;
max-width: 1200px; max-width: $screen-width;
grid-template-rows: auto 1fr; grid-template-rows: auto 1fr;

View File

@ -1,5 +1,4 @@
@import "@/styles/_variables.scss"; @import "~styles/helpers";
@import "@/styles/_mixins.scss";
.layout { .layout {
$footer-height: 287px; $footer-height: 287px;

View File

@ -80,3 +80,5 @@ $popover-default-bottom: -110px;
$footer-width: 800px; $footer-width: 800px;
$news-width: 550px; $news-width: 550px;
$screen-width: 1200px;

View File

@ -426,6 +426,7 @@ type CustomMutation {
} }
type CustomQuery { type CustomQuery {
newsTeasers(offset: Int, before: String, after: String, first: Int, last: Int, date: Date): NewsTeaserNodeConnection
survey(id: ID): SurveyNode survey(id: ID): SurveyNode
surveys(offset: Int, before: String, after: String, first: Int, last: Int): SurveyNodeConnection surveys(offset: Int, before: String, after: String, first: Int, last: Int): SurveyNodeConnection
project(id: ID, slug: String): ProjectNode project(id: ID, slug: String): ProjectNode
@ -458,6 +459,8 @@ type CustomQuery {
_debug: DjangoDebug _debug: DjangoDebug
} }
scalar Date
scalar DateTime scalar DateTime
input DeleteContentBlockInput { input DeleteContentBlockInput {
@ -692,6 +695,28 @@ type MutateContentBlockPayload {
clientMutationId: String clientMutationId: String
} }
type NewsTeaserNode implements Node {
id: ID!
imageUrl: String
title: String!
description: String
date: Date
orderId: Int!
newsArticleUrl: String
imageSource: String!
displayDate: String
}
type NewsTeaserNodeConnection {
pageInfo: PageInfo!
edges: [NewsTeaserNodeEdge]!
}
type NewsTeaserNodeEdge {
node: NewsTeaserNode
cursor: String!
}
interface Node { interface Node {
id: ID! id: ID!
} }