Skip to content

Conversation

@nur-alam
Copy link
Collaborator

No description provided.

- Create new qna.ts page component with Q&A mutation handlers
- Add initializeQnA function to register Q&A component with Alpine.js
- Integrate Q&A page initialization into learning area router
- Implement createQnA, replyQna, and deleteQnA mutation methods
- Add success/error toast notifications for Q&A operations
- Update package-lock.json dependencies
- Enable Q&A functionality in learning area templates
@nur-alam nur-alam requested review from b-l-i-n-d, harunollyo and sazedul-haque and removed request for harunollyo January 19, 2026 11:09
Comment on lines 22 to 25
/**
* Q&A Page Component
* Handles Q&A question creation in learning area
*/
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This comment is unnecessary.

window.location.reload();
},
onError: (error: Error) => {
window.TutorCore.toast.error(error.message || __('Failed to save question', 'tutor'));
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use convertToErrorMessage

Suggested change
window.TutorCore.toast.error(error.message || __('Failed to save question', 'tutor'));
window.TutorCore.toast.error(convertToErrorMessage(error));

window.location.reload();
},
onError: (error: Error) => {
window.TutorCore.toast.error(error.message || __('Failed to save reply', 'tutor'));
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here

},
});

// Q&A delete mutation.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please remove this comment as this is self-explanatory.

}
},
onError: (error: Error) => {
window.TutorCore.toast.error(error.message || __('Failed to delete Q&A', 'tutor'));
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use convertToErrorMessage

Suggested change
window.TutorCore.toast.error(error.message || __('Failed to delete Q&A', 'tutor'));
window.TutorCore.toast.error(convertToErrorMessage(error));

</div>
<?php if ( $current_user_id == $answer->user_id || current_user_can( 'manage_tutor' ) ) : ?>
<div x-data="tutorPopover({ placement: 'bottom-end', offset: 4 })" class="tutor-ml-auto">
<button class="tutor-btn tutor-btn-ghost tutor-btn-icon tutor-btn-x-small" x-ref="trigger" @click="toggle()">
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use php Button component

</div>
</div>
<?php if ( $current_user_id == $answer->user_id || current_user_can( 'manage_tutor' ) ) : ?>
<div x-data="tutorPopover({ placement: 'bottom-end', offset: 4 })" class="tutor-ml-auto">
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If this can be done with php Popover component, then please use that.

?>
<div class="tutor-input-field">
<div class="tutor-input-wrapper">
<input
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use php component

<form
class="tutor-discussion-form tutor-p-6 tutor-border-b tutor-qna-form"
x-data="{ ...tutorForm({ id: '<?php echo esc_attr( $tutor_course_id ); ?>' }), focused : false }"
@submit.prevent="handleSubmit((data) => createQnaMutation?.mutate({...data, course_id: <?php echo esc_html( $tutor_course_id ); ?> }))($event)"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pass course_id as a default value.

$content = strlen( $content ) > 100 ? substr( $content, 0, 100 ) . '...' : $content;
?>
<div class="tutor-discussion-card" @click="window.location.href = '<?php echo esc_url( $question_url ); ?>'" style="cursor: pointer;">
<div class="tutor-avatar tutor-avatar-32">
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use php Avatar component

@harunollyo harunollyo added the 4.0.0 Tutor v4.w0w label Jan 20, 2026
- Import and use convertToErrorMessage utility for consistent error formatting
* @link https://themeum.com
* @since 4.0.0
*/

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Prevent direct access

defined( 'ABSPATH' ) || exit;


// Get course ID and question ID.
global $tutor_course_id;
$question_id = Input::get( 'question_id', null, Input::TYPE_INT );
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use default 0

$order_by = Input::get( 'order', 'DESC' );

// Get question data.
$question = tutor_utils()->get_qa_question( (int) $question_id );
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need to cast. It's already int by Input::TYPE_INT

</button>
5

<?php if ( is_array( $answers ) && count( $answers ) ) : ?>
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of this is_array( $answers ) && count( $answers ) use

tutor_utils()->count( $answers );

* @link https://themeum.com
* @since 4.0.0
*/

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Prevent direct access

);
Sorting::make()
->order( Input::get( 'order', 'DESC' ) )
->label_asc( __( 'Newest First', 'tutor' ) )
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Default value is same as you passed. No need to call label_asc and label_desc

<?php
Pagination::make()
->current( $current_page )
->total( (int) $total_items )
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need to cast int

<?php
Sorting::make()
->order( Input::get( 'order', 'DESC' ) )
->label_asc( __( 'Newest First', 'tutor' ) )
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Default value is same as you passed. No need to call label_asc and label_desc

position: fixed;
height: calc(100vh - 62px);
top: 62px;
position: absolute;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove this.

if ( $subpage ) {
$subpage_template = tutor_get_template( 'learning-area.subpages.' . $subpage );
if ( file_exists( $subpage_template ) ) {
if ( $question_id ) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can be managed inside qna.php template.

- Refactor learning-area index template to handle question_id routing in qna-single subpage
- Update Sorting component usage by removing custom labels
- Improve answer count validation using tutor_utils()->count() helper
- Add SearchFilter component import and implement search functionality in Q&A page
- Add ABSPATH check for security in qna-single template
- Consolidate question_id routing logic into qna-single subpage for better separation of concerns
- Add Avatar component import to qna template
- Add Popover component import to qna-single.php
- Replace manual x-data popover implementation with Popover::make() component for question actions menu
- Replace manual x-data popover implementation with Popover::make() component for reply actions menu
- Update SearchFilter placeholder text from 'Search items...' to 'Search questions, topics...'
- Update textarea placeholder text from 'Ask a question...' to 'Asked questions...'
- Fix indentation inconsistency in SearchFilter component call
- Simplifies popover markup by using component abstraction instead of manual Alpine.js directives
- Add `defined( 'ABSPATH' ) || exit;` security check to both qna.php and qna-single.php templates
- Replace manual form with SearchFilter component using UrlHelper for cleaner URL handling
- Update form submission to use defaultValues in tutorForm configuration
- Remove unnecessary hidden input loop in favor of component-based hidden_inputs parameter
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

4.0.0 Tutor v4.w0w

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants