@windward/core 0.0.5 → 0.0.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (116) hide show
  1. package/README.md +2 -1
  2. package/components/Content/Blocks/ClickableIcons.vue +10 -1
  3. package/components/Content/Blocks/Feedback.vue +12 -4
  4. package/components/Content/Blocks/FeedbackTemplates/FeedbackQuestionOpenResponse.vue +10 -9
  5. package/components/Content/Blocks/Image.vue +1 -6
  6. package/components/Content/Blocks/OpenResponse.vue +137 -0
  7. package/components/Content/Blocks/OpenResponseCollate.vue +158 -0
  8. package/components/Navigation/Items/AskTheExpert.vue +173 -0
  9. package/components/Settings/ClickableIconsSettings.vue +10 -5
  10. package/components/Settings/OpenResponseCollateSettings.vue +170 -0
  11. package/components/Settings/OpenResponseSettings.vue +81 -0
  12. package/components/utils/ContentViewer.vue +15 -4
  13. package/components/utils/FillInBlank/FillInBlankInput.vue +208 -0
  14. package/components/utils/FillInBlank/FillInTheBlanksManager.vue +98 -0
  15. package/components/utils/MathExpressionEditor.vue +8 -6
  16. package/components/utils/TinyMCEWrapper.vue +59 -9
  17. package/components/utils/assets/tinymce/css/content.scss +9 -0
  18. package/components/utils/glossary/CourseGlossary.vue +12 -8
  19. package/components/utils/glossary/CourseGlossaryForm.vue +24 -5
  20. package/helpers/FillInBlankHelper.ts +55 -0
  21. package/helpers/GlossaryHelper.ts +4 -4
  22. package/helpers/tinymce/plugin.ts +99 -4
  23. package/i18n/en-US/components/content/blocks/feedback.ts +3 -0
  24. package/i18n/en-US/components/content/blocks/index.ts +4 -0
  25. package/i18n/en-US/components/content/blocks/open_response.ts +5 -0
  26. package/i18n/en-US/components/content/blocks/open_response_collate.ts +6 -0
  27. package/i18n/en-US/components/index.ts +0 -1
  28. package/i18n/en-US/components/navigation/ask_the_expert.ts +11 -0
  29. package/i18n/en-US/components/navigation/index.ts +2 -0
  30. package/i18n/en-US/components/settings/index.ts +5 -1
  31. package/i18n/en-US/components/settings/open_response.ts +5 -0
  32. package/i18n/en-US/components/settings/open_response_collate.ts +6 -0
  33. package/i18n/en-US/components/utils/FillInBlank/FillInBlankInput.ts +13 -0
  34. package/i18n/en-US/components/utils/FillInBlank/FillInTheBlanksManager.ts +11 -0
  35. package/i18n/en-US/components/utils/FillInBlank/index.ts +6 -0
  36. package/i18n/en-US/components/utils/index.ts +2 -1
  37. package/i18n/en-US/components/utils/tiny_mce_wrapper.ts +1 -0
  38. package/i18n/en-US/shared/content_blocks.ts +2 -0
  39. package/i18n/en-US/shared/menu.ts +1 -0
  40. package/i18n/en-US/shared/settings.ts +3 -1
  41. package/i18n/es-ES/components/content/blocks/feedback.ts +29 -0
  42. package/i18n/es-ES/components/content/blocks/image.ts +5 -0
  43. package/i18n/es-ES/components/content/blocks/index.ts +19 -0
  44. package/i18n/es-ES/components/content/blocks/open_response.ts +6 -0
  45. package/i18n/es-ES/components/content/blocks/open_response_collate.ts +6 -0
  46. package/i18n/es-ES/components/content/blocks/tab.ts +4 -0
  47. package/i18n/es-ES/components/content/blocks/table.ts +4 -0
  48. package/i18n/es-ES/components/content/blocks/user_upload.ts +13 -0
  49. package/i18n/es-ES/components/content/blocks/video.ts +55 -0
  50. package/i18n/es-ES/components/content/index.ts +5 -0
  51. package/i18n/es-ES/components/index.ts +12 -0
  52. package/i18n/es-ES/components/navigation/ask_the_expert.ts +11 -0
  53. package/i18n/es-ES/components/navigation/image.ts +4 -0
  54. package/i18n/es-ES/components/navigation/index.ts +7 -0
  55. package/i18n/es-ES/components/navigation/user_upload.ts +3 -0
  56. package/i18n/es-ES/components/settings/clickable_icon.ts +10 -0
  57. package/i18n/es-ES/components/settings/image.ts +1 -0
  58. package/i18n/es-ES/components/settings/index.ts +17 -0
  59. package/i18n/es-ES/components/settings/open_response.ts +5 -0
  60. package/i18n/es-ES/components/settings/open_response_collate.ts +7 -0
  61. package/i18n/es-ES/components/settings/text_editor.ts +7 -0
  62. package/i18n/es-ES/components/settings/user_upload.ts +11 -0
  63. package/i18n/es-ES/components/settings/video.ts +13 -0
  64. package/i18n/es-ES/components/utils/index.ts +5 -0
  65. package/i18n/es-ES/components/utils/tiny_mce_wrapper.ts +18 -0
  66. package/i18n/es-ES/index.ts +16 -0
  67. package/i18n/es-ES/modules/index.ts +5 -0
  68. package/i18n/es-ES/pages/glossary.ts +7 -0
  69. package/i18n/es-ES/pages/index.ts +7 -0
  70. package/i18n/es-ES/pages/user_upload.ts +3 -0
  71. package/i18n/es-ES/shared/content_blocks.ts +22 -0
  72. package/i18n/es-ES/shared/index.ts +11 -0
  73. package/i18n/es-ES/shared/menu.ts +3 -0
  74. package/i18n/es-ES/shared/permission.ts +15 -0
  75. package/i18n/es-ES/shared/settings.ts +19 -0
  76. package/i18n/sv-SE/components/content/blocks/feedback.ts +29 -0
  77. package/i18n/sv-SE/components/content/blocks/image.ts +5 -0
  78. package/i18n/sv-SE/components/content/blocks/index.ts +19 -0
  79. package/i18n/sv-SE/components/content/blocks/open_response.ts +6 -0
  80. package/i18n/sv-SE/components/content/blocks/open_response_collate.ts +6 -0
  81. package/i18n/sv-SE/components/content/blocks/tab.ts +4 -0
  82. package/i18n/sv-SE/components/content/blocks/table.ts +4 -0
  83. package/i18n/sv-SE/components/content/blocks/user_upload.ts +13 -0
  84. package/i18n/sv-SE/components/content/blocks/video.ts +53 -0
  85. package/i18n/sv-SE/components/content/index.ts +5 -0
  86. package/i18n/sv-SE/components/index.ts +12 -0
  87. package/i18n/sv-SE/components/navigation/ask_the_expert.ts +11 -0
  88. package/i18n/sv-SE/components/navigation/image.ts +4 -0
  89. package/i18n/sv-SE/components/navigation/index.ts +7 -0
  90. package/i18n/sv-SE/components/navigation/user_upload.ts +3 -0
  91. package/i18n/sv-SE/components/settings/clickable_icon.ts +10 -0
  92. package/i18n/sv-SE/components/settings/image.ts +1 -0
  93. package/i18n/sv-SE/components/settings/index.ts +17 -0
  94. package/i18n/sv-SE/components/settings/open_response.ts +5 -0
  95. package/i18n/sv-SE/components/settings/open_response_collate.ts +6 -0
  96. package/i18n/sv-SE/components/settings/text_editor.ts +7 -0
  97. package/i18n/sv-SE/components/settings/user_upload.ts +11 -0
  98. package/i18n/sv-SE/components/settings/video.ts +13 -0
  99. package/i18n/sv-SE/components/utils/index.ts +5 -0
  100. package/i18n/sv-SE/components/utils/tiny_mce_wrapper.ts +18 -0
  101. package/i18n/sv-SE/index.ts +16 -0
  102. package/i18n/sv-SE/modules/index.ts +5 -0
  103. package/i18n/sv-SE/pages/glossary.ts +7 -0
  104. package/i18n/sv-SE/pages/index.ts +7 -0
  105. package/i18n/sv-SE/pages/user_upload.ts +3 -0
  106. package/i18n/sv-SE/shared/content_blocks.ts +22 -0
  107. package/i18n/sv-SE/shared/index.ts +11 -0
  108. package/i18n/sv-SE/shared/menu.ts +3 -0
  109. package/i18n/sv-SE/shared/permission.ts +15 -0
  110. package/i18n/sv-SE/shared/settings.ts +17 -0
  111. package/package.json +1 -1
  112. package/plugin.js +68 -0
  113. package/test/Components/Content/Blocks/OpenResponse.spec.js +31 -0
  114. package/test/Components/Content/Blocks/OpenResponseCollate.spec.js +36 -0
  115. package/test/Components/Settings/OpenResponseCollateSettings.spec.js +20 -0
  116. package/test/Components/Settings/OpenResponseSettings.spec.js +20 -0
