????

Your IP : 216.73.216.79


Current Path : /home/arabianr/public_html/wp-content/plugins/simplybook/app/Support/Widgets/
Upload File :
Current File : //home/arabianr/public_html/wp-content/plugins/simplybook/app/Support/Widgets/ElementorWidget.php

<?php

namespace SimplyBook\Support\Widgets;

use SimplyBook\Bootstrap\App;
use Elementor\Widget_Base;
use SimplyBook\Http\ApiClient;
use Elementor\Controls_Manager;
use SimplyBook\Traits\HasApiAccess;
use SimplyBook\Http\Entities\Service;
use SimplyBook\Http\Entities\ServiceProvider;
use SimplyBook\Support\Helpers\Storages\EnvironmentConfig;

class ElementorWidget extends Widget_Base
{
    use HasApiAccess;

    private const NAME = 'simplybook_widget';

    /**
     * Default value for the dropdowns to indicate no selection
     * @var string
     */
    private const DEFAULT_VALUE = '0';

    /**
     * The API client for fetching data
     */
    private ApiClient $client;

    /**
     * Environment configuration
     */
    private EnvironmentConfig $env;

    /**
     * Required by Elementor for widget registration.
     */
    // phpcs:ignore PSR1.Methods.CamelCapsMethodName.NotCamelCaps
    public function get_name(): string
    {
        return self::NAME;
    }

    /**
     * Shows in the Elementor widget panel.
     */
    // phpcs:ignore PSR1.Methods.CamelCapsMethodName.NotCamelCaps
    public function get_title(): string
    {
        return esc_html__('SimplyBook.me Widget', 'simplybook');
    }

    /**
     * Uses Elementor's icon library (eicon-*).
     */
    // phpcs:ignore PSR1.Methods.CamelCapsMethodName.NotCamelCaps
    public function get_icon(): string
    {
        return 'eicon-calendar';
    }

    /**
     * Helps users find this widget when searching.
     */
    // phpcs:ignore PSR1.Methods.CamelCapsMethodName.NotCamelCaps
    public function get_keywords(): array
    {
        return ['booking', 'calendar', 'appointment', 'SimplyBook.me'];
    }

    /**
     * Registers all widget controls (dropdowns) for the Elementor editor. Also
     * sets some custom properties used during rendering.
     */
    // phpcs:ignore PSR1.Methods.CamelCapsMethodName.NotCamelCaps
    protected function register_controls(): void
    {
        $this->client = App::getInstance()->get(ApiClient::class);
        $this->env = App::getInstance()->get(EnvironmentConfig::class);

        $this->start_controls_section(
            'content_section',
            [
                'label' => esc_html__('SimplyBook.me Settings', 'simplybook'),
                'tab' => Controls_Manager::TAB_CONTENT,
            ]
        );

        if (!$this->companyRegistrationIsCompleted()) {
            $this->addLoginRequiredControl();
        } else {
            $this->addServiceControl();
            $this->addProviderControl();
            $this->addLocationControl();
            $this->addServiceCategoryControl();
        }

        $this->end_controls_section();
    }

    /**
     * Converts widget settings to SimplyBook shortcode and renders it.
     */
    protected function render(): void
    {
        $settings = $this->get_settings_for_display();
        $attributes = $this->buildShortcodeAttributes($settings);

        echo do_shortcode($this->buildShortcode($attributes));
    }

    /**
     * Service dropdown - always visible, populated from API.
     */
    private function addServiceControl(): void
    {
        $this->add_control(
            'service',
            [
                'label' => esc_html__('Service', 'simplybook'),
                'type' => Controls_Manager::SELECT,
                'default' => self::DEFAULT_VALUE,
                'options' => $this->getServicesOptions(),
            ]
        );
    }

    /**
     * Provider dropdown including 'Any provider' when enabled.
     */
    private function addProviderControl(): void
    {
        $this->add_control(
            'provider',
            [
                'label' => esc_html__('Service Provider', 'simplybook'),
                'type' => Controls_Manager::SELECT,
                'default' => self::DEFAULT_VALUE,
                'options' => $this->getProvidersOptions(),
            ]
        );
    }

    /**
     * Location dropdown - shows helpful text when feature disabled.
     */
    private function addLocationControl(): void
    {
        if (!$this->client->isSpecialFeatureEnabled('location')) {
            return;
        }

        $this->add_control(
            'location',
            [
                'label' => esc_html__('Location', 'simplybook'),
                'type' => Controls_Manager::SELECT,
                'default' => self::DEFAULT_VALUE,
                'options' => $this->getLocationsOptions(),
            ]
        );
    }

