297 lines
8.3 KiB
Vue
297 lines
8.3 KiB
Vue
<template>
|
|
<div
|
|
:data-scrollto="value.id"
|
|
class="assignment">
|
|
<p class="assignment__assignment-text">
|
|
{{ assignment.assignment }}
|
|
</p>
|
|
|
|
<solution
|
|
:value="solution"
|
|
v-if="assignment.solution"/>
|
|
|
|
<template v-if="isStudent">
|
|
<submission-form
|
|
:user-input="submission"
|
|
:spellcheck-loading="spellcheckLoading"
|
|
:saved="!unsaved"
|
|
:spellcheck="true"
|
|
:read-only="me.readOnly || me.selectedClass.readOnly"
|
|
placeholder="Ergebnis erfassen"
|
|
action="Ergebnis mit Lehrperson teilen"
|
|
shared-msg="Das Ergebnis wurde mit der Lehrperson geteilt."
|
|
v-if="isStudent"
|
|
@turnIn="turnIn"
|
|
@saveInput="saveInput"
|
|
@reopen="reopen"
|
|
@changeDocumentUrl="changeDocumentUrl"
|
|
@spellcheck="spellcheck"
|
|
/>
|
|
|
|
<spell-check
|
|
:corrections="corrections"
|
|
:text="submission.text"/>
|
|
|
|
<p
|
|
class="assignment__feedback"
|
|
v-if="assignment.submission.submissionFeedback"
|
|
v-html="feedbackText"/>
|
|
</template>
|
|
<template v-if="!isStudent">
|
|
<router-link
|
|
:to="{name: 'submissions', params: { id: assignment.id }}"
|
|
class="button button--primary">Zu den
|
|
Ergebnissen
|
|
</router-link>
|
|
</template>
|
|
</div>
|
|
</template>
|
|
|
|
<script>
|
|
import {mapActions, mapGetters} from 'vuex';
|
|
import ASSIGNMENT_QUERY from '@/graphql/gql/queries/assignmentQuery.gql';
|
|
import ME_QUERY from '@/graphql/gql/queries/meQuery.gql';
|
|
import UPDATE_ASSIGNMENT_MUTATION from '@/graphql/gql/mutations/updateAssignmentMutation.gql';
|
|
import UPDATE_ASSIGNMENT_MUTATION_WITH_SUCCESS from '@/graphql/gql/mutations/updateAssignmentMutationWithSuccess.gql';
|
|
import SPELL_CHECK_MUTATION from '@/graphql/gql/mutations/spellCheck.gql';
|
|
import debounce from 'lodash/debounce';
|
|
import cloneDeep from 'lodash/cloneDeep';
|
|
|
|
import SubmissionForm from '@/components/content-blocks/assignment/SubmissionForm';
|
|
import Solution from '@/components/content-blocks/Solution';
|
|
import SpellCheck from '@/components/content-blocks/assignment/SpellCheck';
|
|
|
|
export default {
|
|
props: ['value'],
|
|
|
|
components: {
|
|
Solution,
|
|
SubmissionForm,
|
|
SpellCheck,
|
|
},
|
|
|
|
data() {
|
|
return {
|
|
assignment: {
|
|
submission: this.initialSubmission(),
|
|
},
|
|
me: {
|
|
permissions: [],
|
|
},
|
|
inputType: 'text',
|
|
unsaved: false,
|
|
saving: 0,
|
|
corrections: '',
|
|
spellcheckLoading: false,
|
|
};
|
|
},
|
|
|
|
computed: {
|
|
...mapGetters(['scrollToAssignmentId']),
|
|
final() {
|
|
return !!this.submission && this.submission.final;
|
|
},
|
|
submission() {
|
|
return this.assignment.submission ? this.assignment.submission : {};
|
|
},
|
|
isStudent() {
|
|
return !this.me.permissions.includes('users.can_manage_school_class_content');
|
|
},
|
|
solution() {
|
|
return {
|
|
text: this.assignment.solution,
|
|
};
|
|
},
|
|
id() {
|
|
return this.assignment.id ? this.assignment.id.replace(/=/g, '') : '';
|
|
},
|
|
feedbackText() {
|
|
let feedback = this.assignment.submission.submissionFeedback;
|
|
return `<span class="inline-title">Feedback von ${feedback.teacher.firstName} ${feedback.teacher.lastName}:</span> ${feedback.text}`;
|
|
},
|
|
},
|
|
|
|
methods: {
|
|
...mapActions(['scrollToAssignmentReady']),
|
|
_save: debounce(function (submission) {
|
|
this.saving++;
|
|
this.$apollo.mutate({
|
|
mutation: UPDATE_ASSIGNMENT_MUTATION_WITH_SUCCESS,
|
|
variables: {
|
|
input: {
|
|
assignment: {
|
|
id: this.assignment.id,
|
|
answer: this.assignment.submission.text,
|
|
document: this.assignment.submission.document,
|
|
},
|
|
},
|
|
},
|
|
update(store, {data: {updateAssignment: {successful, updatedAssignment}}}) {
|
|
try {
|
|
if (successful) {
|
|
const query = ASSIGNMENT_QUERY;
|
|
const variables = {
|
|
id: updatedAssignment.id,
|
|
};
|
|
const data = store.readQuery({query, variables});
|
|
|
|
data.assignment = Object.assign({}, updatedAssignment, {
|
|
submission,
|
|
});
|
|
store.writeQuery({query, variables, data});
|
|
}
|
|
} catch (e) {
|
|
console.error(e);
|
|
// Query did not exist in the cache, and apollo throws a generic Error. Do nothing
|
|
}
|
|
},
|
|
}).then(() => {
|
|
this.saving--;
|
|
if (this.saving === 0) {
|
|
this.unsaved = false;
|
|
}
|
|
});
|
|
}, 500),
|
|
saveInput: function (answer) {
|
|
// reset corrections on input
|
|
this.corrections = '';
|
|
this.unsaved = true;
|
|
/*
|
|
We update the assignment on this component, so the changes are reflected on it. The server does not return
|
|
the updated entity, to prevent the UI to update when the user is entering his input
|
|
*/
|
|
this.assignment.submission.text = answer;
|
|
this._save(this.assignment.submission);
|
|
},
|
|
changeDocumentUrl(documentUrl) {
|
|
this.assignment.submission.document = documentUrl;
|
|
this._save(this.assignment.submission);
|
|
},
|
|
turnIn() {
|
|
// reset corrections on turn in
|
|
this.corrections = '';
|
|
this.$apollo.mutate({
|
|
mutation: UPDATE_ASSIGNMENT_MUTATION,
|
|
variables: {
|
|
input: {
|
|
assignment: {
|
|
id: this.assignment.id,
|
|
answer: this.assignment.submission.text,
|
|
document: this.assignment.submission.document,
|
|
final: true,
|
|
},
|
|
},
|
|
},
|
|
});
|
|
},
|
|
reopen() {
|
|
this.$apollo.mutate({
|
|
mutation: UPDATE_ASSIGNMENT_MUTATION,
|
|
variables: {
|
|
input: {
|
|
assignment: {
|
|
id: this.assignment.id,
|
|
answer: this.assignment.submission.text,
|
|
document: this.assignment.submission.document,
|
|
final: false,
|
|
},
|
|
},
|
|
},
|
|
});
|
|
},
|
|
initialSubmission() {
|
|
return {
|
|
text: '',
|
|
document: '',
|
|
final: false,
|
|
};
|
|
},
|
|
spellcheck() {
|
|
let self = this;
|
|
this.spellcheckLoading = true;
|
|
this.$apollo.mutate({
|
|
mutation: SPELL_CHECK_MUTATION,
|
|
variables: {
|
|
input: {
|
|
assignment: this.assignment.id,
|
|
text: this.assignment.submission.text,
|
|
},
|
|
},
|
|
update(store, {data: {spellCheck: {results}}}) {
|
|
self.corrections = results;
|
|
},
|
|
}).then(() => {
|
|
this.spellcheckLoading = false;
|
|
});
|
|
},
|
|
},
|
|
|
|
apollo: {
|
|
assignment: {
|
|
query: ASSIGNMENT_QUERY,
|
|
variables() {
|
|
return {
|
|
id: this.value.id,
|
|
};
|
|
},
|
|
result(response) {
|
|
const data = response.data;
|
|
this.assignment = cloneDeep(data.assignment);
|
|
this.assignment.submission = Object.assign(this.initialSubmission(), this.assignment.submission);
|
|
if (this.assignment.id === this.scrollToAssignmentId && 'stale' in response) {
|
|
this.$nextTick(() => this.scrollToAssignmentReady(true));
|
|
}
|
|
},
|
|
},
|
|
me: {
|
|
query: ME_QUERY,
|
|
},
|
|
},
|
|
};
|
|
</script>
|
|
|
|
<style scoped lang="scss">
|
|
@import '@/styles/_variables.scss';
|
|
@import '@/styles/_functions.scss';
|
|
@import '@/styles/_mixins.scss';
|
|
|
|
.assignment {
|
|
margin-bottom: 3rem;
|
|
position: relative;
|
|
|
|
&__title {
|
|
font-size: toRem(17px);
|
|
margin-bottom: 1rem;
|
|
}
|
|
|
|
&__toggle-input-container {
|
|
display: flex;
|
|
margin-bottom: 15px;
|
|
}
|
|
|
|
&__toggle-input {
|
|
border: 0;
|
|
font-family: $sans-serif-font-family;
|
|
background: transparent;
|
|
font-size: toRem(14px);
|
|
padding: 5px 0;
|
|
margin-right: 15px;
|
|
outline: 0;
|
|
color: $color-silver-dark;
|
|
cursor: pointer;
|
|
border-bottom: 2px solid transparent;
|
|
|
|
&--active {
|
|
border-bottom-color: $color-charcoal-dark;
|
|
color: $color-charcoal-dark;
|
|
}
|
|
}
|
|
|
|
&__feedback {
|
|
@include regular-text;
|
|
}
|
|
|
|
}
|
|
|
|
</style>
|