diff --git a/content-single.php b/content-single.php
new file mode 100644
index 0000000..cf90f74
--- /dev/null
+++ b/content-single.php
@@ -0,0 +1,102 @@
+
+
+ >
+
+
+
+
+
+
>
+ '
' . __( 'Pages:', 'generatepress' ),
+ 'after' => '
',
+ )
+ );
+ ?>
+
+
+
+
+
diff --git a/functions.php b/functions.php
index 7734ac3..c3a602f 100644
--- a/functions.php
+++ b/functions.php
@@ -4,4 +4,158 @@
*
* Add your custom PHP in this file.
* Only edit this file if you have direct access to it on your server (to fix errors if they happen).
+
+
+function quiztech_theme_enqueue_scripts() {
+ // List of Quiztech custom page templates
+ $quiztech_templates = [
+ 'template-quiztech-dashboard.php',
+ 'template-manage-jobs.php',
+ 'template-manage-assessments.php',
+ 'template-manage-questions.php',
+ 'template-manage-credits.php',
+ 'template-view-results.php',
+ ];
+
+ // Check if the current page is using one of our templates
+ $is_quiztech_template = false;
+ foreach ( $quiztech_templates as $template ) {
+ if ( is_page_template( $template ) ) {
+ $is_quiztech_template = true;
+ break;
+ }
+ }
+
+ // Only enqueue the script on our specific template pages
+ if ( $is_quiztech_template ) {
+ $script_path = get_stylesheet_directory() . '/js/quiztech-theme.js';
+ $script_url = get_stylesheet_directory_uri() . '/js/quiztech-theme.js';
+ $version = file_exists( $script_path ) ? filemtime( $script_path ) : '1.0';
+
+ wp_enqueue_script(
+ 'quiztech-theme-script',
+ $script_url,
+ array( 'jquery' ), // Depends on jQuery
+ $version,
+ true // Load in footer
+ );
+
+ // Localize script with necessary data for AJAX calls
+ wp_localize_script( 'quiztech-theme-script', 'quiztechThemeData', [
+ 'ajax_url' => admin_url( 'admin-ajax.php' ),
+ 'add_job_nonce' => wp_create_nonce( 'quiztech_add_new_job_action' ),
+ 'send_invite_nonce' => wp_create_nonce( 'quiztech_send_job_invite_action' ),
+ 'error_generic' => esc_html__( 'An error occurred. Please try again.', 'quiztech' ),
+ 'error_permissions' => esc_html__( 'You do not have permission to perform this action.', 'quiztech' ),
+ 'error_missing_assessment' => esc_html__( 'Error: No assessment is linked to this job.', 'quiztech' ),
+ 'invite_sent_success' => esc_html__( 'Invite sent successfully!', 'quiztech' ),
+ 'job_added_success' => esc_html__( 'Job added successfully!', 'quiztech' ),
+ ]);
+ }
+}
+add_action( 'wp_enqueue_scripts', 'quiztech_theme_enqueue_scripts' );
+
+
+/**
+ * AJAX handler for adding a new job post from the frontend.
*/
+function quiztech_ajax_add_new_job() {
+ // 1. Verify Nonce
+ check_ajax_referer( 'quiztech_add_new_job_action', 'nonce' );
+
+ // 2. Check Capabilities (adjust capability if needed)
+ if ( ! current_user_can( 'manage_options' ) ) {
+ wp_send_json_error( [ 'message' => esc_html__( 'Insufficient permissions.', 'quiztech' ) ], 403 );
+ }
+
+ // 3. Sanitize Input
+ $job_title = isset( $_POST['job_title'] ) ? sanitize_text_field( wp_unslash( $_POST['job_title'] ) ) : '';
+ $job_description = isset( $_POST['job_description'] ) ? sanitize_textarea_field( wp_unslash( $_POST['job_description'] ) ) : '';
+
+ if ( empty( $job_title ) ) {
+ wp_send_json_error( [ 'message' => esc_html__( 'Job title cannot be empty.', 'quiztech' ) ], 400 );
+ }
+
+ // 4. Create Post
+ $post_data = [
+ 'post_title' => $job_title,
+ 'post_content' => $job_description,
+ 'post_status' => 'publish', // Or 'draft' if preferred
+ 'post_author' => get_current_user_id(),
+ 'post_type' => 'job',
+ ];
+
+ $post_id = wp_insert_post( $post_data, true ); // Pass true to return WP_Error on failure
+
+ // 5. Send Response
+ if ( is_wp_error( $post_id ) ) {
+ wp_send_json_error( [ 'message' => $post_id->get_error_message() ], 500 );
+ } else {
+ // Optionally return HTML for the new row, or just success and let JS handle refresh/update
+ wp_send_json_success( [
+ 'message' => esc_html__( 'Job created successfully.', 'quiztech' ),
+ 'post_id' => $post_id
+ ] );
+ }
+}
+add_action( 'wp_ajax_add_new_job', 'quiztech_ajax_add_new_job' );
+
+
+/**
+ * AJAX handler for sending a job invite from the frontend.
+ */
+function quiztech_ajax_send_job_invite() {
+ // 1. Verify Nonce
+ check_ajax_referer( 'quiztech_send_job_invite_action', 'nonce' );
+
+ // 2. Check Capabilities (adjust capability if needed)
+ if ( ! current_user_can( 'manage_options' ) ) {
+ wp_send_json_error( [ 'message' => esc_html__( 'Insufficient permissions.', 'quiztech' ) ], 403 );
+ }
+
+ // 3. Sanitize Input
+ $job_id = isset( $_POST['job_id'] ) ? absint( $_POST['job_id'] ) : 0;
+ $applicant_email = isset( $_POST['applicant_email'] ) ? sanitize_email( wp_unslash( $_POST['applicant_email'] ) ) : '';
+
+ if ( ! $job_id || ! is_email( $applicant_email ) ) {
+ wp_send_json_error( [ 'message' => esc_html__( 'Invalid job ID or email address.', 'quiztech' ) ], 400 );
+ }
+
+ // 4. Check if Job exists and belongs to user (optional extra check)
+ $job_post = get_post( $job_id );
+ if ( ! $job_post || $job_post->post_type !== 'job' || $job_post->post_author != get_current_user_id() ) {
+ wp_send_json_error( [ 'message' => esc_html__( 'Invalid job specified.', 'quiztech' ) ], 404 );
+ }
+
+ // 5. Get Linked Assessment ID
+ $assessment_id = get_post_meta( $job_id, '_quiztech_linked_assessment_id', true );
+ if ( empty( $assessment_id ) ) {
+ wp_send_json_error( [ 'message' => esc_html__( 'No assessment is linked to this job. Please edit the job and link an assessment.', 'quiztech' ) ], 400 );
+ }
+ $assessment_id = absint( $assessment_id );
+
+ // 6. Use the Invitation Class (ensure plugin is active and class exists)
+ if ( ! class_exists( 'Quiztech\\AssessmentPlatform\\Includes\\Invitations' ) ) {
+ wp_send_json_error( [ 'message' => esc_html__( 'Invitation system is unavailable.', 'quiztech' ) ], 500 );
+ }
+
+ try {
+ $invitations = new \Quiztech\AssessmentPlatform\Includes\Invitations();
+ $result = $invitations->create_invitation( $job_id, $assessment_id, $applicant_email );
+
+ if ( is_wp_error( $result ) ) {
+ wp_send_json_error( [ 'message' => $result->get_error_message() ], 500 );
+ } elseif ( $result === false ) {
+ // Generic failure from create_invitation if no WP_Error
+ wp_send_json_error( [ 'message' => esc_html__( 'Failed to create invitation.', 'quiztech' ) ], 500 );
+ } else {
+ // Success! $result might contain the token or true
+ wp_send_json_success( [ 'message' => esc_html__( 'Invitation sent successfully.', 'quiztech' ) ] );
+ }
+ } catch ( \Exception $e ) {
+ // Catch any unexpected exceptions
+ error_log( 'Quiztech Send Invite Error: ' . $e->getMessage() );
+ wp_send_json_error( [ 'message' => esc_html__( 'An unexpected error occurred while sending the invitation.', 'quiztech' ) ], 500 );
+ }
+}
+add_action( 'wp_ajax_send_job_invite', 'quiztech_ajax_send_job_invite' );
diff --git a/js/quiztech-theme.js b/js/quiztech-theme.js
new file mode 100644
index 0000000..82f14c3
--- /dev/null
+++ b/js/quiztech-theme.js
@@ -0,0 +1,145 @@
+jQuery(document).ready(function($) {
+
+ // --- Add New Job Form ---
+
+ // Show the "Add New Job" form when the button is clicked
+ $('.add-new-job-button').on('click', function(e) {
+ e.preventDefault();
+ $('#add-new-job-form').slideDown();
+ $(this).hide(); // Hide the "Add New Job" button itself
+ });
+
+ // Hide the "Add New Job" form when the cancel button is clicked
+ $('#add-new-job-form .cancel-add-job').on('click', function(e) {
+ e.preventDefault();
+ $('#add-new-job-form').slideUp(function() {
+ // Optional: Clear form fields on cancel
+ // $('#new-job-form')[0].reset();
+ // $('.add-job-status').empty();
+ });
+ $('.add-new-job-button').show(); // Show the "Add New Job" button again
+ });
+
+ // --- Send Invite Form ---
+
+ // Show the specific "Send Invite" form row when the link is clicked
+ $('.send-job-invite').on('click', function(e) {
+ e.preventDefault();
+ var jobId = $(this).data('job-id');
+ var inviteRow = $('#send-invite-row-' + jobId);
+
+ // Hide any other open invite forms first
+ $('.send-invite-form-row').not(inviteRow).slideUp();
+
+ // Toggle the clicked one
+ inviteRow.slideToggle();
+ });
+
+ // Hide the "Send Invite" form row when its cancel button is clicked
+ $('.send-invite-form-row .cancel-invite').on('click', function(e) {
+ e.preventDefault();
+ $(this).closest('.send-invite-form-row').slideUp();
+ });
+
+ // --- AJAX Form Submissions ---
+
+ // Add New Job AJAX
+ $('#new-job-form').on('submit', function(e) {
+ e.preventDefault();
+ var $form = $(this);
+ var $submitButton = $form.find('input[type="submit"]');
+ var $spinner = $form.find('.spinner');
+ var $statusDiv = $form.find('.add-job-status');
+
+ $statusDiv.empty().removeClass('error success');
+ $spinner.css('visibility', 'visible');
+ $submitButton.prop('disabled', true);
+
+ var formData = {
+ action: 'add_new_job',
+ nonce: quiztechThemeData.add_job_nonce,
+ job_title: $form.find('#job_title').val(),
+ job_description: $form.find('#job_description').val()
+ };
+
+ $.post(quiztechThemeData.ajax_url, formData)
+ .done(function(response) {
+ if (response.success) {
+ $statusDiv.text(quiztechThemeData.job_added_success).addClass('success');
+ // Optionally: Clear form, hide it, refresh job list via another AJAX call or page reload
+ $form[0].reset();
+ $('#add-new-job-form').slideUp();
+ $('.add-new-job-button').show();
+ // Consider adding the new job row dynamically instead of full reload
+ location.reload(); // Simple reload for now
+ } else {
+ $statusDiv.text(response.data.message || quiztechThemeData.error_generic).addClass('error');
+ }
+ })
+ .fail(function() {
+ $statusDiv.text(quiztechThemeData.error_generic).addClass('error');
+ })
+ .always(function() {
+ $spinner.css('visibility', 'hidden');
+ $submitButton.prop('disabled', false);
+ });
+ });
+
+ // Send Invite AJAX
+ $('.send-invite-submit').on('click', function(e) {
+ e.preventDefault();
+ var $button = $(this);
+ var jobId = $button.data('job-id');
+ var $wrapper = $button.closest('.send-invite-form-wrapper');
+ var $emailInput = $wrapper.find('input[name="applicant_email"]');
+ var $spinner = $wrapper.find('.spinner');
+ var $statusDiv = $wrapper.find('.invite-status');
+ var applicantEmail = $emailInput.val();
+
+ if (!applicantEmail) {
+ $emailInput.focus();
+ // Maybe add a small visual cue that email is required
+ return;
+ }
+
+ $statusDiv.empty().removeClass('error success');
+ $spinner.css('visibility', 'visible');
+ $button.prop('disabled', true).siblings('.cancel-invite').prop('disabled', true);
+
+ var formData = {
+ action: 'send_job_invite',
+ nonce: quiztechThemeData.send_invite_nonce,
+ job_id: jobId,
+ applicant_email: applicantEmail
+ };
+
+ $.post(quiztechThemeData.ajax_url, formData)
+ .done(function(response) {
+ if (response.success) {
+ $statusDiv.text(quiztechThemeData.invite_sent_success).addClass('success');
+ $emailInput.val(''); // Clear email field on success
+ // Optionally hide the form row after a delay
+ setTimeout(function() {
+ $button.closest('.send-invite-form-row').slideUp();
+ }, 2000);
+ } else {
+ var errorMessage = quiztechThemeData.error_generic;
+ if (response.data && response.data.message) {
+ errorMessage = response.data.message;
+ } else if (response.data && response.data === 'error_missing_assessment') {
+ // Example of handling specific error code if needed
+ errorMessage = quiztechThemeData.error_missing_assessment;
+ }
+ $statusDiv.text(errorMessage).addClass('error');
+ }
+ })
+ .fail(function() {
+ $statusDiv.text(quiztechThemeData.error_generic).addClass('error');
+ })
+ .always(function() {
+ $spinner.css('visibility', 'hidden');
+ $button.prop('disabled', false).siblings('.cancel-invite').prop('disabled', false);
+ });
+ });
+
+});
\ No newline at end of file
diff --git a/single.php b/single.php
new file mode 100644
index 0000000..4ace211
--- /dev/null
+++ b/single.php
@@ -0,0 +1,54 @@
+
+
+
>
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ >
+
+
+
+
+ 'job',
+ 'posts_per_page' => -1, // Get all jobs
+ 'author' => $current_user_id,
+ 'post_status' => 'any', // Include drafts, pending, etc.
+ 'orderby' => 'date',
+ 'order' => 'DESC',
+ );
+
+ $user_jobs_query = new WP_Query( $args );
+
+ if ( $user_jobs_query->have_posts() ) :
+ ?>
+
+
+
+ |
+ |
+ |
+
+
+
+ have_posts() ) : $user_jobs_query->the_post(); ?>
+
+ |
+
+
+ |
+ |
+
+
+ |
+ |
+
+ |
+
+
+ |
+
+ |
+
+
+
+
+ ' . esc_html__( 'You have not created any jobs yet.', 'quiztech' ) . '';
+ endif;
+
+ // Restore original Post Data
+ wp_reset_postdata();
+ ?>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+