package/README.md CHANGED
@@ -24,7 +24,7 @@ Link to Windward ui repo
24
24
  $ cd windward-ui
25
25
  $ npm install
26
26
  $ cd node_modules
27
- $ npm link @mindedge/windward-ui-plugin-core
27
+ $ npm link @windward/core
28
28
  $ npm run dev
29
29
  ```
30
30
 
@@ -61,6 +61,7 @@ Your Repos are linked at this point and you are ready to start developing windwa
61
61
  ```
62
62
  import UserUpload from '@/components/Content/Blocks/UserUpload.vue'
63
63
  ```
64
+
64
65
  4. To add a page use the below format in your `pages: []` in `plugin.js`
65
66
  ```javascript
66
67
  {
@@ -31,7 +31,7 @@
31
31
  outlined
32
32
  @click="item.active = !item.active"
33
33
  >
34
- <v-icon>{{ item.icon }}</v-icon>
34
+ <v-icon>{{ onHandleHtmlEntities(item.icon) }}</v-icon>
35
35
  </v-btn>
36
36
  </v-col>
37
37
  <v-col cols="10" v-if="item.active">
@@ -89,6 +89,15 @@ export default {
89
89
  displayText: false,
90
90
  }
91
91
  },
92
+ methods: {
93
+ onHandleHtmlEntities(str) {
94
+ let txt = document.createElement('textarea')
95
+
96
+ txt.innerHTML = str
97
+
98
+ return txt.value
99
+ },
100
+ },
92
101
  }
