<?php
// pages/components/notification_hub.php
use Components\Data\Notifications;
use Components\Base;
use Components\Button;
use Components\Router;

$activeTab = mh_get('hub_tab', 'notifications');
$lastCheckedIso = date('c');
$lastCheckedRaw = date('Y-m-d H:i:s');

?>

<script>
    function notificationGroup(config = {}) {
        return {
            expanded: config.initialExpanded ?? false,
            itemIds: config.itemIds ?? [],
            leavingIds: [],
            overswing: false,
            overswingExpanding: false,
            overswingTimer: null,
            overswingResetTimer: null,
            maxPeek: config.maxPeek ?? 2,
            labels: config.labels ?? {
                showMore: <?= json_encode(Base::lng('UI_NOTIFICATION_GROUP_SHOW_MORE', 'Show %d more')) ?>,
                collapse: 'Collapse'
            },
            cardHeightUnits: 26,
            expandedGapUnits: 3,
            peekOffsetUnits: 2,
            scaleStep: 0.035,
            expandingGapOvershootUnits: 0.85,
            collapsingPeekUndershootUnits: 0.65,
            dismissDurationMs: 380,
            expandOverswingDelayMs: 18,
            expandOverswingResetMs: 240,
            collapseOverswingResetMs: 60,

            get count() {
                return this.itemIds.length;
            },

            get hasItems() {
                return this.count > 0;
            },

            get remainingCount() {
                return Math.max(0, this.count - 1);
            },

            get currentLabel() {
                return this.expanded
                    ? this.labels.collapse
                    : this.labels.showMore.replace('%d', this.remainingCount);
            },

            isCollapsedPeek(index) {
                return !this.expanded && this.count > 1 && index >= 0 && index <= this.maxPeek;
            },

            toggle() {
                this.setExpanded(!this.expanded);
            },

            setExpanded(nextExpanded) {
                const shouldExpand = !!nextExpanded;

                if (this.expanded === shouldExpand) {
                    return;
                }

                this.expanded = shouldExpand;
                this.triggerOverswingAnimations(shouldExpand);
            },

            triggerOverswingAnimations(isExpanding) {
                const activeFlag = isExpanding ? 'overswingExpanding' : 'overswing';
                const inactiveFlag = isExpanding ? 'overswing' : 'overswingExpanding';
                const triggerDelayMs = isExpanding ? this.expandOverswingDelayMs : 0;
                const resetMs = isExpanding ? this.expandOverswingResetMs : this.collapseOverswingResetMs;

                this[inactiveFlag] = false;
                this[activeFlag] = false;

                if (this.overswingTimer) {
                    window.clearTimeout(this.overswingTimer);
                }

                if (this.overswingResetTimer) {
                    window.clearTimeout(this.overswingResetTimer);
                }

                const activate = () => {
                    this[activeFlag] = true;
                    this.overswingResetTimer = window.setTimeout(() => {
                        this[activeFlag] = false;
                    }, resetMs);
                };

                if (triggerDelayMs <= 0) {
                    activate();
                    return;
                }

                this.overswingTimer = window.setTimeout(activate, triggerDelayMs);
            },

            expandFromPeek(id, event) {
                const index = this.itemIds.indexOf(id);

                if (!this.isCollapsedPeek(index)) {
                    return;
                }

                event.preventDefault();
                event.stopPropagation();
                this.setExpanded(true);
            },

            dismiss(id) {
                if (!this.itemIds.includes(id) || this.leavingIds.includes(id)) {
                    return;
                }

                this.leavingIds.push(id);

                window.setTimeout(() => {
                    this.itemIds = this.itemIds.filter(itemId => itemId !== id);
                    this.leavingIds = this.leavingIds.filter(itemId => itemId !== id);
                    this.$dispatch('notification-dismissed-local');

                    if (this.count <= 1) {
                        this.setExpanded(false);
                    }
                }, this.dismissDurationMs);
            },

            dismissAllInGroup() {
                if (!this.expanded || this.itemIds.length <= 1) {
                    return;
                }

                const ids = [...this.itemIds];
                const dismissButtons = Array.from(this.$root.querySelectorAll('[data-dismiss-id]'));

                ids.forEach((id) => {
                    const button = dismissButtons.find((candidate) => String(candidate.dataset.dismissId) === String(id));

                    if (button) {
                        button.click();
                    }
                });
            },

            stackStyle() {
                if (!this.hasItems) {
                    return '';
                }

                const visibleBehind = Math.min(this.remainingCount, this.maxPeek);
                const collapsedPeekOffsetUnits = this.peekOffsetUnits - (this.overswing ? this.collapsingPeekUndershootUnits : 0);
                const expandedGapUnits = this.expandedGapUnits + (this.overswingExpanding ? this.expandingGapOvershootUnits : 0);
                const collapsedUnits = this.cardHeightUnits + (visibleBehind * collapsedPeekOffsetUnits);
                const expandedUnits = this.cardHeightUnits
                    + (Math.max(0, this.count - 1) * (this.cardHeightUnits + expandedGapUnits));
                const activeUnits = this.expanded ? expandedUnits : collapsedUnits;

                return `height:calc(var(--spacing) * ${activeUnits});`;
            },

            cardClass(id) {
                const index = this.itemIds.indexOf(id);

                if (index === -1) {
                    return 'hidden';
                }

                const interactive = this.expanded || index === 0 || index <= this.maxPeek;
                return `absolute inset-x-0 top-0 ${interactive ? 'pointer-events-auto' : 'pointer-events-none'} ${this.isCollapsedPeek(index) ? 'cursor-pointer' : ''}`;
            },

            cardStyle(id) {
                const index = this.itemIds.indexOf(id);

                if (index === -1) {
                    return 'display:none;';
                }

                if (this.expanded) {
                    const expandedGapUnits = this.expandedGapUnits + (this.overswingExpanding ? this.expandingGapOvershootUnits : 0);
                    const y = index === 0 ? 0 : (index * (this.cardHeightUnits + expandedGapUnits));

                    return `
                    position:absolute;
                    left:0;
                    right:0;
                    top:0;
                    z-index:${30 - index};
                    opacity:1;
                    transform:translateY(calc(var(--spacing) * ${y})) scale(1);
                    transform-origin:top center;
                `;
                }

                if (index === 0) {
                    return `
                    position:absolute;
                    left:0;
                    right:0;
                    top:0;
                    z-index:30;
                    opacity:1;
                    transform:translateY(0) scale(1);
                    transform-origin:top center;
                `;
                }

                const peekIndex = Math.min(index, this.maxPeek);
                const collapsedPeekOffsetUnits = this.peekOffsetUnits - (this.overswing ? this.collapsingPeekUndershootUnits : 0);
                const y = peekIndex * collapsedPeekOffsetUnits;
                const scale = 1 - (peekIndex * this.scaleStep);
                const opacity = index <= this.maxPeek ? 1 : 0;

                return `
                position:absolute;
                left:0;
                right:0;
                top:0;
                z-index:${30 - index};
                opacity:${opacity};
                filter: saturate(50%);
                transform:translateY(calc(var(--spacing) * ${y})) scale(${scale});
                transform-origin:top center;
            `;
            },

            hideInner(id) {
                return !this.expanded && this.itemIds.indexOf(id) > 0;
            },

            isLeaving(id) {
                return this.leavingIds.includes(id);
            }
        };
    }
