VladislavNechepaev

Untitled

Aug 21st, 2020
106
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. <script>
  2.   jQuery(document).on('ready', async function(){
  3.     document.getElementById("show_request_for").remove()
  4.     document.getElementById("add-cc-button").remove()
  5.      
  6.      
  7.     console.log('[INIT]')
  8.     if (window.location.pathname === "/support/catalog/items/27") {
  9.       const durationList = {
  10.         "...": false,
  11.         "Full day": true,
  12.         "Half day": true,
  13.         "Short visit (up to 2 hours)": false
  14.       }
  15.       const officeList = {
  16.         "...": false,
  17.         "Toronto": true,
  18.         "Gulliver": true,
  19.         "Lviv": true,
  20.         "Lab64": true,
  21.         "Lab72": true,
  22.         "Rancho 1": false,
  23.         "Rancho 2": false,
  24.         "QA Studio": false
  25.       }
  26.       const officeMeido = {
  27.         "...": false,
  28.         "Toronto": true,
  29.         "Gulliver": false,
  30.         "Lviv": false,
  31.         "Lab64": true,
  32.         "Lab72": true,
  33.         "Rancho 1": false,
  34.         "Rancho 2": false,
  35.         "QA Studio": false
  36.       }
  37.       const officeAddress = {
  38.         "...": "",
  39.         "Toronto": "м. Київ, вул. Велика Васильківська 100, 8 поверх",
  40.         "Gulliver": "м. Київ, площа Спортивна 1А, 5-6 поверх",
  41.         "Lviv": "м. Львів, вул. Поповича, 9",
  42.         "Lab64": "м. Київ, вул. Велика Васильківська 64",
  43.         "Lab72": "м. Київ, вул. Велика Васильківська 72",
  44.         "Rancho 1": "м. Київ, пров. Малокитаївський, 12",
  45.         "Rancho 2": "м. Київ, вул. Травнева 28",
  46.         "QA Studio": "м. Київ, вул. Північно-Сирецька 1-3"
  47.       }
  48.       const accessWeek = {
  49.         "...": false,
  50.         "Current week": true,
  51.         "Next week": true
  52.       }
  53.       const mealTypes = [
  54.         "Non-vegan",
  55.         "Vegan"
  56.       ]
  57.       const fsFields = {
  58.         duration: "requested_item_values_27_requested_item_value_attributes_cf_visit_duration_63350",
  59.         support_with_lunch: "requested_item_values_27_requested_item_value_attributes_cf_support_with_lunch_63350",
  60.         access_week: "requested_item_values_27_requested_item_value_attributes_cf_access_week_63350",
  61.         lunch_type: "requested_item_values_27_requested_item_value_attributes_cf_lunch_type_63350",
  62.         office: "requested_item_values_27_requested_item_value_attributes_cf_office_63350",
  63.         dates: [
  64.           "requested_item_values_27_requested_item_value_attributes_cf_date_1_63350_date",
  65.           "requested_item_values_27_requested_item_value_attributes_cf_date_2_63350_date",
  66.           "requested_item_values_27_requested_item_value_attributes_cf_date_3_63350_date",
  67.           "requested_item_values_27_requested_item_value_attributes_cf_date_4_63350_date",
  68.           "requested_item_values_27_requested_item_value_attributes_cf_date_5_63350_date"
  69.         ],
  70.         additional_locations: [
  71.           "requested_item_values_27_requested_item_value_attributes_cf_additional_location_1_63350",
  72.           "requested_item_values_27_requested_item_value_attributes_cf_additional_location_2_63350"
  73.         ],
  74.         document_text: "requested_item_values_27_requested_item_value_attributes_cf_document_63350",
  75.         document_check: "requested_item_values_27_requested_item_value_attributes_cf_document_agree_63350",
  76.         meido: "requested_item_values_27_requested_item_value_attributes_cf_meido-body_63350"
  77.       }
  78.       // -------------------------
  79.         meidoActive = true
  80.         meidoToken = "test"
  81.       // -------------------------
  82.      
  83.           // ====================================================================
  84.           // ====================================================================
  85.           // ====================================================================
  86.          
  87.       const fsNative = {
  88.         duration: document.getElementById(fsFields.duration),
  89.         support_with_lunch: document.getElementById(fsFields.support_with_lunch).parentNode.childNodes.item(0),
  90.         access_week: document.getElementById(fsFields.access_week),
  91.         lunch_type: document.getElementById(fsFields.lunch_type),
  92.         office: document.getElementById(fsFields.office),
  93.         meido: document.getElementById(fsFields.meido),
  94.         dates: getElemList(fsFields.dates),
  95.         additional_locations: getElemList(fsFields.additional_locations),
  96.         document_text: document.getElementById(fsFields.document_text),
  97.         document_check: document.getElementById(fsFields.document_check).parentNode.childNodes.item(0)
  98.       }
  99.  
  100.       var activeDateCount = 0
  101.       const today = new Date()
  102.       const todayGlobal = today.toLocaleDateString()
  103.       const weekdayGlobal = today.getDay()
  104.       const currentTimeGlobal = today.getHours()
  105.          
  106.       const durationSelector = replaceInputWithDropdown(fsFields.duration, durationList, "duration")
  107.       const officeSelector = replaceInputWithDropdown(fsFields.office, officeList, "office")
  108.       const accessWeekSelector = replaceInputWithDropdown(fsFields.access_week, accessWeek, "access-week")
  109.       const lunchTypeSelector = createSimplifiedDropdown(fsFields.lunch_type, mealTypes, "lunch_type")
  110.       const lunchCheckboxLabel = document.createTextNode("Please support me with lunch (meals will be provided only on Mon-Fri and in case your office visit is more than 2 hours)")
  111.       const lunchCheckbox = createCustomCheckbox(document.getElementById(fsFields.support_with_lunch).parentNode, "show-lunch", lunchCheckboxLabel)
  112.       const dateList = createCustomDates(fsNative.dates)
  113.       const additionalOfficesList = createAdditionalOfficeSelectors(fsFields.additional_locations, officeList)
  114.      
  115.           //add hotDeskCheckbox
  116.       const hotdeskCheckboxLabel = document.createTextNode("I don`t have a permanent seat and would like to book a hot desk.");
  117.       const hotdeskCheckboxContainer = document.createElement('div');
  118.       document.getElementById(fsFields.office).parentNode.appendChild(hotdeskCheckboxContainer);
  119.       const hotdeskCheckbox = createCustomCheckbox(hotdeskCheckboxContainer, "show-hotdesk", hotdeskCheckboxLabel);
  120.       hotdeskCheckbox.checked = false;
  121.       const hotdeskText = document.createElement("p");
  122.       hotdeskText.innerHTML = "Please, follow the <a href='https://ringukraine.officespacesoftware.com/visual-directory/floors/139' style:='color:lightblue;cursor:pointer;' target='_blank'>link</a> for hot desks booking system (applicable only for Full/half-day visit). Here`re <a href='https://docs.google.com/document/d/1llpCz3RbK0cBew7kSJhZPQwD5Om8Kgj0tTq-1kgONx4/edit' style:='color:lightblue;cursor:pointer;' target='_blank'>instructions</a> on how to make a booking.";
  123.       hotdeskCheckboxContainer.appendChild(hotdeskText);  
  124.      
  125.       const documentCheckboxLabel = document.createElement("span")
  126.       documentCheckboxLabel.innerHTML = "Я, {{ current_user.phone }}, ознайомився з документом та підтверджую що мій стан відповідає нормам відвідування офісу згідно з заявою.<br>*[✓] <i>означає, що дана відмітка прирівнюється до власноручного/факсимільного відтворення підпису особи.</i>"
  127.       const documentCheckbox = createCustomCheckbox(fsNative.document_check.parentNode, "document-check", documentCheckboxLabel)
  128.       const documentText = createDocumentSection(fsNative.document_text, todayGlobal)
  129.          
  130.       const dateControlAdd = document.createElement("button")
  131.       dateControlAdd.innerHTML = "+"
  132.       const dateControlRemove = document.createElement("button")
  133.       dateControlRemove.innerHTML = "-"
  134.          
  135.       lunchCheckbox.parentNode.hidden = true;
  136.       lunchTypeSelector.parentNode.hidden = true;
  137.       hotdeskCheckboxContainer.hidden = true;
  138.       hotdeskText.hidden = true;
  139.          
  140.       durationSelector.addEventListener("change", function(){ renderController() })
  141.       officeSelector.addEventListener("change", function(){ renderController() })
  142.       accessWeekSelector.addEventListener("change", function(){ renderController() })
  143.       lunchCheckbox.addEventListener("change", function(){ renderController() })
  144.       hotdeskCheckbox.addEventListener("change", function(){ renderController() })
  145.       lunchTypeSelector.addEventListener("change", function(){ renderController() })
  146.      
  147.       dateList.forEach(dateElem => {
  148.         jQuery(dateElem).datepicker("option", {
  149.           onSelect: function() {
  150.             renderController()
  151.           }
  152.         })
  153.       })
  154.    
  155.       dateControlAdd.addEventListener("click", function(e){
  156.         e.preventDefault()
  157.         activeDateCount += 1
  158.         renderController()
  159.       })
  160.       dateControlRemove.addEventListener("click", function(e){
  161.         e.preventDefault()
  162.         activeDateCount -= 1
  163.         renderController()
  164.       })
  165.       additionalOfficesList.forEach(elem => {
  166.         elem.addEventListener("change", function(){ renderController() })
  167.       })
  168.    
  169.    
  170.       documentCheckbox.addEventListener("change", function(){ renderController() })
  171.  
  172.       var meidoMenu
  173.       if (meidoActive) {
  174.         document.getElementById(fsFields.meido).parentNode.style.display = "none"
  175.         const elems = document.getElementsByClassName("main pull-left")
  176.         meidoMenu = await meidoInit(elems[0], dateList, fsFields.meido, 250, false)  // change 250 to required limit
  177.         console.log(meidoMenu)
  178.         meidoMenu.hidden = true
  179.         console.log("calling renderController")
  180.         renderController()
  181.       } else {
  182.         renderController()
  183.       }
  184.          
  185.        
  186.      
  187.       function renderController(){
  188.         var values = {
  189.           duration: durationSelector.value,
  190.           office: officeSelector.value,
  191.           access_week: accessWeekSelector.value
  192.         }
  193.            
  194.         fsNative.duration.value = values.duration === "..." ? "" : values.duration
  195.         fsNative.office.value = values.office === "..." ? "" : values.office
  196.            if (fsNative.office.value === 'Toronto') {
  197.             hotdeskCheckboxContainer.hidden = false;
  198.           } else {
  199.             hotdeskCheckbox.checked = false;
  200.             hotdeskCheckboxContainer.hidden = true;
  201.           }
  202.         if (!hotdeskCheckbox.checked) {
  203.                 hotdeskText.hidden = true;
  204.             } else {
  205.                 hotdeskText.hidden = false;
  206.             }
  207.        
  208.         const accessWeekChanged = fsNative.access_week.value === values.access_week ? false : true
  209.         fsNative.access_week.value = values.access_week === "..." ? "" : values.access_week
  210.         var datesInRequest = dateList.map(x => x.value).filter(x => !!x)
  211.         if (activeDateCount === 0) datesInRequest = datesInRequest[0] ? [datesInRequest[0]] : []
  212.         const today = new Date().toISOString().split("T")[0]
  213.         if (durationList[values.duration] && officeList[values.office] && accessWeek[values.access_week] && datesInRequest.length && !(datesInRequest.length === 1 && datesInRequest[0] === today) && !accessWeekChanged) {
  214.           lunchCheckbox.parentNode.hidden = false
  215.         } else {
  216.           lunchCheckbox.parentNode.hidden = true
  217.           lunchCheckbox.checked = false
  218.         }
  219.        
  220.         values.support_with_lunch = lunchCheckbox.checked
  221.         fsNative.support_with_lunch.value = lunchCheckbox.checked ? "1" : "0"
  222.         if (values.support_with_lunch) {
  223.           if (meidoActive) {
  224.             if (weekdayGlobal === 6 || weekdayGlobal === 0 || (weekdayGlobal === 5 && currentTimeGlobal >= 19) || values.access_week === "Current week" || !officeMeido[values.office]) {
  225.               lunchTypeSelector.parentNode.hidden = false
  226.               lunchTypeSelector.value = lunchTypeSelector.value ? lunchTypeSelector.value : mealTypes[0]
  227.               meidoMenu.hidden = true
  228.             } else {
  229.               lunchTypeSelector.parentNode.hidden = true
  230.               lunchTypeSelector.value = null
  231.               meidoMenu.hidden = false
  232.             }
  233.           } else {
  234.             lunchTypeSelector.parentNode.hidden = false
  235.             lunchTypeSelector.value = lunchTypeSelector.value ? lunchTypeSelector.value : mealTypes[0]
  236.           }
  237.         } else {
  238.           lunchTypeSelector.parentNode.hidden = true
  239.           lunchTypeSelector.value = null
  240.           if (meidoActive) meidoMenu.hidden = true
  241.         }
  242.        
  243.         values.lunch_type = lunchTypeSelector.value
  244.         fsNative.lunch_type.value = values.lunch_type ? values.lunch_type : ""
  245.        
  246.         const dateLimits = (values.access_week === "...") ? null : calcDateLimits(values.access_week === "Current week" ? true : false)
  247.         const dateLimitsRaw = dateLimits ? dateLimits.map(x => new Date(x).valueOf()) : null
  248.         var existingDates = []
  249.         var lastUsedFound = false;
  250.         if (accessWeekChanged) activeDateCount = 0
  251.         dateList.forEach((dateElem, index) => {
  252.           const dateNativeElem = fsNative.dates[index]
  253.           const timeNativeElem = document.getElementById(fsFields.dates[index].substring(0, fsFields.dates[index].length - 4) + "time")
  254.           const errorElem = document.getElementById("date_custom_" + (index+1) + "-error")
  255.           if (errorElem) errorElem.style.display = "none"
  256.           if (accessWeekChanged && index === 0) dateElem.value = null
  257.           const dateRawValue = new Date(dateElem.value).valueOf()
  258.           if (existingDates.includes(dateRawValue)) dateElem.value = null
  259.           if (dateLimits) {
  260.             jQuery("#date_custom_"+(index+1)).datepicker("option", {
  261.               minDate: new Date(dateLimits[0]),
  262.               maxDate: new Date(dateLimits[1])
  263.             })
  264.             dateElem.disabled = false
  265.             if (dateRawValue < dateLimitsRaw[0] || dateRawValue > dateLimitsRaw[1]) dateElem.value = null
  266.           } else {
  267.             dateElem.disabled = true
  268.           }
  269.           existingDates.push(dateRawValue)
  270.           const controlWrapper = document.getElementById("controls_" + index)
  271.           controlWrapper.innerHTML = ""
  272.           if (dateElem.value) {
  273.             dateNativeElem.value = reverseForFS(dateElem.value)
  274.             timeNativeElem.value = "00:00"
  275.           } else {
  276.             dateNativeElem.value = null
  277.             timeNativeElem.value = null
  278.           }
  279.           controlWrapper.style.display = "inline"
  280.           if (index < activeDateCount) {
  281.             dateElem.disabled = true
  282.             dateElem.parentNode.style.display = "block"
  283.           } else if (index === activeDateCount) {
  284.             if (dateLimits) dateElem.disabled = false
  285.             if (index > 0 && dateList[index-1].value) {
  286.               const nextDate = new Date(dateList[index-1].value)
  287.               nextDate.setDate(nextDate.getDate() + 1)
  288.               jQuery("#date_custom_"+(index+1)).datepicker("option", {
  289.                 minDate: nextDate
  290.               })
  291.             }
  292.             dateElem.parentNode.style.display = "block"
  293.             if (activeDateCount > 0) controlWrapper.appendChild(dateControlRemove)
  294.             if (activeDateCount < dateList.length-1) {
  295.               controlWrapper.appendChild(dateControlAdd)
  296.               dateControlAdd.disabled = !dateElem.value
  297.             }
  298.           } else {
  299.             dateElem.parentNode.style.display = "none"
  300.             dateElem.value = null
  301.             dateNativeElem.value = null
  302.             timeNativeElem.value = null
  303.           }
  304.         })
  305.          
  306.         if (meidoActive) meidoCart.calcDateCollection()
  307.          
  308.         values.additional_offices = []
  309.         additionalOfficesList.forEach((elem, index) => {
  310.           values.additional_offices.push(elem.value)
  311.           if ((index === 0 && values.office !== "...") || (index > 0 && values.additional_offices[index-1] !== "...")) {
  312.             elem.parentNode.style.display = "block"
  313.           } else {
  314.             elem.parentNode.style.display = "none"
  315.             elem.value = "..."
  316.           }
  317.           fsNative.additional_locations[index].value = elem.value === "..." ? null : elem.value
  318.         })
  319.          
  320.         values.document_check = documentCheckbox.checked
  321.         fsNative.document_check.value = documentCheckbox.checked ? "1" : "0"
  322.         fsNative.document_check.checked = documentCheckbox.checked
  323.         const documentLocations = [values.office, values.additional_offices].flat().map(x => officeAddress[x]).filter(x => !!x).join(", ")
  324.         document.getElementById("doc-address").innerHTML = documentLocations
  325.         // =================================================        
  326.         var text = `Заява на допуск до користування Простором Товариства з обмеженою відповідальністю «ТекХостинг» (далі – ТОВ «ТекХостинг»)
  327.  
  328. Я, фізична особа-підприємець ${"{{ current_user.phone }}"}, прошу допустити мене до користування офісним простором ТОВ «ТекХостинг» (далі – Простір), що знаходиться за адресою: ${documentLocations}.
  329.  
  330.  
  331. Я підтверджую, що на момент надання мені доступу до користування Простором:
  332.  
  333. • у мене відсутні будь-які ознаки ГРВІ, а саме: підвищена температура тіла (більше 37,2 С), кашель, утруднене дихання тощо;
  334. • я ознайомлений(а) з рекомендаціями МОЗ та ВООЗ щодо попередження зараження COVID-19 та їх дотримуюсь;
  335. • протягом останніх 14 днів я не перебував(ла) за межами України та не контактував(ла) з особами, щодо яких наявна підозра/хворими на COVID-19.
  336.  
  337. Я зобов’язуюсь під час користування Простором дотримуватися посилених санітарно-гігієнічних норм, а також рекомендацій МОЗ та ВООЗ щодо запобігання поширенню COVID-19, а саме:
  338.  
  339. • носити медичну маску/респіратор;
  340. • ретельно мити руки з милом протягом 20-40 сек. та регулярно обробляти їх антисептичним засобом під час перебування в Просторі;
  341. • дотримуватися дистанції min 1,5 (півтора) метри від інших відвідувачів Простору.
  342.  
  343. Дата: ${todayGlobal}`
  344.         // =================================================
  345.         fsNative.document_text.value = text
  346.       }
  347.     }
  348.       if (window.location.pathname === "/support/catalog/items/28") {
  349.       const fsFields = {
  350.         from: "requested_item_values_28_requested_item_value_attributes_cf_from_63350",
  351.         to: "requested_item_values_28_requested_item_value_attributes_cf_to_63350",
  352.         country: "requested_item_values_28_requested_item_value_attributes_cf_office_list_63350"
  353.       }
  354.          
  355.       const countryBlacklist = [
  356.         "North Korea",
  357.         "Lebanon"
  358.       ]
  359.          
  360.       // =====================================================
  361.  
  362.       const fsNative = {
  363.         dates: [
  364.           {
  365.             date: document.getElementById(fsFields.from + "_date"),
  366.             time: document.getElementById(fsFields.from + "_time")
  367.           },
  368.           {
  369.             date: document.getElementById(fsFields.to + "_date"),
  370.             time: document.getElementById(fsFields.to + "_time")
  371.           }
  372.         ],
  373.         country: document.getElementById(fsFields.country)
  374.       }
  375.        
  376.           /*
  377.       const countryDropdown = createSimplifiedDropdown(fsFields.country, [], "country")
  378.       countryDropdown.addEventListener("change", function(){ renderController() })
  379.        
  380.       fetch("https://restcountries.eu/rest/v2/all").then(res => {
  381.         return res.json()
  382.       }).then(countries => {
  383.         countries.forEach(country => {
  384.           console.log(country.name)
  385.           if (!countryBlacklist.includes(country.name)) {
  386.             const option = document.createElement("option")
  387.             option.innerHTML = country.name
  388.             option.value = country.name
  389.             countryDropdown.appendChild(option)
  390.           }
  391.         })
  392.         renderController()
  393.       })
  394.           */
  395.       const dateList = createCustomDates(fsNative.dates.map(x => x.date))
  396.       const minDate = new Date()
  397.       minDate.setDate(minDate.getDate() + 14)
  398.  
  399.       dateList.forEach(dateElem => {
  400.         dateElem.parentNode.style.display = "block"
  401.         jQuery(dateElem).datepicker("option", {
  402.           onSelect: function() {
  403.             renderController()
  404.           },
  405.           minDate: minDate
  406.         })
  407.       })
  408.        
  409.       renderController()
  410.        
  411.       function renderController(){
  412.         dateList.forEach((dateElem, index) => {
  413.           if (dateElem.value) {
  414.             fsNative.dates[index].date.value = reverseForFS(dateElem.value)
  415.             fsNative.dates[index].time.value = "00:00"
  416.           } else {
  417.             fsNative.dates[index].date.value = null
  418.             fsNative.dates[index].time.value = null
  419.           }
  420.         })
  421.           //fsNative.country.value = countryDropdown.value
  422.       }
  423.     }
  424.      
  425.     if (window.location.pathname === "/support/catalog/items/30") {
  426.       console.log("dates init")
  427.       const fsFields = {
  428.         dates: [
  429.           "requested_item_values_30_requested_item_value_attributes_cf_date1_63350",
  430.           "requested_item_values_30_requested_item_value_attributes_cf_date2_63350",
  431.           "requested_item_values_30_requested_item_value_attributes_cf_date3_63350",
  432.           "requested_item_values_30_requested_item_value_attributes_cf_date4_63350",
  433.           "requested_item_values_30_requested_item_value_attributes_cf_date5_63350"
  434.         ]
  435.       }
  436.       //==============================================================================
  437.       const fsNative = {
  438.         dates: getElemList(fsFields.dates)
  439.       }
  440.       var activeDateCount = 0
  441.       const dateList = createCustomDates(fsFields.dates.map(x => document.getElementById(x+"_date")))
  442.       const today = new Date()
  443.       const max = new Date()
  444.       max.setDate(max.getDate() + 7 + (today.getDay() === 0 ? 0 : 7 - today.getDay()))
  445.       dateList.forEach(dateElem => {
  446.         jQuery(dateElem).datepicker("option", {
  447.           onSelect: function() {
  448.             renderController()
  449.           },
  450.           minDate: today,
  451.           maxDate: max
  452.         })
  453.       })
  454.       const dateControlAdd = document.createElement("button")
  455.       dateControlAdd.innerHTML = "+"
  456.       const dateControlRemove = document.createElement("button")
  457.       dateControlRemove.innerHTML = "-"
  458.       dateControlAdd.addEventListener("click", function(e){
  459.         e.preventDefault()
  460.         activeDateCount += 1
  461.         renderController()
  462.       })
  463.       dateControlRemove.addEventListener("click", function(e){
  464.         e.preventDefault()
  465.         activeDateCount -= 1
  466.         renderController()
  467.       })
  468.      
  469.       renderController()
  470.      
  471.       function renderController(){
  472.         dateList.forEach((dateElem, index) => {
  473.           const date = document.getElementById(fsFields.dates[index] + "_date")
  474.           const time = document.getElementById(fsFields.dates[index] + "_time")
  475.           const errorElem = document.getElementById("date_custom_" + (index+1) + "-error")
  476.           if (errorElem) errorElem.style.display = "none"
  477.           if (dateElem.value) {
  478.             date.value = reverseForFS(dateElem.value)
  479.             time.value = "00:00"
  480.           } else {
  481.             date.value = null
  482.             time.value = null
  483.           }
  484.           const controlWrapper = document.getElementById("controls_" + index)
  485.           controlWrapper.innerHTML = ""
  486.           controlWrapper.style.display = "inline"
  487.           if (index < activeDateCount) {
  488.             dateElem.disabled = true
  489.             dateElem.parentNode.style.display = "block"
  490.           } else if (index === activeDateCount) {
  491.             dateElem.disabled = false
  492.             if (index > 0 && dateList[index-1].value) {
  493.               const nextDate = new Date(dateList[index-1].value)
  494.               nextDate.setDate(nextDate.getDate() + 1)
  495.               jQuery("#date_custom_"+(index+1)).datepicker("option", {
  496.                 minDate: nextDate
  497.               })
  498.             }
  499.             dateElem.parentNode.style.display = "block"
  500.             if (activeDateCount > 0) controlWrapper.appendChild(dateControlRemove)
  501.             if (activeDateCount < dateList.length-1) {
  502.               controlWrapper.appendChild(dateControlAdd)
  503.               dateControlAdd.disabled = !dateElem.value
  504.             }
  505.           } else {
  506.             dateElem.parentNode.style.display = "none"
  507.             dateElem.value = null
  508.             date.value = null
  509.             time.value = null
  510.           }
  511.         })
  512.       }
  513.     }
  514.   })
  515.    
  516.   function replaceInputWithDropdown(targetId, dataset, facsId = null){
  517.     const nativeContainer = document.getElementById(targetId).parentNode
  518.     document.getElementById(targetId).style.display = "none"
  519.     const selector = document.createElement("select")
  520.     selector.id = facsId
  521.     for (let optionName in dataset) {
  522.       const option = document.createElement("option")
  523.       option.innerHTML = optionName
  524.       option.value = optionName
  525.       selector.appendChild(option)
  526.     }
  527.     nativeContainer.appendChild(selector)
  528.     return selector
  529.   }
  530.  
  531.   function createSimplifiedDropdown(targetId, dataset, facsId = null){
  532.     const nativeContainer = document.getElementById(targetId).parentNode
  533.     document.getElementById(targetId).style.display = "none"
  534.     const selector = document.createElement("select")
  535.     selector.id = facsId
  536.     dataset.forEach(optionName => {
  537.       const option = document.createElement("option")
  538.       option.innerHTML = optionName
  539.       option.value = optionName
  540.       selector.appendChild(option)
  541.     })
  542.     nativeContainer.appendChild(selector)
  543.     return selector
  544.   }
  545.  
  546.   function createCustomCheckbox(container, id, labelText){
  547.     container.childNodes.forEach(elem => {
  548.       elem.style.display = "none"
  549.     })
  550.     const checkboxWrapper = document.createElement("div")
  551.     const checkbox = document.createElement("input")
  552.     checkbox.type = "checkbox"
  553.     checkbox.id = id
  554.     const checkboxLabel = document.createElement("label")
  555.     checkboxLabel.htmlFor = id
  556.     checkboxLabel.style.display = "inline"
  557.     checkboxLabel.style.marginLeft = "5px"
  558.     checkboxLabel.appendChild(labelText)
  559.     checkboxWrapper.appendChild(checkbox)
  560.     checkboxWrapper.appendChild(checkboxLabel)
  561.     container.appendChild(checkboxWrapper)
  562.     return checkbox
  563.   }
  564.  
  565.   function createCustomDates(nativeList){
  566.     var customDateCollection = []  
  567.     nativeList.forEach((dateNativeField, index) => {
  568.       dateNativeField.parentNode.style.display = "none"
  569.       const dateField = document.createElement("input")
  570.       const elemId = "date_custom_" + (index + 1)
  571.       dateField.id = elemId
  572.       const controlWrapper = document.createElement("span")
  573.       controlWrapper.id = "controls_" + index
  574.       controlWrapper.style.marginLeft = "5px"
  575.       dateNativeField.parentNode.parentNode.append(dateField)
  576.       dateNativeField.parentNode.parentNode.append(controlWrapper)
  577.       if (index > 0) dateNativeField.parentNode.parentNode.style.display = "none"
  578.       customDateCollection.push(dateField)
  579.       jQuery("#"+elemId).datepicker({
  580.         dateFormat: "yy-mm-dd",
  581.         firstDay: 1
  582.       })
  583.     })
  584.     return customDateCollection
  585.   }
  586.    
  587.   function createDocumentSection(target, todayGlobal){
  588.     target.parentNode.childNodes.forEach(node => {
  589.       node.style.display = "none"
  590.     })
  591.     const documentTextWrapper = document.createElement("div")
  592.     const documentTextHeader = document.createElement("div")
  593.     documentTextHeader.style.fontSize = "16px"
  594.     const headerArrow = document.createElement("span")
  595.     headerArrow.innerHTML = "▼"
  596.     const headerTitle = document.createElement("span")
  597.     headerTitle.innerHTML = "Текст документа (click to view)"
  598.     documentTextHeader.appendChild(headerArrow)
  599.     documentTextHeader.appendChild(headerTitle)
  600.     const documentTextContent = document.createElement("div")
  601.     documentTextHeader.onclick = function(){
  602.       documentTextContent.hidden = !documentTextContent.hidden
  603.       headerArrow.innerHTML = (headerArrow.innerHTML === "►" ? "▼" : "►")
  604.     }
  605.     documentTextContent.style.width = "600px"
  606.     documentTextContent.style.margin = "15px"
  607.     documentTextContent.insertAdjacentHTML('beforeend', '<div style="text-align: center">         <b>Заява на допуск до користування Простором Товариства з обмеженою відповідальністю «ТекХостинг» (далі – ТОВ «ТекХостинг»)</b>       </div>       <br>       <div style="text-align: justify">         <p>           Я, <b>фізична особа-підприємець</b> {{ current_user.phone }}, прошу допустити мене до користування офісним простором ТОВ «ТекХостинг» (далі – Простір), що знаходиться за адресою: <span id="doc-address"></span>.         </p>         <br>         <p>           <b>Я підтверджую</b>, що на момент надання мені доступу до користування Простором:           <ul>             <li>у мене відсутні будь-які ознаки ГРВІ, а саме: підвищена температура тіла (більше 37,2 С), кашель, утруднене дихання тощо;</li>             <li>я ознайомлений(а) з рекомендаціями МОЗ та ВООЗ щодо попередження зараження COVID-19 та їх дотримуюсь;</li>             <li>протягом останніх 14 днів я не перебував(ла) за межами України та не контактував(ла) з особами, щодо яких наявна підозра/хворими на COVID-19.</li>           </ul>         </p>         <br>         <p>           <b>Я зобов’язуюсь</b> під час користування Простором дотримуватися посилених санітарно-гігієнічних норм, а також рекомендацій МОЗ та ВООЗ щодо запобігання поширенню COVID-19, а саме:           <ul>             <li>носити медичну маску/респіратор;</li>             <li>ретельно мити руки з милом протягом 20-40 сек. та регулярно обробляти їх антисептичним засобом під час перебування в Просторі;</li>             <li>дотримуватися дистанції min 1,5 (півтора) метри від інших відвідувачів Простору.</li>           </ul>         </p>       </div><br>       <div>         <b>Дата</b>: ' + todayGlobal + '       </div>')
  608.     documentTextContent.hidden = true
  609.     documentTextWrapper.appendChild(documentTextHeader)
  610.     documentTextWrapper.appendChild(documentTextContent)
  611.     target.parentNode.appendChild(documentTextWrapper)
  612.     return documentTextContent
  613.   }
  614.    
  615.   function createAdditionalOfficeSelectors(ids, datalist){
  616.     var list = []
  617.     ids.forEach((id, index) => {
  618.       const newID = "additional_office_" + (index+1)
  619.       const selector = replaceInputWithDropdown(id, datalist, newID)
  620.       selector.parentNode.style.display = "none"
  621.       if (index > 0) selector.parentNode.childNodes.item("LABEL").style.display = "none"
  622.       list.push(selector)
  623.     })
  624.     return list
  625.   }
  626.    
  627.   function calcDateLimits(thisWeek){
  628.     const nowDate = new Date()
  629.     var limits = []
  630.     if (thisWeek) {
  631.       const dateMin = nowDate.toISOString().split("T")[0]
  632.       const nowWeekDay = nowDate.getDay()
  633.       const daysToAdd = !nowWeekDay ? 0 : 7 - nowWeekDay
  634.       nowDate.setDate(nowDate.getDate() + daysToAdd)
  635.       const dateMax = nowDate.toISOString().split("T")[0]
  636.       limits.push(dateMin)
  637.       limits.push(dateMax)
  638.     } else {
  639.       const nowWeekDay = nowDate.getDay()
  640.       const daysToAdd = !nowWeekDay ? 1 : 7 - nowWeekDay + 1
  641.       nowDate.setDate(nowDate.getDate() + daysToAdd)
  642.       const dateMin = nowDate.toISOString().split("T")[0]
  643.       nowDate.setDate(nowDate.getDate() + 6)
  644.       const dateMax = nowDate.toISOString().split("T")[0]
  645.       limits.push(dateMin)
  646.       limits.push(dateMax)
  647.     }
  648.     return limits
  649.   }
  650.    
  651.   function reverseForFS(date){
  652.     if (!date) return null
  653.     const vals = date.split("-")
  654.     //return `${vals[2]}-${vals[1]}-${vals[0]}`
  655.     return vals[2]+"-"+vals[1]+"-"+vals[0]
  656.   }
  657.  
  658.   function getElemList(idList){
  659.     var collection = []
  660.     idList.forEach(id => {
  661.       collection.push(document.getElementById(id))
  662.     })
  663.     return collection
  664.   }
  665.  
  666.   // ==================== MEIDO ====================
  667.  
  668.   class MeidoCart{
  669.   constructor(itemList, limit, cartElem, dateElemsCollection, fsMeidoField, reverseDate){
  670.     console.log('constructing')
  671.     this.itemList = itemList
  672.     this.dailyLimit = limit
  673.     //this.renderElementId = elemId
  674.     this.renderTarget = cartElem
  675.     this.reverseDate = reverseDate
  676.     this.targetField = fsMeidoField
  677.     this.dateElemsCollection = dateElemsCollection
  678.     console.log(this.dateElemsCollection)
  679.     this.dateCollection = null
  680.     this.selectedRadio = null
  681.  
  682.     this.dateElemsCollection.forEach(dateElem => {
  683.       dateElem.onchange = function(){
  684.         this.calcDateCollection()
  685.         this.render()
  686.       }
  687.     })
  688.   }
  689.  
  690.   init(){
  691.     this.calcDateCollection()
  692.   }
  693.  
  694.   reverse(date){
  695.     const vals = date.split("-")
  696.     //return `${vals[2]}-${vals[1]}-${vals[0]}`
  697.     return vals[2]+"-"+vals[1]+"-"+vals[0]
  698.   }
  699.  
  700.   calcDateCollection(){
  701.     if (!this.dateCollection) this.dateCollection = {}
  702.     var flag = false
  703.     var collection = []
  704.     var dateObj = {}
  705.     this.dateElemsCollection.forEach(dateElem => {
  706.       if (dateElem.value) {
  707.         flag = true
  708.         collection.push(dateElem.value)
  709.       }
  710.       const weekday = new Date(dateElem.value).getDay()
  711.       if (dateElem.value && weekday !== 6 && weekday !== 0){
  712.         if (!this.dateCollection[dateElem.value]){
  713.           dateObj[dateElem.value] = {
  714.             limit: this.dailyLimit,
  715.             items: {}
  716.           }
  717.         } else {
  718.           dateObj[dateElem.value] = this.dateCollection[dateElem.value]
  719.         }
  720.       }
  721.     })
  722.     if (!this.selectedRadio || !collection.includes(this.selectedRadio)) this.selectedRadio = this.dateElemsCollection[0].value
  723.     if (!flag) dateObj = null
  724.     this.dateCollection = dateObj
  725.     this.render()
  726.   }
  727.  
  728.   get cartState(){
  729.     return JSON.stringify(this.dateCollection)
  730.   }
  731.  
  732.   render(){
  733.     const wrapper = document.createElement("div")
  734.     if (!this.dateCollection) {
  735.       wrapper.innerHTML = "Диапазон дат указан неверно!"
  736.     } else {
  737.       for(let date in this.dateCollection){
  738.         const dateWrapper = document.createElement("div")
  739.         dateWrapper.className += "meido-cart-date-wrapper"
  740.         const header = document.createElement("div")
  741.         header.className += "meido-cart-date-header"
  742.         const radio = document.createElement("input")
  743.         radio.type = "radio"
  744.         radio.id = date
  745.         radio.value = date
  746.         radio.name = "date-radio"
  747.         radio.addEventListener('change', function(e){
  748.           this.selectedRadio = e.target.value
  749.         }.bind(this))
  750.         if (date === this.selectedRadio) radio.checked = true
  751.         header.appendChild(radio)
  752.         const label = document.createElement("label")
  753.         label.htmlFor = date
  754.         //label.innerHTML += `${date} (остаток: ${this.dateCollection[date].limit} грн.)`
  755.         label.innerHTML += date+" (остаток: "+this.dateCollection[date].limit+" грн.)"
  756.         header.appendChild(label)
  757.         dateWrapper.appendChild(header)
  758.         var flag = false
  759.         for(let item in this.dateCollection[date].items){
  760.           flag = true
  761.           const itemElem = document.createElement("div")
  762.           itemElem.className += "meido-cart-item"
  763.           const itemText = document.createElement("span")
  764.           //itemText.innerHTML = `${this.dateCollection[date].items[item]} x ${this.itemList[item].name}`
  765.           itemText.innerHTML = this.dateCollection[date].items[item]+" x "+this.itemList[item].name
  766.           itemElem.appendChild(itemText)
  767.           const itemRemove = document.createElement("button")
  768.           itemRemove.innerHTML = "X"
  769.           itemRemove.className += "meido-cart-item-remove"
  770.           itemRemove.onclick = function(){ this.removeMeidoItem(item, date) }.bind(this)
  771.           itemElem.appendChild(itemRemove)
  772.           dateWrapper.appendChild(itemElem)
  773.         }
  774.         if (!flag) {
  775.           const itemEmpty = document.createElement("div")
  776.           itemEmpty.className += "meido-cart-item"
  777.           itemEmpty.style.color = "grey"
  778.           itemEmpty.innerHTML = "<i>Ничего не добавлено</i>"
  779.           dateWrapper.appendChild(itemEmpty)
  780.         }
  781.         wrapper.appendChild(dateWrapper)
  782.       }
  783.     }
  784.     this.renderTarget.innerHTML = ""
  785.     this.renderTarget.appendChild(wrapper)
  786.     document.getElementById(this.targetField).innerHTML = this.cartState
  787.   }
  788.  
  789.   addMeidoItem(itemId){
  790.     if (this.dateCollection[this.selectedRadio].limit - this.itemList[itemId].price >= 0) {
  791.       if (!this.dateCollection[this.selectedRadio].items[itemId]) {
  792.         this.dateCollection[this.selectedRadio].items[itemId] = 1
  793.       } else {
  794.         this.dateCollection[this.selectedRadio].items[itemId] += 1
  795.       }
  796.       this.dateCollection[this.selectedRadio].limit -= this.itemList[itemId].price
  797.     } else {
  798.       console.error('Insufficient funds!')
  799.     }
  800.     this.render()
  801.   }
  802.  
  803.   removeMeidoItem(itemId, date){
  804.     this.dateCollection[date].items[itemId] -= 1
  805.     if (this.dateCollection[date].items[itemId] === 0) delete this.dateCollection[date].items[itemId]
  806.     this.dateCollection[date].limit += this.itemList[itemId].price
  807.     this.render()
  808.   }
  809. }
  810.  
  811. function meidoInit(container, dateElemsCollection, fsMeidoField, limit, reverseDate = false){
  812.   const innerContainer = document.createElement("div")
  813.  
  814.   return fetch("https://analytics.getmeido.com/api/fs/product-list?token="+meidoToken)
  815.   .then(res => {return res.json()})
  816.   .then(data => {
  817.     const title = document.createElement("h4")
  818.     title.innerHTML = "Заказ еды Meido"
  819.     innerContainer.appendChild(title)
  820.     const mainWindow = buildMeidoWindow(data, dateElemsCollection, fsMeidoField, limit, reverseDate)
  821.     innerContainer.appendChild(mainWindow)
  822.     meidoCart.init()
  823.     container.appendChild(innerContainer)
  824.     return innerContainer
  825.   }).catch(err => {
  826.     console.error("[MEIDO] Cannot get Meido menu!")
  827.     console.error(err)
  828.   })
  829.  
  830. }
  831.  
  832. function buildMeidoWindow(apiData, dateElemsCollection, fsMeidoField, limit, reverseDate){
  833.   const wrapper = document.createElement("div")
  834.   wrapper.className += "meido-main-window"
  835.   const menuElem = document.createElement("div")
  836.   menuElem.id = "meido-menu"
  837.   const cartElem = document.createElement("div")
  838.   cartElem.id = "meido-cart"
  839.   var categorized = {}
  840.   var flat = {}
  841.   apiData.forEach(item => {
  842.     if (!categorized[item.product_contractor_title]) categorized[item.product_contractor_title] = {}
  843.     if (!categorized[item.product_contractor_title][item.category_title]) categorized[item.product_contractor_title][item.category_title] = {}
  844.     categorized[item.product_contractor_title][item.category_title][item.id] = item
  845.     flat[item.id] = {
  846.       name: item.product_title,
  847.       price: parseInt(item.product_price)
  848.     }
  849.   })
  850.   menuElem.appendChild(buildMenu(categorized))
  851.   console.log(limit, dateElemsCollection, reverseDate)
  852.   window.meidoCart = new MeidoCart(flat, limit, cartElem, dateElemsCollection, fsMeidoField, reverseDate)
  853.   cartElem.className += "meido-cart-wrapper"
  854.   wrapper.appendChild(menuElem)
  855.   wrapper.appendChild(cartElem)
  856.   return wrapper
  857. }
  858.  
  859. function buildMenu(data){
  860.   const wrapper = document.createElement("div")
  861.   wrapper.className += "meido-menu-wrapper"
  862.   for(let category in data){
  863.     const categoryWrapper = document.createElement("div")
  864.     const categoryHeader = document.createElement("div")
  865.     categoryHeader.className += "meido-category-title"
  866.     const categoryArrow = document.createElement("span")
  867.     categoryArrow.className += "arrow"
  868.     categoryArrow.innerHTML = "►"
  869.     const categoryTitle = document.createElement("span")
  870.     categoryTitle.innerHTML = category
  871.     categoryHeader.appendChild(categoryArrow)
  872.     categoryHeader.appendChild(categoryTitle)
  873.     const categoryContent = document.createElement("div")
  874.     categoryContent.className += "meido-category-content"
  875.     categoryHeader.onclick = function(){
  876.       categoryContent.hidden = !categoryContent.hidden
  877.       categoryArrow.innerHTML = (categoryArrow.innerHTML === "►" ? "▼" : "►")
  878.     }
  879.     categoryContent.hidden = true
  880.     categoryWrapper.appendChild(categoryHeader)
  881.     for(let contractor in data[category]){
  882.       const contractorWrapper = document.createElement("div")
  883.       const contractorHeader = document.createElement("div")
  884.       contractorHeader.className += "meido-contractor-title"
  885.       const contractorArrow = document.createElement("span")
  886.       contractorArrow.className += "arrow"
  887.       contractorArrow.innerHTML = "►"
  888.       const contractorTitle = document.createElement("span")
  889.       contractorTitle.innerHTML = contractor
  890.       contractorHeader.appendChild(contractorArrow)
  891.       contractorHeader.appendChild(contractorTitle)
  892.       const contractorContent = document.createElement("div")
  893.       contractorContent.className += "meido-contractor-content"
  894.       contractorHeader.onclick = function(){
  895.         contractorContent.hidden = !contractorContent.hidden
  896.         contractorArrow.innerHTML = (contractorArrow.innerHTML === "►" ? "▼" : "►")
  897.       }
  898.       contractorContent.hidden = true
  899.       contractorWrapper.appendChild(contractorHeader)
  900.       for(let item in data[category][contractor]){
  901.         contractorContent.appendChild(buildMenuItem(data[category][contractor][item]))
  902.       }
  903.       contractorWrapper.appendChild(contractorContent)
  904.       categoryContent.appendChild(contractorWrapper)
  905.     }
  906.     categoryWrapper.appendChild(categoryContent)
  907.     wrapper.appendChild(categoryWrapper)
  908.   }
  909.  
  910.   return wrapper
  911. }
  912.  
  913. function buildMenuItem(item){
  914.   const wrapper = document.createElement("div")
  915.   wrapper.className += "meido-item"
  916.   const itemTitle = document.createElement("div")
  917.   itemTitle.innerHTML = "<u>" + item.product_title + "</u>"
  918.   itemTitle.className += "meido-item-title"
  919.   const itemPic = document.createElement("img")
  920.   itemPic.src = item.photo_url
  921.   itemPic.className += "meido-pic"
  922.   const itemDesc = document.createElement("div")
  923.   itemDesc.innerHTML = item.product_description
  924.   const price = document.createElement("span")
  925.   //price.innerHTML = `<i>Цена: ${item.product_price} грн.</i>`
  926.   price.innerHTML = "<i>Цена: "+item.product_price+" грн.</i>"
  927.   price.className += "meido-price"
  928.   const add = document.createElement("button")
  929.   add.innerHTML = "Добавить"
  930.   add.className += "meido-add-button"
  931.   add.onclick = null
  932.   add.onclick = function(e){
  933.     e.preventDefault()
  934.     meidoCart.addMeidoItem(item.id)
  935.   }
  936.   wrapper.appendChild(itemTitle)
  937.   wrapper.appendChild(itemPic)
  938.   wrapper.appendChild(itemDesc)
  939.   wrapper.appendChild(add)
  940.   wrapper.appendChild(price)
  941.   return wrapper
  942. }
  943. </script>
Add Comment
Please, Sign In to add comment