Enhance audience management features with new components and API integrations
- Added `AssignCoursesModal`, `AudienceMemberRow`, `AudienceTable`, and related components for improved audience management UI. - Implemented audience invite actions including resend and revoke functionality. - Updated audience API to support importing members and assigning courses. - Refactored audience data handling to include status and invite management. - Improved overall user experience with pagination and selection features in the audience table.
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
<script lang="ts">
|
||||
import { getExerciseQuestionContractKey } from '@cio/question-types';
|
||||
import type { AnswerData } from '@cio/question-types';
|
||||
import type { AnswerData, ExerciseQuestionModel } from '@cio/question-types';
|
||||
import type { Question } from '$features/course/types';
|
||||
import { Grade, ReasonBox } from '$features/ui/question';
|
||||
import { toExerciseQuestionModel } from './question-type-utils';
|
||||
import { getExerciseQuestionLabels } from './question-labels';
|
||||
@@ -8,15 +9,15 @@
|
||||
import type { QuestionnaireMetaData } from './store';
|
||||
|
||||
interface Props {
|
||||
questions?: any;
|
||||
questions?: Question[];
|
||||
questionnaireMetaData?: Partial<QuestionnaireMetaData>;
|
||||
/** Per-question scores (e.g. from `questionnaireMetaData.grades` or grading modal `questionAnswerByPoint`). */
|
||||
grades?: Record<string, number>;
|
||||
onSubmit?: any;
|
||||
onPrevious?: any;
|
||||
disableGrading?: boolean;
|
||||
isGradeWithAI?: boolean;
|
||||
isLoading?: boolean;
|
||||
reasons?: any;
|
||||
/** Optional AI grading copy keyed by question id. */
|
||||
reasons?: Record<string, string>;
|
||||
}
|
||||
|
||||
let {
|
||||
@@ -33,12 +34,12 @@
|
||||
isGradeWithAI = false;
|
||||
}
|
||||
|
||||
function rejectGradeSuggestion(questionId) {
|
||||
function rejectGradeSuggestion(questionId: Question['id']) {
|
||||
isGradeWithAI = false;
|
||||
grades[questionId] = 0;
|
||||
grades[String(questionId)] = 0;
|
||||
}
|
||||
|
||||
function getAnswerForQuestion(questionModel, fallbackIndex = 0) {
|
||||
function getAnswerForQuestion(questionModel: ExerciseQuestionModel, fallbackIndex = 0): AnswerData | undefined {
|
||||
const questionKey = getExerciseQuestionContractKey(questionModel, fallbackIndex);
|
||||
return _questionnaireMetaData?.answers?.[questionKey];
|
||||
}
|
||||
@@ -59,11 +60,11 @@
|
||||
|
||||
{#if disableGrading && !Object.keys(grades || {}).length}
|
||||
<ExerciseQuestion.QuestionList
|
||||
contract={{ mode: 'view', questions: questionModels, answersByKey, labels: questionLabels, disabled: true }}
|
||||
contract={{ mode: 'review', questions: questionModels, answersByKey, labels: questionLabels, disabled: true }}
|
||||
itemClass="mb-4"
|
||||
/>
|
||||
{:else if disableGrading && Object.keys(grades || {}).length}
|
||||
{#each questions as currentQuestion, index}
|
||||
{#each questions as currentQuestion, index (currentQuestion.id)}
|
||||
{@const questionModel = questionModels[index]}
|
||||
<div class="mb-4 space-y-3">
|
||||
<div class="flex items-center justify-between">
|
||||
@@ -73,7 +74,7 @@
|
||||
|
||||
<ExerciseQuestion.QuestionRenderer
|
||||
contract={{
|
||||
mode: 'view',
|
||||
mode: 'review',
|
||||
question: questionModel,
|
||||
answer: getAnswerForQuestion(questionModel, index),
|
||||
labels: questionLabels,
|
||||
@@ -83,7 +84,7 @@
|
||||
</div>
|
||||
{/each}
|
||||
{:else}
|
||||
{#each questions as currentQuestion, index}
|
||||
{#each questions as currentQuestion, index (currentQuestion.id)}
|
||||
{@const questionModel = questionModels[index]}
|
||||
<div class="mb-4 space-y-3">
|
||||
<div class="flex items-center justify-between">
|
||||
@@ -93,7 +94,7 @@
|
||||
|
||||
<ExerciseQuestion.QuestionRenderer
|
||||
contract={{
|
||||
mode: 'view',
|
||||
mode: 'review',
|
||||
question: questionModel,
|
||||
answer: getAnswerForQuestion(questionModel, index),
|
||||
labels: questionLabels,
|
||||
|
||||
@@ -18,6 +18,9 @@ export function getExerciseQuestionLabels(): ExerciseQuestionLabels {
|
||||
'common.correct_badge': t.get(
|
||||
'course.navItem.lessons.exercises.all_exercises.shared_question.common.correct_badge'
|
||||
),
|
||||
'common.incorrect_badge': t.get(
|
||||
'course.navItem.lessons.exercises.all_exercises.shared_question.common.incorrect_badge'
|
||||
),
|
||||
'common.not_set': t.get('course.navItem.lessons.exercises.all_exercises.shared_question.common.not_set'),
|
||||
'navigation.previous': t.get('course.navItem.lessons.exercises.all_exercises.shared_question.navigation.previous'),
|
||||
'navigation.next': t.get('course.navItem.lessons.exercises.all_exercises.shared_question.navigation.next'),
|
||||
@@ -131,6 +134,12 @@ export function getExerciseQuestionLabels(): ExerciseQuestionLabels {
|
||||
'short_answer.preview.helper': t.get(
|
||||
'course.navItem.lessons.exercises.all_exercises.shared_question.short_answer.preview.helper'
|
||||
),
|
||||
'short_answer.review.your_answer_label': t.get(
|
||||
'course.navItem.lessons.exercises.all_exercises.shared_question.short_answer.review.your_answer_label'
|
||||
),
|
||||
'short_answer.review.accepted_label': t.get(
|
||||
'course.navItem.lessons.exercises.all_exercises.shared_question.short_answer.review.accepted_label'
|
||||
),
|
||||
'numeric.edit.correct_value_label': t.get(
|
||||
'course.navItem.lessons.exercises.all_exercises.shared_question.numeric.edit.correct_value_label'
|
||||
),
|
||||
@@ -158,6 +167,15 @@ export function getExerciseQuestionLabels(): ExerciseQuestionLabels {
|
||||
'numeric.preview.tolerance_label': t.get(
|
||||
'course.navItem.lessons.exercises.all_exercises.shared_question.numeric.preview.tolerance_label'
|
||||
),
|
||||
'numeric.review.your_answer_label': t.get(
|
||||
'course.navItem.lessons.exercises.all_exercises.shared_question.numeric.review.your_answer_label'
|
||||
),
|
||||
'numeric.review.in_range': t.get(
|
||||
'course.navItem.lessons.exercises.all_exercises.shared_question.numeric.review.in_range'
|
||||
),
|
||||
'numeric.review.out_of_range': t.get(
|
||||
'course.navItem.lessons.exercises.all_exercises.shared_question.numeric.review.out_of_range'
|
||||
),
|
||||
'fill_blank.edit.accepted_answers_placeholder': t.get(
|
||||
'course.navItem.lessons.exercises.all_exercises.shared_question.fill_blank.edit.accepted_answers_placeholder'
|
||||
),
|
||||
@@ -167,6 +185,9 @@ export function getExerciseQuestionLabels(): ExerciseQuestionLabels {
|
||||
'fill_blank.preview.accepted_answers_label': t.get(
|
||||
'course.navItem.lessons.exercises.all_exercises.shared_question.fill_blank.preview.accepted_answers_label'
|
||||
),
|
||||
'fill_blank.review.your_answer_label': t.get(
|
||||
'course.navItem.lessons.exercises.all_exercises.shared_question.fill_blank.review.your_answer_label'
|
||||
),
|
||||
'file_upload.edit.accepted_types_placeholder': t.get(
|
||||
'course.navItem.lessons.exercises.all_exercises.shared_question.file_upload.edit.accepted_types_placeholder'
|
||||
),
|
||||
|
||||
+1
-1
@@ -81,7 +81,7 @@
|
||||
<div class="pb-4">
|
||||
<ExerciseQuestion.QuestionRenderer
|
||||
contract={{
|
||||
mode: 'view',
|
||||
mode: 'review',
|
||||
question: { ...toExerciseQuestionModel(q), title: `${i + 1}. ${q.title}` },
|
||||
answer: getStudentAnswerForQuestion($submissions[studentSelected], q),
|
||||
labels: questionLabels,
|
||||
|
||||
Reference in New Issue
Block a user