403Webshell
Server IP : 173.209.174.21  /  Your IP : 216.73.216.89
Web Server : Apache/2.4.58 (Ubuntu)
System : Linux wcfs-server 6.8.0-124-generic #124-Ubuntu SMP PREEMPT_DYNAMIC Tue May 26 13:00:45 UTC 2026 x86_64
User : nodor ( 1000)
PHP Version : 8.3.6
Disable Function : NONE
MySQL : OFF  |  cURL : ON  |  WGET : ON  |  Perl : ON  |  Python : OFF  |  Sudo : ON  |  Pkexec : OFF
Directory :  /var/www/thelittlebigshow/vendor-reg/vendor_spot_assets/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Command :


[ Back ]     

Current File : /var/www/thelittlebigshow/vendor-reg/vendor_spot_assets/vendor_spots.js
const rows = ['A','B','C','D','E','F','G','H','I','J'];
const cols = [1,2,3,4,5,6];
const walkwaySpots = rows.map(row => `${row}3`);
const bufferSpots = rows.map(row => `${row}6`);

const state = {
  mode: window.SPOT_MAP_MODE || 'vendor',
  vendors: [],
  assignments: [],
  allowedSpots: [],
  selectedVendorId: null,
  selectedSpots: [],
};

const els = {
  grid: document.querySelector('#spotGrid'),
  vendorSelect: document.querySelector('#vendorSelect'),
  vendorDetails: document.querySelector('#vendorDetails'),
  assignmentList: document.querySelector('#assignmentList'),
  openCount: document.querySelector('#openCount'),
  reservedCount: document.querySelector('#reservedCount'),
  neededCount: document.querySelector('#neededCount'),
  saveState: document.querySelector('#saveState'),
  message: document.querySelector('#message'),
  clearSelectionBtn: document.querySelector('#clearSelectionBtn'),
  saveSelectionBtn: document.querySelector('#saveSelectionBtn'),
  printBtn: document.querySelector('#printBtn'),
};

function boot() {
  renderSpots();
  bindEvents();
  loadMap();
}

function bindEvents() {
  els.vendorSelect.addEventListener('change', () => {
    state.selectedVendorId = Number(els.vendorSelect.value);
    loadSelectedVendorAssignments();
    renderAll();
  });
  els.clearSelectionBtn.addEventListener('click', () => {
    state.selectedSpots = [];
    renderAll();
    setMessage(state.mode === 'admin' ? 'Click Save Spots to release this vendor.' : 'Selection cleared.', 'ok');
  });
  els.saveSelectionBtn.addEventListener('click', saveSelection);
  els.printBtn.addEventListener('click', () => window.print());
}

async function loadMap() {
  const response = await fetch('vendor_spot_api.php');
  const data = await response.json();
  if (!data.ok) {
    setMessage(data.message || 'Could not load map.', 'error');
    return;
  }
  state.vendors = data.vendors;
  state.assignments = data.assignments;
  state.allowedSpots = data.allowedSpots;
  state.selectedVendorId = data.currentVendorId || Number(state.vendors[0]?.id || 0);
  renderVendorOptions();
  loadSelectedVendorAssignments();
  renderAll();
  const vendor = getSelectedVendor();
  if (state.mode !== 'admin' && vendor && !isPaid(vendor)) {
    setMessage('Payment is needed before spot selection. Use the payment links in the side panel.', 'error');
  } else {
    setMessage('Choose your spot and save.', 'ok');
  }
}

function renderSpots() {
  const template = document.querySelector('#spotTemplate');
  rows.forEach(row => {
    cols.forEach(col => {
      const spotId = `${row}${col}`;
      const node = template.content.firstElementChild.cloneNode(true);
      node.dataset.spotId = spotId;
      node.title = `${spotId}: ${getDefaultSpotNote(spotId, col) || '10x10 vendor spot'}`;
      node.querySelector('.spot-id').textContent = spotId;
      node.addEventListener('click', () => handleSpotClick(spotId));
      els.grid.appendChild(node);
    });
  });
}

function renderVendorOptions() {
  els.vendorSelect.innerHTML = state.vendors.map(vendor => (
    `<option value="${escapeHtml(vendor.id)}">${escapeHtml(vendor.name)} (${vendor.requested_spots} spot${Number(vendor.requested_spots) === 1 ? '' : 's'})</option>`
  )).join('');
  els.vendorSelect.value = state.selectedVendorId;
}

function loadSelectedVendorAssignments() {
  state.selectedSpots = state.assignments
    .filter(item => Number(item.vendor_id) === Number(state.selectedVendorId))
    .map(item => item.spot_id);
}

