@windward/games 0.21.0 → 0.22.0

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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,14 @@
1
1
  # Changelog
2
2
 
3
+ ## Release [0.22.0] - 2025-08-28
4
+
5
+ * Merged in feature/LE-2036/update-core-package-v (pull request #252)
6
+ * Merged in feature/LE-1851-multiple-choice-block-feedback-l (pull request #251)
7
+ * Merged release/0.22.0 into feature/LE-1851-multiple-choice-block-feedback-l
8
+ * Merged in feature/LE-2036/word-jumble-gen (pull request #250)
9
+ * Merged in feature/LE-1851-multiple-choice-block-feedback-l (pull request #249)
10
+
11
+
3
12
  ## Release [0.21.0] - 2025-07-29
4
13
 
5
14
  * Merged in feature/LE-1912/sorting-game-generation (pull request #246)
@@ -228,13 +228,14 @@
228
228
  </div>
229
229
  </template>
230
230
  <template #form="{ on, attrs }">
231
- <div v-bind="attrs" v-on="on">
231
+ <p v-bind="attrs" v-on="on">
232
232
  <TextViewer v-if="hint" v-model="hintText"></TextViewer>
233
233
  <TextViewer
234
234
  v-if="answerDescriptionModal"
235
235
  v-model="answerDescription"
236
+ class="dialog-text-viewer"
236
237
  ></TextViewer>
237
- </div>
238
+ </p>
238
239
  </template>
239
240
  </DialogBox>
240
241
  </v-carousel>
@@ -320,10 +321,14 @@ export default {
320
321
  onAnswerDescription(question, answer) {
321
322
  this.activeQuestion = question
322
323
  this.activeAnswer = answer
323
- //launches modal and displays anwer description
324
+ // launches modal and displays anwer description
324
325
  this.dialog = true
325
326
  this.answerDescriptionModal = true
326
- this.answerDescription = question.answer_description
327
+ if (question.metadata.config.single_feedback) {
328
+ this.answerDescription = question.answer_description
329
+ } else if (!_.isEmpty(answer.feedback)) {
330
+ this.answerDescription = answer.feedback
331
+ }
327
332
  },
328
333
  onChooseAnswer(answer, question) {
329
334
  // check to see if student already answered this question
@@ -467,13 +472,12 @@ export default {
467
472
  }
468
473
  )
469
474
  if (studentsQuestionResponse) {
470
- if (answer.correctAnswer === true && answer.chosen === true) {
471
- return 'mdi-information'
472
- } else if (
473
- answer.correctAnswer === true &&
474
- answer.chosen === false
475
+ if (
476
+ answer.chosen === true &&
477
+ (!_.isEmpty(answer.feedback) ||
478
+ question.metadata.config.single_feedback)
475
479
  ) {
476
- return 'mdi-information-outline'
480
+ return 'mdi-message-alert-outline'
477
481
  }
478
482
  }
479
483
  },
@@ -613,4 +617,7 @@ export default {
613
617
  min-width: 20% !important;
614
618
  margin-right: 16px;
615
619
  }
620
+ .dialog-text-viewer {
621
+ color: var(--v-primary-base);
622
+ }
616
623
  </style>
@@ -119,10 +119,26 @@
119
119
  indeterminate
120
120
  ></v-progress-circular>
121
121
  </div>
122
+ <v-container class="pa-4 mb-6">
123
+ <v-row>
124
+ <v-col cols="12">
125
+ <GenerateAIQuestionButton
126
+ :course="course"
127
+ :content="currentContent"
128
+ :block="block"
129
+ question-type="word_jumble"
130
+ :replace-existing-mode="replaceExisting"
131
+ @click:generate="onGeneratedWordJumble"
132
+ ></GenerateAIQuestionButton>
133
+ </v-col>
134
+ </v-row>
135
+ </v-container>
122
136
  </div>
123
137
  </template>
124
138
  <script>
125
139
  import _ from 'lodash'
140
+ import { mapGetters } from 'vuex'
141
+ import { GenerateAIQuestionButton } from '@windward/core/utils'
126
142
  import BaseContentSettings from '~/components/Content/Settings/BaseContentSettings.js'
127
143
  import SortableExpansionPanel from '~/components/Core/SortableExpansionPanel.vue'
128
144
  import BaseContentBlockSettings from '~/components/Content/Settings/BaseContentBlockSettings.vue'
@@ -133,6 +149,7 @@ export default {
133
149
  components: {
134
150
  SortableExpansionPanel,
135
151
  BaseContentBlockSettings,
152
+ GenerateAIQuestionButton,
136
153
  },
137
154
  beforeMount() {
138
155
  if (_.isEmpty(this.block)) {
@@ -173,8 +190,16 @@ export default {
173
190
  return {
174
191
  valid: true,
175
192
  loading: false,
193
+ replaceExisting: true,
176
194
  }
177
195
  },
196
+ computed: {
197
+
198
+ ...mapGetters({
199
+ course: 'course/get',
200
+ currentContent: 'content/get',
201
+ }),
202
+ },
178
203
  methods: {
179
204
  onBeforeSave() {
180
205
  this.block.metadata.config.words.forEach((element) => {
@@ -226,6 +251,73 @@ export default {
226
251
  this.block.metadata.config.currentWord =
227
252
  this.block.metadata.config.words.length - 1
228
253
  },
254
+ onGeneratedWordJumble(activityData, replaceMode) {
255
+ this.loading = true
256
+ try {
257
+ // Process the activity data
258
+ if (activityData && activityData.metadata &&
259
+ activityData.metadata.config &&
260
+ activityData.metadata.config.words &&
261
+ Array.isArray(activityData.metadata.config.words)) {
262
+
263
+ const newWords = activityData.metadata.config.words
264
+
265
+ if (replaceMode) { this.block.metadata.config.words.splice(0, this.block.metadata.config.words.length)
266
+ newWords.forEach(word => {
267
+ this.block.metadata.config.words.push({
268
+ id: word.id || this.block.metadata.config.words.length + 1,
269
+ value: word.value || '',
270
+ hint: word.hint || '',
271
+ shuffledWord: this.shuffle(word.value || '')
272
+ })
273
+ })
274
+ } else {
275
+ newWords.forEach(word => {
276
+ this.block.metadata.config.words.push({
277
+ id: this.block.metadata.config.words.length + 1,
278
+ value: word.value || '',
279
+ hint: word.hint || '',
280
+ shuffledWord: this.shuffle(word.value || '')
281
+ })
282
+ })
283
+ }
284
+
285
+ if (replaceMode && activityData.metadata.config.title) {
286
+ this.block.metadata.config.title = activityData.metadata.config.title
287
+ }
288
+
289
+ if (replaceMode) {
290
+ if (activityData.metadata.config.feedback_correct) {
291
+ this.block.metadata.config.feedback_correct = activityData.metadata.config.feedback_correct
292
+ }
293
+
294
+ if (activityData.metadata.config.feedback_incorrect) {
295
+ this.block.metadata.config.feedback_incorrect = activityData.metadata.config.feedback_incorrect
296
+ }
297
+ }
298
+
299
+ this.block.metadata.config.currentWord = 0
300
+
301
+ this.$toast.success(
302
+ replaceMode
303
+ ? this.$t('windward.games.components.settings.word_jumble.form.replaced_successfully')
304
+ : this.$t('windward.games.components.settings.word_jumble.form.added_successfully'),
305
+ { duration: 3000 }
306
+ )
307
+ } else {
308
+ this.$toast.error(this.$t('windward.games.components.settings.word_jumble.form.invalid_response'), {
309
+ duration: 5000
310
+ })
311
+ }
312
+ } catch (error) {
313
+ const errorMessage = error.message || 'Unknown error occurred'
314
+ this.$toast.error(`${this.$t('windward.games.components.settings.word_jumble.form.failed_to_process')}: ${errorMessage}`, {
315
+ duration: 5000
316
+ })
317
+ } finally {
318
+ this.loading = false
319
+ }
320
+ },
229
321
  },
230
322
  }
231
323
  </script>
@@ -9,4 +9,13 @@ export default {
9
9
  add: 'Add Word',
10
10
  feedback_correct: 'Feedback when correct',
11
11
  feedback_incorrect: 'Feedback when incorrect',
12
+
13
+ // AI generation keys in nested form structure
14
+ form: {
15
+ replace_existing: 'Replace existing words',
16
+ replaced_successfully: 'Words replaced successfully',
17
+ added_successfully: 'New words added successfully',
18
+ invalid_response: 'Invalid response from word jumble generation',
19
+ failed_to_process: 'Failed to process generated words'
20
+ }
12
21
  }
@@ -9,4 +9,13 @@ export default {
9
9
  add: 'Agregar palabra',
10
10
  feedback_correct: 'Comentarios cuando sea correcto',
11
11
  feedback_incorrect: 'Comentarios cuando sean incorrectos',
12
+
13
+ // AI generation keys in nested form structure
14
+ form: {
15
+ replace_existing: 'Reemplazar palabras existentes',
16
+ replaced_successfully: 'Palabras reemplazadas exitosamente',
17
+ added_successfully: 'Nuevas palabras añadidas exitosamente',
18
+ invalid_response: 'Respuesta inválida de la generación de revoltijo de palabras',
19
+ failed_to_process: 'Error al procesar las palabras generadas'
20
+ }
12
21
  }
@@ -9,4 +9,13 @@ export default {
9
9
  add: 'Lägg till ord',
10
10
  feedback_correct: 'Återkoppling när korrekt',
11
11
  feedback_incorrect: 'Återkoppling när felaktig',
12
+
13
+ // AI generation keys in nested form structure
14
+ form: {
15
+ replace_existing: 'Ersätt befintliga ord',
16
+ replaced_successfully: 'Ord ersatta framgångsrikt',
17
+ added_successfully: 'Nya ord tillagda framgångsrikt',
18
+ invalid_response: 'Ogiltig respons från ordvirrvarr-generering',
19
+ failed_to_process: 'Misslyckades med att bearbeta genererade ord'
20
+ }
12
21
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@windward/games",
3
- "version": "0.21.0",
3
+ "version": "0.22.0",
4
4
  "description": "Windward UI Plugin Games",
5
5
  "main": "plugin.js",
6
6
  "scripts": {
@@ -21,7 +21,7 @@
21
21
  "license": "MIT",
22
22
  "homepage": "https://bitbucket.org/mindedge/windward-ui-plugin-games#readme",
23
23
  "dependencies": {
24
- "@windward/core": "^0.21.0",
24
+ "@windward/core": "^0.22.0",
25
25
  "eslint": "^8.11.0",
26
26
  "lodash": "^4.17.21",
27
27
  "prettier": "^2.6.0",