VBV-525: Refactor feedback submission

This commit is contained in:
Daniel Egger 2023-09-21 16:11:31 +02:00
parent ce15054340
commit 70655935b0
16 changed files with 284 additions and 224 deletions

View File

@ -13,7 +13,6 @@ import type { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-
* Therefore it is highly recommended to use the babel or swc plugin for production.
*/
const documents = {
"\n mutation SendFeedbackMutation($input: SendFeedbackInput!) {\n send_feedback(input: $input) {\n feedback_response {\n id\n }\n errors {\n field\n messages\n }\n }\n }\n": types.SendFeedbackMutationDocument,
"\n mutation AttendanceCheckMutation(\n $attendanceCourseId: ID!\n $attendanceUserList: [AttendanceUserInputType]!\n ) {\n update_course_session_attendance_course_users(\n id: $attendanceCourseId\n attendance_user_list: $attendanceUserList\n ) {\n course_session_attendance_course {\n id\n attendance_user_list {\n user_id\n first_name\n last_name\n email\n status\n }\n }\n }\n }\n": types.AttendanceCheckMutationDocument,
"\n mutation UpsertAssignmentCompletion(\n $assignmentId: ID!\n $courseSessionId: ID!\n $learningContentId: ID\n $assignmentUserId: UUID\n $completionStatus: AssignmentCompletionStatus!\n $completionDataString: String!\n $evaluationGrade: Float\n $evaluationPoints: Float\n $initializeCompletion: Boolean\n ) {\n upsert_assignment_completion(\n assignment_id: $assignmentId\n course_session_id: $courseSessionId\n learning_content_page_id: $learningContentId\n assignment_user_id: $assignmentUserId\n completion_status: $completionStatus\n completion_data_string: $completionDataString\n evaluation_grade: $evaluationGrade\n evaluation_points: $evaluationPoints\n initialize_completion: $initializeCompletion\n ) {\n assignment_completion {\n id\n completion_status\n submitted_at\n evaluation_submitted_at\n evaluation_grade\n evaluation_points\n completion_data\n }\n }\n }\n": types.UpsertAssignmentCompletionDocument,
"\n fragment CoursePageFields on CoursePageInterface {\n title\n id\n slug\n content_type\n frontend_url\n }\n": types.CoursePageFieldsFragmentDoc,
@ -21,6 +20,7 @@ const documents = {
"\n query assignmentCompletionQuery(\n $assignmentId: ID!\n $courseSessionId: ID!\n $learningContentId: ID\n $assignmentUserId: UUID\n ) {\n assignment(id: $assignmentId) {\n assignment_type\n max_points\n content_type\n effort_required\n evaluation_description\n evaluation_document_url\n evaluation_tasks\n id\n intro_text\n performance_objectives\n slug\n tasks\n title\n translation_key\n competence_certificate {\n ...CoursePageFields\n }\n }\n assignment_completion(\n assignment_id: $assignmentId\n course_session_id: $courseSessionId\n assignment_user_id: $assignmentUserId\n learning_content_page_id: $learningContentId\n ) {\n id\n completion_status\n submitted_at\n evaluation_submitted_at\n evaluation_user {\n id\n }\n assignment_user {\n id\n }\n evaluation_grade\n evaluation_points\n completion_data\n }\n }\n": types.AssignmentCompletionQueryDocument,
"\n query courseQuery($courseId: Int!) {\n course(id: $courseId) {\n id\n slug\n title\n category_name\n learning_path {\n id\n }\n }\n }\n": types.CourseQueryDocument,
"\n query competenceCertificateQuery($courseSlug: String!, $courseSessionId: ID!) {\n competence_certificate_list(course_slug: $courseSlug) {\n ...CoursePageFields\n competence_certificates {\n ...CoursePageFields\n assignments {\n ...CoursePageFields\n assignment_type\n max_points\n completion(course_session_id: $courseSessionId) {\n id\n completion_status\n submitted_at\n evaluation_points\n }\n learning_content {\n title\n id\n slug\n content_type\n frontend_url\n circle {\n ...CoursePageFields\n }\n }\n }\n }\n }\n }\n": types.CompetenceCertificateQueryDocument,
"\n mutation SendFeedbackMutation(\n $courseSessionId: ID!\n $learningContentId: ID!\n $data: GenericScalar\n ) {\n send_feedback(\n course_session_id: $courseSessionId\n learning_content_page_id: $learningContentId\n data: $data\n ) {\n feedback_response {\n id\n data\n }\n errors {\n field\n messages\n }\n }\n }\n": types.SendFeedbackMutationDocument,
};
/**
@ -37,10 +37,6 @@ const documents = {
*/
export function graphql(source: string): unknown;
/**
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
*/
export function graphql(source: "\n mutation SendFeedbackMutation($input: SendFeedbackInput!) {\n send_feedback(input: $input) {\n feedback_response {\n id\n }\n errors {\n field\n messages\n }\n }\n }\n"): (typeof documents)["\n mutation SendFeedbackMutation($input: SendFeedbackInput!) {\n send_feedback(input: $input) {\n feedback_response {\n id\n }\n errors {\n field\n messages\n }\n }\n }\n"];
/**
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
*/
@ -69,6 +65,10 @@ export function graphql(source: "\n query courseQuery($courseId: Int!) {\n c
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
*/
export function graphql(source: "\n query competenceCertificateQuery($courseSlug: String!, $courseSessionId: ID!) {\n competence_certificate_list(course_slug: $courseSlug) {\n ...CoursePageFields\n competence_certificates {\n ...CoursePageFields\n assignments {\n ...CoursePageFields\n assignment_type\n max_points\n completion(course_session_id: $courseSessionId) {\n id\n completion_status\n submitted_at\n evaluation_points\n }\n learning_content {\n title\n id\n slug\n content_type\n frontend_url\n circle {\n ...CoursePageFields\n }\n }\n }\n }\n }\n }\n"): (typeof documents)["\n query competenceCertificateQuery($courseSlug: String!, $courseSessionId: ID!) {\n competence_certificate_list(course_slug: $courseSlug) {\n ...CoursePageFields\n competence_certificates {\n ...CoursePageFields\n assignments {\n ...CoursePageFields\n assignment_type\n max_points\n completion(course_session_id: $courseSessionId) {\n id\n completion_status\n submitted_at\n evaluation_points\n }\n learning_content {\n title\n id\n slug\n content_type\n frontend_url\n circle {\n ...CoursePageFields\n }\n }\n }\n }\n }\n }\n"];
/**
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
*/
export function graphql(source: "\n mutation SendFeedbackMutation(\n $courseSessionId: ID!\n $learningContentId: ID!\n $data: GenericScalar\n ) {\n send_feedback(\n course_session_id: $courseSessionId\n learning_content_page_id: $learningContentId\n data: $data\n ) {\n feedback_response {\n id\n data\n }\n errors {\n field\n messages\n }\n }\n }\n"): (typeof documents)["\n mutation SendFeedbackMutation(\n $courseSessionId: ID!\n $learningContentId: ID!\n $data: GenericScalar\n ) {\n send_feedback(\n course_session_id: $courseSessionId\n learning_content_page_id: $learningContentId\n data: $data\n ) {\n feedback_response {\n id\n data\n }\n errors {\n field\n messages\n }\n }\n }\n"];
export function graphql(source: string) {
return (documents as any)[source] ?? {};

View File

@ -270,13 +270,10 @@ export type ErrorType = {
messages: Array<Scalars['String']['output']>;
};
export type FeedbackResponse = Node & {
__typename?: 'FeedbackResponse';
circle: CircleObjectType;
created_at: Scalars['DateTime']['output'];
export type FeedbackResponseObjectType = {
__typename?: 'FeedbackResponseObjectType';
data?: Maybe<Scalars['GenericScalar']['output']>;
/** The ID of the object */
id: Scalars['ID']['output'];
id: Scalars['UUID']['output'];
};
export type LearningContentAssignmentObjectType = LearningContentInterface & {
@ -537,14 +534,16 @@ export type LearnpathLearningContentAssignmentAssignmentTypeChoices =
export type Mutation = {
__typename?: 'Mutation';
send_feedback?: Maybe<SendFeedbackPayload>;
send_feedback?: Maybe<SendFeedbackMutation>;
update_course_session_attendance_course_users?: Maybe<AttendanceCourseUserMutation>;
upsert_assignment_completion?: Maybe<AssignmentCompletionMutation>;
};
export type MutationSendFeedbackArgs = {
input: SendFeedbackInput;
course_session_id: Scalars['ID']['input'];
data?: InputMaybe<Scalars['GenericScalar']['input']>;
learning_content_page_id: Scalars['ID']['input'];
};
@ -566,12 +565,6 @@ export type MutationUpsertAssignmentCompletionArgs = {
learning_content_page_id?: InputMaybe<Scalars['ID']['input']>;
};
/** An object with an ID */
export type Node = {
/** The ID of the object */
id: Scalars['ID']['output'];
};
export type Query = {
__typename?: 'Query';
assignment?: Maybe<AssignmentObjectType>;
@ -647,19 +640,11 @@ export type QueryLearningPathArgs = {
slug?: InputMaybe<Scalars['String']['input']>;
};
export type SendFeedbackInput = {
clientMutationId?: InputMaybe<Scalars['String']['input']>;
course_session: Scalars['Int']['input'];
data?: InputMaybe<Scalars['GenericScalar']['input']>;
page: Scalars['Int']['input'];
};
export type SendFeedbackPayload = {
__typename?: 'SendFeedbackPayload';
clientMutationId?: Maybe<Scalars['String']['output']>;
export type SendFeedbackMutation = {
__typename?: 'SendFeedbackMutation';
/** May contain more than one error for same field. */
errors?: Maybe<Array<Maybe<ErrorType>>>;
feedback_response?: Maybe<FeedbackResponse>;
feedback_response?: Maybe<FeedbackResponseObjectType>;
};
export type TopicObjectType = CoursePageInterface & {
@ -689,13 +674,6 @@ export type UserType = {
username: Scalars['String']['output'];
};
export type SendFeedbackMutationMutationVariables = Exact<{
input: SendFeedbackInput;
}>;
export type SendFeedbackMutationMutation = { __typename?: 'Mutation', send_feedback?: { __typename?: 'SendFeedbackPayload', feedback_response?: { __typename?: 'FeedbackResponse', id: string } | null, errors?: Array<{ __typename?: 'ErrorType', field: string, messages: Array<string> } | null> | null } | null };
export type AttendanceCheckMutationMutationVariables = Exact<{
attendanceCourseId: Scalars['ID']['input'];
attendanceUserList: Array<InputMaybe<AttendanceUserInputType>> | InputMaybe<AttendanceUserInputType>;
@ -811,11 +789,20 @@ export type CompetenceCertificateQueryQuery = { __typename?: 'Query', competence
& { ' $fragmentRefs'?: { 'CoursePageFieldsCompetenceCertificateListObjectTypeFragment': CoursePageFieldsCompetenceCertificateListObjectTypeFragment } }
) | null };
export type SendFeedbackMutationMutationVariables = Exact<{
courseSessionId: Scalars['ID']['input'];
learningContentId: Scalars['ID']['input'];
data?: InputMaybe<Scalars['GenericScalar']['input']>;
}>;
export type SendFeedbackMutationMutation = { __typename?: 'Mutation', send_feedback?: { __typename?: 'SendFeedbackMutation', feedback_response?: { __typename?: 'FeedbackResponseObjectType', id: any, data?: any | null } | null, errors?: Array<{ __typename?: 'ErrorType', field: string, messages: Array<string> } | null> | null } | null };
export const CoursePageFieldsFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"CoursePageFields"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"CoursePageInterface"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"slug"}},{"kind":"Field","name":{"kind":"Name","value":"content_type"}},{"kind":"Field","name":{"kind":"Name","value":"frontend_url"}}]}}]} as unknown as DocumentNode<CoursePageFieldsFragment, unknown>;
export const SendFeedbackMutationDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"SendFeedbackMutation"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SendFeedbackInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"send_feedback"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"feedback_response"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}},{"kind":"Field","name":{"kind":"Name","value":"errors"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"field"}},{"kind":"Field","name":{"kind":"Name","value":"messages"}}]}}]}}]}}]} as unknown as DocumentNode<SendFeedbackMutationMutation, SendFeedbackMutationMutationVariables>;
export const AttendanceCheckMutationDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"AttendanceCheckMutation"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"attendanceCourseId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"attendanceUserList"}},"type":{"kind":"NonNullType","type":{"kind":"ListType","type":{"kind":"NamedType","name":{"kind":"Name","value":"AttendanceUserInputType"}}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"update_course_session_attendance_course_users"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"attendanceCourseId"}}},{"kind":"Argument","name":{"kind":"Name","value":"attendance_user_list"},"value":{"kind":"Variable","name":{"kind":"Name","value":"attendanceUserList"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"course_session_attendance_course"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"attendance_user_list"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"user_id"}},{"kind":"Field","name":{"kind":"Name","value":"first_name"}},{"kind":"Field","name":{"kind":"Name","value":"last_name"}},{"kind":"Field","name":{"kind":"Name","value":"email"}},{"kind":"Field","name":{"kind":"Name","value":"status"}}]}}]}}]}}]}}]} as unknown as DocumentNode<AttendanceCheckMutationMutation, AttendanceCheckMutationMutationVariables>;
export const UpsertAssignmentCompletionDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"UpsertAssignmentCompletion"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"assignmentId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"courseSessionId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"learningContentId"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"assignmentUserId"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"UUID"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"completionStatus"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"AssignmentCompletionStatus"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"completionDataString"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"evaluationGrade"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Float"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"evaluationPoints"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Float"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"initializeCompletion"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Boolean"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"upsert_assignment_completion"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"assignment_id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"assignmentId"}}},{"kind":"Argument","name":{"kind":"Name","value":"course_session_id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"courseSessionId"}}},{"kind":"Argument","name":{"kind":"Name","value":"learning_content_page_id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"learningContentId"}}},{"kind":"Argument","name":{"kind":"Name","value":"assignment_user_id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"assignmentUserId"}}},{"kind":"Argument","name":{"kind":"Name","value":"completion_status"},"value":{"kind":"Variable","name":{"kind":"Name","value":"completionStatus"}}},{"kind":"Argument","name":{"kind":"Name","value":"completion_data_string"},"value":{"kind":"Variable","name":{"kind":"Name","value":"completionDataString"}}},{"kind":"Argument","name":{"kind":"Name","value":"evaluation_grade"},"value":{"kind":"Variable","name":{"kind":"Name","value":"evaluationGrade"}}},{"kind":"Argument","name":{"kind":"Name","value":"evaluation_points"},"value":{"kind":"Variable","name":{"kind":"Name","value":"evaluationPoints"}}},{"kind":"Argument","name":{"kind":"Name","value":"initialize_completion"},"value":{"kind":"Variable","name":{"kind":"Name","value":"initializeCompletion"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"assignment_completion"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"completion_status"}},{"kind":"Field","name":{"kind":"Name","value":"submitted_at"}},{"kind":"Field","name":{"kind":"Name","value":"evaluation_submitted_at"}},{"kind":"Field","name":{"kind":"Name","value":"evaluation_grade"}},{"kind":"Field","name":{"kind":"Name","value":"evaluation_points"}},{"kind":"Field","name":{"kind":"Name","value":"completion_data"}}]}}]}}]}}]} as unknown as DocumentNode<UpsertAssignmentCompletionMutation, UpsertAssignmentCompletionMutationVariables>;
export const AttendanceCheckQueryDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"attendanceCheckQuery"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"courseSessionId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"course_session_attendance_course"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"courseSessionId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"attendance_user_list"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"user_id"}},{"kind":"Field","name":{"kind":"Name","value":"status"}}]}}]}}]}}]} as unknown as DocumentNode<AttendanceCheckQueryQuery, AttendanceCheckQueryQueryVariables>;
export const AssignmentCompletionQueryDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"assignmentCompletionQuery"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"assignmentId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"courseSessionId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"learningContentId"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"assignmentUserId"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"UUID"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"assignment"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"assignmentId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"assignment_type"}},{"kind":"Field","name":{"kind":"Name","value":"max_points"}},{"kind":"Field","name":{"kind":"Name","value":"content_type"}},{"kind":"Field","name":{"kind":"Name","value":"effort_required"}},{"kind":"Field","name":{"kind":"Name","value":"evaluation_description"}},{"kind":"Field","name":{"kind":"Name","value":"evaluation_document_url"}},{"kind":"Field","name":{"kind":"Name","value":"evaluation_tasks"}},{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"intro_text"}},{"kind":"Field","name":{"kind":"Name","value":"performance_objectives"}},{"kind":"Field","name":{"kind":"Name","value":"slug"}},{"kind":"Field","name":{"kind":"Name","value":"tasks"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"translation_key"}},{"kind":"Field","name":{"kind":"Name","value":"competence_certificate"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"CoursePageFields"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"assignment_completion"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"assignment_id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"assignmentId"}}},{"kind":"Argument","name":{"kind":"Name","value":"course_session_id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"courseSessionId"}}},{"kind":"Argument","name":{"kind":"Name","value":"assignment_user_id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"assignmentUserId"}}},{"kind":"Argument","name":{"kind":"Name","value":"learning_content_page_id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"learningContentId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"completion_status"}},{"kind":"Field","name":{"kind":"Name","value":"submitted_at"}},{"kind":"Field","name":{"kind":"Name","value":"evaluation_submitted_at"}},{"kind":"Field","name":{"kind":"Name","value":"evaluation_user"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}},{"kind":"Field","name":{"kind":"Name","value":"assignment_user"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}},{"kind":"Field","name":{"kind":"Name","value":"evaluation_grade"}},{"kind":"Field","name":{"kind":"Name","value":"evaluation_points"}},{"kind":"Field","name":{"kind":"Name","value":"completion_data"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"CoursePageFields"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"CoursePageInterface"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"slug"}},{"kind":"Field","name":{"kind":"Name","value":"content_type"}},{"kind":"Field","name":{"kind":"Name","value":"frontend_url"}}]}}]} as unknown as DocumentNode<AssignmentCompletionQueryQuery, AssignmentCompletionQueryQueryVariables>;
export const CourseQueryDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"courseQuery"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"courseId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"course"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"courseId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"slug"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"category_name"}},{"kind":"Field","name":{"kind":"Name","value":"learning_path"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}}]}}]}}]} as unknown as DocumentNode<CourseQueryQuery, CourseQueryQueryVariables>;
export const CompetenceCertificateQueryDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"competenceCertificateQuery"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"courseSlug"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"courseSessionId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"competence_certificate_list"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"course_slug"},"value":{"kind":"Variable","name":{"kind":"Name","value":"courseSlug"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"CoursePageFields"}},{"kind":"Field","name":{"kind":"Name","value":"competence_certificates"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"CoursePageFields"}},{"kind":"Field","name":{"kind":"Name","value":"assignments"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"CoursePageFields"}},{"kind":"Field","name":{"kind":"Name","value":"assignment_type"}},{"kind":"Field","name":{"kind":"Name","value":"max_points"}},{"kind":"Field","name":{"kind":"Name","value":"completion"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"course_session_id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"courseSessionId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"completion_status"}},{"kind":"Field","name":{"kind":"Name","value":"submitted_at"}},{"kind":"Field","name":{"kind":"Name","value":"evaluation_points"}}]}},{"kind":"Field","name":{"kind":"Name","value":"learning_content"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"slug"}},{"kind":"Field","name":{"kind":"Name","value":"content_type"}},{"kind":"Field","name":{"kind":"Name","value":"frontend_url"}},{"kind":"Field","name":{"kind":"Name","value":"circle"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"CoursePageFields"}}]}}]}}]}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"CoursePageFields"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"CoursePageInterface"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"slug"}},{"kind":"Field","name":{"kind":"Name","value":"content_type"}},{"kind":"Field","name":{"kind":"Name","value":"frontend_url"}}]}}]} as unknown as DocumentNode<CompetenceCertificateQueryQuery, CompetenceCertificateQueryQueryVariables>;
export const CompetenceCertificateQueryDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"competenceCertificateQuery"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"courseSlug"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"courseSessionId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"competence_certificate_list"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"course_slug"},"value":{"kind":"Variable","name":{"kind":"Name","value":"courseSlug"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"CoursePageFields"}},{"kind":"Field","name":{"kind":"Name","value":"competence_certificates"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"CoursePageFields"}},{"kind":"Field","name":{"kind":"Name","value":"assignments"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"CoursePageFields"}},{"kind":"Field","name":{"kind":"Name","value":"assignment_type"}},{"kind":"Field","name":{"kind":"Name","value":"max_points"}},{"kind":"Field","name":{"kind":"Name","value":"completion"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"course_session_id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"courseSessionId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"completion_status"}},{"kind":"Field","name":{"kind":"Name","value":"submitted_at"}},{"kind":"Field","name":{"kind":"Name","value":"evaluation_points"}}]}},{"kind":"Field","name":{"kind":"Name","value":"learning_content"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"slug"}},{"kind":"Field","name":{"kind":"Name","value":"content_type"}},{"kind":"Field","name":{"kind":"Name","value":"frontend_url"}},{"kind":"Field","name":{"kind":"Name","value":"circle"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"CoursePageFields"}}]}}]}}]}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"CoursePageFields"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"CoursePageInterface"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"slug"}},{"kind":"Field","name":{"kind":"Name","value":"content_type"}},{"kind":"Field","name":{"kind":"Name","value":"frontend_url"}}]}}]} as unknown as DocumentNode<CompetenceCertificateQueryQuery, CompetenceCertificateQueryQueryVariables>;
export const SendFeedbackMutationDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"SendFeedbackMutation"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"courseSessionId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"learningContentId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"data"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"GenericScalar"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"send_feedback"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"course_session_id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"courseSessionId"}}},{"kind":"Argument","name":{"kind":"Name","value":"learning_content_page_id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"learningContentId"}}},{"kind":"Argument","name":{"kind":"Name","value":"data"},"value":{"kind":"Variable","name":{"kind":"Name","value":"data"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"feedback_response"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"data"}}]}},{"kind":"Field","name":{"kind":"Name","value":"errors"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"field"}},{"kind":"Field","name":{"kind":"Name","value":"messages"}}]}}]}}]}}]} as unknown as DocumentNode<SendFeedbackMutationMutation, SendFeedbackMutationMutationVariables>;

