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
21 changes: 21 additions & 0 deletions assets/images/illustrations/retake-course.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
28 changes: 28 additions & 0 deletions assets/src/js/frontend/learning-area/pages/course-info.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,22 @@
import { type MutationState } from '@Core/ts/services/Query';
import { convertToErrorMessage } from '@TutorShared/utils/util';
import { wpAjaxInstance } from '@TutorShared/utils/api';
import { __ } from '@wordpress/i18n';

interface CourseCompletePayload {
course_id: number;
}
interface CourseRetakePayload {
course_id: number;
}

const courseCompleteHandler = () => {
const query = window.TutorCore.query;
const toast = window.TutorCore.toast;

return {
courseCompleteMutation: null as MutationState<unknown, CourseCompletePayload> | null,
courseRetakeMutation: null as MutationState<unknown, CourseRetakePayload> | null,

init() {
if (this.courseCompleteMutation) {
Expand All @@ -27,15 +32,38 @@ const courseCompleteHandler = () => {
toast.error(convertToErrorMessage(error));
},
});

this.courseRetakeMutation = query.useMutation(this.retakeCourseRequest, {
onSuccess: (res) => {
if (res.data?.redirect_to) {
window.location.href = res.data.redirect_to;
} else {
toast.error(__('Something went wrong', 'tutor'));
}
},
onError: (error: Error) => {
toast.error(convertToErrorMessage(error));
},
});
},

// Complete
async completeCourseRequest(payload: CourseCompletePayload) {
return wpAjaxInstance.post('tutor_complete_course', payload);
},

async handleCourseComplete(courseId: number) {
await this.courseCompleteMutation?.mutate({ course_id: courseId });
},

// Retake
async retakeCourseRequest(payload: CourseRetakePayload) {
return wpAjaxInstance.post('tutor_reset_course_progress', payload);
},

async handleCourseRetake(courseId: number) {
await this.courseRetakeMutation?.mutate({ course_id: courseId });
},
};
};

Expand Down
21 changes: 20 additions & 1 deletion classes/Course.php
Original file line number Diff line number Diff line change
Expand Up @@ -319,7 +319,7 @@
global $wp_query;
$course_coming_soon_enabled = (int) get_post_meta( $content->ID, '_tutor_course_enable_coming_soon', true );
$is_instructor = tutor_utils()->is_instructor_of_this_course( get_current_user_id(), $content->ID, true );
if ( ! CourseModel::get_post_types( $content ) || current_user_can( 'administrator' ) || $is_instructor || $course_coming_soon_enabled ) {

Check failure on line 322 in classes/Course.php

View workflow job for this annotation

GitHub Actions / WPCS

Capabilities should be used instead of roles. Found &quot;administrator&quot; in function call to current_user_can()
return $content;
}