93
102
  </script>
94
103
  <style scoped>
@@ -13,6 +13,13 @@
13
13
  </h3>
14
14
  </v-row>
15
15
  <v-row class="pt-2">
16
+ <p>
17
+ {{
18
+ $t(
19
+ 'windward.core.components.content.blocks.feedback.likert_directions'
20
+ )
21
+ }}
22
+ </p>
16
23
  <p>
17
24
  {{
18
25
  $t(
@@ -24,9 +31,9 @@
24
31
  </v-container>
25
32
  <v-container v-if="doesFeedbackExist">
26
33
  <v-row>
27
- <h3>
28
- {{ block.metadata.config.definition.name }}
29
- </h3>
34
+ <h2>
35
+ {{ existingFeedback.survey_type }}
36
+ </h2>
30
37
  </v-row>
31
38
  <v-row class="pt-2">
32
39
  <p>
@@ -187,8 +194,8 @@ export default {
187
194
  courseUserId: '',
188
195
  valid: true,
189
196
  key: '0',
190
- existingFeedback: '',
191
197
  doesFeedbackExist: false,
198
+ existingFeedback: '',
192
199
  templates: '',
193
200
  chosenPreset: '',
194
201
  studentResponse: '',
@@ -271,6 +278,7 @@ export default {
271
278
  survey_snapshot:
272
279
  this.block.metadata.config.definition.metadata.definition,
273
280
  survey_question_answers: this.chosenPreset,
281
+ survey_type: this.block.metadata.config.definition.name,
274
282
  version: version,
275
283
  }
276
284
  let feedback = new SurveyResult(feedbackData).for(
@@ -4,27 +4,28 @@
4
4
  {{ value.body }}
5
5
  </p>
6
6
  <div v-if="!feedbackExist">
7
- <TextEditor v-model="value.response"></TextEditor>
7
+ <v-text-field
8
+ outlined
9
+ v-model="value.response"
10
+ :label="
11
+ $t('windward.core.components.content.blocks.feedback.enter')
12
+ "
13
+ ></v-text-field>
8
14
  </div>
9
15
  <div v-else>
10
16
  <div v-if="value.response">
11
- <TextViewer v-model="value.response" text-viewer></TextViewer>
17
+ <div>{{ value.response }}</div>
12
18
  </div>
13
19
  <div v-else>
14
- <TextViewer v-model="noResponse" text-viewer></TextViewer>
20
+ <div>{{ noResponse }}</div>
15
21
  </div>
16
22
  </div>
17
23
  </v-container>
18
24
  </template>
19
25
  <script>
20
- import TextEditor from '~/components/Text/TextEditor.vue'
21
- import TextViewer from '~/components/Text/TextViewer.vue'
22
26
  export default {
23
27
  name: 'FeedbackQuestionOpenResponse',
24
- components: {
25
- TextEditor,
26
- TextViewer,
27
- },
28
+ components: {},
28
29
  props: {
29
30
  value: { type: Object, required: true, default: '' },
30
31
  feedbackExist: { type: Boolean, required: false, default: false },
@@ -48,10 +48,10 @@ export default {
48
48
  },
49
49
  data() {
50
50
  return {
51
+ id: 'image_' + Crypto.id(),
51
52
  aspectRatio: undefined,
52
53
  }
53
54
  },
54
- extends: BaseContentBlock,
55
55
  beforeMount() {
56
56
  if (_.isEmpty(this.block.metadata.config)) {
57
57
  this.block.metadata.config = {}
@@ -63,11 +63,6 @@ export default {
63
63
  this.block.metadata.config.aria_describedby = ''
64
64
  }
65
65
  },
66
- data() {
67
- return {
68
- id: 'image_' + Crypto.id(),
69
- }
70
- },
71
66
  computed: {
72
67
  describedById() {
73
68
  // If there's a described by
@@ -0,0 +1,137 @@
1
+ <template>
2
+ <div>
3
+ <div v-if="stateLoaded">
4
+ <div v-if="block.body && !submitted">
5
+ <TextViewer v-model="block.body" :height="200"></TextViewer>
6
+ <TextEditor
7
+ v-model="response"
8
+ :height="200"
9
+ menubar=""
10
+ ></TextEditor>
11
+ <p class="pa-3 text-center blue-grey lighten-5">
12
+ <v-btn
13
+ color="primary"
14
+ :disabled="!canSubmit"
15
+ @click="onSubmit"
16
+ >
17
+ {{ $t('shared.forms.submit') }}
18
+ </v-btn>
19
+ </p>
20
+ </div>
21
+
22
+ <div v-else-if="block.body && submitted">
23
+ <TextViewer v-model="block.body" :height="200"></TextViewer>
24
+ <p>
25
+ {{
26
+ $t(
27
+ 'windward.core.components.content.blocks.open_response.your_response'
28
+ )
29
+ }}
30
+ </p>
31
+ <v-alert color="light-blue lighten-4">
32
+ <TextViewer v-model="response" :height="200"></TextViewer>
33
+ </v-alert>
34
+ <div v-if="block.metadata.config.sample_response">
35
+ <p>
36
+ {{
37
+ $t(
38
+ 'windward.core.components.content.blocks.open_response.sample_response'
39
+ )
40
+ }}
41
+ </p>
42
+ <v-alert color="light-blue lighten-4">
43
+ <TextViewer
44
+ v-model="block.metadata.config.sample_response"
45
+ :height="200"
46
+ ></TextViewer>
47
+ </v-alert>
48
+ </div>
49
+ <p class="pa-3 text-center blue-grey lighten-5">
50
+ <v-btn color="primary" @click="submitted = false">{{
51
+ $t('shared.forms.edit')
52
+ }}</v-btn>
53
+ </p>
54
+ </div>
55
+
56
+ <v-alert v-else type="warning">
57
+ {{
58
+ $t(
59
+ 'windward.core.components.content.blocks.open_response.initial_setup'
60
+ )
61
+ }}
62
+ </v-alert>
63
+ </div>
64
+ <div v-if="!stateLoaded">
65
+ <v-progress-circular
66
+ indeterminate
67
+ :size="64"
68
+ :width="4"
69
+ color="white"
70
+ >
71
+ </v-progress-circular>
72
+ </div>
73
+ </div>
74
+ </template>
75
+
76
+ <script>
77
+ import _ from 'lodash'
78
+ import TextViewer from '~/components/Text/TextViewer.vue'
79
+ import TextEditor from '~/components/Text/TextEditor.vue'
80
+ import BaseContentBlock from '~/components/Content/Blocks/BaseContentBlock'
81
+
82
+ export default {
83
+ name: 'ContentBlockOpenResponse',
84
+ extends: BaseContentBlock,
85
+ components: {
86
+ TextViewer,
87
+ TextEditor,
88
+ },
89
+ data() {
90
+ return {
91
+ stateLoaded: false,
92
+ response: '',
93
+ submitted: false,
94
+ }
95
+ },
96
+ beforeMount() {
97
+ if (_.isEmpty(this.block.body)) {
98
+ this.block.body = ''
99
+ }
100
+ if (_.isEmpty(this.block.metadata.config)) {
101
+ this.block.metadata.config = {}
102
+ }
103
+ if (_.isEmpty(this.block.metadata.config.sample_response)) {
104
+ this.block.metadata.config.sample_response = ''
105
+ }
106
+ if (_.isEmpty(this.block.metadata.config.starting_text)) {
107
+ this.block.metadata.config.starting_text = ''
108
+ }
109
+ },
110
+ computed: {
111
+ canSubmit() {
112
+ // Make sure the response is not empty and not equal to the starting text
113
+ return (
114
+ this.response &&
115
+ this.response !== this.block.metadata.config.starting_text
116
+ )
117
+ },
118
+ },
119
+ watch: {},
120
+ mounted() {},
121
+ methods: {
122
+ onAfterSetContentBlockState() {
123
+ // If after the state is applied the response is still empty then apply the default response
124
+ if (this.response === '') {
125
+ this.response = this.block.metadata.config.starting_text
126
+ }
127
+ this.stateLoaded = true
128
+ },
129
+ onSubmit() {
130
+ this.submitted = true
131
+
132
+ // Force the state to save on submit and not wait
133
+ this.$Tracking.flushState()
134
+ },
135
+ },
136
+ }
137
+ </script>
@@ -0,0 +1,158 @@
1
+ <template>
2
+ <div>
3
+ <div v-if="block.metadata.config.linked.length">
4
+ <v-btn color="primary" block @click="onCollate">
5
+ <v-icon class="mr-3">mdi-file-word</v-icon>
6
+ {{
7
+ $t(
8
+ 'windward.core.components.content.blocks.open_response_collate.download_document'
9
+ )
10
+ }}
11
+ </v-btn>
12
+ </div>
13
+ <v-alert v-else type="warning">
14
+ {{
15
+ $t(
16
+ 'windward.core.components.content.blocks.open_response_collate.initial_setup'
17
+ )
18
+ }}
19
+ </v-alert>
20
+ </div>
21
+ </template>
22
+
23
+ <script>
24
+ import _ from 'lodash'
25
+ import { mapGetters } from 'vuex'
26
+ import BaseContentBlock from '~/components/Content/Blocks/BaseContentBlock'
27
+ import UserContentBlockState from '~/models/UserContentBlockState'
28
+
29
+ export default {
30
+ name: 'ContentBlockOpenResponseCollate',
31
+ extends: BaseContentBlock,
32
+ components: {},
33
+ data() {
34
+ return {}
35
+ },
36
+ beforeMount() {
37
+ if (_.isEmpty(this.block.body)) {
38
+ this.block.body = ''
39
+ }
40
+ if (_.isEmpty(this.block.metadata.config)) {
41
+ this.block.metadata.config = {}
42
+ }
43
+ if (_.isEmpty(this.block.metadata.config.linked)) {
44
+ this.block.metadata.config.linked = []
45
+ }
46
+ if (_.isEmpty(this.block.metadata.config.filename)) {
47
+ this.block.metadata.config.filename = ''
48
+ }
49
+ if (_.isEmpty(this.block.metadata.config.include_prompts)) {
50
+ this.block.metadata.config.include_prompts = false
51
+ }
52
+ },
53
+ computed: {
54
+ ...mapGetters({
55
+ organization: 'organization/get',
56
+ course: 'course/get',
57
+ enrollment: 'enrollment/get',
58
+ content: 'content/get',
59
+ }),
60
+ },
61
+ watch: {},
62
+ mounted() {},
63
+ methods: {
64
+ async onCollate() {
65
+ let userState = await UserContentBlockState.where({
66
+ 'metadata->block->tag': 'plugin-core-open-response',
67
+ course_user_id: this.enrollment.id,
68
+ })
69
+ .whereIn('content_block_id', this.block.metadata.config.linked)
70
+ .get()
71
+ let collated = ''
72
+
73
+ userState.forEach((state) => {
74
+ // Prepend the prompt from the state if include prompts is enabled
75
+ if (this.block.metadata.config.include_prompts) {
76
+ collated +=
77
+ '<strong>' +
78
+ state.metadata.block.body +
79
+ '</strong><hr />'
80
+ }
81
+ if (!_.isEmpty(state.metadata.response)) {
82
+ collated += '\n' + state.metadata.response
83
+ } else {
84
+ collated +=
85
+ '\n<p>' +
86
+ this.$t(
87
+ 'windward.core.components.content.blocks.open_response_collate.no_response'
88
+ ) +
89
+ '</p>'
90
+ }
91
+ })
92
+ let filename = this.block.metadata.config.filename
93
+ if (_.isEmpty(this.block.metadata.config.filename)) {
94
+ // Default filename is the users name + the current page
95
+ filename =
96
+ this.$auth.user.last_name +
97
+ '_' +
98
+ this.$auth.user.first_name +
99
+ '_' +
100
+ _.get(this.content, 'content.name_prefix') +
101
+ _.get(this.content, 'content.name')
102
+
103
+ // Change spaces to underscores and remove special characters
104
+ filename = filename.replaceAll(/\s+/gi, '_')
105
+ filename = filename.replaceAll(/[^a-z0-9\-\_]/gi, '')
106
+ }
107
+
108
+ this.generateDocument(collated, filename)
109
+ },
110
+ generateDocument(htmlBody, filename = '') {
111
+ // Specify file name. If one isn't supplied then a default name of `exported_document_YYYY-MM-DD.doc` is used
112
+ filename = filename
113
+ ? filename + '.doc'
114
+ : 'exported_document_' +
115
+ new Date().toISOString().split('T')[0] +
116
+ '.doc'
117
+
118
+ var preHtml =
119
+ "<html xmlns:o='urn:schemas-microsoft-com:office:office' xmlns:w='urn:schemas-microsoft-com:office:word' xmlns='http://www.w3.org/TR/REC-html40'>" +
120
+ "<head><meta charset='utf-8'><title>" +
121
+ filename +
122
+ '</title></head>' +
123
+ '<body>'
124
+ var postHtml = '</body></html>'
125
+ var html = preHtml + htmlBody + postHtml
126
+
127
+ var blob = new Blob(['\ufeff', html], {
128
+ type: 'application/msword',
129
+ })
130
+
131
+ // Specify link url
132
+ var url =
133
+ 'data:application/vnd.ms-word;charset=utf-8,' +
134
+ encodeURIComponent(html)
135
+
136
+ // Create download link element
137
+ var downloadLink = document.createElement('a')
138
+
139
+ document.body.appendChild(downloadLink)
140
+
141
+ if (navigator.msSaveOrOpenBlob) {
142
+ navigator.msSaveOrOpenBlob(blob, filename)
143
+ } else {
144
+ // Create a link to the file
145
+ downloadLink.href = url
146
+
147
+ // Setting the file name
148
+ downloadLink.download = filename
149
+
150
+ //triggering the function
151
+ downloadLink.click()
152
+ }
153
+
154
+ document.body.removeChild(downloadLink)
155
+ },
156
+ },
157
+ }
158
+ </script>
@@ -0,0 +1,173 @@
1
+ <template>
2
+ <v-list-item @click="dialog = true">
3
+ <v-list-item-action>
4
+ <v-icon>{{ config.icon }}</v-icon>
5
+ </v-list-item-action>
6
+ <v-list-item-content>
7
+ <v-list-item-title>
8
+ {{ $t(config.i18n) }}
9
+ </v-list-item-title>
10
+ <Dialog v-model="dialog" color="primary" text :trigger="false">
11
+ <template #title>{{ $t(config.i18n) }}</template>
12
+ <template #form="{ on, attrs }">
13
+ <v-card flat v-bind="attrs" v-on="on">
14
+ <v-container fluid>
15
+ <v-row>
16
+ <v-col cols="12" class="pl-6">
17
+ <h3>
18
+ {{
19
+ $t(
20
+ 'windward.core.components.navigation.ask_the_expert.description'
21
+ )
22
+ }}
23
+ </h3>
24
+ </v-col>
25
+ <v-col
26
+ v-if="
27
+ $PermissionService.userHasAccessTo(
28
+ 'windward.global.course,windward.organization.course.contentBlock',
29
+ 'writable'
30
+ )
31
+ "
32
+ cols="12"
33
+ >
34
+ <v-col cols="12">
35
+ <h3 class="pb-4">
36
+ {{
37
+ $t(
38
+ 'windward.core.components.navigation.ask_the_expert.config'
39
+ )
40
+ }}
41
+ </h3>
42
+ </v-col>
43
+ <v-col cols="12">
44
+ <v-text-field
45
+ v-model="courseAndContentName"
46
+ disabled
47
+ outlined
48
+ :label="
49
+ $t(
50
+ 'windward.core.components.navigation.ask_the_expert.course_info'
51
+ )
52
+ "
53
+ ></v-text-field>
54
+ </v-col>
55
+ </v-col>
56
+ <v-col
57
+ v-if="
58
+ !$PermissionService.userHasAccessTo(
59
+ 'windward.global.course,windward.organization.course.contentBlock',
60
+ 'writable'
61
+ )
62
+ "
63
+ cols="12"
64
+ >
65
+ <v-col cols="12">
66
+ <v-text-field
67
+ v-model="subject"
68
+ outlined
69
+ :label="
70
+ $t(
71
+ 'windward.core.components.navigation.ask_the_expert.subject'
72
+ )
73
+ "
74
+ ></v-text-field>
75
+ </v-col>
76
+ <v-col cols="12">
77
+ <v-textarea v-model="body" outlined>
78
+ <template #label>
79
+ <div>
80
+ {{
81
+ $t(
82
+ 'windward.core.components.navigation.ask_the_expert.question'
83
+ )
84
+ }}
85
+ </div>
86
+ </template>
87
+ </v-textarea>
88
+ </v-col>
89
+ <v-col
90
+ cols="12"
91
+ class="pt-5 pb-5 d-flex flex-row-reverse"
92
+ >
93
+ <v-btn
94
+ class="primary"
95
+ :disabled="valid"
96
+ @click="onSubmit"
97
+ >{{
98
+ $t('shared.forms.submit')
99
+ }}</v-btn
100
+ >
101
+ </v-col>
102
+ </v-col>
103
+ </v-row>
104
+ </v-container>
105
+ </v-card>
106
+ </template>
107
+ </Dialog>
108
+ </v-list-item-content>
109
+ </v-list-item>
110
+ </template>
111
+
112
+ <script>
113
+ import { mapGetters } from 'vuex'
114
+ import AuthUserRepository from '~/models/repositories/AuthUserRepository'
115
+ import AskTheExpert from '~/models/AskTheExpert'
116
+
117
+ export default {
118
+ name: 'NavigationItemAskTheExpert',
119
+ components: {},
120
+ props: {
121
+ config: { type: Object, required: true },
122
+ },
123
+ data() {
124
+ return {
125
+ currentUser: new AuthUserRepository(this.$nuxt),
126
+ expert: '',
127
+ course: this.$ContentService.getCourse(),
128
+ content: this.$ContentService.get().content,
129
+ courseAndContentName: '',
130
+ body: '',
131
+ subject: '',
132
+ dialog: false,
133
+ }
134
+ },
135
+ computed: {
136
+ ...mapGetters({
137
+ enrollment: 'enrollment/get',
138
+ }),
139
+ valid() {
140
+ if (this.body === '' || this.subject === '') {
141
+ return true
142
+ } else {
143
+ return false
144
+ }
145
+ },
146
+ },
147
+ mounted() {
148
+ this.courseAndContentName = this.course.name + ': ' + this.content.name
149
+ },
150
+ methods: {
151
+ async onSubmit() {
152
+ const askTheExpertSubmission = new AskTheExpert({
153
+ body: this.body,
154
+ subject: this.subject,
155
+ currentUser: this.currentUser,
156
+ enrollment: this.enrollment,
157
+ content: this.content,
158
+ course: this.course,
159
+ courseAndContentName: this.courseAndContentName,
160
+ })
161
+ await askTheExpertSubmission.save()
162
+ if (askTheExpertSubmission) {
163
+ this.$dialog.success('Ask The Expert Email Sent Successfully')
164
+ this.body = ''
165
+ this.subject = ''
166
+ this.dialog = false
167
+ } else {
168
+ this.$dialog.error('Ask The Expert Email Failed')
169
+ }
170
+ },
171
+ },
172
+ }
173
+ </script>
@@ -1,7 +1,7 @@
1
1
  <template>
2
2
  <div>
3
3
  <v-container>
4
- <v-col>
4
+ <v-col class="pa-0">
5
5
  <v-text-field
6
6
  v-model="block.metadata.config.title"
7
7
  :label="
@@ -18,7 +18,11 @@
18
18
  )
19
19
  "
20
20
  ></v-text-field>
21
- <v-btn color="primary" outlined @click="onAddElement"
21
+ <v-btn
22
+ color="primary"
23
+ outlined
24
+ @click="onAddElement"
25
+ class="btn-add"
22
26
  ><v-icon>mdi-plus</v-icon
23
27
  >{{ $t('shared.forms.add') }}</v-btn
24
28
  >
@@ -29,7 +33,7 @@
29
33
  :key="itemIndex"
30
34
  class="elevation-0"
31
35
  >
32
- <v-expansion-panel-header class="elevation-0">{{
36
+ <v-expansion-panel-header class="elevation-0 pa-0">{{
33
37
  'item ' + (itemIndex + 1)
34
38
  }}</v-expansion-panel-header>
35
39
  <v-expansion-panel-content
@@ -37,8 +41,6 @@
37
41
  :key="expansionPanelKey"
38
42
  >
39
43
  <v-text-field
40
- :counter="1"
41
- maxlength="1"
42
44
  v-model="
43
45
  block.metadata.config.items[itemIndex].icon
44
46
  "
@@ -186,4 +188,7 @@ export default {
186
188
  .v-progress-circular {
187
189
  margin: 1rem;
188
190
  }
191
+ .btn-add {
192
+ width: 100%;
193
+ }
189
194
  </style>