File "taskdetails.php"

Full Path: /home/romayxjt/public_html/wp-content/plugins/vikbooking/site/layouts/taskmanager/taskdetails.php
File size: 17.56 KB
MIME-type: text/x-php
Charset: utf-8

<?php
/** 
 * @package     VikBooking
 * @subpackage  core
 * @author      E4J s.r.l.
 * @copyright   Copyright (C) 2025 E4J s.r.l. All Rights Reserved.
 * @license     http://www.gnu.org/licenses/gpl-2.0.html GNU/GPL
 * @link        https://vikwp.com
 */

// No direct access
defined('ABSPATH') or die('No script kiddies please!');

/**
 * Obtain vars from arguments received in the layout file.
 * 
 * @var string $tool         The operator tool identifier calling this layout file.
 * @var array  $operator     The operator record accessing the tool.
 * @var object $permissions  The operator-tool permissions registry.
 * @var string $tool_uri     The base URI for rendering this tool.
 * @var array  $data         The data for rendering the tasks of a given month within a calendar.
 */
extract($displayData);

if (!$operator || empty($operator['id'])) {
    throw new Exception('Missing operator details', 400);
}

// get task details
$taskId = $data['filters']['task_id'] ?? 0;

if (empty($taskId)) {
    throw new Exception('Missing task details', 400);
}

// get the current operator permissions
$accept_tasks = (bool) ($permissions ? $permissions->get('accept_tasks', 0) : 0);

// get a registry of the requested task record
$taskRegistry = VBOTaskTaskregistry::getRecordInstance((int) $taskId);

if (!$taskRegistry->getID()) {
    // task record not found
    throw new Exception('Cannot find task details', 404);
}

// get the task assignee IDs
$assingeeIds = $taskRegistry->getAssigneeIds();

if ((!$assingeeIds && !$accept_tasks) || ($assingeeIds && !in_array($operator['id'], $assingeeIds))) {
    // task record not accessible by the current operator
    throw new Exception('Cannot access task details', 403);
}

// get the current task area object wrapper
$taskArea = VBOTaskArea::getRecordInstance($taskRegistry->getAreaID());

if ($taskArea->isPrivate()) {
    // the area of this task seems to be private
    throw new Exception('Cannot access this area', 403);
}

// inject current area in task registry wrapper
$taskRegistry->setArea($taskArea);

// access data for backward navigation
$calendar_back_type = $data['filters']['calendar_back_type'] ?? 'month';
$calendar_back_type = in_array($calendar_back_type, ['month', 'day']) ? $calendar_back_type : 'month';

// access the task manager object
$taskManager = VBOFactory::getTaskManager();

// load task assignees
$assignees = $taskRegistry->getAssigneeDetails();

// load task tags
$tags = $taskRegistry->getTags() ? $taskRegistry->getTagRecords() : [];

// get task status object
$status = $taskManager->statusTypeExists($taskRegistry->getStatus()) ? $taskManager->getStatusTypeInstance($taskRegistry->getStatus()) : null;

// load all the available status types
$statusTypes = [];

foreach ($taskManager->getStatusGroupElements($taskArea->getStatuses()) as $groupId => $group) {
    // push group button
    $statusTypes[] = [
        'id' => null,
        'text' => $group['text'],
    ];

    // iterate over the statuses of this group
    foreach ($group['elements'] as $statusType) {
        // push status button
        $statusTypes[] = [
            'id' => $statusType['id'],
            'text' => $statusType['text'],
            'color' => $statusType['color'],
        ];
    }
}

$roomInfo = null;

?>

