CINXE.COM
Space Availability - Tech Commons at Parnassus - LibCal - University of California, San Francisco
<!DOCTYPE html> <html lang="en"> <head> <!-- iid: 138 --> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=Edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <link href="https://static-assets-us.libcal.com/css_651/bootstrap3.min.css" rel="stylesheet"> <link href="//cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet"> <link href="https://static-assets-us.libcal.com/css_651/LibCal_public.min.css" rel="stylesheet"> <link href="https://static-assets-us.libcal.com/css_651/print.min.css" rel="stylesheet" media="print"> <script src="https://static-assets-us.libcal.com/js_651/jquery.min.js"></script> <script src="https://static-assets-us.libcal.com/js_651/bootstrap3.min.js"></script> <script src="https://static-assets-us.libcal.com/js_651/LibCal_public.min.js"></script> <script> springSpace.dateFormat = "dddd, MMM D YYYY"; springSpace.dateShortFormat = "MMMM D, YYYY"; springSpace.timeFormat = "h:mma"; springSpace.timezone = 'America/Los_Angeles'; springSpace.currency = "USD"; springSpace.currencySymbol = "$"; springSpace.language = 'en'; // en springSpace.locale = 'en-US'; // en-US springSpace.phpTimeFormat = 'g:ia'; springSpace.bootstrapAsset = 'https://static-assets-us.libcal.com/css_651/bootstrap3_16.min.css'; springSpace.publicCssAsset = 'https://static-assets-us.libcal.com/css_651/LibCal_public.min.css'; springSpace.adminCssAsset = 'https://static-assets-us.libcal.com/css_651/LibCal_admin.min.css'; </script> <title> Space Availability - Tech Commons at Parnassus - LibCal - University of California, San Francisco </title> <style> #s-lc-public-banner { padding: 0; margin: 0; } .s-lc-public-footer { margin: 0; } </style> <link rel="stylesheet" href="https://static-assets-us.libcal.com/css_651/fullcalendar.min.css"/> <style> .s-lc-eq-avail, .label-eq-avail, .s-lc-eq-period-available { background: #14951f none !important; border-color: #14951f !important; } .s-lc-eq-avail:hover, .s-lc-eq-period-available:hover { background: #095212 none !important; border-color: #095212 !important; } .s-lc-eq-pending, .label-eq-pending, .s-lc-eq-period-pending { background: #F59F16 none !important; border-color: #F59F16 !important; } .s-lc-eq-checkout, .s-lc-eq-r-unavailable, .s-lc-eq-r-padding, .label-eq-unavailable, .s-lc-eq-period-booked { background: #c91908 none !important; border-color: #c91908 !important; } </style> <style> @media (max-width: 768px) { .fc-timeline .fc-cell-text { font-size: 12px !important; } } </style> <!-- Start of ucsflibrary Zendesk Widget script --> <script id="ze-snippet" src="https://static.zdassets.com/ekr/snippet.js?key=adf68403-a4fd-4dfb-8db7-26bd8920eef0"> </script> <!-- End of ucsflibrary Zendesk Widget script --> <style> /*Remove empty bullet point from calendar home page*/ #s-lc-content-eqlist-26122 > ul > li.divider { display: none; } /*Change color of tentative blocks*/ .lc_rm_t { background-color: #999; } /* UCSF banner & library logo styles */ body { padding: 0; margin: 0; } #ucsf-banner-nav .top-header-container, #ucsf-headers { margin-right: auto; margin-left: auto; max-width: 100%; } #ucsf-banner-nav { height: 40px; overflow: visible; font-family: "Helvetica Neue", arial, sans-serif; background: #052049; } #ucsf-banner-nav.no-logo .top-header-container ul.menu li.first { background: 0 0; text-indent: 0; padding-left: 0; } #ucsf-banner-nav .top-header-container { padding-left: 15px; padding-right: 15px; } #ucsf-banner-nav .top-header-container ul.menu { padding: 0; margin: 0; } #ucsf-banner-nav .top-header-container ul.menu li.first { display: inline-block; float: left; padding: 12px 0 12px 58px; background: url(ucsf-logo-banner.png) 0 35% no-repeat; background-position-x: 0; background-position-y: 35%; } #ucsf-banner-nav .top-header-container ul.menu li { display: inline-block; float: right; font-size: 14px; padding: 12px 10px; } @media (max-width: 830px) { #ucsf-banner-nav .top-header-container ul.menu li { display: none; } } @media (max-width: 600px) { #ucsf-banner-nav .top-header-container ul.menu li.first { text-indent: 100%; white-space: nowrap; overflow: visible; } #ucsf-banner-nav .top-header-container ul.menu li { display: none; } } #ucsf-banner-nav .top-header-container ul.menu li a { text-decoration: none; color: #fff; } #ucsf-banner-nav .top-header-container ul.menu li a:hover { text-decoration: underline; } #ucsf-banner-nav.arial { font-family: arial, sans-serif; } #ucsf-banner-nav.bluetint { background: #506380; } :root #ucsf-banner-nav .top-header-container ul.menu li.first { background: 0 35%; background-size: 45px 22px; background-position-x: 0; background-position-y: 35%; } header { background: #052049; padding: 1.25em; margin: 0 0 0.5em; border-radius: 0; } /* footer feedback button styles */ .ucsf-footer { width: 100%; margin: 15px auto 0; max-width: 1230px; padding: 5px 15px; border-top: 1px solid #aaa; } #s-lc-public-footer { background-color: #052049; color: white; } #s-lc-public-footer a { color: white; } .inline-list { margin: 0 0 1.0625rem -1.375rem; padding: 0; list-style: none; overflow: visible; } .inline-list > li { list-style: none; float: left; margin-left: 1.375rem; margin-top: 5px; display: block; } .inline-list > li > * { display: block; } #feedback-link { background-color: #007cbe; color: #fff; font-weight: 700; padding: 0 4px; -moz-border-radius: 3px; -webkit-border-radius: 3px; border-radius: 3px; } #feedback-link:hover { cursor: pointer; background-color: #052429; } /* Overrides Equipment image fixed height and makes equipment images responsive */ .col-item .photo img { height: auto; } /* Makes equipment cards consistently sized */ @media (min-width: 992px) { .col-item .info { position: absolute; bottom: 20px; width: 90%; } .col-item { min-height: 400px; } } @media (min-width: 768px) and (max-width: 991px) { .col-item .info { position: absolute; bottom: 20px; width: 90%; } .col-item { min-height: 300px; } } /*Adds title to LibCal landing page in Book a Consultation dropdown*/ /*Anneliese Taylor*/ #s-lc-content-mysched-494243953:after { content: ' - Publishing and Open Access Expert'; } /*Ariel Deardorff*/ #s-lc-content-mysched-4942410642::after { content: ' - Data Science Services Librarian'; } /*Evans Whiteaker*/ #s-lc-content-mysched-49424921::after { content: ' - Medicine and Pharmacy Research Librarian'; } /*Geoff Boushey*/ #s-lc-content-mysched-4942415596::after { content: ' - Data Science Expert'; } /*Karla Lindquist*/ #s-lc-content-mysched-4942434278::after { content: ' - Data Science Expert'; } /*Min-Lin Fang*/ #s-lc-content-mysched-494243941::after { content: ' - Nursing and Social and Behavioral Sciences Research Librarian'; } /*Peggy Tahir*/ #s-lc-content-mysched-494243950::after { content: ' - Research and Copyright Librarian'; } /*Stephen Fernandez*/ #s-lc-content-mysched-4942411486::after { content: ' - Student IT Support'; } /*Lisa Leiva*/ #s-lc-content-mysched-494249794::after { content: ' - Instructional Designer'; } /*Angelo Pelonero*/ #s-lc-content-mysched-4942451469::after { content: ' - Data Science Instructional Designer'; } /* Adds color to Next Available button */ #eq-time-grid > div.fc-toolbar.fc-header-toolbar > div.fc-left > button.fc-goToNextAvailable-button.btn.btn-default { background-color: #5bc0de; Border-color: #46b8da; color: #ffffff; } /* Equipment module increasing card height #cat_cont .col-sm-3 { height: 350px; }*/ </style> </head> <body id="equip_" class="s-lc-public s-lc-public-page-5"> <a class="s-lc-skiplink alert-info" href="/r/accessible?lid=31&gid=942"> Alternate page for screen reader Users </a> <a id="s-lc-public-skiplink" class="s-lc-skiplink alert-info" href="#s-lc-public-title-area">Skip to Main Content</a> <div id="s-lc-public-cust-header" role="banner"><body> <div id="ucsf-headers container"> <div id="ucsf-banner-nav" class="bluetint no-logo"> <div class="top-header-container row"> <ul class="menu"> <li class="first"><a href="http://www.ucsf.edu">University of California San Francisco</a></li> <li><a href="http://www.ucsfhealth.org/">UCSF Medical Center</a></li> <li><a href="http://www.ucsf.edu/about">About UCSF</a></li> </ul> </div> </div> <header> <div class="container"><a href="http://library.ucsf.edu/"><img alt="" src="https://ucsf-ckm.github.io/assets/ucsf_library_logo2015.svg"></a></div> </header> </div> </body></div> <div class="container"> <div id="s-lc-public-bc" class="row"> <div class="col-md-12"> <nav aria-label="Breadcrumb"> <ol class="breadcrumb"> <li><a href="http://www.library.ucsf.edu/">University of California, San Francisco</a></li> <li class="s-lc-desktop-only"><a href="https://calendars.library.ucsf.edu">LibCal</a></li> <li class="active s-lc-desktop-only"> Space Availability - Tech Commons at Parnassus </li> </ol> </nav> </div> </div> <noscript> <div class="alert alert-danger" id="noscript">Your browser has javascript disabled. Without javascript some functions will not work.</div> </noscript> <div id="s-lc-public-title-area"> </div> <main> <div id="s-lc-public-main" class="s-lc-public-main"> <div id="s-lc-public-page-content" class="row"> <div id="col1" class="col-md-12 center" > <div id="s-lc-eq-navform" class="s-lc-spaces-setup-info"> <h1 class="sr-only"> Space Availability - Tech Commons at Parnassus </h1> <form class="form-inline" role="search" autocomplete="off"> <input type="hidden" name="page" id="page" value="1"> <input type="hidden" name="type" id="type" value="2"> <div class="form-group form-group-sm"> <label class="hidden-sm" for="lid">Location</label> <select class="form-control" name="lid" id="lid"> <option value="31" selected="selected">Tech Commons at Parnassus</option> <option value="242" >Makers Lab at Parnassus</option> <option value="7407" >Library at ZSFG</option> <option value="7503" >Reservable Study Spaces at Parnassus</option> <option value="7504" >Music at Parnassus</option> <option value="7725" >Reservable Faculty Carrels</option> <option value="0"> View All Locations </option> </select> </div> <div class="form-group form-group-sm"> <label class="hidden-sm" for="gid">Category</label> <select class="form-control" name="gid" id="gid"> <option value="942" selected="selected">Multimedia Workstations</option> <option value="45745" >CL245 Recording Studio</option> <option value="0" >Show All</option> </select> </div> <div class="form-group form-group-sm"> <label class="hidden-sm" for="capacity"> Capacity </label> <select class="form-control" name="capacity" id="capacity"> <option value="0"> All Spaces (not seats) </option> <option value="1"> Space For 1-4 people </option> </select> </div> </form> </div> <div id="s-lc-group-description" role="region" aria-label="description" class="s-lc-resource-description s-lc-spaces-setup-info"> <p> </p> <div style="background-color:#178CCB;"> <div class="flex-container" style="padding: 2%;"> <p style="color: #FFE957; font-size:22px;"><strong><span style="color:#ffffff;">TECH COMMONS:</span> HOW IT WORKS</strong></p> <hr style="margin-top: auto;" /> <div class="grid2x2" style="line-height: normal; align-items: flex-start; justify-content: center; color: white; min-height: 100%; display: flex; flex-wrap: wrap; flex-direction: row; "> <div class="box box1" style="flex-basis: calc(50% - 40px); min-width: 300px; padding: 0 2% 2%;"> <div> <p style="font-size:20px;">Reserve & Collaborate</p> <ul style="list-style: inside; padding-left: 0;"> <li><span style="font-size:14px;"><span style="color:#FFE957;"><strong>Get access to individual workstations and the eLearning Studio</strong></span> for all your multimedia needs</span></li> <li><span style="color:#FFE957;"><strong><span style="font-size:14px;">Reserve for up to 3 hours</span></strong></span></li> <li><span style="font-size:14px;">Available to UCSF students, faculty, and staff</span></li> </ul> </div> </div> <div class="box box2" style="flex-basis: calc(50% - 40px); min-width: 300px; padding: 0 2% 2%;"> <div> <p style="font-size:20px;">Plan Ahead</p> <p><span style="font-size:14px;"><span style="color:#FFE957;"><strong>Anticipate needing assistance with multimedia hardware or software?</strong> </span><a href="http://www.library.ucsf.edu/ask-an-expert/learning-tech-contact/" target="_blank"><span style="color:#ffffff;"><u>Contact us</u></span></a> at least 24 hours in advance to schedule a consultation.</span></p> </div> </div> <div class="box box3" style="flex-basis: calc(50% - 40px); min-width: 300px; padding: 0 2% 2%;"> <div> <p style="font-size:20px;">Find Us</p> <p><span style="font-size:14px;">We’re located in CL240 on the 2nd floor of the Parnassus Library.</span></p> </div> </div> <div class="box box4" style="flex-basis: calc(50% - 40px); min-width: 300px; padding: 0 2% 2%;"> <div> <p style="font-size:20px;">Give Feedback</p> <p style="font-size:14px;"><span style="font-size:14px;">Your feedback helps us continue to improve this service. <a href="https://ucsf.co1.qualtrics.com/jfe/form/SV_3QcakpI1xP3Oqi1" target="_blank"><span style="color:#FFE957;"><u><strong>Let us know how we’re doing.</strong></u></span></a></span> <a href="http://tiny.ucsf.edu/roomfeedback" target="_blank"><span style="color:#ffffff;"></span></a></p> </div> </div> </div> <hr style="margin-top: auto;" /> <p style="color:#ffffff;"><em>Need help? <u><a href="http://www.library.ucsf.edu/ask-an-expert/learning-tech-contact/" target="_blank"><span style="color:#ffffff;">Contact us</span></a></u> or see <a href="https://ucsflibrary.zendesk.com/hc/en-us/articles/360023931553" target="_blank"><span style="color:#ffffff;"><u>How Can I Reserve Multimedia Workstations?</u></span></a> </em></p> </div> </div> </div> <div id="s-lc-window-limit-warning" class="alert alert-info margin-top-med margin-bottom-none" role="alert" style="display: none;"> You have reached the end of the bookable window. No availability will be shown past this point. </div> <div id="time_grid_cont" role="grid" class="s-lc-spaces-time-grid s-lc-spaces-setup-info"> <div id="eq-time-grid"> </div> <div id="s-lc-time-grid-pagination" class="s-lc-time-grid-pagination"> </div> <div class="s-lc-time-grid-legend" id="eq-time-grid-legend"> <span class="label-eq-cont" data-toggle="tooltip" data-placement="top" title="Slot is available, click to book!"><span class="label label-eq-avail"> </span> Available</span> <span class="label-eq-cont" data-toggle="tooltip" data-placement="top" title="Your pending booking."><span class="label label-eq-pending"> </span> Your Booking</span> <span class="label-eq-cont" data-toggle="tooltip" data-placement="top" title="This slot is unavailable for starting a new booking. Bookings may occasionally extend into this slot."><span class="label label-eq-unavailable"> </span> Unavailable/Padding</span> </div> </div> <div id="s-lc-eq-form-box" class="s-lc-spaces-setup-info" style="display: none;" role="region" aria-label="booking form" aria-live="polite"> <form id="s-lc-eq-form-times" class="form-horizontal" method="post"> <fieldset> <div id="s-lc-eq-bwell" class="well" tabindex="0"> </div> <div id="s-lc-eq-bform-inner" class="col-sm-offset-5"> <button class="btn btn-primary" name="submit_times" id="submit_times">Submit Times</button> <button class="btn btn-default" name="eq_cart" id="eq_cart"><i class="fa fa-shopping-cart fa-lg" aria-hidden="true"></i> Add Equipment</button> </div> </fieldset> </form> </div> <div id="s-lc-eq-form" style="clear:both; display: none;" role="region" aria-live="polite" aria-label="Booking details"></div> <div id="s-lc-eq-errors" class="alert alert-danger" style="display: none;" role="region" aria-live="polite" aria-label="Error encountered"></div> <div id="s-lc-eq-success" style="display: none;" role="region" aria-live="polite" aria-labelledby="s-lc-eq-success-title"> </div> </div> </div> </div> </main> <footer id="s-lc-public-footer" class="row s-lc-public-footer"> <div id="s-lc-public-footer-brand"> <span title="libcal-us-2">Powered by</span> <a href="https://www.springshare.com">Springshare</a>. </div> <div id="s-lc-public-footer-rights"> All rights reserved. </div> <div id="s-lc-footer-support-link"> <a href="https://ucsflibrary.zendesk.com/hc/en-us/requests/new">Report a tech support issue.</a> </div> <div id="s-lc-public-footer-print-link"> View this page in a format suitable for <a href="/r/accessible?lid=31&gid=942"> screen-readers and keyboard-only users </a> </div> <div id="s-lc-public-footer-admin-links" role="navigation" aria-label="Admin Footer"> <a id="s-lc-sign-in" href="https://ucsf.libapps.com/libapps/login.php?site_id=4237&target=">Login to LibApps</a> </div> <div class="s-lc-public-footer-actions"> <div id="s-lc-language"> <select id="s-lc-language-selector" aria-label="Select Language"> <option value="ca" >català</option> <option value="cy" >Cymraeg</option> <option value="en" selected>English</option> <option value="es" >español</option> <option value="fr" >français</option> <option value="ga" >Irish</option> <option value="ja" >日本語 Nihongo</option> <option value="nl" >Nederlands</option> <option value="sl" >slovenski jezik</option> <option value="vi" >Tiếng Việt</option> <option value="zh" >中文 Zhōngwén</option> </select> </div> </div> </footer> <!-- Google Analytics tracking script--> <script> (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){ (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o), m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m) })(window,document,'script','https://www.google-analytics.com/analytics.js','ga'); ga('create', 'UA-552286-50', 'auto'); ga('send', 'pageview'); </script> <!-- SiteImprove tracking script--> <script type="text/javascript"> /*<![CDATA[*/ (function() { var sz = document.createElement('script'); sz.type = 'text/javascript'; sz.async = true; sz.src = '//siteimproveanalytics.com/js/siteanalyze_8343.js'; var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(sz, s); })(); /*]]>*/ </script> <!-- Crazy Egg heatmap tracking --> <script type="text/javascript" src="//script.crazyegg.com/pages/scripts/0014/1423.js" async="async"></script> </div> <div id="s-lc-public-cust-footer"><div class="ucsf-footer"> <ul class="inline-list"> <li><a href="https://www.library.ucsf.edu/about">About the Library</a></li> <li><a href="https://www.library.ucsf.edu/contact">Contact Us</a></li> </ul> </div></div> <script defer src="https://static-assets-us.libcal.com/js_651/fullcalendar.min.js"></script> <script defer src="https://static-assets-us.libcal.com/js_651/datepicker.min.js"></script> <link rel="stylesheet" href="https://static-assets-us.libcal.com/css_651/datepicker.min.css"/> <script> var springyFullCalendar = { commonOptions: { schedulerLicenseKey: '0391239527-fcs-1659132663', now: '2024\u002D11\u002D26\u002019\u003A40', nowIndicator: true, scrollTime: '18\u003A00\u003A00', lazyFetching: false, locale: springSpace.language, themeSystem: 'bootstrap', eventTextColor: '#222', eventDisplay: 'block', moreLinkClick: 'day', bootstrapFontAwesome: { goToDate: 'fa-calendar', goToNextAvailable: 'fa-fast-forward', refresh: 'fa-refresh', }, navLinks: true, // https://fullcalendar.io/docs/navLinks resourceOrder: false, // https://fullcalendar.io/docs/resourceOrder stickyHeaderDates: false, // https://fullcalendar.io/docs/stickyHeaderDates && https://github.com/springshare/LibCal/issues/11801 dayCellContent: function (info) { // regardless of language, show the day as a number with no extra characters return info.date.getDate(); }, }, timelineOptions: { height: 'auto', refetchResourcesOnNavigate: false, eventOverlap: false, displayEventTime: false, slotDuration: '01\u003A00', titleFormat: springSpace.dateFormat, views: { timelineSingleDay: { type: 'resourceTimeline', buttonText: 'Day\u0020View', duration: {days: 1}, slotLabelFormat: springSpace.timeFormat, }, timelineHourlyShort: { type: 'resourceTimeline', duration: {days: 3}, slotLabelFormat: [springSpace.dateFormat, springSpace.timeFormat], }, timelineHourlyLong: { type: 'resourceTimeline', duration: {days: 7}, slotLabelFormat: [springSpace.dateFormat, springSpace.timeFormat], }, timelineDailyLong: { type: 'resourceTimeline', slotDuration: '24:00', duration: {days: 28}, slotLabelFormat: ['dd D'], nowIndicator: false }, resourceTimeGridWeek: { buttonText: 'Week\u0020View', slotLabelFormat: springSpace.timeFormat, } }, }, publicTexts: { allDay: 'All\u0020Day', available: 'Available', dayGridMonth: 'Month', dayGridWeek: 'Agenda', goToDate: 'Go\u0020To\u0020Date', goToNextAvailable: 'Next\u0020Available', next: 'Next', prev: 'Previous', timeGridDay: 'Day', timeGridWeek: 'Week', today: 'Today', unavailable: 'Unavailable\/Padding', yourBooking: 'Your\u0020Booking', listWeek: 'Week\u0020List', }, adminTexts: { goToDate: 'Go\u0020To\u0020Date', refresh: 'Refresh', prev: 'Previous', next: 'Next', today: 'Today', week: 'Week', month: 'Month', day: 'Day', dayGridWeek: 'Agenda', allDay: 'All\u0020Day', atLocation: '\u0025title\u0025\u0020at\u0020\u0025location\u0025', }, dateTimeFormats: { monthViewTitle: 'MMMM YYYY', }, }; // placeholder for dynamic content boxes with a full calendar var calendarList = {}; function reRenderCalendarList() { for (var calId in calendarList) { calendarList[calId].render(); } } </script> <script defer src="https://static-assets-us.libcal.com/js_651/direct/full-calendar-common.min.js"></script> <script> var springLang = { eq_js_until_det: 'until...', eq_js_rem_pending: 'Remove\u0020Pending\u0020Booking', eq_js_cart_tt: 'Create\u0020a\u0020reservation\u0020with\u0020these\u0020space\u0020bookings\u0020and\u0020go\u0020to\u0020the\u0020equipment\u0020reservation\u0020page\u0020to\u0020add\u0020more\u0020items.\u0020', eq_js_isRequired: 'is\u0020required\u0021', }; </script> <script defer src="https://static-assets-us.libcal.com/js_651/direct/public/equipment/common.min.js"></script> <script defer src="https://static-assets-us.libcal.com/js_651/direct/public/equipment/spaces.min.js"></script> <script defer src="https://static-assets-us.libcal.com/js_651/direct/public/equipment/session.min.js"></script> <script> var pendingRoomBookings = []; var pendingBookingNextId = 1; var pendingBookingsBlowAwayCart = false; function addError(msg, id) { jQuery(".s-lc-eq-" + id).addClass("has-error").find(".form-control").attr("aria-invalid", true); jQuery(".s-lc-eq-" + id).find(".s-lc-eq-flab").append('<div class="error-message">' + msg + "</div>"); jQuery("#" + id).focus(); return false; } function removeErrors() { jQuery(".s-lc-eq-q").removeClass("has-error").find(".error-message").remove(); } function agreeToTermsAndConditions() { jQuery("#bform-terms-container").hide(); jQuery("#bform-form-container").show(); scrollAndFocusOnElement('#s-lc-bform-help'); return false; } function toggleSubmitButton() { var isTermsAgreedTo = jQuery(this).is(':checked'); jQuery('#btn-form-submit').prop('disabled', !isTermsAgreedTo); } function customFormValidation() { // exists to be overwritten by the specific group validation function } function preFormValidationAndPayload() { removeErrors(); jQuery("#s-lc-eq-errors").hide(); if (!isVisibleFieldsValid()) { return false; } if (!customFormValidation()) { return false; } pageBusyBegin("#btn-form-submit"); var formElement = '#s-lc-eq-bform'; var bookings = preparePendingBookingsPayload(); var bookingsPayload = JSON.stringify(bookings); springyCommon.appendHiddenInput('bookings', bookingsPayload, formElement); springyCommon.appendHiddenInput('returnUrl', springySpaces.getReturnUrl(), formElement); springyCommon.appendHiddenInput('pickupHolds', jQuery('#s-lc-pickup-holds').val(), formElement); springyCommon.appendHiddenInput('method', springyPage.bookingMethod, formElement); return true; } function bookingSuccessCallback(data) { pageBusyEnd("#btn-form-submit"); if (data.error) { jQuery("#s-lc-eq-errors").html(data.error).show(); return; } jQuery('#s-lc-eq-form, .s-lc-spaces-setup-info').hide(); jQuery('#s-lc-eq-success').html(data.html).show().focus(); springySession.clear(); return; } function bookingErrorCallback(xhr) { pageBusyEnd("#btn-form-submit"); var errorMessage = ajaxErrorGetText(xhr); jQuery('#s-lc-eq-errors').html(errorMessage).show().focus(); } function submitPendingTimes() { var payload = { patron: springySpaces.patron, patronHash: springySpaces.patronHash, returnUrl: springySpaces.getReturnUrl(), bookings: preparePendingBookingsPayload(), method: springyPage.bookingMethod, }; pageBusyBegin("#submit_times"); jQuery.ajax({ type: 'post', url: '/ajax/space/times', data: payload, dataType: 'json', }) .always(function () { pageBusyEnd("#submit_times"); }) .done(function(data) { if (data.redirect) { // redirect to libauth checkout page window.location = data.redirect; return; } // hide a bunch of stuff jQuery('.s-lc-spaces-setup-info').hide(); // setup booking form + terms html jQuery("#s-lc-eq-form").html(data.html).show(); // scroll to the top of the page window.scrollTo(0, 0); }) .fail(ajaxErrorHandler); return false; } function makeCartAndGoToEquipPage() { // we only allow user to do this if all the room bookings start at the same time if (pendingRoomBookings.length > 1) { var startTime = pendingRoomBookings[0].start; for (var i = 1; i < pendingRoomBookings.length; i++) { var bookingInfo = pendingRoomBookings[i]; if (!bookingInfo.start.isSame(startTime)) { errorAlert('You can only create an Equipment Cart if all your room bookings begin at the same time.'); return false; } } } var payload = { blowAwayCart: pendingBookingsBlowAwayCart, returnUrl: springySpaces.getReturnUrl(), bookings: preparePendingBookingsPayload(), method: springyPage.bookingMethod, }; workingAlert(); jQuery.ajax({ type: 'post', url: "/ajax/space/createcart", data: payload, dataType: 'json', }) .always(function (data) { stopAlert(); }) .done(function(data) { if (data.success) { // redirect to new page window.location = data.redirect; } else if (data.hasItems) { errorAlert("Cart already has items in it. If you click the shopping cart again, the existing items in the cart will be replaced by the selected rooms."); pendingBookingsBlowAwayCart = true; } else { errorAlert(data.error); } }) .fail(ajaxErrorHandler); return false; } function changeBookingTimes() { // show the old form box + availability grid jQuery('.s-lc-spaces-setup-info').show(); // hide the terms + booking form jQuery('#s-lc-eq-form, #s-lc-eq-errors').hide(); return false; } function getSpaceResourceContent(info) { var html = ''; var resourceData = info.resource.extendedProps; var resourceId = springyPage.isSeatBooking ? resourceData.seatId : resourceData.eid; var title = escapeHtml(info.fieldValue); if (resourceData.hasInfo) { html += '<a href="#" class="s-lc-item-more-info" data-eid="' + resourceId + '"' + ' aria-label="Click\u0020for\u0020more\u0020info\u0020about ' + title + '">' + '<span class="s-lc-info-label">Info</span>' + '</a>'; } var additionalClasses = ''; var additionalIcons = ''; var filterIds = resourceData.filterIds || []; for (var i = 0; i < filterIds.length; i++) { var filterId = filterIds[i]; if (filterId in springyPage.searchFilters) { var filter = springyPage.searchFilters[filterId]; additionalClasses += ' s-lc-filter-' + filterId; additionalIcons += ' <i class="fa ' + filter.icon + ' fa-lg" aria-hidden="true"></i>'; } } var resourceLabel = '<span class="fc-cell-text' + additionalClasses + '">' + title + additionalIcons + '</span>'; if (resourceData.url !== undefined) { html += '<a href="' + resourceData.url + '">' + resourceLabel + '</a>'; } else { html += resourceLabel; } return { html: html, }; } jQuery(function () { springyPublic.registerClearBackForwardCache(); jQuery('#lid').on('change', goToPageForLocation); jQuery('#gid').on('change', goToPageForGroup); jQuery('#eq_cart').on('click', makeCartAndGoToEquipPage); jQuery('#s-lc-eq-form-times').on('submit', submitPendingTimes); }); </script> <script src="https://static-assets-us.libcal.com/js_651/direct/pagination.min.js"></script> <script src="https://static-assets-us.libcal.com/js_651/direct/public/equipment/spaces-standard.min.js"></script> <script> var springyPage = { wantAlternatingBackground: true, timelineOptions: { resourceAreaWidth: '33%', }, locationId: 31, groupId: 942, itemId: -1, isSeatBooking: 0, seatId: 0, zoneId: 0, searchFilters: {"651":{"id":651,"icon":"fa-wheelchair-alt","name":"Accessible Seat\/Space"},"652":{"id":652,"icon":"fa-plug","name":"Power Available"}}, filterIds: [], isDailyBookings: 0, resourceRows: 6, resourceColumnLabel: 'Space', viewMode: 'timelineHourlyLong', returnUrl: '', capacitySeatValue: -1, pageIndex: 0, pageSize: 18, bookingMethod: 11, }; var resources = []; var resourceNameIdMap = []; resources.push({ id: "eid_47479", title: "Multimedia\u0020workstation\u0020\u00231\u0020\u0028Mac\u0029 (Capacity 1)", url: "/space/47479", eid: 47479, gid: 942, lid: 31, grouping: "Multimedia\u0020Workstations", gtype: 2, gBookingSelectableTime: false, capacity: 1, hasInfo: true, thumbnail: "https://libapps.s3.amazonaws.com/customers/396/images/imac-2017.jpg", filterIds: [], }); resourceNameIdMap["eid_47479"] = "Multimedia\u0020workstation\u0020\u00231\u0020\u0028Mac\u0029"; resources.push({ id: "eid_47480", title: "Multimedia\u0020workstation\u0020\u00232\u0020\u0028Mac\u0029 (Capacity 1)", url: "/space/47480", eid: 47480, gid: 942, lid: 31, grouping: "Multimedia\u0020Workstations", gtype: 2, gBookingSelectableTime: false, capacity: 1, hasInfo: true, thumbnail: "https://libapps.s3.amazonaws.com/customers/396/images/imac-2017.jpg", filterIds: [], }); resourceNameIdMap["eid_47480"] = "Multimedia\u0020workstation\u0020\u00232\u0020\u0028Mac\u0029"; resources.push({ id: "eid_47481", title: "Multimedia\u0020workstation\u0020\u00233\u0020\u0028Mac\u0029 (Capacity 1)", url: "/space/47481", eid: 47481, gid: 942, lid: 31, grouping: "Multimedia\u0020Workstations", gtype: 2, gBookingSelectableTime: false, capacity: 1, hasInfo: true, thumbnail: "https://libapps.s3.amazonaws.com/customers/396/images/imac-2017.jpg", filterIds: [], }); resourceNameIdMap["eid_47481"] = "Multimedia\u0020workstation\u0020\u00233\u0020\u0028Mac\u0029"; resources.push({ id: "eid_47482", title: "Multimedia\u0020workstation\u0020\u00234\u0020\u0028Mac\u0029 (Capacity 1)", url: "/space/47482", eid: 47482, gid: 942, lid: 31, grouping: "Multimedia\u0020Workstations", gtype: 2, gBookingSelectableTime: false, capacity: 1, hasInfo: true, thumbnail: "https://libapps.s3.amazonaws.com/customers/396/images/imac-2017.jpg", filterIds: [], }); resourceNameIdMap["eid_47482"] = "Multimedia\u0020workstation\u0020\u00234\u0020\u0028Mac\u0029"; resources.push({ id: "eid_47483", title: "Multimedia\u0020workstation\u0020\u00235\u0020\u0028PC\u0029 (Capacity 1)", url: "/space/47483", eid: 47483, gid: 942, lid: 31, grouping: "Multimedia\u0020Workstations", gtype: 2, gBookingSelectableTime: false, capacity: 1, hasInfo: true, thumbnail: "https://libapps.s3.amazonaws.com/customers/396/images/Dell-Precision.jpg", filterIds: [], }); resourceNameIdMap["eid_47483"] = "Multimedia\u0020workstation\u0020\u00235\u0020\u0028PC\u0029"; resources.push({ id: "eid_47484", title: "Multimedia\u0020workstation\u0020\u00236\u0020\u0028PC\u0029 (Capacity 1)", url: "/space/47484", eid: 47484, gid: 942, lid: 31, grouping: "Multimedia\u0020Workstations", gtype: 2, gBookingSelectableTime: false, capacity: 1, hasInfo: true, thumbnail: "https://libapps.s3.amazonaws.com/customers/396/images/Dell-Precision.jpg", filterIds: [], }); resourceNameIdMap["eid_47484"] = "Multimedia\u0020workstation\u0020\u00236\u0020\u0028PC\u0029"; var paginatedResources = springyPagination.createPaginatedResources(resources, springyPage.pageSize); var capacityRangesMap = {}; capacityRangesMap[0] = { min: 0, max: 9223372036854775807 }; capacityRangesMap[1] = { min: 0, max: 4 }; capacityRangesMap[2] = { min: 5, max: 8 }; capacityRangesMap[3] = { min: 9, max: 12 }; capacityRangesMap[4] = { min: 13, max: 9223372036854775807 }; var resourceSettings = createResourceSettings(1); springyPage.resourceCount = resources.length; </script> <script> var pendingBookingsLimitIssues = null; var dateFormatStartTimeDict = "MMDDHHmm"; var dateFormatDayOfYear = "YYYY-MM-DD"; var issueTypeAdditionalText = { "duration": " minutes", "frequency": " bookings", }; var frequencyDisplayStrings = { "d": " per\u0020day", "w": " per\u0020week", "m": " per\u0020month", "y": " per\u0020year", "t": " at\u0020a\u0020time", }; function pendingRoomBookingsAreNowEmpty() { jQuery("#s-lc-eq-form-box").hide(); } function renderPendingRoomBookings() { // ensure all tooltips are hidden jQuery(".tooltip").hide(); if (pendingRoomBookings.length == 0) { pendingRoomBookingsAreNowEmpty(); return; } // refresh the shown cart items // format the room data as html var html = '<div>'; var startDateTimeFormat = springyPage.isDailyBookings ? springSpace.dateFormat : springSpace.getDateTimeFormat(); var endDateTimeFormat = springyPage.isDailyBookings ? springSpace.dateFormat : springSpace.getShortDateTimeFormat(); var totalCost = 0; for (var i = 0; i < pendingRoomBookings.length; i++) { var bookingInfo = pendingRoomBookings[i]; var bookingCost = bookingInfo.cost; var resourceId = bookingInfo.seat_id > 0 ? bookingInfo.seat_id : bookingInfo.eid; var resourceName = resourceNameIdMap['eid_' + resourceId]; html += '<div class="form-group s-lc-pending-booking" id="pending_booking_' + bookingInfo.id + '">'; html += ' <label class="col-md-5 control-label" for="bookingend_' + bookingInfo.id + '"><strong>' + resourceName + '</strong>: ' + bookingInfo.start.format(startDateTimeFormat) + ' ' + springLang.eq_js_until_det + '</label>'; html += ' <div class="col-md-3">'; html += ' <div class="input-group">'; html += ' <select id="bookingend_' + bookingInfo.id + '" name="bookingend_' + bookingInfo.id + '" data-booking="' + bookingInfo.id + '" class="form-control input-sm b-end-date">'; for (var selectionIndex = 0; selectionIndex < bookingInfo.options.length; selectionIndex++) { var selected = bookingInfo.optionSelected == selectionIndex ? 'selected="selected"' : ''; var value = bookingInfo.options[selectionIndex]; var name = moment(value).format(endDateTimeFormat); var checksum = bookingInfo.optionChecksums[selectionIndex]; html += '<option value="' + value + '" ' + selected + ' data-crc="' + checksum + '">' + name + '</option>'; } html += ' </select>'; html += ' <div class="input-group-btn">'; html += ' <button type="button" class="btn btn-default btn-sm" onclick="return removePendingBooking(' + bookingInfo.id + ',' + bookingInfo.lid + ');"><i class="fa fa-trash-o" aria-hidden="true"></i><span class="sr-only">' + springLang.eq_js_rem_pending + '</span></button>'; html += ' </div>'; html += ' </div>'; html += ' </div>'; if (bookingCost > 0) { var costDisplay = springSpace.formatCurrency(bookingCost); var costPreview = "\u007Bamount\u007D".replace("\u007Bamount\u007D", costDisplay).replace("\u007Brate\u007D", ""); html += '<label class="col-md-3 control-label s-lc-billing-cost-single">' + costPreview + '</label>'; } html += ' </div>'; html += ' </div>'; html += '</div>'; totalCost += bookingCost; } var bookingDurationOkay = true; if (pendingBookingsLimitIssues) { bookingDurationOkay = false; pendingBookingsLimitIssues.forEach(function(issueDetails) { var limitDisplay = issueDetails.allowed + issueTypeAdditionalText[issueDetails.type] + frequencyDisplayStrings[issueDetails.frequency]; var usedDisplay = issueDetails.used + issueTypeAdditionalText[issueDetails.type]; var issueDisplay = 'Sorry,\u0020you\u0020can\u0020only\u0020reserve\u0020\u007BlimitAmount\u007D,\u0020and\u0020you\u0020currently\u0020have\u0020\u007BusedAmount\u007D.\u0020Please\u0020adjust\u0020your\u0020booking.'.replace('{limitAmount}', limitDisplay).replace('{usedAmount}', usedDisplay); var issueHtml = '<strong>' + issueDetails.group + '</strong>: ' + issueDisplay; html += '\ <div class="form-group">\ <div class="col-md-offset-1 col-md-10">\ <div class="alert alert-warning">' + issueHtml + '</div>\ </div>\ </div>'; }); } if (totalCost > 0) { html += '\ <div class="form-group s-lc-pending-booking">\ <label class="col-md-5 control-label">Total\u0020cost\u0020for\u0020this\u0020reservation\u003A</label>\ <label class="col-md-5 control-label s-lc-billing-cost-total">' + springSpace.formatCurrency(totalCost) + '</label>\ </div>'; } html += '</div>'; // show the booking form box which contains the booking well, the terms + conditions and the booking form jQuery("#s-lc-eq-form-box").show(); // put the item in the displayed cart + set the window focus to the cart var roomCart = jQuery("#s-lc-eq-bwell"); roomCart.empty(); roomCart.html(html); roomCart.focus(); // disable the add equipment and form submission buttons until the times are okay jQuery("#submit_times, #eq_cart").prop('disabled', !bookingDurationOkay); // setup delete icon tooltips accessibleIcons(); // make the tooltip for the cart icon jQuery("#eq_cart").tooltip({ title: springLang.eq_js_cart_tt, html: true, container: "body" }); jQuery('.b-end-date').on('change', function() { var changedBooking = jQuery(this); updatePendingBookingDuration(changedBooking); }); } function preparePendingBookingsPayload() { var payload = []; for (var i = 0; i < pendingRoomBookings.length; i++) { var bookingInfo = pendingRoomBookings[i]; payload.push({ id: bookingInfo.id, eid: bookingInfo.eid, seat_id: bookingInfo.seat_id, gid: bookingInfo.gid, lid: bookingInfo.lid, start: bookingInfo.start.format(springSpace.phpDateTimeFormat), end: bookingInfo.end.format(springSpace.phpDateTimeFormat), checksum: bookingInfo.checksum, }); } return payload; } function updatePendingBookingsFromData(bookings) { pendingRoomBookings = []; for (var i = 0; i < bookings.length; i++) { var booking = bookings[i]; pendingRoomBookings.push({ id: booking.id, eid: booking.eid, seat_id: booking.seat_id, gid: booking.gid, lid: booking.lid, cost: booking.cost, checksum: booking.checksum, name: booking.name, start: moment(booking.start), end: moment(booking.end), options: booking.options, optionSelected: booking.optionSelected, optionChecksums: booking.optionChecksums, }); } } function pendingRoomBookingsUpdateListAndAvailability(payload, fcInstance) { // if we are adding rooms, we might need to hide the previous booking success message jQuery("#s-lc-eq-success").hide(); workingAlert(); // find out booking information jQuery.ajax({ type: "post", url: "/spaces/availability/booking/add", data: payload, dataType: "json", }) .always(stopAlert) .done(function(data) { if (data.error) { if (data.isRefreshRequired) { fcInstance.refetchEvents(); } return errorAlert(data.error); } // success! the entire pending bookings array can be re-created now pendingBookingsLimitIssues = data.limitIssues; updatePendingBookingsFromData(data.bookings); // this request might have came back with updated grid data // if it did not - refresh the whole grid if (data.gridUpdateData) { updateGridEventsForItem(data.gridUpdateData, fcInstance); } else if (fcInstance) { fcInstance.refetchEvents(); } renderPendingRoomBookings(); }) .fail(ajaxErrorHandler); return false; } function createStartTimeToClassMap(gridData) { var startTimeToClassMap = {}; gridData.forEach(function(gridElement) { var startMoment = moment(gridElement.start); startTimeToClassMap[startMoment.format(dateFormatStartTimeDict)] = [gridElement.className]; }); return startTimeToClassMap; } function updateGridEventsForItem(gridUpdateData, fcInstance) { var changedItemId = gridUpdateData.itemId; var changedRangeStart = moment(gridUpdateData.dateStart, springSpace.phpDateTimeFormat); var changedRangeEnd = moment(gridUpdateData.dateEnd, springSpace.phpDateTimeFormat); var startTimeToClassMap = createStartTimeToClassMap(gridUpdateData.gridData); fcInstance.batchRendering(function() { fcInstance.getEvents().forEach(function (clientEvent) { if (clientEvent.extendedProps.itemId !== changedItemId) { return; } var clientEventStart = moment(clientEvent.start); // if this event is before the day of events that was changed - forget it // and we only want to process events that start before the changed range "end" if (clientEventStart.isBefore(changedRangeStart) || !clientEventStart.isBefore(changedRangeEnd)) { return; } var startKey = clientEventStart.format(dateFormatStartTimeDict); if (startKey in startTimeToClassMap) { // this slot is unavailable clientEvent.setProp('classNames', startTimeToClassMap[startKey]); clientEvent.setExtendedProp('status', 1); } else { // this slot is available clientEvent.setProp('classNames', ["s-lc-eq-avail"]); clientEvent.setExtendedProp('status', 0); } }); }); } function timeGridClickedOnAvailableRoom(calEvent, fcInstance) { var resource = calEvent.getResources()[0]; var resourceData = resource.extendedProps; var timeslotData = calEvent.extendedProps; var view = fcInstance.view; var payload = { add: { eid: resourceData.eid, seat_id: resourceData.seatId, gid: resourceData.gid, lid: resourceData.lid, start: moment(calEvent.start).format(springSpace.phpDateTimeFormat), checksum: timeslotData.checksum, }, lid: 31, gid: 942, start: moment(view.activeStart).format(dateFormatDayOfYear), end: moment(view.activeEnd).format(dateFormatDayOfYear), bookings: preparePendingBookingsPayload(), } return pendingRoomBookingsUpdateListAndAvailability(payload, fcInstance); } function updatePendingBookingDuration(changedBooking) { var fcInstance = getCurrentTimelineInstance(31); var view = fcInstance.view; var selectedElement = changedBooking.find(':selected'); var payload = { update: { id: changedBooking.data('booking'), checksum: selectedElement.data('crc'), end: changedBooking.val() }, lid: 31, gid: 942, start: moment(view.activeStart).format(dateFormatDayOfYear), end: moment(view.activeEnd).format(dateFormatDayOfYear), bookings: preparePendingBookingsPayload(), } return pendingRoomBookingsUpdateListAndAvailability(payload, fcInstance); } function removePendingBooking(pendingId, locationId) { var timeline = getCurrentTimelineInstance(locationId); var view = timeline.view; var payload = { removeId: pendingId, lid: 31, gid: 942, start: moment(view.activeStart).format(dateFormatDayOfYear), end: moment(view.activeEnd).format(dateFormatDayOfYear), bookings: preparePendingBookingsPayload(), } return pendingRoomBookingsUpdateListAndAvailability(payload, timeline); } function formatEventsForFullCalendar(events) { events.forEach(function(eventData) { eventData.resourceId = "eid_" + eventData.itemId; if (eventData.className) { // this slot is unavailable eventData.status = 1; eventData.classNames = [eventData.className]; } else { // this slot is available eventData.classNames = ["s-lc-eq-avail"]; eventData.status = 0; } }); return events; } function timeGridRoomFetchEventsForTimePeriod(start, end, callback, lid, gid, eid) { var data = { lid: lid, gid: gid, eid: eid, seat: springyPage.isSeatBooking, seatId: springyPage.seatId, zone: springyPage.zoneId, filters: springyPage.filterIds, start: moment(start).format(dateFormatDayOfYear), end: moment(end).format(dateFormatDayOfYear), bookings: preparePendingBookingsPayload(), pageIndex: springyPage.pageIndex, pageSize: springyPage.pageSize, }; var url = '/spaces/availability/grid'; if (typeof springyPage.autoCreateBookingDate === 'string') { url = '/spaces/availability/grid/pre-create' data.autoCreateBookingDate = springyPage.autoCreateBookingDate; springyPage.autoCreateBookingDate = null; } springyCommon.closeAllPopups(); jQuery.ajax({ type: 'post', url: url, data: data, dataType: 'json', }) .done(function(data) { callback(formatEventsForFullCalendar(data.slots)); // sometimes on an initial view of the availability grid we auto-create a booking // (currently this is only possible via maps) if (data.isPreCreatedBooking) { updatePendingBookingsFromData(data.bookings); renderPendingRoomBookings(); } var isAtEndOfWindowLimit = data.windowEnd === true; jQuery('#s-lc-window-limit-warning').toggle(isAtEndOfWindowLimit); jQuery('.fc-next-button').prop('disabled', isAtEndOfWindowLimit); var selectorPrefix = ''; var isNextAvailableButtonWanted = (document.querySelector(selectorPrefix + '.s-lc-eq-avail') === null); jQuery(selectorPrefix + '.fc-goToNextAvailable-button').toggle(isNextAvailableButtonWanted); }) .fail(function(xhr) { // let fullcalendar know that the request has completed with no results callback([]); // and display the error to the user ajaxErrorHandler(xhr); }); } </script> </body> </html>