function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : String(i); }
function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); }
function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; }
function _iterableToArrayLimit(r, l) { var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (null != t) { var e, n, i, u, a = [], f = !0, o = !1; try { if (i = (t = t.call(r)).next, 0 === l) { if (Object(t) !== t) return; f = !1; } else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0); } catch (r) { o = !0, n = r; } finally { try { if (!f && null != t.return && (u = t.return(), Object(u) !== u)) return; } finally { if (o) throw n; } } return a; } }
function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
/**
 * 时段网格
 * 核心交互组件：横轴为时间（每 30 分钟一格），纵轴为资源/场地
 * 数据来自 PisellOS venueBooking.getTimeSlotGrid()
 *
 * 结构：
 * - 表头段（sticky）：外层 overflow-hidden 作为窗口，内层 grid 用 transform 跟随
 *   表体横向 scrollLeft。纵向 sticky 相对外层页面滚动容器生效，实现吸顶。
 * - 表体段：保留 overflow-x: auto、横向拖拽、点击选中/取消时段、切换日期自动滚到
 *   首个可用时段。
 * - 同步方向单向：body.scrollLeft -> headerInner.style.transform。
 */
import React, { useEffect, useMemo, useRef, useCallback, useState } from 'react';
import { Iconfont, PisellText } from '@pisell/materials';
import { locales, isIos } from '@pisell/utils';
import { useVenueBookingContext } from "../../../context";
import { isSlotSelected as checkSlotSelected, isSlotDisabledBySelection, useVenueBookingSymbol } from "../../../hooks";
import { formatHourHeader, isHourBoundary, buildHourGroups, buildSlotPriceInfo, getPriceColor, getSlotTag, getColumnTag, getTimeMetaFromGrid, getResourceCourtMeta, getTableGridStyle, getFirstAvailableSlotIndex, FIRST_COLUMN_WIDTH } from "../../../utils";
export default function TimeGrid() {
  var symbol = useVenueBookingSymbol();
  var _useVenueBookingConte = useVenueBookingContext(),
    viewModel = _useVenueBookingConte.viewModel,
    venueBookingModule = _useVenueBookingConte.venueBookingModule,
    toggleSlot = _useVenueBookingConte.toggleSlot,
    filter = _useVenueBookingConte.filter,
    search = _useVenueBookingConte.search,
    isGridLoading = _useVenueBookingConte.isGridLoading;
  var grid = viewModel.timeSlotGrid;
  var timeLabels = (grid === null || grid === void 0 ? void 0 : grid.timeLabels) || [];
  var resources = (grid === null || grid === void 0 ? void 0 : grid.resources) || [];
  var hourGroups = useMemo(function () {
    return buildHourGroups(timeLabels);
  }, [timeLabels]);
  var tableGridStyle = useMemo(function () {
    return getTableGridStyle(timeLabels.length);
  }, [timeLabels.length]);

  /**
   * iOS 需要 overscroll-behavior: none 阻止 body 橡皮筋回弹导致的异常；
   * 桌面端保留 Y 方向的 scroll chaining，使鼠标悬停在此区域时仍能上下滚页面。
   */
  var isIosDevice = useMemo(function () {
    if (typeof navigator === 'undefined') return false;
    return isIos();
  }, []);
  var scrollerOverscrollStyle = useMemo(function () {
    return isIosDevice ? {
      overscrollBehavior: 'none'
    } : {
      overscrollBehaviorX: 'none',
      overscrollBehaviorY: 'auto'
    };
  }, [isIosDevice]);
  var visibleResources = useMemo(function () {
    return resources.filter(function (resource) {
      var hitType = filter === 'ALL' || resource.productTitle === filter;
      var hitSearch = !search || resource.resourceName.toLowerCase().includes(search.toLowerCase());
      return hitType && hitSearch;
    });
  }, [filter, search, resources]);
  var scrollTableRef = useRef(null);
  var headerInnerRef = useRef(null);
  /**
   * Courts 左上角单元格。由于表头外层 overflow-hidden 不是滚动容器，
   * sticky 对其无效；通过反向 transform 抵消 headerInner 的横向位移，
   * 使其在横向滚动时视觉上固定在左侧。
   */
  var headerFixedColRef = useRef(null);
  var dragStateRef = useRef({
    isDragging: false,
    pointerId: null,
    startX: 0,
    startY: 0,
    startScrollLeft: 0,
    moved: false
  });

  /**
   * 将表头内层位移同步到 body 的 scrollLeft，保持列对齐。
   * 同时对 Courts 单元格施加正向 transform 抵消父级位移，横向"钉"在左侧。
   */
  var applyHeaderTransform = useCallback(function (scrollLeft) {
    if (headerInnerRef.current) {
      headerInnerRef.current.style.transform = "translateX(".concat(-scrollLeft, "px)");
    }
    if (headerFixedColRef.current) {
      headerFixedColRef.current.style.transform = "translateX(".concat(scrollLeft, "px)");
    }
  }, []);
  function syncHeader(e) {
    applyHeaderTransform(e.currentTarget.scrollLeft);
  }

  // 切换日期/首次加载完成时自动滚动到第一个可用时段（留 1 格前置空间便于用户感知上下文）。
  // 依赖 isGridLoading：骨架屏阶段真实 table DOM 卸载，ref 为 null；
  // 骨架屏结束时重新触发，此时新 DOM 已挂载且布局完成，scrollWidth 可靠。
  useEffect(function () {
    if (isGridLoading) return;
    var scroller = scrollTableRef.current;
    if (!scroller || !timeLabels.length || !grid) return;
    var firstAvailableIndex = getFirstAvailableSlotIndex(grid);
    if (firstAvailableIndex <= 0) {
      // 无需滚动时也要对齐首帧表头位置（可能从横向位移状态切回来）
      applyHeaderTransform(scroller.scrollLeft);
      return;
    }
    var slotAreaWidth = Math.max(0, scroller.scrollWidth - FIRST_COLUMN_WIDTH);
    var slotWidth = timeLabels.length ? slotAreaWidth / timeLabels.length : 0;
    var scrollToIndex = Math.max(0, firstAvailableIndex - 1);
    var targetLeft = Math.max(0, scrollToIndex * slotWidth);
    scroller.scrollTo({
      left: targetLeft,
      behavior: 'smooth'
    });
    // smooth 滚动不会立即触发 onScroll 到目标值，先手动同步一次避免首帧错位
    applyHeaderTransform(targetLeft);
  }, [grid === null || grid === void 0 ? void 0 : grid.date, timeLabels.length, isGridLoading, applyHeaderTransform]);

  // 横向拖拽滚动
  useEffect(function () {
    var scroller = scrollTableRef.current;
    if (!scroller) return undefined;
    function onPointerDown(e) {
      if (e.pointerType === 'mouse' && e.button !== 0) return;
      if (e.target instanceof Element && e.target.closest('[data-cart-button="true"], input, textarea')) return;
      dragStateRef.current = {
        isDragging: true,
        pointerId: e.pointerId,
        startX: e.clientX,
        startY: e.clientY,
        startScrollLeft: scroller.scrollLeft,
        moved: false
      };
      // 不在 pointerdown 时立即 setPointerCapture，否则会拦截 button 的 onClick 事件。
      // 等确认是真实拖拽（移动超过阈值）后再捕获。
    }
    function onPointerMove(e) {
      var state = dragStateRef.current;
      if (!state.isDragging || state.pointerId !== e.pointerId) return;
      var dx = e.clientX - state.startX;
      var dy = e.clientY - state.startY;
      if (Math.abs(dx) > 6 || Math.abs(dy) > 6) {
        var _hasPointerCapture, _ref;
        state.moved = true;
        if (!((_hasPointerCapture = (_ref = scroller).hasPointerCapture) !== null && _hasPointerCapture !== void 0 && _hasPointerCapture.call(_ref, e.pointerId))) {
          var _setPointerCapture, _ref2;
          (_setPointerCapture = (_ref2 = scroller).setPointerCapture) === null || _setPointerCapture === void 0 || _setPointerCapture.call(_ref2, e.pointerId);
        }
      }
      if (Math.abs(dx) >= Math.abs(dy)) {
        e.preventDefault();
        scroller.scrollLeft = state.startScrollLeft - dx;
        // 拖拽期间直接同步，避免 onScroll 事件节流导致表头滞后
        applyHeaderTransform(scroller.scrollLeft);
      }
    }
    function endDrag(e) {
      var _releasePointerCaptur, _ref3;
      var state = dragStateRef.current;
      if (state.pointerId !== e.pointerId) return;
      dragStateRef.current.isDragging = false;
      dragStateRef.current.pointerId = null;
      (_releasePointerCaptur = (_ref3 = scroller).releasePointerCapture) === null || _releasePointerCaptur === void 0 || _releasePointerCaptur.call(_ref3, e.pointerId);
    }
    scroller.addEventListener('pointerdown', onPointerDown);
    scroller.addEventListener('pointermove', onPointerMove, {
      passive: false
    });
    scroller.addEventListener('pointerup', endDrag);
    scroller.addEventListener('pointercancel', endDrag);
    return function () {
      scroller.removeEventListener('pointerdown', onPointerDown);
      scroller.removeEventListener('pointermove', onPointerMove);
      scroller.removeEventListener('pointerup', endDrag);
      scroller.removeEventListener('pointercancel', endDrag);
    };
  }, [applyHeaderTransform]);

  // overflow-x: auto 会使该容器成为滚动容器，浏览器默认将 wheel 事件优先交给它处理，
  // 导致纵向滚动被静默吞掉、页面无法上下滚动。
  // 此处拦截纵向主导的 wheel 事件，转发给 window，还原正常的页面滚动体验。
  useEffect(function () {
    var scroller = scrollTableRef.current;
    if (!scroller) return undefined;
    function onWheel(e) {
      // 仅纵向滚动意图（deltaY 占主导）才转发给页面；
      // 横向滚动（含 shift+scroll）不干预，由 overflow-x: auto 正常处理。
      if (Math.abs(e.deltaY) > Math.abs(e.deltaX)) {
        e.preventDefault();
        window.scrollBy({
          top: e.deltaY,
          behavior: 'instant'
        });
      }
    }
    scroller.addEventListener('wheel', onWheel, {
      passive: false
    });
    return function () {
      return scroller.removeEventListener('wheel', onWheel);
    };
  }, []);

  /** 记录哪些多商品资源是展开态（resourceId -> expanded） */
  var _useState = useState({}),
    _useState2 = _slicedToArray(_useState, 2),
    expandedResources = _useState2[0],
    setExpandedResources = _useState2[1];
  var toggleExpanded = useCallback(function (resourceId) {
    setExpandedResources(function (prev) {
      return _objectSpread(_objectSpread({}, prev), {}, _defineProperty({}, String(resourceId), !prev[String(resourceId)]));
    });
  }, []);
  function handleSlotClick(resourceId, productId, slot) {
    if (dragStateRef.current.moved) {
      dragStateRef.current.moved = false;
      return;
    }
    if (slot.status !== 'available') return;
    toggleSlot(resourceId, productId, slot);
  }

  // 网格加载中（周数据拉取 / 切换日期过渡 / 数据未就绪）：渲染骨架屏
  if (isGridLoading || !grid || !timeLabels.length) {
    return /*#__PURE__*/React.createElement(TimeGridSkeleton, null);
  }
  return /*#__PURE__*/React.createElement("div", {
    className: "relative"
  }, /*#__PURE__*/React.createElement("div", {
    className: "sticky z-30 overflow-hidden bg-[#fff7f7]",
    style: {
      top: 'var(--vb-grid-sticky-top, 0px)'
    }
  }, /*#__PURE__*/React.createElement("div", {
    ref: headerInnerRef,
    className: "grid border-b border-black/6",
    style: _objectSpread(_objectSpread({}, tableGridStyle), {}, {
      willChange: 'transform'
    }),
    key: "".concat(grid.date, "-header")
  }, /*#__PURE__*/React.createElement("div", {
    ref: headerFixedColRef,
    className: "relative z-20 row-span-2 flex items-center gap-2 border-r border-black/6 bg-[#fff7f7] px-2 py-4 font-bold text-zinc-900 shadow-[10px_0_16px_-14px_rgba(0,0,0,0.2)] md:px-4",
    style: {
      willChange: 'transform'
    }
  }, /*#__PURE__*/React.createElement(Iconfont, {
    type: "pisell2-clock",
    style: {
      fontSize: 16,
      color: 'var(--vb-primary, #ea1018)'
    }
  }), /*#__PURE__*/React.createElement("span", null, locales.getText('pisell2.venue.label.courts') || '场地')), hourGroups.map(function (slot, hourIdx) {
    var slotIndex = timeLabels.indexOf(slot);
    var nextSlotIndex = slotIndex + 1;
    var timeMeta1 = getTimeMetaFromGrid(resources, slotIndex);
    var timeMeta2 = nextSlotIndex < timeLabels.length ? getTimeMetaFromGrid(resources, nextSlotIndex) : timeMeta1;
    var hourSoldOut = timeMeta1.soldOut && timeMeta2.soldOut;
    return /*#__PURE__*/React.createElement("div", {
      key: slot,
      className: "col-span-2 px-1 py-3 text-center text-[12px] font-bold md:text-sm ".concat(hourSoldOut ? 'bg-zinc-100 text-zinc-400' : 'text-zinc-700'),
      style: {
        borderLeft: '1px solid rgba(0,0,0,0.08)'
      }
    }, formatHourHeader(slot));
  }), timeLabels.map(function (slot, slotIndex) {
    var timeMeta = getTimeMetaFromGrid(resources, slotIndex);
    var headerTag = getColumnTag(resources, slotIndex);
    return /*#__PURE__*/React.createElement("div", {
      key: "".concat(slot, "-tag"),
      className: "px-1 py-1.5 text-center ".concat(timeMeta.soldOut ? 'bg-zinc-100 text-zinc-400' : 'bg-white/55'),
      style: {
        borderTop: '1px solid rgba(0,0,0,0.04)',
        borderLeft: isHourBoundary(slot) ? '1px solid rgba(0,0,0,0.08)' : '1px solid rgba(0,0,0,0.03)'
      }
    }, headerTag && !timeMeta.soldOut ? /*#__PURE__*/React.createElement("span", {
      className: "inline-flex rounded-full px-1.5 py-0.5 text-[8px] font-semibold ring-1 md:text-[9px] ".concat(headerTag.className)
    }, headerTag.text) : null, timeMeta.soldOut ? /*#__PURE__*/React.createElement("div", {
      className: "mt-1 text-[10px] font-bold text-zinc-400"
    }, locales.getText('pisell2.venue.label.sold.out') || '已满') : null, !timeMeta.soldOut && timeMeta.fewLeft ? /*#__PURE__*/React.createElement("div", {
      className: "mt-1 text-[10px] font-bold",
      style: {
        color: 'var(--vb-primary)'
      }
    }, locales.getText('pisell2.venue.label.few.left') || '即将满') : null, !timeMeta.soldOut && !timeMeta.fewLeft && !headerTag ? /*#__PURE__*/React.createElement("div", {
      className: "mt-1 text-[10px] font-bold text-zinc-500"
    }, locales.getText('pisell2.venue.label.bookable') || '充足') : null);
  }))), /*#__PURE__*/React.createElement("div", {
    ref: scrollTableRef,
    onScroll: syncHeader,
    className: "max-w-full overflow-x-auto cursor-grab select-none touch-pan-y active:cursor-grabbing",
    style: _objectSpread({
      WebkitOverflowScrolling: 'touch'
    }, scrollerOverscrollStyle)
  }, /*#__PURE__*/React.createElement("div", {
    className: "w-full",
    key: grid.date
  }, visibleResources.map(function (resource) {
    var courtMeta = getResourceCourtMeta(resource);
    var isMultiProduct = !!resource.hasMultipleProducts && Array.isArray(resource.products);
    var expanded = !!expandedResources[String(resource.resourceId)];
    return /*#__PURE__*/React.createElement(React.Fragment, {
      key: "".concat(resource.resourceId, "-").concat(grid.date)
    }, /*#__PURE__*/React.createElement("div", {
      className: "grid border-b border-black/6",
      style: tableGridStyle
    }, /*#__PURE__*/React.createElement("div", {
      className: "sticky left-0 z-10 border-r border-black/6 px-2 py-2 shadow-[10px_0_16px_-14px_rgba(0,0,0,0.2)] md:px-4 ".concat(courtMeta.soldOut ? 'bg-zinc-50' : 'bg-white')
    }, /*#__PURE__*/React.createElement("div", {
      className: "flex items-start justify-between gap-2"
    }, /*#__PURE__*/React.createElement("div", {
      className: "flex items-center gap-1.5"
    }, isMultiProduct ? /*#__PURE__*/React.createElement("button", {
      type: "button",
      "data-cart-button": "true",
      onClick: function onClick(e) {
        e.stopPropagation();
        toggleExpanded(resource.resourceId);
      },
      className: "flex h-5 w-5 items-center justify-center rounded text-zinc-500 hover:bg-black/5",
      "aria-label": expanded ? 'collapse' : 'expand'
    }, /*#__PURE__*/React.createElement(Iconfont, {
      type: expanded ? 'pisell2-chevron-down' : 'pisell2-chevron-right',
      style: {
        fontSize: 12
      }
    })) : null, /*#__PURE__*/React.createElement("div", {
      className: "text-[13px] font-extrabold leading-5 md:text-[15px] ".concat(courtMeta.soldOut ? 'text-zinc-400' : 'text-zinc-900')
    }, resource.resourceName)))), resource.slots.map(function (slot, slotIndex) {
      var isAvailable = slot.status === 'available';
      var isUnavailable = slot.status === 'occupied' || slot.status === 'past' || slot.status === 'unavailable';
      var timeLabel = timeLabels[slotIndex] || '';
      var priceInfo = buildSlotPriceInfo(slot);
      var priceClass = getPriceColor(_objectSpread(_objectSpread({}, priceInfo), {}, {
        courtType: resource.productTitle
      }));
      var tag = getSlotTag(priceInfo);
      var tagText = (tag === null || tag === void 0 ? void 0 : tag.text) === 'pisell2.venue.label.promo' ? locales.getText('pisell2.venue.label.promo') || '促销' : (tag === null || tag === void 0 ? void 0 : tag.text) === 'pisell2.venue.label.off.peak' ? locales.getText('pisell2.venue.label.off.peak') || '非高峰' : null;

      // 单商品：保持原选中/禁用判定；多商品：外层 slot 不可直接选，点击仅触发展开
      var productIdForSingle = resource.productId;
      var disabledBySelection = !isMultiProduct && !isUnavailable ? isSlotDisabledBySelection(venueBookingModule, {
        resourceId: resource.resourceId,
        productId: productIdForSingle,
        startTime: slot.startTime
      }) : false;
      // 跨行互斥禁用视觉上与 unavailable 一致（灰底 + ×），用户能明确看到冲突
      var isBlocked = isUnavailable || disabledBySelection;
      var selected = !isMultiProduct && isAvailable && checkSlotSelected(venueBookingModule, resource.resourceId, slot.startTime, productIdForSingle);
      var interactive = !isMultiProduct && !isBlocked;
      var showPlusLabel = isMultiProduct && !isBlocked;
      return /*#__PURE__*/React.createElement("button", {
        "data-slot-button": "true",
        key: "".concat(resource.resourceId, "-outer-").concat(slot.startTime),
        onClick: function onClick() {
          if (isMultiProduct) {
            if (isBlocked) return;
            toggleExpanded(resource.resourceId);
            return;
          }
          if (isBlocked) return;
          handleSlotClick(resource.resourceId, productIdForSingle, slot);
        },
        disabled: isBlocked,
        className: "px-1 py-2 text-center transition md:px-2 ".concat(isBlocked ? 'cursor-not-allowed bg-zinc-100 text-zinc-400' : selected ? 'text-white' : 'bg-white hover:bg-[#fff6f6]'),
        style: _objectSpread({
          borderLeft: isHourBoundary(timeLabel) ? '1px solid rgba(0,0,0,0.08)' : '1px solid rgba(0,0,0,0.03)',
          borderBottom: '1px solid rgba(0,0,0,0.04)'
        }, selected && interactive ? {
          backgroundColor: 'var(--vb-primary)'
        } : null)
      }, isBlocked ? /*#__PURE__*/React.createElement("div", {
        className: "flex flex-col items-center justify-center gap-1 text-zinc-400"
      }, /*#__PURE__*/React.createElement("div", {
        className: "text-lg font-bold leading-none"
      }, "\xD7")) : selected ? /*#__PURE__*/React.createElement("div", {
        className: "space-y-0.5"
      }, /*#__PURE__*/React.createElement(PisellText.Amount, {
        value: Number(slot.price || 0),
        symbol: symbol,
        precision: 2,
        showCurrencySymbol: true,
        className: "text-[13px] font-extrabold leading-4 text-white md:text-sm"
      })) : /*#__PURE__*/React.createElement("div", {
        className: "space-y-0.5"
      }, /*#__PURE__*/React.createElement("div", {
        className: "flex items-baseline justify-center gap-0.5"
      }, /*#__PURE__*/React.createElement(PisellText.Amount, {
        value: Number(slot.price || 0),
        symbol: symbol,
        precision: 2,
        showCurrencySymbol: true,
        hideDecimalForWholeNumbers: true,
        className: "text-[13px] font-normal leading-4 ".concat(priceClass, " md:text-sm")
      }), showPlusLabel ? /*#__PURE__*/React.createElement("span", {
        className: "text-[13px] font-semibold leading-4 ".concat(priceClass, " md:text-sm")
      }, "+") : null), tag ? /*#__PURE__*/React.createElement("div", {
        className: "inline-flex rounded-full px-1.5 py-0 text-[8px] font-semibold leading-4 ring-1 md:text-[9px] ".concat(tag.className)
      }, tagText) : null));
    })), isMultiProduct && expanded && resource.products.map(function (subRow) {
      return /*#__PURE__*/React.createElement("div", {
        key: "".concat(resource.resourceId, "-sub-").concat(subRow.productId),
        className: "grid border-b border-black/6 bg-zinc-50/60",
        style: tableGridStyle
      }, /*#__PURE__*/React.createElement("div", {
        className: "sticky left-0 z-10 border-r border-black/6 bg-zinc-50/60 px-2 py-2 pl-8 shadow-[10px_0_16px_-14px_rgba(0,0,0,0.2)] md:px-4 md:pl-10"
      }, /*#__PURE__*/React.createElement("div", {
        className: "text-[12px] font-semibold leading-5 text-zinc-700 md:text-[13px]"
      }, subRow.productTitle)), subRow.slots.map(function (slot, slotIndex) {
        var isAvailable = slot.status === 'available';
        var isUnavailable = slot.status === 'occupied' || slot.status === 'past' || slot.status === 'unavailable';
        var timeLabel = timeLabels[slotIndex] || '';
        var disabledBySelection = !isUnavailable && isSlotDisabledBySelection(venueBookingModule, {
          resourceId: resource.resourceId,
          productId: subRow.productId,
          startTime: slot.startTime
        });
        var isBlocked = isUnavailable || disabledBySelection;
        var selected = isAvailable && checkSlotSelected(venueBookingModule, resource.resourceId, slot.startTime, subRow.productId);
        var interactive = !isBlocked;
        var priceInfo = buildSlotPriceInfo(slot);
        var priceClass = getPriceColor(_objectSpread(_objectSpread({}, priceInfo), {}, {
          courtType: subRow.productTitle
        }));
        return /*#__PURE__*/React.createElement("button", {
          "data-slot-button": "true",
          key: "".concat(resource.resourceId, "-").concat(subRow.productId, "-").concat(slot.startTime),
          onClick: function onClick() {
            if (!interactive) return;
            handleSlotClick(resource.resourceId, subRow.productId, slot);
          },
          disabled: !interactive,
          className: "px-1 py-2 text-center transition md:px-2 ".concat(isBlocked ? 'cursor-not-allowed bg-zinc-100 text-zinc-400' : selected ? 'text-white' : 'bg-white hover:bg-[#fff6f6]'),
          style: _objectSpread({
            borderLeft: isHourBoundary(timeLabel) ? '1px solid rgba(0,0,0,0.08)' : '1px solid rgba(0,0,0,0.03)',
            borderBottom: '1px solid rgba(0,0,0,0.04)'
          }, selected && interactive ? {
            backgroundColor: 'var(--vb-primary)'
          } : null)
        }, isBlocked ? /*#__PURE__*/React.createElement("div", {
          className: "flex flex-col items-center justify-center gap-1 text-zinc-400"
        }, /*#__PURE__*/React.createElement("div", {
          className: "text-lg font-bold leading-none"
        }, "\xD7")) : /*#__PURE__*/React.createElement("div", {
          className: "space-y-0.5"
        }, /*#__PURE__*/React.createElement(PisellText.Amount, {
          value: Number(slot.price || 0),
          symbol: symbol,
          precision: 2,
          showCurrencySymbol: true,
          hideDecimalForWholeNumbers: true,
          className: "text-[13px] leading-4 ".concat(selected ? 'font-extrabold text-white' : "font-normal ".concat(priceClass), " md:text-sm")
        })));
      }));
    }));
  }))));
}