<div class="vbo-tm-calendar-wrap">

    <div class="vbo-tm-task-details" data-task-id="<?php echo (int) $taskRegistry->getID(); ?>">

        <div class="vbo-tm-task-head">
            <div class="vbo-tm-calendar-head">
                <div class="vbo-tm-calendar-info">
                    <a href="javascript:void(0)" class="vbo-tm-calendar-day-back" data-month="<?php echo $data['filters']['calendar_month'] ?? ''; ?>" data-day="<?php echo $data['filters']['calendar_day'] ?? ''; ?>">
                        <?php echo VikBookingIcons::e('chevron-left'); ?>
                    </a>
                    <h4 class="vbo-tm-task-title"><?php echo $taskRegistry->getTitle(); ?></h4>
                </div>
            </div>

            <div class="vbo-tm-task-status-snapshot">

                <?php if ($status): ?>
                    <?php echo JHtml::fetch('vbohtml.taskmanager.status', $status); ?>
                <?php endif; ?>

                <?php if ($dueDate = $taskRegistry->getDueDate()): ?>
                    <div class="vbo-tm-task-due date">
                        <?php VikBookingIcons::e('calendar-day'); ?>
                        <span><?php echo JHtml::fetch('date', $dueDate, 'd F Y'); ?></span>
                    </div>
                    <div class="vbo-tm-task-due time">
                        <?php VikBookingIcons::e('stopwatch'); ?>
                        <?php if ($assignees): ?>
                            <input type="time" class="task-time-picker" value="<?php echo JHtml::fetch('date', $dueDate, 'H:i'); ?>" />
                        <?php else: ?>
                            <span><?php echo JHtml::fetch('date', $dueDate, 'H:i'); ?></span>
                        <?php endif; ?>
                    </div>
                <?php endif; ?>

            </div>
        </div>

        <div class="vbo-tm-task-body">

            <div class="vbo-tm-task-info">

                <div class="vbo-tm-task-summary">

                    <div class="vbo-tm-task-summary-block vbo-tm-task-assignees">
                        <div class="vbo-tm-task-summary-lbl">
                            <span><?php echo JText::translate('VBO_ASSIGNEES'); ?></span>
                        </div>
                        <div class="vbo-tm-task-summary-cont">
                        <?php
                        foreach ($assignees as $operator) {
                            ?>
                            <span class="vbo-tm-list-area-task-assignee vbo-tm-task-assignee">
                                <span class="vbo-tm-list-area-task-assignee-avatar vbo-tm-task-assignee-avatar" title="<?php echo JHtml::fetch('esc_attr', $operator['name']); ?>">
                                <?php
                                if (!empty($operator['img_uri'])) {
                                    ?>
                                    <img src="<?php echo $operator['img_uri']; ?>" alt="<?php echo JHtml::fetch('esc_attr', $operator['initials']); ?>" decoding="async" loading="lazy" />
                                    <?php
                                } else {
                                    ?>
                                    <span><?php echo $operator['initials']; ?></span>
                                    <?php
                                }
                                ?>
                                </span>
                            </span>
                            <?php
                        }

                        if (!$assignees) {
                            ?>
                            <span class="vbo-tm-task-no-assignees"><?php echo JText::translate('VBO_TASK_NO_ASSIGNEES'); ?></span>
                            <?php
                        }
                        ?>
                        </div>
                    </div>

                <?php
                if ($taskRegistry->getListingId()) {
                    $roomInfo = VikBooking::getRoomInfo($taskRegistry->getListingId(), $columns = ['name', 'params'], $no_cache = true);
                    $roomInfo['params'] = json_decode($roomInfo['params']);
                    $geo = $roomInfo['params']->geo ?? null;
                    ?>
                    <div class="vbo-tm-task-summary-block vbo-tm-task-listing-info">
                        <div class="vbo-tm-task-summary-lbl">
                            <span><?php echo JText::translate('VBO_LISTING'); ?></span>
                        </div>
                        <div class="vbo-tm-task-summary-cont">
                            <?php if (!empty($geo->enabled) && !empty($geo->latitude) && !empty($geo->longitude)): ?>
                                <a href="javascript:void(0)" class="listing-name open-map"><?php VikBookingIcons::e('home'); ?><?php echo $roomInfo['name']; ?></a>
                            <?php else: ?>
                                <span class="listing-name"><?php VikBookingIcons::e('home'); ?> <?php echo $roomInfo['name']; ?></span>
                            <?php endif; ?>
                        </div>
                    </div>
                    <?php
                }

                if ($taskRegistry->getBookingId() && $bookingElement = $taskRegistry->buildBookingElement()) {
                    if (!empty($bookingElement['img'])) {
                        $img = '<img src="' . $bookingElement['img'] . '" class="vbo-booking-badge-avatar" decoding="async" loading="lazy" />';
                    } else {
                        $img = '<span class="vbo-booking-badge-avatar"><i class="' . VikBookingIcons::i($bookingElement['icon_class'] ?? 'hotel') . '"></i></span>';
                    }

                    $bookingText = $bookingElement['text'] . ' #' . $bookingElement['id'];
                    ?>
                    <div class="vbo-tm-task-summary-block vbo-tm-task-booking-info">
                        <div class="vbo-tm-task-summary-lbl">
                            <span><?php echo JText::translate('VBORDNOL'); ?></span>
                        </div>
                        <div class="vbo-tm-task-summary-cont">
                            <?php echo $img; ?>
                            <span class="guest-name"><?php echo $bookingText; ?></span>
                        </div>
                    </div>
                    <?php
                }
                ?>

                </div>

                <?php if ($tags): ?>
                <div class="vbo-tm-task-tags">
                <?php
                foreach ($tags as $tag) {
                    $tag = (array) $tag;
                    ?>
                    <span class="vbo-tm-task-tag vbo-tm-color <?php echo $tag['color']; ?>"><?php echo $tag['name']; ?></span>
                    <?php
                }
                ?>
                </div>
                <?php endif; ?>

                <?php if ($status && ($statusDisplay = $status->display($taskRegistry))): ?>
                    <div class="vbo-tm-task-status-notes"><?php echo $statusDisplay; ?></div>
                <?php endif; ?>

                <?php if ($notes = $taskRegistry->getNotes()): ?>
                    <div class="vbo-tm-task-notes"><?php echo $notes; ?></div>
                <?php endif; ?>

                <div class="vbo-tm-task-listing-map" style="display: none; width: 100%; height: 500px; margin-top: 10px;">
                    
                </div>

            </div>

            <div class="vbo-tm-task-chat">
            <?php
            // get the chat mediator
            $chat = VBOFactory::getChatMediator();
            // build chat for the given context
            $chat_context = $chat->createContext('task', $taskRegistry->getID());
            // display the chat for the current task context
            echo $chat->render($chat_context, [
                'assets' => false,
            ]);
            ?>
            </div>

        </div>

    </div>

