HEX
Server: LiteSpeed
System: Linux s787.bom1.mysecurecloudhost.com 4.18.0-477.13.1.lve.el8.x86_64 #1 SMP Thu Jun 1 16:40:47 EDT 2023 x86_64
User: mobilech (5348)
PHP: 8.1.34
Disabled: NONE
Upload Files
File: //proc/self/cwd/wp-content/plugins/tutor/components/ConfirmationModal.php
<?php
/**
 * Tutor Component: Confirmation Modal
 *
 * Provides a reusable confirmation modal with Alpine.js integration.
 *
 * @package Tutor\Components
 * @author Themeum
 * @link https://themeum.com
 * @since 4.0.0
 */

namespace Tutor\Components;

use TUTOR\Icon;

defined( 'ABSPATH' ) || exit;

/**
 * Confirmation Modal Component Class.
 *
 * ```
 * // Example usage:
 *
 * ConfirmationModal::make()
 *     ->id( 'delete-course-modal' )
 *     ->title( 'Delete This Course?' )
 *     ->message( 'Are you sure you want to delete this course permanently? Please confirm your choice.' )
 *     ->confirm_handler( 'handleDeleteCourse(payload?.courseId)' )
 *     ->mutation_state( 'deleteMutation' )
 *     ->render();
 *
 * // With custom icon
 * ConfirmationModal::make()
 *     ->id( 'delete-announcement-modal' )
 *     ->title( 'Delete This Announcement?' )
 *     ->message( 'This action cannot be undone.' )
 *     ->icon( Icon::DELETE_2, 80 )
 *     ->confirm_handler( 'handleDeleteAnnouncement(payload?.announcementId)' )
 *     ->render();
 * ```
 *
 * @since 4.0.0
 */
class ConfirmationModal extends BaseComponent {
	const ICON_TYPE_HTML = 'html';

	/**
	 * Modal unique ID.
	 *
	 * @since 4.0.0
	 *
	 * @var string
	 */
	protected $id = '';

	/**
	 * Modal title.
	 *
	 * @since 4.0.0
	 *
	 * @var string
	 */
	protected $title;

	/**
	 * Confirmation message.
	 *
	 * @since 4.0.0
	 *
	 * @var string
	 */
	protected $message;

	/**
	 * Allowed HTML tags and attributes. Keys are tag names and values are allowed attributes.
	 *
	 * @since 4.0.0
	 *
	 * @var array
	 */
	protected $allowed_html_tags = array(
		'span'   => array(
			'class'  => true,
			'x-text' => true,
		),
		'b'      => array(),
		'strong' => array(),
		'i'      => array(),
		'em'     => array(),
		'br'     => array(),
	);

	/**
	 * Icon name from Icon class.
	 *
	 * @since 4.0.0
	 *
	 * @var string
	 */
	protected $icon = '';

	/**
	 * Icon width.
	 *
	 * @since 4.0.0
	 *
	 * @var int
	 */
	protected $icon_width = 100;

	/**
	 * Icon height.
	 *
	 * @since 4.0.0
	 *
	 * @var int
	 */
	protected $icon_height = 100;

	/**
	 * Icon type.
	 *
	 * @since 4.0.0
	 *
	 * @var string|null
	 */
	protected $icon_type = null;

	/**
	 * Confirm handler function name (Alpine.js method).
	 *
	 * @since 4.0.0
	 *
	 * @var string
	 */
	protected $confirm_handler = '';

	/**
	 * Mutation state variable name (e.g., 'deleteMutation').
	 *
	 * @since 4.0.0
	 *
	 * @var string
	 */
	protected $mutation_state = 'confirmMutation';

	/**
	 * Cancel button text.
	 *
	 * @since 4.0.0
	 *
	 * @var string
	 */
	protected $cancel_text = '';

	/**
	 * Confirm button text.
	 *
	 * @since 4.0.0
	 *
	 * @var string
	 */
	protected $confirm_text = '';

	/**
	 * Custom width for modal content.
	 *
	 * @since 4.0.0
	 *
	 * @var string
	 */
	protected $width = '426px';