/**
 * TimeGrid 骨架屏
 * 结构对齐正常态：左侧固定"Courts"列 + 右侧横向时段列
 * 不依赖 grid 数据，避免闪烁；骨架块用 vb-skeleton-shimmer 的光条动画
 */
function TimeGridSkeleton() {
  var SKELETON_ROWS = 5;
  var SKELETON_COLS = 8;
  return /*#__PURE__*/React.createElement("div", {
    className: "relative",
    "aria-busy": "true",
    "aria-live": "polite"
  }, /*#__PURE__*/React.createElement("div", {
    className: "sticky z-30 overflow-hidden bg-[#fff7f7]",
    style: {
      top: 'var(--vb-grid-sticky-top, 0px)'
    }
  }, /*#__PURE__*/React.createElement("div", {
    className: "grid border-b border-black/6",
    style: {
      gridTemplateColumns: "".concat(FIRST_COLUMN_WIDTH, "px repeat(").concat(SKELETON_COLS, ", minmax(90px, 1fr))")
    }
  }, /*#__PURE__*/React.createElement("div", {
    className: "relative z-20 flex items-center gap-2 border-r border-black/6 bg-[#fff7f7] px-2 py-4 font-bold text-zinc-900 shadow-[10px_0_16px_-14px_rgba(0,0,0,0.2)] md:px-4"
  }, /*#__PURE__*/React.createElement(Iconfont, {
    type: "pisell2-clock",
    style: {
      fontSize: 16,
      color: 'var(--vb-primary, #ea1018)'
    }
  }), /*#__PURE__*/React.createElement("span", null, locales.getText('pisell2.venue.label.courts') || '场地')), Array.from({
    length: SKELETON_COLS
  }).map(function (_, idx) {
    return /*#__PURE__*/React.createElement("div", {
      key: "sk-h-".concat(idx),
      className: "relative flex items-center justify-center overflow-hidden px-1 py-3",
      style: {
        borderLeft: '1px solid rgba(0,0,0,0.08)'
      }
    }, /*#__PURE__*/React.createElement("div", {
      className: "h-3 w-10 rounded bg-zinc-200/80"
    }), /*#__PURE__*/React.createElement("span", {
      className: "vb-skeleton-shimmer",
      "aria-hidden": "true"
    }));
  }))), /*#__PURE__*/React.createElement("div", {
    className: "w-full"
  }, Array.from({
    length: SKELETON_ROWS
  }).map(function (_, rowIdx) {
    return /*#__PURE__*/React.createElement("div", {
      key: "sk-row-".concat(rowIdx),
      className: "grid border-b border-black/6",
      style: {
        gridTemplateColumns: "".concat(FIRST_COLUMN_WIDTH, "px repeat(").concat(SKELETON_COLS, ", minmax(90px, 1fr))")
      }
    }, /*#__PURE__*/React.createElement("div", {
      className: "sticky left-0 z-10 border-r border-black/6 bg-white px-2 py-4 shadow-[10px_0_16px_-14px_rgba(0,0,0,0.2)] md:px-4"
    }, /*#__PURE__*/React.createElement("div", {
      className: "relative overflow-hidden"
    }, /*#__PURE__*/React.createElement("div", {
      className: "h-4 w-20 rounded bg-zinc-200/80 md:w-24"
    }), /*#__PURE__*/React.createElement("div", {
      className: "mt-2 h-2.5 w-14 rounded bg-zinc-200/60 md:w-16"
    }), /*#__PURE__*/React.createElement("span", {
      className: "vb-skeleton-shimmer",
      "aria-hidden": "true"
    }))), Array.from({
      length: SKELETON_COLS
    }).map(function (_, colIdx) {
      return /*#__PURE__*/React.createElement("div", {
        key: "sk-cell-".concat(rowIdx, "-").concat(colIdx),
        className: "relative overflow-hidden px-1 py-3",
        style: {
          borderLeft: colIdx % 2 === 0 ? '1px solid rgba(0,0,0,0.08)' : '1px solid rgba(0,0,0,0.03)',
          borderBottom: '1px solid rgba(0,0,0,0.04)',
          backgroundColor: '#fff'
        }
      }, /*#__PURE__*/React.createElement("div", {
        className: "mx-auto h-3 w-10 rounded bg-zinc-200/70 md:h-3.5 md:w-12"
      }), /*#__PURE__*/React.createElement("span", {
        className: "vb-skeleton-shimmer",
        "aria-hidden": "true"
      }));
    }));
  })));
}