    /**
     * Category dropdown - shows helpful text when feature disabled.
     */
    private function addServiceCategoryControl(): void
    {
        if (!$this->client->isSpecialFeatureEnabled('event_category')) {
            return;
        }

        $this->add_control(
            'category',
            [
                'label' => esc_html__('Service Category', 'simplybook'),
                'type' => Controls_Manager::SELECT,
                'default' => self::DEFAULT_VALUE,
                'options' => $this->getServiceCategoriesOptions(),
            ]
        );
    }

    /**
     * Fetches services from API with error handling.
     */
    private function getServicesOptions(): array
    {
        if (!$this->companyRegistrationIsCompleted()) {
            return []; // we shouldn't be here
        }

        $serviceEntity = App::getInstance()->get(Service::class);

        return $this->buildOptionsFromApiData(
            $serviceEntity->all(),
            esc_html__('Select a service', 'simplybook')
        );
    }

    /**
     * Fetches providers from API, includes 'Any' option when available.
     */
    private function getProvidersOptions(): array
    {
        if (!$this->companyRegistrationIsCompleted()) {
            return []; // we shouldn't be here
        }

        $providerEntity = App::getInstance()->get(ServiceProvider::class);

        $options = $this->buildOptionsFromApiData(
            $providerEntity->all(),
            esc_html__('Select a service provider', 'simplybook')
        );

        // Return early if "Any Provider" feature is not enabled
        if ($this->client->isSpecialFeatureEnabled('any_unit') === false) {
            return $options;
        }

        // Insert 'any' option after the default option
        $defaultOption = array_slice($options, 0, 1, true);
        $restOptions = array_slice($options, 1, null, true);
        return $defaultOption + ['any' => esc_html__('Any provider', 'simplybook')] + $restOptions;
    }

    /**
     * Returns locations only if Multiple Locations feature is active.
     */
    private function getLocationsOptions(): array
    {
        if (!$this->companyRegistrationIsCompleted() || !$this->client->isSpecialFeatureEnabled('location')) {
            return []; // we shouldn't be here
        }

        $locations = $this->client->getLocations(true);
        return $this->buildOptionsFromApiData(
            is_array($locations) ? $locations : [],
            esc_html__('Select a location', 'simplybook')
        );
    }

    /**
     * Returns categories only if Service Categories feature is active.
     */
    private function getServiceCategoriesOptions(): array
    {
        if (!$this->companyRegistrationIsCompleted() || !$this->client->isSpecialFeatureEnabled('event_category')) {
            return []; // we shouldn't be here
        }

        $categories = $this->client->getCategories(true);
        return $this->buildOptionsFromApiData(
            is_array($categories) ? $categories : [],
            esc_html__('Select a category', 'simplybook')
        );
    }

    /**
     * Filters widget settings to only include valid SimplyBook shortcode parameters.
     * Parameters must match the controls we register in {@see add_controls()}.
     */
    private function buildShortcodeAttributes(array $settings): array
    {
        $attributes = [];
        $possibleAttributes = ['service', 'provider', 'location', 'category'];

        foreach ($possibleAttributes as $key) {
            $value = $settings[$key] ?? '';
            if (!empty($value)) {
                $attributes[$key] = $value;
            }
        }

        return $attributes;
    }

    /**
     * Formats attributes as [simplybook_widget key="value"] string.
     */
    private function buildShortcode(array $attributes): string
    {
        if (empty($attributes)) {
            return '[' . self::NAME . ']';
        }

        $attributePairs = array_map(
            fn($key, $value) => sprintf('%s="%s"', sanitize_text_field($key), sanitize_text_field($value)),
            array_keys($attributes),
            array_values($attributes)
        );

        return sprintf('[%s %s]', self::NAME, implode(' ', $attributePairs));
    }

    /**
     * Generic method to build options array from API data.
     *
     * @param array $items API response items
     * @param string $defaultLabel Default option label
     */
    private function buildOptionsFromApiData(array $items, string $defaultLabel): array
    {
        $options = [
            self::DEFAULT_VALUE => $defaultLabel,
        ];

        foreach ($items as $item) {
            if (isset($item['id']) && isset($item['name'])) {
                $options[$item['id']] = esc_html($item['name']);
            }
        }

        return $options;
    }

    /**
     * Shows login required message with dashboard link.
     */
    private function addLoginRequiredControl(): void
    {
        $dashboardUrl = $this->env->getUrl('plugin.dashboard_url');
        $loginMessage = sprintf(
            '%s<br><br><a href="%s" target="_blank">%s</a>',
            esc_html__('Please log in to SimplyBook.me to use this widget.', 'simplybook'),
            esc_url($dashboardUrl),
            esc_html__('Go to the SimplyBook.me dashboard', 'simplybook')
        );

        $this->add_control(
            'login_required',
            [
                'type' => Controls_Manager::RAW_HTML,
                'raw' => $loginMessage,
                'content_classes' => 'elementor-panel-alert elementor-panel-alert-warning',
            ]
        );
    }
}