	/**
	 * Custom confirm button HTML.
	 *
	 * @since 4.0.0
	 *
	 * @var string
	 */
	protected $confirm_btn = '';

	/**
	 * Custom cancel button HTML.
	 *
	 * @since 4.0.0
	 *
	 * @var string
	 */
	protected $cancel_btn = '';

	/**
	 * Set modal ID.
	 *
	 * @since 4.0.0
	 *
	 * @param string $id Modal unique ID.
	 *
	 * @return $this
	 */
	public function id( $id ) {
		$this->id = sanitize_key( $id );
		return $this;
	}

	/**
	 * Set modal title.
	 *
	 * @since 4.0.0
	 *
	 * @param string $title Modal title.
	 *
	 * @return $this
	 */
	public function title( string $title ) {
		$this->title = $title;
		return $this;
	}

	/**
	 * Sets the confirmation message.
	 *
	 * @since 4.0.0
	 *
	 * @param string $message The confirmation message text.
	 * @param array  $allowed_html_tags Optional. Allowed HTML tags and attributes. Keys are tag names and values are allowed attributes.
	 *
	 * @return $this
	 */
	public function message( string $message, array $allowed_html_tags = array() ) {
		$this->message           = $message;
		$this->allowed_html_tags = wp_parse_args( $allowed_html_tags, $this->allowed_html_tags );
		return $this;
	}

	/**
	 * Set icon.
	 *
	 * @since 4.0.0
	 *
	 * @param string $icon Icon name from Icon class.
	 * @param int    $width Icon width.
	 * @param int    $height Icon height.
	 * @param string $type Icon type.
	 *
	 * @return $this
	 */
	public function icon( string $icon, int $width = 100, int $height = 100, $type = null ) {
		$this->icon        = $icon;
		$this->icon_width  = $width;
		$this->icon_height = $height;
		$this->icon_type   = $type;
		return $this;
	}

	/**
	 * Set confirm handler function name.
	 *
	 * @since 4.0.0
	 *
	 * @param string $handler Alpine.js method name.
	 *
	 * @return $this
	 */
	public function confirm_handler( string $handler ) {
		$this->confirm_handler = $handler;
		return $this;
	}

	/**
	 * Set mutation state variable name.
	 *
	 * @since 4.0.0
	 *
	 * @param string $state Mutation state variable name.
	 *
	 * @return $this
	 */
	public function mutation_state( string $state ) {
		$this->mutation_state = $state;
		return $this;
	}

	/**
	 * Set cancel button text.
	 *
	 * @since 4.0.0
	 *
	 * @param string $text Cancel button text.
	 *
	 * @return $this
	 */
	public function cancel_text( string $text ) {
		$this->cancel_text = $text;
		return $this;
	}

	/**
	 * Set confirm button text.
	 *
	 * @since 4.0.0
	 *
	 * @param string $text Confirm button text.
	 *
	 * @return $this
	 */
	public function confirm_text( string $text ) {
		$this->confirm_text = $text;
		return $this;
	}

	/**
	 * Set custom width for modal content.
	 *
	 * @since 4.0.0
	 *
	 * @param string $width Width value (e.g., '426px', '50%').
	 *
	 * @return $this
	 */
	public function width( string $width ) {
		$this->width = $width;
		return $this;
	}

	/**
	 * Set custom confirm button HTML.
	 *
	 * @since 4.0.0
	 *
	 * @param string $html Button HTML.
	 *
	 * @return $this
	 */
	public function confirm_button( string $html ) {
		$this->confirm_btn = $html;
		return $this;
	}

	/**
	 * Set custom cancel button HTML.
	 *
	 * @since 4.0.0
	 *
	 * @param string $html Button HTML.
	 *
	 * @return $this
	 */
	public function cancel_button( string $html ) {
		$this->cancel_btn = $html;
		return $this;
	}