</div>

<script type="text/javascript">
    VBOCore.DOMLoaded(() => {
        // register click event on calendar backward navigation
        document.querySelectorAll('.vbo-tm-calendar-day-back').forEach((backBtn) => {
            backBtn.addEventListener('click', () => {
                let navMonth = backBtn.getAttribute('data-month');
                let navDay = backBtn.getAttribute('data-day');
                let navType = navDay ? 'day' : 'month';
                VBOCore.emitEvent('vbo-tm-apply-filters', {
                    filters: {
                        calendar_type: navType,
                        calendar_month: navMonth || '<?php echo date('Y-m-01'); ?>',
                        calendar_day: navDay,
                    },
                });
            });
        });

        // register change event on due time picker
        document.querySelectorAll('.task-time-picker').forEach((timePicker) => {
            let currentTime = timePicker.value;

            timePicker.addEventListener('blur', () => {
                if (timePicker.value == currentTime) {
                    // nothing has change, do not proceed with the update
                    return;
                }

                timePicker.disabled = true;

                // make the request
                VBOCore.doAjax(
                    '<?php echo VikBooking::ajaxUrl('index.php?option=com_vikbooking&task=taskmanager.updateTask'); ?>',
                    {
                        data: {
                            id: <?php echo $taskId ?>,
                            dueon: '<?php echo JHtml::fetch('date', $dueDate, 'Y-m-d'); ?> ' + timePicker.value,
                        }
                    },
                    (resp) => {
                        timePicker.disabled = false;
                        currentTime = timePicker.value;
                    },
                    (error) => {
                        // display error message
                        alert(error.responseText);

                        timePicker.disabled = false;
                    }
                );
            });
        });

        let checklistQueue = [], isUpdatingChecklist = false;

        const updateChecklist = (checklistTask) => {
            // update checklist task
            jQuery(checklistTask.node).attr('data-checked', checklistTask.status ? 'true' : 'false');

            if (isUpdatingChecklist) {
                checklistQueue.push(checklistTask);
                return;
            }

            isUpdatingChecklist = true;

            // make the request
            VBOCore.doAjax(
                '<?php echo VikBooking::ajaxUrl('index.php?option=com_vikbooking&task=taskmanager.updateChecklist'); ?>',
                {
                    id: <?php echo $taskId ?>,
                    index: checklistTask.index + 1,
                    status: checklistTask.status ? 1 : 0,
                },
                (resp) => {
                    isUpdatingChecklist = false;

                    if (checklistQueue.length) {
                        // move to the next one
                        updateChecklist(checklistQueue.shift());
                    }
                },
                (error) => {
                    // display error message
                    alert(error.responseText);

                    // restore previous value
                    jQuery(checklistTask.node).attr('data-checked', checklistTask.status ? 'false' : 'true');

                    isUpdatingChecklist = false;

                    if (checklistQueue.length) {
                        // move to the next one
                        updateChecklist(checklistQueue.shift());
                    }
                }
            );
        }

        jQuery('.vbo-tm-task-notes ul[data-checked]').on('click', function(event) {
            if (event.originalEvent.offsetX > 16) {
                // simulate click only on the pseudo-element
                return false;
            }

            // fetch the nth-index of the clicked checkbox
            const index = jQuery('.vbo-tm-task-notes ul[data-checked]').index(this);
            const status = jQuery(this).attr('data-checked') === 'true' ? false : true;

            updateChecklist({
                index: index,
                status: status,
                node: this,
            });
        });

        <?php if (!empty($roomInfo)): ?>
            jQuery('.listing-name.open-map').on('click', () => {
                const mapTarget = jQuery('.vbo-tm-task-listing-map');

                if (mapTarget.is(':visible')) {
                    mapTarget.hide();
                    jQuery('.vbo-tm-task-notes').show();
                } else {
                    jQuery('.vbo-tm-task-notes').hide();
                    mapTarget.show();
                }

                initializeListingMap(mapTarget[0]);
            });

            let mapInitialized = false;

            const initializeListingMap = async (target) => {
                if (mapInitialized) {
                    return;
                }

                mapInitialized = true;

                // init libraries
                const { Map, InfoWindow } = await google.maps.importLibrary('maps');
                const { AdvancedMarkerElement } = await google.maps.importLibrary('marker');

                const position = {
                    lat: <?php echo floatval($roomInfo['params']->geo->latitude ?? null); ?>,
                    lng: <?php echo floatval($roomInfo['params']->geo->longitude ?? null); ?>,
                };

                const map = new Map(target, {
                    zoom: 14,
                    center: position,
                    mapId: 'listing_location',
                });

                const popup = new InfoWindow({
                    content: <?php echo json_encode($roomInfo['params']->geo->address ?? $roomInfo['name']); ?>,
                    ariaLabel: <?php echo json_encode($roomInfo['name']); ?>,
                });

                const marker = new AdvancedMarkerElement({
                    position: position,
                    map: map,
                    title: <?php echo json_encode($roomInfo['name']); ?>,
                });

                marker.addListener('gmp-click', () => {
                    popup.open({
                        anchor: marker,
                        map: map,
                    });
                });
            }
        <?php endif; ?>

        VBOCore.emitEvent('vbo-tm-contents-loaded', {
            element: document.querySelector('.vbo-tm-task-details'),
            statuses: <?php echo json_encode($taskArea->getStatuses()); ?>,
        });
    });
</script>