</script>


<div class="flex flex-col h-full"
     data-no-local-loader="true"
     data-no-global-loader="true"
     hx-get="<?= Router::url('notification_hub', ['hub_tab' => 'notifications', 'partial' => 1]) ?>"
     hx-trigger="notifications-refresh from:body, notifications-changed from:body"
     hx-target="this"
     hx-swap="outerHTML"
>
    <div class="flex-1 min-h-0 overflow-auto">
        <!-- Notifications Tab -->
        <?php $notifications = Notifications::getList(0); ?>
        <div class="grid grid-cols-1"
             x-data="{
                count: <?= count($notifications) ?>,
                loading: false
            }"
             @notifications-changed.window="if ($event.detail.count !== undefined) {
                if ($event.detail.count > count) {
                    loading = false;
                }
                count = $event.detail.count;
            }"
             @notification-dismissed-local.window="count = Math.max(0, count - 1)"
        >
            <div x-show="count > 0 && !loading"
                 x-transition:leave="transition ease-in duration-200"
                 x-transition:leave-start="opacity-100"
                 x-transition:leave-end="opacity-0"
                 class="col-start-1 row-start-1 space-y-5 pb-4"
                 id="notification-list"
            >
                <?php
                $severityGroups = [
                        'alert' => [
                                'label' => Base::lng('UI_NOTIFICATION_GROUP_ALERTS', 'Alerts'),
                                'headerClass' => 'notification-group__header',
                                'badgeClass' => 'notification-group__count notification-group__count--danger',
                                'cardClass' => 'notification-card notification-card--danger',
                                'iconClass' => 'notification-icon notification-icon--danger',
                                'titleClass' => 'text-danger-700 dark:text-danger-300',
                                'summaryClass' => 'text-danger-700/80 dark:text-danger-300/80',
                                'timeClass' => 'text-danger-600/75 dark:text-danger-300/70',
                        ],
                        'warning' => [
                                'label' => Base::lng('UI_NOTIFICATION_GROUP_WARNINGS', 'Warnings'),
                                'headerClass' => 'notification-group__header',
                                'badgeClass' => 'notification-group__count notification-group__count--warning',
                                'cardClass' => 'notification-card notification-card--warning',
                                'iconClass' => 'notification-icon notification-icon--warning',
                                'titleClass' => 'text-warning-700 dark:text-warning-300',
                                'summaryClass' => 'text-warning-700/80 dark:text-warning-300/80',
                                'timeClass' => 'text-warning-600/75 dark:text-warning-300/70',
                        ],
                        'info' => [
                                'label' => Base::lng('UI_NOTIFICATION_GROUP_NOTES', 'Notes'),
                                'headerClass' => 'notification-group__header',
                                'badgeClass' => 'notification-group__count notification-group__count--info',
                                'cardClass' => 'notification-card notification-card--info',
                                'iconClass' => 'notification-icon notification-icon--info',
                                'titleClass' => 'text-info-700 dark:text-info-300',
                                'summaryClass' => 'text-info-700/80 dark:text-info-300/80',
                                'timeClass' => 'text-info-600/75 dark:text-info-300/70',
                        ],
                ];

                $groupedNotifications = [
                        'alert' => [],
                        'warning' => [],
                        'info' => [],
                ];

                foreach ($notifications as $item) {
                    $severity = (int)($item['severity'] ?? 5);
                    $bucket = ($severity <= 2) ? 'alert' : (($severity <= 4) ? 'warning' : 'info');
                    $groupedNotifications[$bucket][] = $item;
                }

                foreach ($groupedNotifications as &$items) {
                    usort($items, static function ($left, $right) {
                        $leftTs = strtotime((string)($left['date_added'] ?? '')) ?: 0;
                        $rightTs = strtotime((string)($right['date_added'] ?? '')) ?: 0;
                        return $rightTs <=> $leftTs;
                    });
                }
                unset($items);
                ?>

                <?php foreach ($severityGroups as $bucket => $meta): ?>
                    <?php if (empty($groupedNotifications[$bucket])) continue; ?>
                    <?php
                    $groupCount = count($groupedNotifications[$bucket]);
                    $stackConfig = [
                            'maxPeek' => 2,
                            'itemIds' => array_column($groupedNotifications[$bucket], 'id'),
                            'labels' => [
                                    'showMore' => Base::lng('UI_NOTIFICATION_GROUP_SHOW_MORE', 'Show %d more'),
                                    'collapse' => Base::lng('UI_NOTIFICATION_GROUP_COLLAPSE', 'Collapse')
                            ]
                    ];
                    $stackConfigHtml = Base::h(json_encode($stackConfig), false);
                    $visibleBehindInitial = min(max(0, $groupCount - 1), (int)$stackConfig['maxPeek']);
                    $peekOffsetUnits = 3;
                    $collapsedUnitsInitial = 26 + ($visibleBehindInitial * $peekOffsetUnits);
                    $collapsedStackStyle = 'height:calc(var(--spacing) * ' . $collapsedUnitsInitial . ');';
                    ?>

                    <section class="notification-group"
                             data-severity="<?= Base::h($bucket) ?>"
                             x-data="notificationGroup(<?= $stackConfigHtml ?>)"
                             x-show="hasItems"
                             x-transition:leave="transition ease-in duration-150"
                             x-transition:leave-start="opacity-100"
                             x-transition:leave-end="opacity-0"
                    >
                        <div class="<?= Base::h($meta['headerClass']) ?> min-w-0 gap-2">
                            <span class="truncate"><?= Base::h($meta['label']) ?></span>
                            <div class="flex min-w-0 items-center gap-2">
                                <span class="<?= Base::h($meta['badgeClass']) ?>" x-text="itemIds.length"><?= $groupCount ?></span>
                                <template x-if="expanded && itemIds.length > 1">
                                    <button type="button"
                                            class="notification-group__toggle min-w-0 max-w-full transition-[color,transform] duration-200 ease-out-back-xs"
                                            @click.stop="dismissAllInGroup()"
                                            title="<?= Base::h(Base::lng('UI_DISMISS_ALL_IN_GROUP', 'Dismiss all in group')) ?>"
                                    >
                                        <span class="block min-w-0 max-w-24 truncate sm:max-w-40"><?= Base::h(Base::lng('UI_DISMISS_ALL_IN_GROUP', 'Dismiss all in group')) ?></span>
                                        <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" class="size-3.5">
                                            <path fill-rule="evenodd" d="M4.22 4.22a.75.75 0 0 1 1.06 0L10 8.94l4.72-4.72a.75.75 0 1 1 1.06 1.06L11.06 10l4.72 4.72a.75.75 0 1 1-1.06 1.06L10 11.06l-4.72 4.72a.75.75 0 1 1-1.06-1.06L8.94 10 4.22 5.28a.75.75 0 0 1 0-1.06Z" clip-rule="evenodd"/>
                                        </svg>
                                    </button>
                                </template>
                                <template x-if="itemIds.length > 1">
                                    <button type="button"
                                            class="notification-group__toggle min-w-0 max-w-full transition-[color,transform] duration-200 ease-out-back-xs"
                                            @click="toggle()"
                                            :aria-expanded="expanded.toString()"
                                            :title="currentLabel"
                                    >
                                        <span class="block min-w-0 max-w-24 truncate sm:max-w-40" x-text="currentLabel"></span>
                                        <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor"
                                             class="size-3.5 transition-transform duration-200 ease-out-back-sm"
                                             :class="expanded ? 'rotate-180' : ''">
                                            <path fill-rule="evenodd"
                                                  d="M5.23 7.21a.75.75 0 0 1 1.06.02L10 11.168l3.71-3.938a.75.75 0 1 1 1.08 1.04l-4.25 4.5a.75.75 0 0 1-1.08 0l-4.25-4.5a.75.75 0 0 1 .02-1.06Z"
                                                  clip-rule="evenodd"/>
                                        </svg>
                                    </button>
                                </template>
                            </div>
                        </div>

                        <div class="notification-list relative overflow-hidden transition-[height] will-change-[height] motion-reduce:transition-none"
                             style="<?= Base::h($collapsedStackStyle) ?>"
                             :class="expanded ? 'duration-200 ease-out-back-sm' : 'duration-60'"
                             :style="stackStyle()"
                        >
                            <?php foreach ($groupedNotifications[$bucket] as $index => $n): ?>
                                <?php
                                $dateAddedRaw = trim((string)($n['date_added'] ?? ''));
                                $timestamp = ($dateAddedRaw !== '') ? strtotime($dateAddedRaw) : false;
                                $dateIso = $timestamp ? date('c', $timestamp) : '';
                                $nIdJs = Base::h(json_encode($n['id']), false);
                                $maxPeek = (int)$stackConfig['maxPeek'];
                                $interactiveInitial = ($index === 0 || $index <= $maxPeek);
                                $isCollapsedPeekInitial = ($groupCount > 1 && $index <= $maxPeek);
                                $initialCardClass = 'absolute inset-x-0 top-0 '
                                        . ($interactiveInitial ? 'pointer-events-auto' : 'pointer-events-none')
                                        . ($isCollapsedPeekInitial ? ' cursor-pointer' : '');
                                $peekIndex = min($index, $maxPeek);
                                $initialY = ($index === 0) ? 0 : ($peekIndex * $peekOffsetUnits);
                                $initialScale = ($index === 0) ? 1 : (1 - ($peekIndex * 0.035));
                                $initialOpacity = ($index <= $maxPeek) ? 1 : 0;
                                $initialCardStyle = 'position:absolute;left:0;right:0;top:0;z-index:' . (30 - $index)
                                        . ';opacity:' . $initialOpacity
                                        . ';transform:translateY(calc(var(--spacing) * ' . $initialY . ')) scale(' . number_format($initialScale, 3, '.', '') . ');transform-origin:top center;';
                                $learnMoreAttrs = [
                                        '@click.stop' => '$event.stopPropagation()',
                                ];
                                if (($n['link_type'] ?? '') === 'I') {
                                    $learnMoreAttrs = [
                                            '@click.prevent.stop' => "\$dispatch('mb:navigate', { active: " . json_encode((string)$n['link']) . ' })',
                                    ];
                                }
                                ?>
                                <div class="notification-list__item group transition-[transform,opacity] will-change-[transform,opacity] motion-reduce:transition-none <?= Base::h($initialCardClass) ?>"
                                     id="notification-<?= $n['id'] ?>"
                                     style="<?= Base::h($initialCardStyle) ?>"
                                     x-show="itemIds.includes(<?= $nIdJs ?>)"
                                     @click="expandFromPeek(<?= $nIdJs ?>, $event)"
                                     :class="`${cardClass(<?= $nIdJs ?>)} ${isLeaving(<?= $nIdJs ?>) ? 'opacity-0 pointer-events-none' : 'opacity-100'} ${expanded ? 'duration-200 ease-out-back-sm' : 'duration-60 '}`"
                                     :style="cardStyle(<?= $nIdJs ?>)"
                                >
                                    <div class="notification-card-shell overflow-hidden">
                                        <div class="<?= Base::h($meta['cardClass']) ?> h-26 overflow-hidden">
                                            <div class="relative flex h-full items-start gap-3 pr-2 transition-opacity duration-200"
                                                 :class="hideInner(<?= $nIdJs ?>) ? 'opacity-0' : 'opacity-100'"
                                            >
                                                <div class="absolute -right-3 -top-3 z-20 opacity-0 transition-opacity duration-150 pointer-events-none group-hover:opacity-100 group-focus-within:opacity-100"
                                                     :class="hideInner(<?= $nIdJs ?>) ? 'hidden' : ''"
                                                >
                                                    <div class="pointer-events-none absolute inset-y-0 right-0 w-14 rounded-tr-xl bg-gradient-to-l from-white/95 via-white/75 to-transparent"></div>
                                                    <div class="pointer-events-none absolute -inset-1 rounded-2xl bg-white/80 blur-xl" ></div>
                                                <?= Button::render('', [
                                                        'variant' => 'ghost',
                                                        'size' => 'md',
                                                        'icon' => Base::SVG_X_MARK,
                                                        'class' => 'relative pointer-events-auto rounded-xl bg-white/75 text-secondary hover:text-primary backdrop-blur-sm focus:ring-0! z-10',
                                                        'attrs' => [
                                                                'hx-post' => Router::url('notification_dismiss', ['id' => $n['id']]),
                                                                'hx-swap' => 'none',
                                                                'data-dismiss-id' => (string)$n['id'],
                                                                '@click' => "\$event.preventDefault(); \$event.stopPropagation(); dismiss($nIdJs); \$dispatch('notification-dismissed-optimistic', { severity: " . (int)$n['severity'] . " })",
                                                                '@htmx:response-error' => "\$dispatch('notifications-refresh')",
                                                                'data-no-local-loader' => 'true',
                                                                'data-no-global-loader' => 'true',
                                                                'title' => Base::lng('UI_DISMISS', 'Dismiss'),
                                                        ],
                                                ]) ?>
                                                </div>
                                                <div class="<?= Base::h($meta['iconClass']) ?> self-start mt-0.5">
                                                    <?= Base::SVG_BELL ?>
                                                </div>
                                                <div class="flex h-full flex-1 min-w-0 flex-col overflow-hidden py-0.5">
                                                    <div class="flex items-start justify-between gap-2 min-w-0">
                                                        <h4 class="text-sm font-semibold leading-snug tracking-tight truncate <?= Base::h($meta['titleClass']) ?>"><?= Base::h($n['title']) ?></h4>
                                                        <?php if ($dateIso !== ''): ?>
                                                            <time datetime="<?= Base::h($dateIso) ?>"
                                                                  title="<?= Base::h($dateAddedRaw) ?>"
                                                                  class="notification-time transition-opacity duration-150 group-hover:opacity-0 <?= Base::h($meta['timeClass']) ?>"
                                                                  x-data="{ date: new Date('<?= Base::h($dateIso) ?>') }"
                                                                  x-timeago="date">...</time>
                                                        <?php endif; ?>
                                                    </div>
                                                    <p class="text-xs mt-0.5 line-clamp-3 leading-tight tracking-tight <?= Base::h($meta['summaryClass']) ?>"><?= Base::h($n['notification_summary']) ?></p>
                                                </div>

                                                <?php if ($n['link']): ?>
                                                    <div class="absolute bottom-0 right-0 z-20 flex items-end justify-end opacity-0 transition-opacity duration-150 pointer-events-none group-hover:opacity-100 group-focus-within:opacity-100"
                                                         :class="hideInner(<?= $nIdJs ?>) ? 'hidden' : ''"
                                                    >
                                                        <div class="pointer-events-none absolute inset-y-0 right-0 w-28 "></div>
                                                        <div class="pointer-events-none absolute -inset-1 rounded-full bg-white blur-xl"></div>
                                                        <?= Button::render(Base::lng('UI_NOTIFICATION_LEARN_MORE', 'Learn more') . ' ?', [
                                                                'as' => 'a',
                                                                'href' => $n['link'],
                                                                'variant' => 'secondary',
                                                                'rounded' => 'full',
                                                                'size' => 'xs',
                                                                'class' => 'relative pointer-events-auto   z-10',
                                                                'attrs' => $learnMoreAttrs,
                                                        ]) ?>
                                                    </div>
                                                <?php endif; ?>
                                            </div>
                                        </div>
                                    </div>
                                </div>
                            <?php endforeach; ?>
                        </div>
                    </section>
                <?php endforeach; ?>

            </div>
            <!-- Loading Skeleton -->
            <div x-show="loading"
                 x-cloak
                 class="col-start-1 row-start-1 space-y-3 pb-4"
            >
                <?php for ($i = 0; $i < min(3, max(1, count($notifications))); $i++): ?>
                    <div class="animate-pulse flex gap-3 p-3 border border-divider rounded-xl">
                        <div class="rounded-full bg-muted h-5 w-5"></div>
                        <div class="flex-1 space-y-2">
                            <div class="h-4 bg-muted rounded w-3/4"></div>
                            <div class="h-3 bg-muted rounded w-5/6"></div>
                        </div>
                    </div>
                <?php endfor; ?>
            </div>

            <!-- All caught up message -->
            <div x-show="count === 0 && !loading"
                 x-cloak
                 x-transition:enter="transition ease-out duration-300 delay-200"
                 x-transition:enter-start="opacity-0"
                 x-transition:enter-end="opacity-100"
                 class="col-start-1 row-start-1"
            >
                <?= \Components\Ui\EmptyState::simple([
                        'icon' => Base::SVG_BELL,
                        'title' => Base::lng('UI_NO_NOTIFICATIONS', 'All caught up!'),
                        'text' => Base::lng('UI_NO_NOTIFICATIONS_DESC', 'No new notifications at the moment.')
                ]) ?>
            </div>
        </div>

        <div class="mt-6 flex items-center justify-center gap-1.5 text-xs text-secondary/55 pb-2">
            <span>
                <?= Base::h(Base::lng('UI_LAST_CHECKED_PREFIX', 'Last checked')) ?>
                <time datetime="<?= Base::h($lastCheckedIso) ?>"
                      title="<?= Base::h($lastCheckedRaw, false) ?>"
                      x-data="{ date: new Date('<?= Base::h($lastCheckedIso) ?>') }"
                      @notifications-polled.window="date = new Date(($event.detail && $event.detail.checked_at) ? $event.detail.checked_at : new Date().toISOString())"
                      x-timeago="date">...</time>
            </span>
            <button type="button"
                    @click="refreshCurrentTab()"
                    class="group relative flex size-5 items-center justify-center hover:text-primary transition-all active:scale-95"
                    title="<?= Base::h(Base::lng('UI_REFRESH', 'Refresh')) ?>">
                <div class="[&_svg]:size-3.5" :class="isRefreshing ? 'animate-spin' : ''">
                    <?= Base::SVG_REFRESH ?>
                </div>
            </button>
        </div>
    </div>
</div>