	/**
	 * Get the modal HTML.
	 *
	 * @since 4.0.0
	 *
	 * @return string HTML output.
	 */
	public function get(): string {
		if ( empty( $this->id ) ) {
			return '';
		}

		if ( empty( $this->icon ) ) {
			$this->icon      = tutor_utils()->get_themed_svg( 'images/illustrations/delete.svg' );
			$this->icon_type = self::ICON_TYPE_HTML;
		}

		// Set default button texts if not provided.
		if ( empty( $this->cancel_text ) ) {
			$this->cancel_text = __( 'Cancel', 'tutor' );
		}
		if ( empty( $this->confirm_text ) ) {
			$this->confirm_text = __( 'Yes', 'tutor' );
		}

		// Build Alpine.js x-data.
		$alpine_data = array( 'id' => $this->id );
		$alpine_json = wp_json_encode( $alpine_data );

		// Build style attribute for custom width.
		$style_attr = $this->width
			? sprintf( ' style="max-width: %s;"', esc_attr( $this->width ) )
			: '';

		// Build icon HTML.
		$icon_html = '';
		if ( ! empty( $this->icon ) ) {
			if ( self::ICON_TYPE_HTML === $this->icon_type ) {
				$icon_html = $this->icon;
			} elseif ( filter_var( $this->icon, FILTER_VALIDATE_URL ) !== false ) {
				$icon_html = sprintf( '<img src="%s" style="width:%spx;height:%spx;"/>', $this->icon, $this->icon_width, $this->icon_height );
			} else {
				ob_start();
				SvgIcon::make()->name( $this->icon )->width( $this->icon_width )->height( $this->icon_height )->render();
				$icon_html = ob_get_clean();
			}
		}

		// Prepare message HTML with allowed HTML tags.
		$message_html = wp_kses( $this->message ?? __( 'Are you sure you want to perform this action? Please confirm your choice.', 'tutor' ), $this->allowed_html_tags );

		// Prepare confirm button HTML.
		$confirm_html = $this->confirm_btn;
		if ( empty( $confirm_html ) ) {
			$confirm_html = sprintf(
				'<button 
					class="tutor-btn tutor-btn-destructive tutor-btn-small"
					:class="%s?.isPending ? \'tutor-btn-loading\' : \'\'"
					@click="%s"
					:disabled="%s?.isPending"
				>
					%s
				</button>',
				esc_js( $this->mutation_state ),
				$this->confirm_handler,
				esc_js( $this->mutation_state ),
				esc_html( $this->confirm_text )
			);
		}

		// Prepare cancel button HTML.
		$cancel_html = $this->cancel_btn;
		if ( empty( $cancel_html ) ) {
			$cancel_html = sprintf(
				'<button 
					class="tutor-btn tutor-btn-secondary tutor-btn-small" 
					@click="TutorCore.modal.closeModal(\'%s\')"
				>
					%s
				</button>',
				esc_js( $this->id ),
				esc_html( $this->cancel_text )
			);
		}

		$this->component_string = sprintf(
			'<div x-data="tutorModal(%s)" x-cloak style="display: none;">
				<template x-teleport="body">
					<div x-bind="getModalBindings()">
						<div x-bind="getBackdropBindings()"></div>
						<div x-bind="getModalContentBindings()"%s>
							<button x-data="tutorIcon({ name: \'cross\', width: 16, height: 16})" x-bind="getCloseButtonBindings()" aria-label="%s"></button>

							<div class="tutor-p-7 tutor-pt-10 tutor-flex tutor-flex-column tutor-items-center">
								%s
								<h5 class="tutor-h5 tutor-font-medium tutor-mt-7">
									%s
								</h5>
								<p class="tutor-p3 tutor-text-secondary tutor-mt-2 tutor-text-center">
									%s
								</p>
							</div>

							<div class="tutor-grid tutor-grid-cols-2 tutor-gap-4 tutor-px-7 tutor-pb-6">
								%s
								%s
							</div>
						</div>
					</div>
				</template>
			</div>',
			esc_attr( $alpine_json ),
			$style_attr,
			esc_attr__( 'Close', 'tutor' ),
			$icon_html,
			esc_html( $this->title ?? __( 'Are you sure?', 'tutor' ) ),
			$message_html,
			$cancel_html,
			$confirm_html,
		);

		return $this->component_string;
	}
}