function renderAll() {
  const assignmentMap = new Map(state.assignments.map(item => [item.spot_id, item]));
  document.querySelectorAll('.spot').forEach(node => {
    const spotId = node.dataset.spotId;
    const assignment = assignmentMap.get(spotId);
    const blocked = !state.allowedSpots.includes(spotId);
    const selected = state.selectedSpots.includes(spotId);
    node.classList.toggle('blocked', blocked);
    node.classList.toggle('reserved', Boolean(assignment) && !selected);
    node.classList.toggle('selected', selected);
    node.disabled = blocked;
    node.querySelector('.spot-vendor').textContent = getSpotLabel(spotId, assignment);
  });
  renderVendorDetails();
  renderStats();
  renderAssignments();
}

function renderVendorDetails() {
  const vendor = getSelectedVendor();
  if (!vendor) {
    els.vendorDetails.textContent = 'No vendor selected.';
    return;
  }
  const needed = Number(vendor.requested_spots || 0);
  els.vendorDetails.innerHTML = `
    <strong>${escapeHtml(vendor.name)}</strong>
    <div>Vendor ID: ${escapeHtml(vendor.id)}</div>
    <div>${escapeHtml(vendor.category || 'Vendor')} ยท ${needed === 0 ? 'street setup, no park spots' : `needs ${needed} spot${needed === 1 ? '' : 's'}`}</div>
    <div class="vendor-description">${escapeHtml(vendor.description || '')}</div>
    <div class="chips">
      <span class="chip">${state.selectedSpots.length ? escapeHtml(state.selectedSpots.join(', ')) : 'Not picked yet'}</span>
      <span class="chip">${escapeHtml(formatPayment(vendor.payment_status))}</span>
    </div>
    ${state.mode !== 'admin' && !isPaid(vendor) ? renderPaymentPrompt(vendor) : ''}
  `;
  els.neededCount.textContent = needed;
}

function renderStats() {
  const assigned = new Set(state.assignments.map(item => item.spot_id));
  els.openCount.textContent = state.allowedSpots.filter(spotId => !assigned.has(spotId)).length;
  els.reservedCount.textContent = assigned.size;
}

function renderAssignments() {
  const visibleAssignments = state.assignments.filter(item => state.mode === 'admin' || Number(item.vendor_id) === Number(state.selectedVendorId));
  els.assignmentList.innerHTML = visibleAssignments.length ? visibleAssignments.map(item => `
    <div class="assignment">
      <strong>${escapeHtml(item.name)}</strong>
      <span>${escapeHtml(item.spot_id)}</span>
    </div>
  `).join('') : '<div class="assignment"><span>No spots assigned yet.</span></div>';
}

function handleSpotClick(spotId) {
  const vendor = getSelectedVendor();
  if (!vendor || !state.allowedSpots.includes(spotId)) return;
  const assignment = state.assignments.find(item => item.spot_id === spotId);
  if (state.mode === 'admin' && assignment && Number(assignment.vendor_id) !== Number(state.selectedVendorId)) {
    state.selectedVendorId = Number(assignment.vendor_id);
    els.vendorSelect.value = state.selectedVendorId;
    loadSelectedVendorAssignments();
    renderAll();
    setMessage(`${assignment.name} is assigned to ${spotId}. Click Release Spots, then Save Spots to remove it.`, 'ok');
    return;
  }

  const needed = Number(vendor.requested_spots || 0);
  if (state.mode !== 'admin' && !isPaid(vendor)) {
    setMessage('Your registration must be paid before you can pick a spot. Use the payment links in the side panel.', 'error');
    return;
  }
  if (needed < 1) {
    setMessage('This vendor is marked street setup only.', 'error');
    return;
  }
  if (assignment && Number(assignment.vendor_id) !== Number(state.selectedVendorId) && state.mode !== 'admin') {
    setMessage('That spot has already been taken.', 'error');
    return;
  }

  if (!toggleSingleSpot(spotId, needed)) {
    renderAll();
    return;
  }
  renderAll();
  setMessage(`${state.selectedSpots.length} of ${needed} spot${needed === 1 ? '' : 's'} selected.`, 'ok');
}

function toggleSingleSpot(spotId, needed) {
  if (state.selectedSpots.includes(spotId)) {
    state.selectedSpots = state.selectedSpots.filter(id => id !== spotId);
    return true;
  }
  if (state.selectedSpots.length >= needed) {
    setMessage(`This vendor only has ${needed} registered spot${needed === 1 ? '' : 's'}. Click a selected spot to remove it first.`, 'error');
    return false;
  }
  state.selectedSpots = [...state.selectedSpots, spotId].sort(compareSpotIds);
  return true;
}