Expand Down Expand Up @@ -627,7 +627,7 @@
} else {
$errors['pricing'] = __( 'Invalid product', 'tutor' );
}
} else {

Check failure on line 630 in classes/Course.php

View workflow job for this annotation

GitHub Actions / WPCS

If control structure block found as the only statement within an &quot;else&quot; block. Use elseif instead.
/**
* If user does not select WC product
* Then automatic WC product will be create name with course title.
Expand Down Expand Up @@ -764,7 +764,7 @@
update_post_meta( $post_id, self::COURSE_PRICE_TYPE_META, $params['pricing']['type'] );
}
} catch ( \Throwable $th ) {
throw new \Exception( $th->getMessage() );

Check failure on line 767 in classes/Course.php

View workflow job for this annotation

GitHub Actions / WPCS

All output should be run through an escaping function (see the Security sections in the WordPress Developer Handbooks), found '$th'.
}
}

Expand Down Expand Up @@ -2288,7 +2288,7 @@
}

// Check if user is only an instructor.
if ( ! current_user_can( 'administrator' ) ) {

Check failure on line 2291 in classes/Course.php

View workflow job for this annotation

GitHub Actions / WPCS

Capabilities should be used instead of roles. Found &quot;administrator&quot; in function call to current_user_can()
// Check if instructor can trash course.
$can_trash_post = tutor_utils()->get_option( 'instructor_can_delete_course' );

Expand Down Expand Up @@ -2332,7 +2332,7 @@
/**
* Only admin can change main author
*/
if ( $courses_post_type === $post_type && ! current_user_can( 'administrator' ) ) {

Check failure on line 2335 in classes/Course.php

View workflow job for this annotation

GitHub Actions / WPCS

Capabilities should be used instead of roles. Found &quot;administrator&quot; in function call to current_user_can()
global $wpdb;
$post_ID = (int) tutor_utils()->avalue_dot( 'ID', $postarr );
$post_author = (int) $wpdb->get_var( $wpdb->prepare( "SELECT post_author FROM {$wpdb->posts} WHERE ID = %d ", $post_ID ) );
Expand Down Expand Up @@ -3005,7 +3005,7 @@
*/
public function tutor_reset_course_progress() {
tutor_utils()->checking_nonce();
$course_id = Input::post( 'course_id' );
$course_id = Input::post( 'course_id', 0, Input::TYPE_INT );

if ( ! $course_id || ! is_numeric( $course_id ) || ! tutor_utils()->is_enrolled( $course_id ) ) {
wp_send_json_error( array( 'message' => __( 'Invalid Course ID or Access Denied.', 'tutor' ) ) );
Expand Down Expand Up @@ -3440,4 +3440,23 @@

$button->render();
}

/**
* Render course retake button
*
* @since 4.0.0
*
* @param string $modal_id Modal id.

Check failure on line 3449 in classes/Course.php

View workflow job for this annotation

GitHub Actions / WPCS

Expected 1 spaces after parameter type; 2 found
*
* @return void
*/
public static function render_course_retake_btn( string $modal_id ): void {
Button::make()
->label( __( 'Retake this Course', 'tutor' ) )
->icon( Icon::RELOAD_3 )
->variant( Variant::SECONDARY )
->attr( 'type', 'button' )
->attr( '@click', "TutorCore.modal.showModal('{$modal_id}')" )
->render();
}
}
6 changes: 0 additions & 6 deletions classes/Utils.php
Original file line number Diff line number Diff line change
Expand Up @@ -5724,12 +5724,6 @@ public function dashboard_page_id() {
* @return bool
*/
public function is_dashboard_page( $subpage = null ): bool {
$user_id = get_current_user_id();
if ( ! $user_id ) {
// If user is not login then the dashboard slug show the login screen.
return false;
}

if ( $subpage ) {
return $this->is_tutor_frontend_dashboard( $subpage );
}
Expand Down
25 changes: 25 additions & 0 deletions templates/learning-area/subpages/course-info.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
use TUTOR\Course;
use TUTOR\Icon;
use Tutor\Components\SvgIcon;
use Tutor\Helpers\UrlHelper;
use Tutor\Models\CourseModel;

// Globals inherited from learning-area/index.php template.
Expand All @@ -34,7 +35,13 @@
$can_complete_course = CourseModel::can_complete_course( $tutor_course_id, $current_user_id ) && ! $is_course_completed;
$course_progress = tutor_utils()->get_course_completed_percent( $tutor_course_id, $current_user_id );

$completion_mode = tutor_utils()->get_option( 'course_completion_process' );
$retake_course = tutor_utils()->can_user_retake_course();

$can_retake_course = $retake_course && ( CourseModel::MODE_FLEXIBLE === $completion_mode || $is_completed_course );

$course_complete_modal_id = 'tutor-course-complete-modal';
$course_retake_modal_id = 'tutor-course-retake-modal';

ob_start();
foreach ( $instructors as $key => $instructor ) {
Expand Down Expand Up @@ -151,11 +158,17 @@
);
?>
</div>
<div class="tutor-items-center tutor-flex tutor-gap-2 tutor-items-center tutor-justify-center">
<?php
if ( $can_complete_course ) {
Course::render_course_complete_btn( $course_complete_modal_id, $tutor_course_id, $course_progress );
}
if ( $can_retake_course ) {
Course::render_course_retake_btn( $course_retake_modal_id );
}
?>
</div>

</div>

<!-- TODO: sticky behaviour -->
Expand Down Expand Up @@ -256,6 +269,18 @@
->render();
}
}
if ( $can_retake_course ) {
ConfirmationModal::make()
->id( $course_retake_modal_id )
->title( __( 'Start the Course Again?', 'tutor' ) )
->message( __( 'Retaking the course will reset your progress and start everything from the beginning.', 'tutor' ) )
->icon( UrlHelper::asset( 'images/illustrations/retake-course.svg' ) )
->cancel_text( __( 'Cancel', 'tutor' ) )
->confirm_text( __( 'Start Retake', 'tutor' ) )
->confirm_handler( "handleCourseRetake($tutor_course_id)" )
->mutation_state( 'courseRetakeMutation' )
->render();
}
?>
</div>

Loading