Ajjaanvaraus

<!doctype html>
<html lang="fi">
 <head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Ajanvarausjärjestelmä</title>
  <script src="/_sdk/data_sdk.js"></script>
  <script src="/_sdk/element_sdk.js"></script>
  <style>
    body {
      box-sizing: border-box;
      margin: 0;
      padding: 0;
      font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
      background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
      min-height: 100%;
      display: flex;
      align-items: center;
      justify-content: center;
      padding: 20px;
    }
    
    html {
      height: 100%;
    }
    
    .container {
      background: white;
      border-radius: 16px;
      box-shadow: 0 20px 60px rgba(0,0,0,0.3);
      max-width: 900px;
      width: 100%;
      padding: 40px;
    }
    
    h1 {
      margin: 0 0 8px 0;
      font-size: 32px;
      font-weight: 700;
    }
    
    .description {
      color: #666;
      margin: 0 0 32px 0;
      font-size: 16px;
    }
    
    .calendar-grid {
      display: grid;
      grid-template-columns: repeat(7, 1fr);
      gap: 8px;
      margin-bottom: 32px;
    }
    
    .calendar-header {
      text-align: center;
      font-weight: 600;
      padding: 12px;
      color: #333;
      font-size: 14px;
    }
    
    .calendar-day {
      aspect-ratio: 1;
      border: 2px solid #e0e0e0;
      border-radius: 8px;
      display: flex;
      align-items: center;
      justify-content: center;
      cursor: pointer;
      transition: all 0.2s;
      font-weight: 500;
      background: white;
    }
    
    .calendar-day:hover {
      border-color: #667eea;
      background: #f5f7ff;
    }
    
    .calendar-day.selected {
      background: #667eea;
      color: white;
      border-color: #667eea;
    }
    
    .calendar-day.disabled {
      opacity: 0.3;
      cursor: not-allowed;
      pointer-events: none;
    }
    
    .time-slots {
      display: grid;
      grid-template-columns: repeat(auto-fill, minmax(100px, 1fr));
      gap: 12px;
      margin-bottom: 32px;
    }
    
    .time-slot {
      padding: 12px;
      border: 2px solid #e0e0e0;
      border-radius: 8px;
      text-align: center;
      cursor: pointer;
      transition: all 0.2s;
      font-weight: 500;
      background: white;
    }
    
    .time-slot:hover {
      border-color: #667eea;
      background: #f5f7ff;
    }
    
    .time-slot.selected {
      background: #667eea;
      color: white;
      border-color: #667eea;
    }
    
    .time-slot.booked {
      background: #f5f5f5;
      color: #999;
      cursor: not-allowed;
      border-color: #e0e0e0;
    }
    
    .booking-form {
      display: none;
      margin-top: 32px;
    }
    
    .booking-form.active {
      display: block;
    }
    
    .form-group {
      margin-bottom: 20px;
    }
    
    label {
      display: block;
      margin-bottom: 8px;
      font-weight: 600;
      color: #333;
    }
    
    input {
      width: 100%;
      padding: 12px;
      border: 2px solid #e0e0e0;
      border-radius: 8px;
      font-size: 16px;
      transition: border-color 0.2s;
      box-sizing: border-box;
    }
    
    input:focus {
      outline: none;
      border-color: #667eea;
    }
    
    .button-group {
      display: flex;
      gap: 12px;
      margin-top: 24px;
    }
    
    button {
      flex: 1;
      padding: 14px 24px;
      border: none;
      border-radius: 8px;
      font-size: 16px;
      font-weight: 600;
      cursor: pointer;
      transition: all 0.2s;
    }
    
    .btn-primary {
      background: #667eea;
      color: white;
    }
    
    .btn-primary:hover {
      background: #5568d3;
    }
    
    .btn-primary:disabled {
      background: #ccc;
      cursor: not-allowed;
    }
    
    .btn-secondary {
      background: #f5f5f5;
      color: #333;
    }
    
    .btn-secondary:hover {
      background: #e0e0e0;
    }
    
    .success-message {
      display: none;
      background: #4caf50;
      color: white;
      padding: 16px;
      border-radius: 8px;
      margin-top: 20px;
      text-align: center;
      font-weight: 500;
    }
    
    .success-message.active {
      display: block;
    }
    
    .section-title {
      font-size: 20px;
      font-weight: 600;
      margin: 0 0 16px 0;
      color: #333;
    }
    
    .loading {
      opacity: 0.6;
      pointer-events: none;
    }
  </style>
  <style>@view-transition { navigation: auto; }</style>
  <script src="https://cdn.tailwindcss.com" type="text/javascript"></script>
 </head>
 <body>
  <div class="container">
   <h1 id="page-title">Ajanvaraus</h1>
   <p class="description" id="description">Varaa aika palveluumme</p>
   <div class="section-title">
    Valitse päivä
   </div>
   <div class="calendar-grid" id="calendar"></div>
   <div id="time-section" style="display: none;">
    <div class="section-title">
     Valitse aika
    </div>
    <div class="time-slots" id="time-slots"></div>
   </div>
   <div class="booking-form" id="booking-form">
    <div class="section-title">
     Yhteystiedot
    </div>
    <form id="contact-form">
     <div class="form-group"><label for="name">Nimi</label> <input type="text" id="name" required>
     </div>
     <div class="form-group"><label for="email">Sähköposti</label> <input type="email" id="email" required>
     </div>
     <div class="form-group"><label for="phone">Puhelinnumero</label> <input type="tel" id="phone" required>
     </div>
     <div class="button-group"><button type="button" class="btn-secondary" id="cancel-btn">Peruuta</button> <button type="submit" class="btn-primary" id="book-btn">Varaa aika</button>
     </div>
    </form>
   </div>
   <div class="success-message" id="success-message">
    Aika varattu onnistuneesti!
   </div>
  </div>
  <script>
    const defaultConfig = {
      page_title: "Ajanvaraus",
      description: "Varaa aika palveluumme",
      book_button_text: "Varaa aika",
      cancel_button_text: "Peruuta",
      background_color: "#667eea",
      surface_color: "#ffffff",
      text_color: "#333333",
      primary_action_color: "#667eea",
      secondary_action_color: "#f5f5f5",
      font_family: "-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto",
      font_size: 16
    };

    let config = { ...defaultConfig };
    let bookings = [];
    let selectedDate = null;
    let selectedTime = null;
    let recordCount = 0;

    const timeSlots = [
      "09:00", "09:30", "10:00", "10:30", "11:00", "11:30",
      "12:00", "12:30", "13:00", "13:30", "14:00", "14:30",
      "15:00", "15:30", "16:00", "16:30"
    ];

    function generateCalendar() {
      const calendar = document.getElementById('calendar');
      calendar.innerHTML = '';
      
      const weekdays = ['Ma', 'Ti', 'Ke', 'To', 'Pe', 'La', 'Su'];
      weekdays.forEach(day => {
        const header = document.createElement('div');
        header.className = 'calendar-header';
        header.textContent = day;
        calendar.appendChild(header);
      });
      
      const today = new Date();
      const currentMonth = today.getMonth();
      const currentYear = today.getFullYear();
      
      const firstDay = new Date(currentYear, currentMonth, 1);
      const lastDay = new Date(currentYear, currentMonth + 1, 0);
      
      let startDay = firstDay.getDay() - 1;
      if (startDay === -1) startDay = 6;
      
      for (let i = 0; i < startDay; i++) {
        const emptyDay = document.createElement('div');
        emptyDay.className = 'calendar-day disabled';
        calendar.appendChild(emptyDay);
      }
      
      for (let day = 1; day <= lastDay.getDate(); day++) {
        const dayElement = document.createElement('div');
        dayElement.className = 'calendar-day';
        dayElement.textContent = day;
        
        const date = new Date(currentYear, currentMonth, day);
        if (date < today.setHours(0, 0, 0, 0)) {
          dayElement.classList.add('disabled');
        } else {
          dayElement.addEventListener('click', () => selectDate(date));
        }
        
        calendar.appendChild(dayElement);
      }
    }

    function selectDate(date) {
      selectedDate = date;
      selectedTime = null;
      
      document.querySelectorAll('.calendar-day').forEach(day => {
        day.classList.remove('selected');
      });
      
      event.target.classList.add('selected');
      
      document.getElementById('time-section').style.display = 'block';
      document.getElementById('booking-form').classList.remove('active');
      
      renderTimeSlots();
    }

    function renderTimeSlots() {
      const container = document.getElementById('time-slots');
      container.innerHTML = '';
      
      const dateStr = selectedDate.toISOString().split('T')[0];
      
      timeSlots.forEach(time => {
        const slot = document.createElement('div');
        slot.className = 'time-slot';
        slot.textContent = time;
        
        const isBooked = bookings.some(b => b.date === dateStr && b.time === time);
        
        if (isBooked) {
          slot.classList.add('booked');
        } else {
          slot.addEventListener('click', () => selectTime(time, slot));
        }
        
        container.appendChild(slot);
      });
    }

    function selectTime(time, element) {
      selectedTime = time;
      
      document.querySelectorAll('.time-slot').forEach(slot => {
        slot.classList.remove('selected');
      });
      
      element.classList.add('selected');
      document.getElementById('booking-form').classList.add('active');
    }

    document.getElementById('contact-form').addEventListener('submit', async (e) => {
      e.preventDefault();
      
      if (recordCount >= 999) {
        const successMsg = document.getElementById('success-message');
        successMsg.textContent = 'Varausraja (999) saavutettu. Poista varauksia ensin.';
        successMsg.style.background = '#f44336';
        successMsg.classList.add('active');
        setTimeout(() => successMsg.classList.remove('active'), 3000);
        return;
      }
      
      const bookBtn = document.getElementById('book-btn');
      bookBtn.disabled = true;
      bookBtn.textContent = 'Varataan...';
      
      const booking = {
        date: selectedDate.toISOString().split('T')[0],
        time: selectedTime,
        name: document.getElementById('name').value,
        email: document.getElementById('email').value,
        phone: document.getElementById('phone').value,
        createdAt: new Date().toISOString()
      };
      
      const result = await window.dataSdk.create(booking);
      
      bookBtn.disabled = false;
      bookBtn.textContent = config.book_button_text || defaultConfig.book_button_text;
      
      if (result.isOk) {
        document.getElementById('contact-form').reset();
        document.getElementById('booking-form').classList.remove('active');
        
        const successMsg = document.getElementById('success-message');
        successMsg.style.background = '#4caf50';
        successMsg.textContent = 'Aika varattu onnistuneesti!';
        successMsg.classList.add('active');
        
        setTimeout(() => {
          successMsg.classList.remove('active');
        }, 3000);
        
        selectedDate = null;
        selectedTime = null;
        document.querySelectorAll('.calendar-day').forEach(d => d.classList.remove('selected'));
        document.getElementById('time-section').style.display = 'none';
      } else {
        const successMsg = document.getElementById('success-message');
        successMsg.textContent = 'Virhe varauksessa. Yritä uudelleen.';
        successMsg.style.background = '#f44336';
        successMsg.classList.add('active');
        setTimeout(() => successMsg.classList.remove('active'), 3000);
      }
    });

    document.getElementById('cancel-btn').addEventListener('click', () => {
      document.getElementById('contact-form').reset();
      document.getElementById('booking-form').classList.remove('active');
    });

    const dataHandler = {
      onDataChanged(data) {
        bookings = data;
        recordCount = data.length;
        
        if (selectedDate) {
          renderTimeSlots();
        }
      }
    };

    async function onConfigChange(newConfig) {
      config = { ...config, ...newConfig };
      
      document.getElementById('page-title').textContent = config.page_title || defaultConfig.page_title;
      document.getElementById('description').textContent = config.description || defaultConfig.description;
      document.getElementById('book-btn').textContent = config.book_button_text || defaultConfig.book_button_text;
      document.getElementById('cancel-btn').textContent = config.cancel_button_text || defaultConfig.cancel_button_text;
      
      const bgColor = config.background_color || defaultConfig.background_color;
      const surfaceColor = config.surface_color || defaultConfig.surface_color;
      const textColor = config.text_color || defaultConfig.text_color;
      const primaryColor = config.primary_action_color || defaultConfig.primary_action_color;
      const secondaryColor = config.secondary_action_color || defaultConfig.secondary_action_color;
      const fontFamily = config.font_family || defaultConfig.font_family;
      const fontSize = config.font_size || defaultConfig.font_size;
      
      document.body.style.background = `linear-gradient(135deg, ${bgColor} 0%, ${bgColor} 100%)`;
      document.querySelector('.container').style.background = surfaceColor;
      document.body.style.fontFamily = `${fontFamily}, sans-serif`;
      document.body.style.fontSize = `${fontSize}px`;
      
      document.getElementById('page-title').style.color = textColor;
      document.getElementById('page-title').style.fontSize = `${fontSize * 2}px`;
      document.querySelector('.description').style.fontSize = `${fontSize}px`;
      document.querySelectorAll('.section-title').forEach(el => {
        el.style.color = textColor;
        el.style.fontSize = `${fontSize * 1.25}px`;
      });
      document.querySelectorAll('label').forEach(el => {
        el.style.color = textColor;
        el.style.fontSize = `${fontSize}px`;
      });
      
      document.querySelectorAll('.btn-primary').forEach(btn => {
        btn.style.background = primaryColor;
        btn.style.fontSize = `${fontSize}px`;
      });
      
      document.querySelectorAll('.btn-secondary').forEach(btn => {
        btn.style.background = secondaryColor;
        btn.style.color = textColor;
        btn.style.fontSize = `${fontSize}px`;
      });
      
      document.querySelectorAll('.calendar-day').forEach(day => {
        if (day.classList.contains('selected')) {
          day.style.background = primaryColor;
          day.style.borderColor = primaryColor;
        }
      });
      
      document.querySelectorAll('.time-slot').forEach(slot => {
        if (slot.classList.contains('selected')) {
          slot.style.background = primaryColor;
          slot.style.borderColor = primaryColor;
        }
      });
    }

    if (window.elementSdk) {
      window.elementSdk.init({
        defaultConfig,
        onConfigChange,
        mapToCapabilities: (cfg) => ({
          recolorables: [
            {
              get: () => cfg.background_color || defaultConfig.background_color,
              set: (value) => {
                cfg.background_color = value;
                window.elementSdk.setConfig({ background_color: value });
              }
            },
            {
              get: () => cfg.surface_color || defaultConfig.surface_color,
              set: (value) => {
                cfg.surface_color = value;
                window.elementSdk.setConfig({ surface_color: value });
              }
            },
            {
              get: () => cfg.text_color || defaultConfig.text_color,
              set: (value) => {
                cfg.text_color = value;
                window.elementSdk.setConfig({ text_color: value });
              }
            },
            {
              get: () => cfg.primary_action_color || defaultConfig.primary_action_color,
              set: (value) => {
                cfg.primary_action_color = value;
                window.elementSdk.setConfig({ primary_action_color: value });
              }
            },
            {
              get: () => cfg.secondary_action_color || defaultConfig.secondary_action_color,
              set: (value) => {
                cfg.secondary_action_color = value;
                window.elementSdk.setConfig({ secondary_action_color: value });
              }
            }
          ],
          borderables: [],
          fontEditable: {
            get: () => cfg.font_family || defaultConfig.font_family,
            set: (value) => {
              cfg.font_family = value;
              window.elementSdk.setConfig({ font_family: value });
            }
          },
          fontSizeable: {
            get: () => cfg.font_size || defaultConfig.font_size,
            set: (value) => {
              cfg.font_size = value;
              window.elementSdk.setConfig({ font_size: value });
            }
          }
        }),
        mapToEditPanelValues: (cfg) => new Map([
          ["page_title", cfg.page_title || defaultConfig.page_title],
          ["description", cfg.description || defaultConfig.description],
          ["book_button_text", cfg.book_button_text || defaultConfig.book_button_text],
          ["cancel_button_text", cfg.cancel_button_text || defaultConfig.cancel_button_text]
        ])
      });
      
      config = window.elementSdk.config;
    }

    async function init() {
      generateCalendar();
      
      if (window.dataSdk) {
        const result = await window.dataSdk.init(dataHandler);
        if (!result.isOk) {
          console.error('Data SDK initialization failed');
        }
      }
    }

    init();
  </script>
 <script>(function(){function c(){var b=a.contentDocument||a.contentWindow.document;if(b){var d=b.createElement('script');d.innerHTML="window.__CF$cv$params={r:'99942831e15dbba2',t:'MTc2MjI1OTc4Ni4wMDAwMDA='};var a=document.createElement('script');a.nonce='';a.src='/cdn-cgi/challenge-platform/scripts/jsd/main.js';document.getElementsByTagName('head')[0].appendChild(a);";b.getElementsByTagName('head')[0].appendChild(d)}}if(document.body){var a=document.createElement('iframe');a.height=1;a.width=1;a.style.position='absolute';a.style.top=0;a.style.left=0;a.style.border='none';a.style.visibility='hidden';document.body.appendChild(a);if('loading'!==document.readyState)c();else if(window.addEventListener)document.addEventListener('DOMContentLoaded',c);else{var e=document.onreadystatechange||function(){};document.onreadystatechange=function(b){e(b);'loading'!==document.readyState&&(document.onreadystatechange=e,c())}}}})();</script></body>
</html>