Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions functions/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

95 changes: 92 additions & 3 deletions src/app/plugins/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -1323,6 +1323,14 @@
"camera": "Camera",
"audio": "Audio"
}
},
"taskPreview": {
"screenRecord": "Screen Record",
"screenRecordDesc": "Captures clicks, scrolling, and interactions to analyze user behavior.",
"camera": "Camera",
"cameraDesc": "Records facial expressions and reactions to understand user emotions.",
"audioRecord": "Audio Record",
"audioRecordDesc": "Captures verbal feedback and think-aloud protocols during the task."
}
},
"UserTestView": {
Expand Down Expand Up @@ -1830,6 +1838,8 @@
"buttons": {
"next": "Next",
"previous": "Previous",
"continue": "Continue",
"back": "Back",
"seeCode": "See the code",
"username": "Username",
"goToConsole": "Go to Console",
Expand Down Expand Up @@ -2065,22 +2075,101 @@
}
},
"CardSorting": {
"title": "Card Sorting",
"noCategory": "No category",
"noCards": "No cards found",
"of": "of",
"cards": "Cards",
"cards_low": "cards",
"unsortedCards": "Unsorted Cards",
"dropCardsHere": "Drop cards here",
"allCardsSorted": "All cards have been sorted",
"card": "Card",
"currentCards": "Current Cards",
"addNewCard": "Add New Card",
"settings": "Settings",
"configureCards": "Configure how cards will be displayed",
"currentCategories": "Current Categories",
"addNewTask": "Add New Task",
"addNewTask": "Add New Category",
"addNewCategory": "Add New Category",
"configureCategories": "Configure how categories will be displayed",
"newTask": "New task",
"showCategoryDescription": "Show Category Description",
"showCardDescription": "Show Card Description",
"showImage": "Show Image",
"allowCreateCategories": "Allow participants to create categories",
"closedModeHint": "Closed sorting: participants can only use the categories you define.",
"hybridModeHint": "Hybrid sorting: participants use your categories and can also create their own.",
"openModeHint": "Open sorting: no predefined categories — participants create all categories during the test.",
"createCategory": "Create category",
"newCategory": "New Category",
"newCategoryHint": "Name a group and start sorting",
"newCategoryFormHint": "Define a category that participants can use while sorting cards.",
"editCategory": "Edit Category",
"editCategoryHint": "Update the category name and optional details.",
"newCard": "New Card",
"newCardHint": "Create a card that participants will sort into categories.",
"editCard": "Edit Card",
"editCardHint": "Update the card name and optional details.",
"cardName": "Card name",
"cardNamePlaceholder": "e.g. Checkout, Search, Profile",
"categoryNamePlaceholder": "e.g. Navigation, Content, Settings",
"imageHint": "Upload an image to show with this item",
"renameCategory": "Rename category",
"categoryName": "Category name",
"categoryNameRequired": "Category name is required",
"categoryNameDuplicate": "A category with this name already exists",
"categoryNameInvalid": "This category name is not allowed",
"createCategoryHint": "Create at least one category to start sorting the cards.",
"participantCategory": "Created by you",
"customCategory": "Custom",
"newTask": "New Category",
"customizeSettings": "Customize the settings and preferences of your test",
"test": "Test",
"categories": "Categories"
"categories": "Categories",
"step": "Step",
"allocateAll": "Allocate all cards ({count} left)",
"thankYou": "Thank you for participating!",
"answerSubmitted": "Answer submitted",
"saveError": "Failed to save your answer. Please try again.",
"nameRequired": "Name is required",
"acceptConsent": "I accept the consent terms",
"results": "Results",
"resultsSubtitle": "Aggregated card sorting results across all participants",
"totalParticipants": "Participants",
"answers": "Answers",
"answersSubtitle": "Overview of card sorting results and individual participant answers",
"noAnswers": "No answers collected yet",
"anonymous": "Anonymous",
"submitted": "Submitted",
"inProgress": "In progress",
"emptyCategory": "No cards",
"notCategorized": "Not categorized",
"matrixHint": "Number of participants who placed each card in each category (based on {total} submitted answers)",
"categoryMatrix": "Card × Category Matrix",
"categoryMatrixHint": "How often each card was placed in each category",
"similarityMatrix": "Similarity Matrix",
"similarityMatrixHint": "How often two cards were placed in the same category by participants",
"similarityMatrixFooter": "Based on {total} submitted answers. Higher values mean cards were grouped together more often.",
"absoluteValues": "Absolute",
"percentageValues": "Percentage",
"dendrogram": "Dendrogram",
"dendrogramHint": "Hierarchical clustering of cards based on similarity (UPGMA). Cards that were frequently grouped together appear closer in the tree.",
"similarityScale": "Similarity",
"participantsDescription": "{total} total answers including in-progress",
"cardsDescription": "Cards defined in this study",
"categoriesDescription": "Categories used across the study",
"categoriesUsed": "{count} categories",
"studyStructure": "Study Structure",
"studyStructureSubtitle": "Cards and categories overview",
"viewResults": "View results",
"recording": "Recording",
"recordingTitle": "Recording options",
"recordingDescription": "Choose which media to capture while participants sort the cards. Recordings are saved with each answer for later review.",
"sortingPreview": "Sorting Preview",
"recordingInfo": "This session will record the following data during your sorting:",
"startSorting": "Start sorting",
"uploadingRecordings": "Uploading recordings...",
"recordings": "Recordings"
},
"analytics": {
"searchByName": "Search by name",
Expand Down
95 changes: 92 additions & 3 deletions src/app/plugins/locales/es.json
Original file line number Diff line number Diff line change
Expand Up @@ -1243,6 +1243,14 @@
"camera": "Cámara",
"audio": "Audio"
}
},
"taskPreview": {
"screenRecord": "Grabación de pantalla",
"screenRecordDesc": "Captura clics, desplazamiento e interacciones para analizar el comportamiento del usuario.",
"camera": "Cámara",
"cameraDesc": "Registra expresiones faciales y reacciones para entender las emociones del usuario.",
"audioRecord": "Grabación de audio",
"audioRecordDesc": "Captura comentarios verbales y protocolos de pensamiento en voz alta durante la tarea."
}
},
"UserTestView": {
Expand Down Expand Up @@ -1740,6 +1748,8 @@
"buttons": {
"next": "Siguiente",
"previous": "Anterior",
"continue": "Continuar",
"back": "Volver",
"seeCode": "Ver el código",
"username": "Nombre de usuario",
"goToConsole": "Ir a la consola",
Expand Down Expand Up @@ -1967,22 +1977,101 @@
}
},
"CardSorting": {
"title": "Card Sorting",
"noCategory": "Sin categoría",
"noCards": "No se encontraron tarjetas",
"of": "de",
"cards": "Tarjetas",
"cards_low": "tarjetas",
"unsortedCards": "Tarjetas sin ordenar",
"dropCardsHere": "Suelta las tarjetas aquí",
"allCardsSorted": "Todas las tarjetas han sido ordenadas",
"card": "Tarjeta",
"currentCards": "Tarjetas actuales",
"addNewCard": "Agregar nueva tarjeta",
"settings": "Configuración",
"configureCards": "Configura cómo se mostrarán las tarjetas",
"currentCategories": "Categorías actuales",
"addNewTask": "Agregar nueva tarea",
"addNewTask": "Agregar nueva categoría",
"addNewCategory": "Agregar nueva categoría",
"configureCategories": "Configura cómo se mostrarán las categorías",
"newTask": "Nueva tarea",
"showCategoryDescription": "Mostrar descripción de la categoría",
"showCardDescription": "Mostrar descripción de la tarjeta",
"showImage": "Mostrar imagen",
"allowCreateCategories": "Permitir que los participantes creen categorías",
"closedModeHint": "Sorting cerrado: los participantes solo pueden usar las categorías que definas.",
"hybridModeHint": "Sorting híbrido: los participantes usan tus categorías y también pueden crear las suyas.",
"openModeHint": "Sorting abierto: sin categorías predefinidas — los participantes crean todas las categorías durante la prueba.",
"createCategory": "Crear categoría",
"newCategory": "Nueva categoría",
"newCategoryHint": "Nombra un grupo y empieza a ordenar",
"newCategoryFormHint": "Define una categoría que los participantes puedan usar al ordenar las tarjetas.",
"editCategory": "Editar categoría",
"editCategoryHint": "Actualiza el nombre de la categoría y los detalles opcionales.",
"newCard": "Nueva tarjeta",
"newCardHint": "Crea una tarjeta que los participantes ordenarán en categorías.",
"editCard": "Editar tarjeta",
"editCardHint": "Actualiza el nombre de la tarjeta y los detalles opcionales.",
"cardName": "Nombre de la tarjeta",
"cardNamePlaceholder": "ej. Checkout, Búsqueda, Perfil",
"categoryNamePlaceholder": "ej. Navegación, Contenido, Ajustes",
"imageHint": "Sube una imagen para mostrar con este elemento",
"renameCategory": "Renombrar categoría",
"categoryName": "Nombre de la categoría",
"categoryNameRequired": "El nombre de la categoría es obligatorio",
"categoryNameDuplicate": "Ya existe una categoría con este nombre",
"categoryNameInvalid": "Este nombre de categoría no está permitido",
"createCategoryHint": "Crea al menos una categoría para empezar a ordenar las tarjetas.",
"participantCategory": "Creada por ti",
"customCategory": "Personalizada",
"newTask": "Nueva categoría",
"customizeSettings": "Personaliza los ajustes y preferencias de tu prueba",
"test": "Prueba",
"categories": "Categorías"
"categories": "Categorías",
"step": "Paso",
"allocateAll": "Coloca todas las tarjetas (faltan {count})",
"thankYou": "¡Gracias por participar!",
"answerSubmitted": "Respuesta enviada",
"saveError": "No se pudo guardar tu respuesta. Inténtalo de nuevo.",
"nameRequired": "El nombre es obligatorio",
"acceptConsent": "Acepto los términos del consentimiento",
"results": "Resultados",
"resultsSubtitle": "Resultados agregados del card sorting de todos los participantes",
"totalParticipants": "Participantes",
"answers": "Respuestas",
"answersSubtitle": "Resumen de resultados de card sorting y respuestas individuales por participante",
"noAnswers": "Aún no se han recopilado respuestas",
"anonymous": "Anónimo",
"submitted": "Enviado",
"inProgress": "En progreso",
"emptyCategory": "Sin tarjetas",
"notCategorized": "Sin categorizar",
"matrixHint": "Número de participantes que colocaron cada tarjeta en cada categoría (según {total} respuestas enviadas)",
"categoryMatrix": "Matriz Tarjeta × Categoría",
"categoryMatrixHint": "Con qué frecuencia cada tarjeta se colocó en cada categoría",
"similarityMatrix": "Matriz de similitud",
"similarityMatrixHint": "Con qué frecuencia dos tarjetas se colocaron en la misma categoría",
"similarityMatrixFooter": "Basado en {total} respuestas enviadas. Valores más altos indican que las tarjetas se agruparon juntas con más frecuencia.",
"absoluteValues": "Absoluto",
"percentageValues": "Porcentaje",
"dendrogram": "Dendrograma",
"dendrogramHint": "Agrupación jerárquica de tarjetas según similitud (UPGMA). Las tarjetas agrupadas con frecuencia aparecen más cerca en el árbol.",
"similarityScale": "Similitud",
"participantsDescription": "{total} respuestas totales incluyendo las en progreso",
"cardsDescription": "Tarjetas definidas en este estudio",
"categoriesDescription": "Categorías usadas en el estudio",
"categoriesUsed": "{count} categorías",
"studyStructure": "Estructura del estudio",
"studyStructureSubtitle": "Resumen de tarjetas y categorías",
"viewResults": "Ver resultados",
"recording": "Grabación",
"recordingTitle": "Opciones de grabación",
"recordingDescription": "Elige qué medios capturar mientras los participantes ordenan las tarjetas. Las grabaciones se guardan con cada respuesta para revisión posterior.",
"sortingPreview": "Vista previa del ordenamiento",
"recordingInfo": "Esta sesión grabará los siguientes datos durante tu ordenamiento:",
"startSorting": "Comenzar ordenamiento",
"uploadingRecordings": "Subiendo grabaciones...",
"recordings": "Grabaciones"
},
"analytics": {
"searchByName": "Buscar por nombre",
Expand Down
3 changes: 1 addition & 2 deletions src/features/ux_creation/ChooseStudyMethods.vue
Original file line number Diff line number Diff line change
Expand Up @@ -100,8 +100,7 @@ const methodsByCategory = {
'studyCreation.methods.test.card_sorting_unmoderated.description',
icon: 'mdi-card-multiple',
color: 'error',
available: false,
comingSoon: true,
available: true,
},
{
id: 'ab-testing',
Expand Down
5 changes: 4 additions & 1 deletion src/shared/components/template/StartScreenTest.vue
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,10 @@ defineProps({
})

// Emits
defineEmits(['start'])
const emit = defineEmits(['start'])

// Methods
const startTest = () => emit('start')
</script>

<style scoped>
Expand Down
2 changes: 1 addition & 1 deletion src/shared/constants/methodDefinitions.js
Original file line number Diff line number Diff line change
Expand Up @@ -268,7 +268,7 @@ export const METHOD_DEFINITIONS = {
color: '#3F51B5',
description: 'Content organization through card sorting',
category: METHOD_CATEGORIES.inquiry.id,
status: METHOD_STATUSES.IMPROVING.id,
status: METHOD_STATUSES.AVAILABLE.id,
},
COGNITIVE_WALKTHROUGH: {
id: 'COGNITIVE_WALKTHROUGH',
Expand Down
3 changes: 3 additions & 0 deletions src/shared/controllers/AnswerController.js
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,9 @@ export default class AnswerController extends Controller {
if (testType === STUDY_TYPES.HEURISTIC) {
fieldToUpdate[`heuristicAnswers.${payload.userDocId}`] =
payload.toFirestore()
} else if (testType === STUDY_TYPES.CARD_SORTING) {
fieldToUpdate[`cardSortingAnswers.${payload.userDocId}`] =
payload.toFirestore()
} else if (testType === STUDY_TYPES.USER) {
if (!payload.userDocId) {
const taskAnswer = (await this.getAnswerById(answersDocId)).taskAnswers // get taskAnswers
Expand Down
1 change: 1 addition & 0 deletions src/shared/controllers/ReportController.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ export default class ReportController extends Controller {

if (testType === STUDY_TYPES.HEURISTIC) testType = 'heuristicAnswers'
if (testType === STUDY_TYPES.USER) testType = 'taskAnswers'
if (testType === STUDY_TYPES.CARD_SORTING) testType = 'cardSortingAnswers'

try {
// 1 - Remover a referência no usuário
Expand Down
28 changes: 28 additions & 0 deletions src/shared/store/Answer.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import { STUDY_TYPES } from '@/shared/constants/methodDefinitions'
import UserStudyEvaluatorAnswer from '@/ux/UserTest/models/UserStudyEvaluatorAnswer'
import TaskAnswer from '@/ux/UserTest/models/TaskAnswer'
import CardSortingEvaluatorAnswer from '@/ux/CardSorting/models/CardSortingEvaluatorAnswer'
import { showError } from '@/shared/utils/toast'

const answerController = new AnswerController()
Expand Down Expand Up @@ -169,6 +170,28 @@
answer.hidden !== true,
)
},
currentCardSortingAnswer(state, rootGetters) {
if (!state.testAnswerDocument) return {}
if (!rootGetters.test || !rootGetters.user) return {}

const cardSortingAnswers =
state.testAnswerDocument.cardSortingAnswers || {}
const existing = cardSortingAnswers[rootGetters.user.id]

return existing
? CardSortingEvaluatorAnswer.toModel(existing)
: new CardSortingEvaluatorAnswer({ userDocId: rootGetters.user.id })
},
cardSortingAnswersList(state) {
const doc = state.testAnswerDocument
if (!doc?.cardSortingAnswers) return []
return Object.values(doc.cardSortingAnswers).filter(
(answer) =>
typeof answer === 'object' &&
answer !== null &&
answer.hidden !== true,
)
},
},
mutations: {
SET_ANSWER_DOCUMENT(state, payload) {
Expand Down Expand Up @@ -284,7 +307,7 @@
commit('setLoading', false)
}
},
async saveTestAnswer({ commit, state, rootState }, payload) {

Check failure on line 310 in src/shared/store/Answer.js

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Refactor this function to reduce its Cognitive Complexity from 19 to the 15 allowed.

See more on https://sonarcloud.io/project/issues?id=ruxailab_RUXAILAB&issues=AZ9b170wDOT93DBKa5dk&open=AZ9b170wDOT93DBKa5dk&pullRequest=2186
commit('setLoading', true)
try {
await answerController.saveTestAnswer(
Expand All @@ -306,6 +329,11 @@
state.testAnswerDocument.taskAnswers = {}
}
state.testAnswerDocument.taskAnswers[userId] = payload.data
} else if (payload.testType === STUDY_TYPES.CARD_SORTING) {
if (!state.testAnswerDocument.cardSortingAnswers) {
state.testAnswerDocument.cardSortingAnswers = {}
}
state.testAnswerDocument.cardSortingAnswers[userId] = payload.data
}
}

Expand Down
Loading
Loading