View File

@ -546,31 +546,21 @@ type CompetenceCertificateListObjectType implements CoursePageInterface {
}
type Mutation {
send_feedback(input: SendFeedbackInput!): SendFeedbackPayload
send_feedback(course_session_id: ID!, data: GenericScalar, learning_content_page_id: ID!): SendFeedbackMutation
update_course_session_attendance_course_users(attendance_user_list: [AttendanceUserInputType]!, id: ID!): AttendanceCourseUserMutation
upsert_assignment_completion(assignment_id: ID!, assignment_user_id: UUID, completion_data_string: String, completion_status: AssignmentCompletionStatus, course_session_id: ID!, evaluation_grade: Float, evaluation_points: Float, initialize_completion: Boolean, learning_content_page_id: ID): AssignmentCompletionMutation
}
type SendFeedbackPayload {
feedback_response: FeedbackResponse
type SendFeedbackMutation {
feedback_response: FeedbackResponseObjectType
"""May contain more than one error for same field."""
errors: [ErrorType]
clientMutationId: String
}
type FeedbackResponse implements Node {
"""The ID of the object"""
id: ID!
type FeedbackResponseObjectType {
id: UUID!
data: GenericScalar
created_at: DateTime!
circle: CircleObjectType!
}
"""An object with an ID"""
interface Node {
"""The ID of the object"""
id: ID!
}
type ErrorType {
@ -578,13 +568,6 @@ type ErrorType {
messages: [String!]!
}
input SendFeedbackInput {
page: Int!
course_session: Int!
data: GenericScalar
clientMutationId: String
}
type AttendanceCourseUserMutation {
course_session_attendance_course: CourseSessionAttendanceCourseType
}

View File

@ -18,7 +18,7 @@ export const CoursePageInterface = "CoursePageInterface";
export const CourseSessionAttendanceCourseType = "CourseSessionAttendanceCourseType";
export const DateTime = "DateTime";
export const ErrorType = "ErrorType";
export const FeedbackResponse = "FeedbackResponse";
export const FeedbackResponseObjectType = "FeedbackResponseObjectType";
export const Float = "Float";
export const GenericScalar = "GenericScalar";
export const ID = "ID";
@ -41,10 +41,8 @@ export const LearningSequenceObjectType = "LearningSequenceObjectType";
export const LearningUnitObjectType = "LearningUnitObjectType";
export const LearnpathLearningContentAssignmentAssignmentTypeChoices = "LearnpathLearningContentAssignmentAssignmentTypeChoices";
export const Mutation = "Mutation";
export const Node = "Node";
export const Query = "Query";
export const SendFeedbackInput = "SendFeedbackInput";
export const SendFeedbackPayload = "SendFeedbackPayload";
export const SendFeedbackMutation = "SendFeedbackMutation";
export const String = "String";
export const TopicObjectType = "TopicObjectType";
export const UUID = "UUID";

View File

@ -10,7 +10,7 @@ import type { Component } from "vue";
import { computed, onUnmounted } from "vue";
import AssignmentBlock from "./blocks/AssignmentBlock.vue";
import AttendanceCourseBlock from "./blocks/AttendanceCourseBlock.vue";
import FeedbackBlock from "./blocks/FeedbackBlock.vue";
import FeedbackBlock from "./feedback/FeedbackBlock.vue";
import IframeBlock from "./blocks/IframeBlock.vue";
import MediaLibraryBlock from "./blocks/MediaLibraryBlock.vue";
import PlaceholderBlock from "./blocks/PlaceholderBlock.vue";

View File

@ -1,12 +0,0 @@
<template>
<FeedbackForm :page="content" />
</template>
<script setup lang="ts">
import FeedbackForm from "@/components/FeedbackForm.vue";
import type { LearningContentFeedback } from "@/types";
defineProps<{
content: LearningContentFeedback;
}>();
</script>

View File

@ -1,8 +1,7 @@
<script setup lang="ts">
import ItRadioGroup from "@/components/ui/ItRadioGroup.vue";
import ItTextarea from "@/components/ui/ItTextarea.vue";
import { graphql } from "@/gql/";
import type { SendFeedbackInput } from "@/gql/graphql";
import { graphql } from "@/gql";
import FeedbackCompletition from "@/pages/learningPath/learningContentPage/feedback/FeedbackCompletition.vue";
import {
PERCENTAGES,
@ -18,16 +17,16 @@ import { useRouteQuery } from "@vueuse/router";
import log from "loglevel";
import { computed, onMounted, reactive, ref } from "vue";
import { useTranslation } from "i18next-vue";
import { useCurrentCourseSession } from "@/composables";
const props = defineProps<{ page: LearningContentFeedback }>();
const props = defineProps<{
content: LearningContentFeedback;
}>();
const courseSessionsStore = useCourseSessionsStore();
const courseSession = useCurrentCourseSession();
const circleStore = useCircleStore();
const { t } = useTranslation();
onMounted(async () => {
log.debug("Feedback mounted");
});
const stepNo = useRouteQuery("step", "0", { transform: Number, mode: "push" });
const title = computed(
@ -51,11 +50,21 @@ const stepLabels = [
const numSteps = stepLabels.length;
// noinspection GraphQLUnresolvedReference
const sendFeedbackMutation = graphql(`
mutation SendFeedbackMutation($input: SendFeedbackInput!) {
send_feedback(input: $input) {
mutation SendFeedbackMutation(
$courseSessionId: ID!
$learningContentId: ID!
$data: GenericScalar
) {
send_feedback(
course_session_id: $courseSessionId
learning_content_page_id: $learningContentId
data: $data
) {
feedback_response {
id
data
}
errors {
field
@ -64,18 +73,71 @@ const sendFeedbackMutation = graphql(`
}
}
`);
const { executeMutation } = useMutation(sendFeedbackMutation);
const satisfaction = ref(null);
const goalAttainment = ref(null);
const proficiency = ref(null);
const preparationTaskClarity = ref(null);
const instructorCompetence = ref(null);
const instructorRespect = ref(null);
const instructorOpenFeedback = ref("");
const wouldRecommend = ref(null);
const courseNegativeFeedback = ref("");
const coursePositiveFeedback = ref("");
const feedbackData = reactive({
satisfaction: null,
goal_attainment: null,
proficiency: null,
preparation_task_clarity: null,
instructor_competence: null,
instructor_respect: null,
instructor_open_feedback: "",
would_recommend: null,
course_negative_feedback: "",
course_positive_feedback: "",
});
const questionData = [
{
modelKey: "satisfaction",
items: RATINGS,
component: ItRadioGroup,
},
{
modelKey: "goal_attainment",
items: RATINGS,
component: ItRadioGroup,
},
{
modelKey: "proficiency",
items: PERCENTAGES,
component: ItRadioGroup,
},
{
modelKey: "preparation_task_clarity",
items: YES_NO,
component: ItRadioGroup,
},
{
modelKey: "instructor_competence",
items: RATINGS,
component: ItRadioGroup,
},
{
modelKey: "instructor_respect",
items: RATINGS,
component: ItRadioGroup,
},
{
modelKey: "instructor_open_feedback",
component: ItTextarea,
},
{
modelKey: "would_recommend",
items: YES_NO,
component: ItRadioGroup,
},
{
modelKey: "course_negative_feedback",
component: ItTextarea,
},
{
modelKey: "course_positive_feedback",
component: ItTextarea,
},
];
const mutationResult = ref<any>(null);
@ -84,63 +146,60 @@ const previousStep = () => {
stepNo.value -= 1;
}
};
const nextStep = () => {
if (stepNo.value < numSteps) {
if (stepNo.value < numSteps && hasStepValidInput(stepNo.value)) {
stepNo.value += 1;
}
log.info(`next step ${stepNo.value} of ${numSteps}`);
log.debug(`next step ${stepNo.value} of ${numSteps}`);
mutateFeedback();
};
const sendFeedback = () => {
log.info("sending feedback");
const courseSession = courseSessionsStore.currentCourseSession;
if (!courseSession || !courseSession.id) {
log.error("no course session set");
return;
function hasStepValidInput(stepNumber: number) {
const question = questionData[stepNumber - 1];
if (question) {
return Boolean(feedbackData[question.modelKey]);
}
const input: SendFeedbackInput = reactive({
data: {
preparation_task_clarity: preparationTaskClarity,
course_negative_feedback: courseNegativeFeedback,
course_positive_feedback: coursePositiveFeedback,
goal_attainment: goalAttainment,
instructor_competence: instructorCompetence,
instructor_respect: instructorRespect,
instructor_open_feedback: instructorOpenFeedback,
satisfaction,
proficiency,
would_recommend: wouldRecommend,
},
page: props.page.id,
course_session: courseSession.id,
});
const variables = reactive({
input,
});
log.debug(variables);
executeMutation(variables)
.then(({ data }) => {
log.debug(data);
mutationResult.value = data;
return true;
}
function mutateFeedback() {
log.debug("mutate feedback", feedbackData);
executeMutation({
courseSessionId: courseSession.value.id.toString(),
learningContentId: props.content.id.toString(),
data: feedbackData,
})
.then((result) => {
log.debug("feedback mutation result", result);
if (result.data?.send_feedback?.feedback_response?.data) {
Object.assign(feedbackData, result.data.send_feedback.feedback_response.data);
}
})
.catch((e) => log.error(e));
};
}
onMounted(async () => {
log.debug("Feedback mounted");
mutateFeedback();
});
</script>
<template>
<LearningContentMultiLayout
:title="title"
sub-title="Feedback"
:learning-content="page"
:learning-content="content"
:show-start-button="stepNo === 0"
:show-next-button="stepNo > 0 && stepNo + 1 < numSteps"
:disable-next-button="!hasStepValidInput(stepNo)"
:show-previous-button="stepNo > 0"
:show-exit-button="stepNo + 1 === numSteps"
:current-step="stepNo"
:steps-count="numSteps"
:start-badge-text="$t('general.introduction')"
:end-badge-text="$t('general.submission')"
:base-url="props.page.frontend_url"
:base-url="props.content.frontend_url"
close-button-variant="close"
@previous="previousStep()"
@next="nextStep()"
@ -156,51 +215,14 @@ const sendFeedback = () => {
<p v-if="stepNo > 0 && stepNo + 1 < numSteps" class="pb-2">
{{ stepLabels[stepNo] }}
</p>
<ItRadioGroup
v-if="stepNo === 1"
v-model="satisfaction"
class="mb-8"
:items="RATINGS"
/>
<ItRadioGroup
v-if="stepNo === 2"
v-model="goalAttainment"
class="mb-8"
:items="RATINGS"
/>
<ItRadioGroup
v-if="stepNo === 3"
v-model="proficiency"
class="mb-8"
:items="PERCENTAGES"
/>
<ItRadioGroup
v-if="stepNo === 4"
v-model="preparationTaskClarity"
class="mb-8"
:items="YES_NO"
/>
<ItRadioGroup
v-if="stepNo === 5"
v-model="instructorCompetence"
class="mb-8"
:items="RATINGS"
/>
<ItRadioGroup
v-if="stepNo === 6"
v-model="instructorRespect"
class="mb-8"
:items="RATINGS"
/>
<ItTextarea v-if="stepNo === 7" v-model="instructorOpenFeedback" class="mb-8" />
<ItRadioGroup
v-if="stepNo === 8"
v-model="wouldRecommend"
class="mb-8"
:items="YES_NO"
/>
<ItTextarea v-if="stepNo === 9" v-model="courseNegativeFeedback" class="mb-8" />
<ItTextarea v-if="stepNo === 10" v-model="coursePositiveFeedback" class="mb-8" />
<div v-for="(question, index) in questionData" :key="index">
<component
:is="question.component"
v-if="index + 1 === stepNo"
v-model="feedbackData[question.modelKey]"
:items="question['items']"
/>
</div>
<FeedbackCompletition
v-if="stepNo === 11"
:avatar-url="courseSessionsStore.circleExperts[0].avatar_url"
@ -215,19 +237,4 @@ const sendFeedback = () => {
/>
</div>
</LearningContentMultiLayout>
<!--
<pre>
satisfaction {{ satisfaction }}
goalAttainment {{ goalAttainment }}
proficiency {{ proficiency }}
receivedMaterials {{ receivedMaterials }}
materialsRating {{ materialsRating }}
instructorCompetence {{ instructorCompetence }}
instructorRespect {{ instructorRespect }}
instructorOpenFeedback {{ instructorOpenFeedback }}
wouldRecommend {{ wouldRecommend }}
coursePositiveFeedback {{ coursePositiveFeedback }}
courseNegativeFeedback {{ courseNegativeFeedback }}
mutationResult: {{ mutationResult }}
</pre> -->
</template>

View File

@ -8,6 +8,7 @@ const props = defineProps<{
showStartButton: boolean;
showPreviousButton: boolean;
showNextButton: boolean;
disableNextButton: boolean;
showExitButton: boolean;
closingButtonVariant: ClosingButtonVariant;
}>();
@ -41,6 +42,7 @@ const closingButtonText = computed(() => {
</button>
<button
v-if="props.showNextButton"
:disabled="props.disableNextButton"
class="btn-blue z-10 flex items-center"
data-cy="next-step"
@click="$emit('next')"

View File

@ -16,6 +16,7 @@ interface Props {
showStartButton: boolean;
showPreviousButton: boolean;
showNextButton: boolean;
disableNextButton: boolean;
showExitButton: boolean;
currentStep: number;
stepsCount: number;
@ -37,6 +38,7 @@ const props = withDefaults(defineProps<Props>(), {
closeButtonVariant: "mark_as_done",
baseUrl: undefined,
stepQueryParam: undefined,
disableNextButton: false,
beforeExitCallback: async () => Promise.resolve(),
});
@ -103,6 +105,7 @@ const emit = defineEmits(["previous", "next", "exit"]);
:show-previous-button="props.showPreviousButton"
:show-exit-button="props.showExitButton"
:closing-button-variant="props.closeButtonVariant"
:disable-next-button="props.disableNextButton"
@previous="emit('previous')"
@next="emit('next')"
@start="emit('next')"

View File

@ -69,6 +69,7 @@ const closingButtonVariant = computed(() => {
<slot></slot>
<LearningContentFooter
:show-next-button="false"
:disable-next-button="false"
:show-previous-button="false"
:show-exit-button="true"
:show-start-button="false"

View File

@ -18,6 +18,18 @@ def has_course_access(user, course_id):
return False
def has_course_session_access(user, course_session_id: int):
if user.is_superuser:
return True
if CourseSessionUser.objects.filter(
course_session_id=course_session_id, user=user
).exists():
return True
return False
def is_course_session_expert(user, course_session_id: int):
if user.is_superuser:
return True

View File

@ -1,55 +1,107 @@
import graphene
import structlog
from graphene import ClientIDMutation, Field, Int, List
from graphene.types.generic import GenericScalar
from graphene_django.types import ErrorType
from vbv_lernwelt.course.models import CourseSession
from vbv_lernwelt.feedback.graphql.types import FeedbackResponse as FeedbackResponseType
from vbv_lernwelt.course.permissions import has_course_session_access
from vbv_lernwelt.feedback.graphql.types import (
FeedbackResponseObjectType as FeedbackResponseType,
)
from vbv_lernwelt.feedback.models import FeedbackResponse
from vbv_lernwelt.feedback.serializers import CourseFeedbackSerializer
from wagtail.models import Page
from vbv_lernwelt.learnpath.models import LearningContentFeedback
logger = structlog.get_logger(__name__)
# https://medium.com/open-graphql/jsonfield-models-in-graphene-django-308ae43d14ee
class SendFeedback(ClientIDMutation):
feedback_response = Field(FeedbackResponseType)
errors = List(
class SendFeedbackMutation(graphene.Mutation):
feedback_response = graphene.Field(FeedbackResponseType)
errors = graphene.List(
ErrorType, description="May contain more than one error for same field."
)
class Input:
page = Int(required=True)
course_session = Int(required=True)
class Arguments:
course_session_id = graphene.ID(required=True)
learning_content_page_id = graphene.ID(required=True)
data = GenericScalar()
@classmethod
def mutate_and_get_payload(cls, _, info, **input):
page_id = input["page"]
course_session_id = input["course_session"]
logger.info("creating feedback")
learning_content = Page.objects.get(id=page_id)
circle = learning_content.get_parent().specific
def mutate(
cls,
root,
info,
course_session_id,
learning_content_page_id,
data,
):
feedback_user_id = info.context.user.id
learning_content = LearningContentFeedback.objects.get(
id=learning_content_page_id
)
circle = learning_content.get_circle()
course_session = CourseSession.objects.get(id=course_session_id)
data = input.get("data", {})
if not has_course_session_access(
info.context.user,
course_session.id,
):
return SendFeedbackMutation(
errors=[
ErrorType(
field="send_feedback", messages=["Insufficient permissions"]
)
]
)
logger.info(
"creating feedback",
label="feedback",
feedback_user_id=feedback_user_id,
circle_title=circle.title,
course_session_id=course_session_id,
)
serializer = CourseFeedbackSerializer(data=data)
if not serializer.is_valid():
logger.error(serializer.errors)
return SendFeedback(errors=serializer.errors)
logger.error(
"creating feedback serializer invalid",
error_list=serializer.errors,
label="feedback",
)
errors = [
ErrorType(field=field, messages=msgs)
for field, msgs in serializer.errors.items()
]
return SendFeedbackMutation(errors=errors)
feedback_response = FeedbackResponse.objects.create(
circle=circle,
feedback_response, _ = FeedbackResponse.objects.get_or_create(
feedback_user_id=feedback_user_id,
circle_id=circle.id,
course_session=course_session,
data=serializer.validated_data,
)
logger.info(feedback_response)
original_data = feedback_response.data
updated_data = serializer.validated_data
return SendFeedback(feedback_response=feedback_response)
merged_data = {
key: updated_data[key] if updated_data.get(key) else original_data.get(key)
for key in updated_data.keys()
}
feedback_response.data = merged_data
feedback_response.save()
logger.info(
"feedback successfully created",
label="feedback",
feedback_user_id=feedback_user_id,
circle_title=circle.title,
course_session_id=course_session_id,
)
return SendFeedbackMutation(feedback_response=feedback_response)
class FeedbackMutation(object):
send_feedback = SendFeedback.Field()
send_feedback = SendFeedbackMutation.Field()

View File

@ -1,13 +1,15 @@
from graphene.relay import Node
from graphene.types.generic import GenericScalar
from graphene_django import DjangoObjectType
from vbv_lernwelt.feedback.models import FeedbackResponse as FeedbackResponseModel
class FeedbackResponse(DjangoObjectType):
class FeedbackResponseObjectType(DjangoObjectType):
data = GenericScalar()
class Meta:
model = FeedbackResponseModel
interfaces = (Node,)
fields = [
"id",
"data",
]

View File

@ -0,0 +1,22 @@
# Generated by Django 3.2.20 on 2023-09-21 13:30
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('feedback', '0003_alter_feedbackresponse_course_session'),
]
operations = [
migrations.AddField(
model_name='feedbackresponse',
name='feedback_user',
field=models.ForeignKey(default='872efd96-3bd7-4a1e-a239-2d72cad9f604', on_delete=django.db.models.deletion.CASCADE, to='core.user'),
preserve_default=False,
),
]

View File

@ -25,6 +25,7 @@ class FeedbackIntegerField(models.IntegerField):
class FeedbackResponse(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
feedback_user = models.ForeignKey(User, on_delete=models.CASCADE)
class DiscoveredChoices(models.TextChoices):
INTERNET = "I", _("Internet")

View File

@ -1,3 +1,5 @@
from unittest import skip
from rest_framework.test import APITestCase
from vbv_lernwelt.core.create_default_users import create_default_users
@ -148,6 +150,7 @@ class FeedbackSummaryApiTestCase(FeedbackApiBaseTestCase):
]
self.assertEqual(response.data, expected)
@skip("For now every trainer can see all feedback from the same course session")
def test_can_only_see_feedback_from_own_circle(self):
number_basis_feedback = 5
number_analyse_feedback = 10
@ -195,8 +198,7 @@ class FeedbackSummaryApiTestCase(FeedbackApiBaseTestCase):
f"/api/core/feedback/{csu.course_session.id}/summary/"
)
self.assertEqual(response.status_code, 200)
self.assertEqual(response.data, [])
self.assertEqual(response.status_code, 403)
class FeedbackDetailApiTestCase(FeedbackApiBaseTestCase):
@ -259,6 +261,7 @@ class FeedbackDetailApiTestCase(FeedbackApiBaseTestCase):
self.assertEqual(response.status_code, 200)
self.assertDictEqual(response.data, expected)
@skip("For now every trainer can see all feedback from the same course session")
def test_cannot_receive_feedback_from_other_circle(self):
csu = CourseSessionUser.objects.get(
course_session=self.course_session,
@ -289,5 +292,4 @@ class FeedbackDetailApiTestCase(FeedbackApiBaseTestCase):
f"/api/core/feedback/{csu.course_session.id}/{circle.id}/"
)
self.assertEqual(response.status_code, 200)
self.assertEqual(response.data, {"amount": 0, "questions": {}})
self.assertEqual(response.status_code, 403)