VladislavNechepaev

Untitled

Aug 21st, 2020
129
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.           console.log("{{ current_user.phone }}")
  326.         // =================================================        
  327.         var text = `Заява на допуск до користування Простором Товариства з обмеженою відповідальністю «ТекХостинг» (далі – ТОВ «ТекХостинг»)
  328.  
  329. Я, фізична особа-підприємець ${"{{ current_user.phone }}"}, прошу допустити мене до користування офісним простором ТОВ «ТекХостинг» (далі – Простір), що знаходиться за адресою: ${documentLocations}.
  330.  
  331.  
  332. Я підтверджую, що на момент надання мені доступу до користування Простором:
  333.  
  334. • у мене відсутні будь-які ознаки ГРВІ, а саме: підвищена температура тіла (більше 37,2 С), кашель, утруднене дихання тощо;
  335. • я ознайомлений(а) з рекомендаціями МОЗ та ВООЗ щодо попередження зараження COVID-19 та їх дотримуюсь;
  336. • протягом останніх 14 днів я не перебував(ла) за межами України та не контактував(ла) з особами, щодо яких наявна підозра/хворими на COVID-19.
  337.  
  338. Я зобов’язуюсь під час користування Простором дотримуватися посилених санітарно-гігієнічних норм, а також рекомендацій МОЗ та ВООЗ щодо запобігання поширенню COVID-19, а саме:
  339.  
  340. • носити медичну маску/респіратор;
  341. • ретельно мити руки з милом протягом 20-40 сек. та регулярно обробляти їх антисептичним засобом під час перебування в Просторі;
  342. • дотримуватися дистанції min 1,5 (півтора) метри від інших відвідувачів Простору.
  343.  
  344. Дата: ${todayGlobal}`
  345.         // =================================================
  346.         fsNative.document_text.value = text
  347.       }
  348.     }
  349.       if (window.location.pathname === "/support/catalog/items/28") {
  350.       const fsFields = {
  351.         from: "requested_item_values_28_requested_item_value_attributes_cf_from_63350",
  352.         to: "requested_item_values_28_requested_item_value_attributes_cf_to_63350",
  353.         country: "requested_item_values_28_requested_item_value_attributes_cf_office_list_63350"
  354.       }
  355.          
  356.       const countryBlacklist = [
  357.         "North Korea",
  358.         "Lebanon"
  359.       ]
  360.          
  361.       // =====================================================
  362.  
  363.       const fsNative = {
  364.         dates: [
  365.           {
  366.             date: document.getElementById(fsFields.from + "_date"),
  367.             time: document.getElementById(fsFields.from + "_time")
  368.           },
  369.           {
  370.             date: document.getElementById(fsFields.to + "_date"),
  371.             time: document.getElementById(fsFields.to + "_time")
  372.           }
  373.         ],
  374.         country: document.getElementById(fsFields.country)
  375.       }
  376.        
  377.           /*
  378.       const countryDropdown = createSimplifiedDropdown(fsFields.country, [], "country")
  379.       countryDropdown.addEventListener("change", function(){ renderController() })
  380.        
  381.       fetch("https://restcountries.eu/rest/v2/all").then(res => {
  382.         return res.json()
  383.       }).then(countries => {
  384.         countries.forEach(country => {
  385.           console.log(country.name)
  386.           if (!countryBlacklist.includes(country.name)) {
  387.             const option = document.createElement("option")
  388.             option.innerHTML = country.name
  389.             option.value = country.name
  390.             countryDropdown.appendChild(option)
  391.           }
  392.         })
  393.         renderController()
  394.       })
  395.           */
  396.       const dateList = createCustomDates(fsNative.dates.map(x => x.date))
  397.       const minDate = new Date()
  398.       minDate.setDate(minDate.getDate() + 14)
  399.  
  400.       dateList.forEach(dateElem => {
  401.         dateElem.parentNode.style.display = "block"
  402.         jQuery(dateElem).datepicker("option", {
  403.           onSelect: function() {
  404.             renderController()
  405.           },
  406.           minDate: minDate
  407.         })
  408.       })
  409.        
  410.       renderController()
  411.        
  412.       function renderController(){
  413.         dateList.forEach((dateElem, index) => {
  414.           if (dateElem.value) {
  415.             fsNative.dates[index].date.value = reverseForFS(dateElem.value)
  416.             fsNative.dates[index].time.value = "00:00"
  417.           } else {
  418.             fsNative.dates[index].date.value = null
  419.             fsNative.dates[index].time.value = null
  420.           }
  421.         })
  422.           //fsNative.country.value = countryDropdown.value
  423.       }
  424.     }
  425.      
  426.     if (window.location.pathname === "/support/catalog/items/30") {
  427.       console.log("dates init")
  428.       const fsFields = {
  429.         dates: [
  430.           "requested_item_values_30_requested_item_value_attributes_cf_date1_63350",
  431.           "requested_item_values_30_requested_item_value_attributes_cf_date2_63350",
  432.           "requested_item_values_30_requested_item_value_attributes_cf_date3_63350",
  433.           "requested_item_values_30_requested_item_value_attributes_cf_date4_63350",
  434.           "requested_item_values_30_requested_item_value_attributes_cf_date5_63350"
  435.         ]
  436.       }
  437.       //==============================================================================
  438.       const fsNative = {
  439.         dates: getElemList(fsFields.dates)
  440.       }
  441.       var activeDateCount = 0
  442.       const dateList = createCustomDates(fsFields.dates.map(x => document.getElementById(x+"_date")))
  443.       const today = new Date()
  444.       const max = new Date()
  445.       max.setDate(max.getDate() + 7 + (today.getDay() === 0 ? 0 : 7 - today.getDay()))
  446.       dateList.forEach(dateElem => {
  447.         jQuery(dateElem).datepicker("option", {
  448.           onSelect: function() {
  449.             renderController()
  450.           },
  451.           minDate: today,
  452.           maxDate: max
  453.         })
  454.       })
  455.       const dateControlAdd = document.createElement("button")
  456.       dateControlAdd.innerHTML = "+"
  457.       const dateControlRemove = document.createElement("button")
  458.       dateControlRemove.innerHTML = "-"
  459.       dateControlAdd.addEventListener("click", function(e){
  460.         e.preventDefault()
  461.         activeDateCount += 1
  462.         renderController()
  463.       })
  464.       dateControlRemove.addEventListener("click", function(e){
  465.         e.preventDefault()
  466.         activeDateCount -= 1
  467.         renderController()
  468.       })
  469.      
  470.       renderController()
  471.      
  472.       function renderController(){
  473.         dateList.forEach((dateElem, index) => {
  474.           const date = document.getElementById(fsFields.dates[index] + "_date")
  475.           const time = document.getElementById(fsFields.dates[index] + "_time")
  476.           const errorElem = document.getElementById("date_custom_" + (index+1) + "-error")
  477.           if (errorElem) errorElem.style.display = "none"
  478.           if (dateElem.value) {
  479.             date.value = reverseForFS(dateElem.value)
  480.             time.value = "00:00"
  481.           } else {
  482.             date.value = null
  483.             time.value = null
  484.           }
  485.           const controlWrapper = document.getElementById("controls_" + index)
  486.           controlWrapper.innerHTML = ""
  487.           controlWrapper.style.display = "inline"
  488.           if (index < activeDateCount) {
  489.             dateElem.disabled = true
  490.             dateElem.parentNode.style.display = "block"
  491.           } else if (index === activeDateCount) {
  492.             dateElem.disabled = false
  493.             if (index > 0 && dateList[index-1].value) {
  494.               const nextDate = new Date(dateList[index-1].value)
  495.               nextDate.setDate(nextDate.getDate() + 1)
  496.               jQuery("#date_custom_"+(index+1)).datepicker("option", {
  497.                 minDate: nextDate
  498.               })
  499.             }
  500.             dateElem.parentNode.style.display = "block"
  501.             if (activeDateCount > 0) controlWrapper.appendChild(dateControlRemove)
  502.             if (activeDateCount < dateList.length-1) {
  503.               controlWrapper.appendChild(dateControlAdd)
  504.               dateControlAdd.disabled = !dateElem.value
  505.             }
  506.           } else {
  507.             dateElem.parentNode.style.display = "none"
  508.             dateElem.value = null
  509.             date.value = null
  510.             time.value = null
  511.           }
  512.         })
  513.       }
  514.     }
  515.   })
  516.    
  517.   function replaceInputWithDropdown(targetId, dataset, facsId = null){
  518.     const nativeContainer = document.getElementById(targetId).parentNode
  519.     document.getElementById(targetId).style.display = "none"
  520.     const selector = document.createElement("select")
  521.     selector.id = facsId
  522.     for (let optionName in dataset) {
  523.       const option = document.createElement("option")
  524.       option.innerHTML = optionName
  525.       option.value = optionName
  526.       selector.appendChild(option)
  527.     }
  528.     nativeContainer.appendChild(selector)
  529.     return selector
  530.   }
  531.  
  532.   function createSimplifiedDropdown(targetId, dataset, facsId = null){
  533.     const nativeContainer = document.getElementById(targetId).parentNode
  534.     document.getElementById(targetId).style.display = "none"
  535.     const selector = document.createElement("select")
  536.     selector.id = facsId
  537.     dataset.forEach(optionName => {
  538.       const option = document.createElement("option")
  539.       option.innerHTML = optionName
  540.       option.value = optionName
  541.       selector.appendChild(option)
  542.     })
  543.     nativeContainer.appendChild(selector)
  544.     return selector
  545.   }
  546.  
  547.   function createCustomCheckbox(container, id, labelText){
  548.     container.childNodes.forEach(elem => {
  549.       elem.style.display = "none"
  550.     })
  551.     const checkboxWrapper = document.createElement("div")
  552.     const checkbox = document.createElement("input")
  553.     checkbox.type = "checkbox"
  554.     checkbox.id = id
  555.     const checkboxLabel = document.createElement("label")
  556.     checkboxLabel.htmlFor = id
  557.     checkboxLabel.style.display = "inline"
  558.     checkboxLabel.style.marginLeft = "5px"
  559.     checkboxLabel.appendChild(labelText)
  560.     checkboxWrapper.appendChild(checkbox)
  561.     checkboxWrapper.appendChild(checkboxLabel)
  562.     container.appendChild(checkboxWrapper)
  563.     return checkbox
  564.   }
  565.  
  566.   function createCustomDates(nativeList){
  567.     var customDateCollection = []  
  568.     nativeList.forEach((dateNativeField, index) => {
  569.       dateNativeField.parentNode.style.display = "none"
  570.       const dateField = document.createElement("input")
  571.       const elemId = "date_custom_" + (index + 1)
  572.       dateField.id = elemId
  573.       const controlWrapper = document.createElement("span")
  574.       controlWrapper.id = "controls_" + index
  575.       controlWrapper.style.marginLeft = "5px"
  576.       dateNativeField.parentNode.parentNode.append(dateField)
  577.       dateNativeField.parentNode.parentNode.append(controlWrapper)
  578.       if (index > 0) dateNativeField.parentNode.parentNode.style.display = "none"
  579.       customDateCollection.push(dateField)
  580.       jQuery("#"+elemId).datepicker({
  581.         dateFormat: "yy-mm-dd",
  582.         firstDay: 1
  583.       })
  584.     })
  585.     return customDateCollection
  586.   }
  587.    
  588.   function createDocumentSection(target, todayGlobal){
  589.     target.parentNode.childNodes.forEach(node => {
  590.       node.style.display = "none"
  591.     })
  592.     const documentTextWrapper = document.createElement("div")
  593.     const documentTextHeader = document.createElement("div")
  594.     documentTextHeader.style.fontSize = "16px"
  595.     const headerArrow = document.createElement("span")
  596.     headerArrow.innerHTML = "▼"
  597.     const headerTitle = document.createElement("span")
  598.     headerTitle.innerHTML = "Текст документа (click to view)"
  599.     documentTextHeader.appendChild(headerArrow)
  600.     documentTextHeader.appendChild(headerTitle)
  601.     const documentTextContent = document.createElement("div")
  602.     documentTextHeader.onclick = function(){
  603.       documentTextContent.hidden = !documentTextContent.hidden
  604.       headerArrow.innerHTML = (headerArrow.innerHTML === "►" ? "▼" : "►")
  605.     }
  606.     documentTextContent.style.width = "600px"
  607.     documentTextContent.style.margin = "15px"
  608.     documentTextContent.insertAdjacentHTML('beforeend', '<div style="text-align: center">         <b>Заява на допуск до користування Простором Товариства з обмеженою відповідальністю «ТекХостинг» (далі – ТОВ «ТекХостинг»)</b>       </div>       <br>       <div style="text-align: justify">         <p>           Я, <b>фізична особа-підприємець</b> {{ current_user.name }}, прошу допустити мене до користування офісним простором ТОВ «ТекХостинг» (далі – Простір), що знаходиться за адресою: <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>')
  609.     documentTextContent.hidden = true
  610.     documentTextWrapper.appendChild(documentTextHeader)
  611.     documentTextWrapper.appendChild(documentTextContent)
  612.     target.parentNode.appendChild(documentTextWrapper)
  613.     return documentTextContent
  614.   }
  615.    
  616.   function createAdditionalOfficeSelectors(ids, datalist){
  617.     var list = []
  618.     ids.forEach((id, index) => {
  619.       const newID = "additional_office_" + (index+1)
  620.       const selector = replaceInputWithDropdown(id, datalist, newID)
  621.       selector.parentNode.style.display = "none"
  622.       if (index > 0) selector.parentNode.childNodes.item("LABEL").style.display = "none"
  623.       list.push(selector)
  624.     })
  625.     return list
  626.   }
  627.    
  628.   function calcDateLimits(thisWeek){
  629.     const nowDate = new Date()
  630.     var limits = []
  631.     if (thisWeek) {
  632.       const dateMin = nowDate.toISOString().split("T")[0]
  633.       const nowWeekDay = nowDate.getDay()
  634.       const daysToAdd = !nowWeekDay ? 0 : 7 - nowWeekDay
  635.       nowDate.setDate(nowDate.getDate() + daysToAdd)
  636.       const dateMax = nowDate.toISOString().split("T")[0]
  637.       limits.push(dateMin)
  638.       limits.push(dateMax)
  639.     } else {
  640.       const nowWeekDay = nowDate.getDay()
  641.       const daysToAdd = !nowWeekDay ? 1 : 7 - nowWeekDay + 1
  642.       nowDate.setDate(nowDate.getDate() + daysToAdd)
  643.       const dateMin = nowDate.toISOString().split("T")[0]
  644.       nowDate.setDate(nowDate.getDate() + 6)
  645.       const dateMax = nowDate.toISOString().split("T")[0]
  646.       limits.push(dateMin)
  647.       limits.push(dateMax)
  648.     }
  649.     return limits
  650.   }
  651.    
  652.   function reverseForFS(date){
  653.     if (!date) return null
  654.     const vals = date.split("-")
  655.     //return `${vals[2]}-${vals[1]}-${vals[0]}`
  656.     return vals[2]+"-"+vals[1]+"-"+vals[0]
  657.   }
  658.  
  659.   function getElemList(idList){
  660.     var collection = []
  661.     idList.forEach(id => {
  662.       collection.push(document.getElementById(id))
  663.     })
  664.     return collection
  665.   }
  666.  
  667.   // ==================== MEIDO ====================
  668.  
  669.   class MeidoCart{
  670.   constructor(itemList, limit, cartElem, dateElemsCollection, fsMeidoField, reverseDate){
  671.     console.log('constructing')
  672.     this.itemList = itemList
  673.     this.dailyLimit = limit
  674.     //this.renderElementId = elemId
  675.     this.renderTarget = cartElem
  676.     this.reverseDate = reverseDate
  677.     this.targetField = fsMeidoField
  678.     this.dateElemsCollection = dateElemsCollection
  679.     console.log(this.dateElemsCollection)
  680.     this.dateCollection = null
  681.     this.selectedRadio = null
  682.  
  683.     this.dateElemsCollection.forEach(dateElem => {
  684.       dateElem.onchange = function(){
  685.         this.calcDateCollection()
  686.         this.render()
  687.       }
  688.     })
  689.   }
  690.  
  691.   init(){
  692.     this.calcDateCollection()
  693.   }
  694.  
  695.   reverse(date){
  696.     const vals = date.split("-")
  697.     //return `${vals[2]}-${vals[1]}-${vals[0]}`
  698.     return vals[2]+"-"+vals[1]+"-"+vals[0]
  699.   }
  700.  
  701.   calcDateCollection(){
  702.     if (!this.dateCollection) this.dateCollection = {}
  703.     var flag = false
  704.     var collection = []
  705.     var dateObj = {}
  706.     this.dateElemsCollection.forEach(dateElem => {
  707.       if (dateElem.value) {
  708.         flag = true
  709.         collection.push(dateElem.value)
  710.       }
  711.       const weekday = new Date(dateElem.value).getDay()
  712.       if (dateElem.value && weekday !== 6 && weekday !== 0){
  713.         if (!this.dateCollection[dateElem.value]){
  714.           dateObj[dateElem.value] = {
  715.             limit: this.dailyLimit,
  716.             items: {}
  717.           }
  718.         } else {
  719.           dateObj[dateElem.value] = this.dateCollection[dateElem.value]
  720.         }
  721.       }
  722.     })
  723.     if (!this.selectedRadio || !collection.includes(this.selectedRadio)) this.selectedRadio = this.dateElemsCollection[0].value
  724.     if (!flag) dateObj = null
  725.     this.dateCollection = dateObj
  726.     this.render()
  727.   }
  728.  
  729.   get cartState(){
  730.     return JSON.stringify(this.dateCollection)
  731.   }
  732.  
  733.   render(){
  734.     const wrapper = document.createElement("div")
  735.     if (!this.dateCollection) {
  736.       wrapper.innerHTML = "Диапазон дат указан неверно!"
  737.     } else {
  738.       for(let date in this.dateCollection){
  739.         const dateWrapper = document.createElement("div")
  740.         dateWrapper.className += "meido-cart-date-wrapper"
  741.         const header = document.createElement("div")
  742.         header.className += "meido-cart-date-header"
  743.         const radio = document.createElement("input")
  744.         radio.type = "radio"
  745.         radio.id = date
  746.         radio.value = date
  747.         radio.name = "date-radio"
  748.         radio.addEventListener('change', function(e){
  749.           this.selectedRadio = e.target.value
  750.         }.bind(this))
  751.         if (date === this.selectedRadio) radio.checked = true
  752.         header.appendChild(radio)
  753.         const label = document.createElement("label")
  754.         label.htmlFor = date
  755.         //label.innerHTML += `${date} (остаток: ${this.dateCollection[date].limit} грн.)`
  756.         label.innerHTML += date+" (остаток: "+this.dateCollection[date].limit+" грн.)"
  757.         header.appendChild(label)
  758.         dateWrapper.appendChild(header)
  759.         var flag = false
  760.         for(let item in this.dateCollection[date].items){
  761.           flag = true
  762.           const itemElem = document.createElement("div")
  763.           itemElem.className += "meido-cart-item"
  764.           const itemText = document.createElement("span")
  765.           //itemText.innerHTML = `${this.dateCollection[date].items[item]} x ${this.itemList[item].name}`
  766.           itemText.innerHTML = this.dateCollection[date].items[item]+" x "+this.itemList[item].name
  767.           itemElem.appendChild(itemText)
  768.           const itemRemove = document.createElement("button")
  769.           itemRemove.innerHTML = "X"
  770.           itemRemove.className += "meido-cart-item-remove"
  771.           itemRemove.onclick = function(){ this.removeMeidoItem(item, date) }.bind(this)
  772.           itemElem.appendChild(itemRemove)
  773.           dateWrapper.appendChild(itemElem)
  774.         }
  775.         if (!flag) {
  776.           const itemEmpty = document.createElement("div")
  777.           itemEmpty.className += "meido-cart-item"
  778.           itemEmpty.style.color = "grey"
  779.           itemEmpty.innerHTML = "<i>Ничего не добавлено</i>"
  780.           dateWrapper.appendChild(itemEmpty)
  781.         }
  782.         wrapper.appendChild(dateWrapper)
  783.       }
  784.     }
  785.     this.renderTarget.innerHTML = ""
  786.     this.renderTarget.appendChild(wrapper)
  787.     document.getElementById(this.targetField).innerHTML = this.cartState
  788.   }
  789.  
  790.   addMeidoItem(itemId){
  791.     if (this.dateCollection[this.selectedRadio].limit - this.itemList[itemId].price >= 0) {
  792.       if (!this.dateCollection[this.selectedRadio].items[itemId]) {
  793.         this.dateCollection[this.selectedRadio].items[itemId] = 1
  794.       } else {
  795.         this.dateCollection[this.selectedRadio].items[itemId] += 1
  796.       }
  797.       this.dateCollection[this.selectedRadio].limit -= this.itemList[itemId].price
  798.     } else {
  799.       console.error('Insufficient funds!')
  800.     }
  801.     this.render()
  802.   }
  803.  
  804.   removeMeidoItem(itemId, date){
  805.     this.dateCollection[date].items[itemId] -= 1
  806.     if (this.dateCollection[date].items[itemId] === 0) delete this.dateCollection[date].items[itemId]
  807.     this.dateCollection[date].limit += this.itemList[itemId].price
  808.     this.render()
  809.   }
  810. }
  811.  
  812. function meidoInit(container, dateElemsCollection, fsMeidoField, limit, reverseDate = false){
  813.   const innerContainer = document.createElement("div")
  814.  
  815.   return fetch("https://analytics.getmeido.com/api/fs/product-list?token="+meidoToken)
  816.   .then(res => {return res.json()})
  817.   .then(data => {
  818.     const title = document.createElement("h4")
  819.     title.innerHTML = "Заказ еды Meido"
  820.     innerContainer.appendChild(title)
  821.     const mainWindow = buildMeidoWindow(data, dateElemsCollection, fsMeidoField, limit, reverseDate)
  822.     innerContainer.appendChild(mainWindow)
  823.     meidoCart.init()
  824.     container.appendChild(innerContainer)
  825.     return innerContainer
  826.   }).catch(err => {
  827.     console.error("[MEIDO] Cannot get Meido menu!")
  828.     console.error(err)
  829.   })
  830.  
  831. }
  832.  
  833. function buildMeidoWindow(apiData, dateElemsCollection, fsMeidoField, limit, reverseDate){
  834.   const wrapper = document.createElement("div")
  835.   wrapper.className += "meido-main-window"
  836.   const menuElem = document.createElement("div")
  837.   menuElem.id = "meido-menu"
  838.   const cartElem = document.createElement("div")
  839.   cartElem.id = "meido-cart"
  840.   var categorized = {}
  841.   var flat = {}
  842.   apiData.forEach(item => {
  843.     if (!categorized[item.product_contractor_title]) categorized[item.product_contractor_title] = {}
  844.     if (!categorized[item.product_contractor_title][item.category_title]) categorized[item.product_contractor_title][item.category_title] = {}
  845.     categorized[item.product_contractor_title][item.category_title][item.id] = item
  846.     flat[item.id] = {
  847.       name: item.product_title,
  848.       price: parseInt(item.product_price)
  849.     }
  850.   })
  851.   menuElem.appendChild(buildMenu(categorized))
  852.   console.log(limit, dateElemsCollection, reverseDate)
  853.   window.meidoCart = new MeidoCart(flat, limit, cartElem, dateElemsCollection, fsMeidoField, reverseDate)
  854.   cartElem.className += "meido-cart-wrapper"
  855.   wrapper.appendChild(menuElem)
  856.   wrapper.appendChild(cartElem)
  857.   return wrapper
  858. }
  859.  
  860. function buildMenu(data){
  861.   const wrapper = document.createElement("div")
  862.   wrapper.className += "meido-menu-wrapper"
  863.   for(let category in data){
  864.     const categoryWrapper = document.createElement("div")
  865.     const categoryHeader = document.createElement("div")
  866.     categoryHeader.className += "meido-category-title"
  867.     const categoryArrow = document.createElement("span")
  868.     categoryArrow.className += "arrow"
  869.     categoryArrow.innerHTML = "►"
  870.     const categoryTitle = document.createElement("span")
  871.     categoryTitle.innerHTML = category
  872.     categoryHeader.appendChild(categoryArrow)
  873.     categoryHeader.appendChild(categoryTitle)
  874.     const categoryContent = document.createElement("div")
  875.     categoryContent.className += "meido-category-content"
  876.     categoryHeader.onclick = function(){
  877.       categoryContent.hidden = !categoryContent.hidden
  878.       categoryArrow.innerHTML = (categoryArrow.innerHTML === "►" ? "▼" : "►")
  879.     }
  880.     categoryContent.hidden = true
  881.     categoryWrapper.appendChild(categoryHeader)
  882.     for(let contractor in data[category]){
  883.       const contractorWrapper = document.createElement("div")
  884.       const contractorHeader = document.createElement("div")
  885.       contractorHeader.className += "meido-contractor-title"
  886.       const contractorArrow = document.createElement("span")
  887.       contractorArrow.className += "arrow"
  888.       contractorArrow.innerHTML = "►"
  889.       const contractorTitle = document.createElement("span")
  890.       contractorTitle.innerHTML = contractor
  891.       contractorHeader.appendChild(contractorArrow)
  892.       contractorHeader.appendChild(contractorTitle)
  893.       const contractorContent = document.createElement("div")
  894.       contractorContent.className += "meido-contractor-content"
  895.       contractorHeader.onclick = function(){
  896.         contractorContent.hidden = !contractorContent.hidden
  897.         contractorArrow.innerHTML = (contractorArrow.innerHTML === "►" ? "▼" : "►")
  898.       }
  899.       contractorContent.hidden = true
  900.       contractorWrapper.appendChild(contractorHeader)
  901.       for(let item in data[category][contractor]){
  902.         contractorContent.appendChild(buildMenuItem(data[category][contractor][item]))
  903.       }
  904.       contractorWrapper.appendChild(contractorContent)
  905.       categoryContent.appendChild(contractorWrapper)
  906.     }
  907.     categoryWrapper.appendChild(categoryContent)
  908.     wrapper.appendChild(categoryWrapper)
  909.   }
  910.  
  911.   return wrapper
  912. }
  913.  
  914. function buildMenuItem(item){
  915.   const wrapper = document.createElement("div")
  916.   wrapper.className += "meido-item"
  917.   const itemTitle = document.createElement("div")
  918.   itemTitle.innerHTML = "<u>" + item.product_title + "</u>"
  919.   itemTitle.className += "meido-item-title"
  920.   const itemPic = document.createElement("img")
  921.   itemPic.src = item.photo_url
  922.   itemPic.className += "meido-pic"
  923.   const itemDesc = document.createElement("div")
  924.   itemDesc.innerHTML = item.product_description
  925.   const price = document.createElement("span")
  926.   //price.innerHTML = `<i>Цена: ${item.product_price} грн.</i>`
  927.   price.innerHTML = "<i>Цена: "+item.product_price+" грн.</i>"
  928.   price.className += "meido-price"
  929.   const add = document.createElement("button")
  930.   add.innerHTML = "Добавить"
  931.   add.className += "meido-add-button"
  932.   add.onclick = null
  933.   add.onclick = function(e){
  934.     e.preventDefault()
  935.     meidoCart.addMeidoItem(item.id)
  936.   }
  937.   wrapper.appendChild(itemTitle)
  938.   wrapper.appendChild(itemPic)
  939.   wrapper.appendChild(itemDesc)
  940.   wrapper.appendChild(add)
  941.   wrapper.appendChild(price)
  942.   return wrapper
  943. }
  944. </script>
Add Comment
Please, Sign In to add comment