async function saveSelection() {
  const vendor = getSelectedVendor();
  if (!vendor) return;
  const needed = Number(vendor.requested_spots || 0);
  if (state.mode !== 'admin' && !isPaid(vendor)) {
    setMessage('Your registration must be paid before you can save a spot. Use the payment links in the side panel.', 'error');
    return;
  }
  const adminRelease = state.mode === 'admin' && state.selectedSpots.length === 0;
  if (!adminRelease && state.selectedSpots.length !== needed) {
    setMessage(`Select exactly ${needed} spot${needed === 1 ? '' : 's'} before saving.`, 'error');
    return;
  }
  els.saveState.textContent = 'Saving...';
  const response = await fetch('vendor_spot_api.php', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ vendor_id: state.selectedVendorId, spot_ids: state.selectedSpots }),
  });
  const data = await response.json();
  if (!data.ok) {
    els.saveState.textContent = 'Not saved';
    setMessage(data.message || 'Could not save spots.', 'error');
    await loadMap();
    return;
  }
  els.saveState.textContent = 'Saved';
  setMessage('Spots saved.', 'ok');
  await loadMap();
}

function getSelectedVendor() {
  return state.vendors.find(vendor => Number(vendor.id) === Number(state.selectedVendorId));
}

function compareSpotIds(a, b) {
  const parsedA = /^([A-J])([1-6])$/.exec(a);
  const parsedB = /^([A-J])([1-6])$/.exec(b);
  if (!parsedA || !parsedB) return a.localeCompare(b);
  if (parsedA[1] !== parsedB[1]) return parsedA[1].localeCompare(parsedB[1]);
  return Number(parsedA[2]) - Number(parsedB[2]);
}

function getDefaultSpotNote(id, col) {
  if (walkwaySpots.includes(id)) return 'Walkway between booth rows';
  if (bufferSpots.includes(id)) return 'Buffer inside 68.42 ft width';
  if (col === 1 || col === 2) return 'Back-to-back booth row 1';
  if (col === 4 || col === 5) return 'Back-to-back booth row 2';
  return '';
}

function getSpotLabel(spotId, assignment) {
  if (walkwaySpots.includes(spotId)) return 'WALK';
  if (bufferSpots.includes(spotId)) return 'BUFFER';
  return assignment?.name || '';
}

function formatPayment(value) {
  if (String(value) === '1') return 'Paid';
  if (String(value) === '2') return 'Pending';
  if (String(value) === '0' || String(value).toLowerCase() === 'unpaid') return 'Unpaid';
  return 'Unknown';
}

function isPaid(vendor) {
  const value = String(vendor.payment_status ?? '').trim().toLowerCase();
  return value === '1' || value === 'paid';
}

function renderPaymentPrompt(vendor) {
  const spots = Number(vendor.requested_spots || 0);
  const isFood = String(vendor.category || '').toLowerCase().includes('food');
  return `
    <div class="payment-prompt">
      <strong>Payment needed before spot selection</strong>
      <p>After you pay, your registration may need a little time to be confirmed by the event team before spot selection opens. Please use the same name and email from this registration.</p>
      <p>If you have already paid and still cannot choose a spot, email <a href="mailto:info@thelittlebigshow.com">info@thelittlebigshow.com</a> and we will help get it updated.</p>
      <div class="payment-actions">
        ${isFood ? `<a href="https://square.link/u/9suAWD0n?src=embed" target="_blank" rel="noopener">Pay Food Vendor - $35</a>` : ''}
        <a href="https://square.link/u/UVVjNjOo?src=embed" target="_blank" rel="noopener">Pay Vendor Spot - $25</a>
      </div>
      ${spots > 1 ? `<p class="payment-note">Registered spots: ${spots}. If Square asks for quantity, use ${spots}.</p>` : ''}
    </div>
  `;
}

function setMessage(text, type = '') {
  els.message.textContent = text;
  els.message.className = `message ${type}`.trim();
}

function escapeHtml(value) {
  return String(value ?? '').replace(/[&<>"']/g, char => ({
    '&': '&amp;',
    '<': '&lt;',
    '>': '&gt;',
    '"': '&quot;',
    "'": '&#039;',
  }[char]));
}

boot();

Youez - 2016 - github.com/yon3zu
LinuXploit