UNPKG

react-schedule-meeting

Version:
401 lines (383 loc) 18.8 kB
import{isValid as e,startOfMonth as t,format as r,differenceInMinutes as a,addMinutes as o,isSameDay as n,isSameMinute as i,isPast as l,isAfter as c,subMonths as d,addMonths as s,subDays as m,addDays as g,isBefore as b,isEqual as u}from"date-fns";import*as p from"react";import x,{useState as v,useEffect as T}from"react";import f from"color";import y from"react-calendar";import{setup as h,styled as _}from"goober";import{shouldForwardProp as w}from"goober/should-forward-prop";const k=({direction:e})=>p.createElement("svg",{xmlns:"http://www.w3.org/2000/svg",width:"26",height:"26",viewBox:"0 0 512 512"},p.createElement("path",{fill:"none",stroke:"currentColor",strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:"48",d:"back"===e?"M328 112L184 256l144 144":"M184.001 400L328.001 256L184.001 112"}));h(x.createElement,void 0,void 0,w((e=>"$"!==e[0])));const E=_(y)` &.react-calendar, &.react-calendar *, &.react-calendar *:before, &.react-calendar *:after { -moz-box-sizing: border-box; -webkit-box-sizing: border-box; box-sizing: border-box; } button { margin: 0; border: 0; outline: none; } button:enabled:hover { cursor: pointer; } .react-calendar__navigation { height: 44px; margin-bottom: 1em; } .react-calendar__navigation button { min-width: 44px; background: none; } .react-calendar__navigation button:enabled:hover, .react-calendar__navigation button:enabled:focus { background-color: hsl(0, 0%, 90.19607843137256%); } .react-calendar__navigation button[disabled] { background-color: hsl(0, 0%, 94.11764705882352%); } .react-calendar__month-view__weekdays { text-align: center; text-transform: uppercase; font-weight: bold; font-size: 0.75em; } .react-calendar__month-view__weekdays__weekday { padding: 0.5em; } .react-calendar__month-view__weekNumbers { font-weight: bold; } .react-calendar__month-view__weekNumbers .react-calendar__tile { display: flex; align-items: center; justify-content: center; font-size: 0.75em; padding: calc(0.75em / 0.75) calc(0.5em / 0.75); } .react-calendar__year-view .react-calendar__tile, .react-calendar__decade-view .react-calendar__tile, .react-calendar__century-view .react-calendar__tile { padding: 2em 0.5em; } .react-calendar__tile { max-width: 100%; text-align: center; padding: 0.75em 0.5em; background: none; } .day-tile { width: 60px; height: 60px; @media (max-width: 768px) { height: 45px; } color: rgba(var(--text-color-rgb), .9); padding: 5px; position: relative; z-index: 1; &::after { content: ''; position: absolute; left: 2px; top: 2px; bottom: 2px; right: 2px; z-index: -1; } } .day-tile abbr { font-weight: bold; font-size: 15.33px; } .react-calendar__month-view__days__day--neighboringMonth { color: rgba(var(--text-color-rgb), .6); } button { margin-top: 2.5px !important; margin-bottom: 2.5px !important; } .active-day-tile { &::after { background: rgba(var(--primary-color-rgb), 0.222); border-radius: var(--border-radius); } color: rgba(var(--primary-color-text-shade-rgb), 1); } .active-day-tile:hover { opacity: 0.5; } .react-calendar__tile:disabled.day-tile { background: rgba(var(--background-color-rgb), 1); } .react-calendar__tile--now.day-tile { background: rgba(var(--background-color-rgb), 1); &::after { border-radius: var(--border-radius); background: rgba(var(--primary-color-rgb), 0.111); } } .react-calendar__tile--now:hover.day-tile { background: rgba(var(--background-color-rgb), 1); &::after { border-radius: var(--border-radius); background: rgba(var(--primary-color-rgb), 0.111); } } .react-calendar__tile:hover.day-tile { background: rgba(var(--background-color-rgb), 1); } .react-calendar__tile--active.day-tile { background: rgba(var(--background-color-rgb), 1); color: rgba(var(--primary-color-text-shade-rgb), 1); &::after { border-radius: var(--border-radius); border: solid rgba(var(--primary-color-rgb), 0.111) 1px; } } .react-calendar__tile--active:enabled.day-tile, .react-calendar__tile--active:enabled:focus.day-tile { &::after { background: rgba(var(--primary-color-rgb), 0.222) border-radius: var(--border-radius); border: solid rgba(var(--primary-color-rgb), 1) 1px; } &.react-calendar__tile--now { &::after { background: rgba(var(--primary-color-rgb), 0.111); } } } /* month day titles */ .react-calendar__month-view__weekdays__weekday abbr { text-decoration: none; font-weight: normal; color: rgba(var(--text-color-rgb), 1); font-size: 14px; font-weight: 700; } .react-calendar__navigation__label__labelText.react-calendar__navigation__label__labelText--from { color: rgba(var(--text-color-rgb), 1); } /* calendar styles */ &.react-calendar { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif; border: none !important; width: 100% !important; min-height: 390px; @media (max-width: 768px) { min-height: 302px; } } `,S=(e,t)=>r(e,"MM/dd/yyyy",{locale:t}),C=({startTimeEventsList:r,onDaySelected:a,selectedDay:o,locale:n})=>{const[i,l]=v([]);T((()=>{const t=[];r.map((r=>{if(!e(new Date(r.startTime)))throw new Error(`Invalid date for start time on slot ${r.availableTimeslot.id}`);const a=S(r.startTime,n);return-1===t.indexOf(a)&&t.push(a),null})),l(t)}),[r]);return x.createElement(E,{defaultView:"month",onClickDay:e=>{a(e)},showNavigation:!1,tileDisabled:e=>"month"===e.view&&!i.some((t=>t===S(e.date,n))),tileClassName:e=>i.some((t=>t===S(e.date,n)))?["day-tile","active-day-tile"]:"month"===e.view?"day-tile":null,value:o,activeStartDate:t(o),locale:null==n?void 0:n.code})},D=_("button")` padding: 16px; border: none; color: ${({selected:e})=>e?"rgba(var(--primary-color-contrast-rgb), 1)":"rgba(var(--text-color-rgb), 1)"}; background-color: ${({selected:e})=>e?"rgba(var(--primary-color-rgb), 1)":"rgba(0,0,0,0)"}; border-radius: var(--border-radius); outline: none; width: 100%; cursor: pointer; font-size: 16px; opacity: 1; &:hover { opacity: 0.8; background-color: ${({selected:e})=>e?"rgba(var(--primary-color-rgb), 1)":"rgba(var(--background-color-contrast-rgb), 0.06)"}; } `,N=_("button")` padding: 12px 16px; margin: 4px; border: none; color: rgba(var(--primary-color-contrast-rgb), 1); background-color: rgba(var(--primary-color-rgb), 1); border-radius: var(--border-radius); outline: none; cursor: pointer; font-size: 16px; opacity: 1; @media (max-width: 768px) { padding: 7px 12px; } :hover { opacity: 0.8; } `,B=_("div")` display: flex; width: 100%; align-items: center; `,L=_("button")` padding: 8px 24px; border: none; background-color: rgb(0, 0, 0, 0); border-radius: var(--border-radius); outline: none; margin-left: 8px; cursor: pointer; display: flex; justify-content: center; align-items: center; font-size: 16px; height: 100%; color: rgba(var(--text-color-rgb), 1); &:hover { background-color: rgba(var(--background-color-contrast-rgb), 0.06); } `,$=({confirmState:e,onStartTimeSelect:t,startTimeEvent:a,selected:o,onCancelClicked:n,format_startTimeFormatString:i,lang_confirmButtonText:l,lang_cancelButtonText:c,lang_selectedButtonText:d,locale:s})=>x.createElement(B,{className:"rsm-start-time-item"},x.createElement(D,{type:"button",className:"rsm-confirm-button",selected:Boolean(o||e),onClick:t},e&&!o&&`${l} `,o&&`${d} `,r(a.startTime,i,{locale:s})),(e||o)&&x.createElement(L,{type:"button",className:"rsm-cancel-button",onClick:n},c)),F=_("div")` position: relative; display: flex; flex-direction: column; overflow-y: scroll; padding-bottom: 24px; padding-top: 16px; `,z=_("div")` position: relative; display: flex; flex-wrap: wrap; overflow-y: scroll; align-items: stretch; justify-content: flex-start; &.has-selection { button:not(.is-selected) { opacity: 0.5; } } `,j=_("div")` position: absolute; width: 100%; height: 24px; left: 0; right: 0; z-index: 12; pointer-events: none; &.top { background: linear-gradient(180deg, rgba(var(--background-color-rgb), 1), rgba(var(--background-color-rgb), 0)); top: 42px; } &.bottom { bottom: 0; background: linear-gradient(0deg, rgba(var(--background-color-rgb), 1), rgba(var(--background-color-rgb), 0)); } `,R=_("div")` flex-shrink: 0; flex: 1; padding: 0.5px; margin: 0px 8px; position: relative; background: ${({makeTransparent:e})=>e?"transparent":"rgba(var(--background-color-contrast-rgb), 0.05)"}; `,G=_("p")` margin: 0; opacity: 0.5; margin-bottom: 24px; font-size: 18px; color: rgba(var(--text-color-rgb), 1); `,A=_("div")` height: 100%; flex: 1; width: 100%; display: flex; justify-content: center; align-items: center; flex-direction: column; `,M=_(D)` border: none; padding: 6px 18px; width: auto; text-align: left; p { margin: 0; color: inherit; font-weight: inherit; text-align: inherit; } small { font-weight: 700; } display: flex; align-items: center; svg { margin-left: 14px; margin-right: -4px; } `,I=_(G)` font-size: 90%; font-weight: 700; padding: 3px 10px; border-radius: var(--border-radius); border: 1px solid rgba(var(--background-color-contrast-rgb), 0.5); `,O=({skipConfirmCheck:e,selectedDay:t,selectedStartTime:a,startTimeListItems:o=[],onStartTimeSelect:n,emptyListContentEl:i,lang_emptyListText:l,format_startTimeFormatString:c,lang_confirmButtonText:d,lang_cancelButtonText:s,lang_goToNextAvailableDayText:m,lang_noFutureTimesText:g,lang_selectedButtonText:b,onGoToNextAvailableDayClick:u,nextFutureStartTimeAvailable:p,format_nextFutureStartTimeAvailableFormatString:f,startTimeListStyle:y,setSelectedStartTime:h,locale:_})=>{const[w,E]=v(-1);T((()=>{E(-1)}),[t]);const S=x.createElement(A,null,x.createElement(x.Fragment,null,i||x.createElement(G,{className:"rsm-empty-list-text"},l),p?x.createElement(M,{type:"button",selected:!0,className:"rsm-next-available-date-button",onClick:u},x.createElement("p",null,x.createElement("small",null,m),x.createElement("br",null),r(p,f,{locale:_})),x.createElement(k,{direction:"forward"})):x.createElement(I,{className:"rsm-no-future-times-text"},g)));return x.createElement(x.Fragment,null,0===o.length?S:"scroll-list"===y?x.createElement(x.Fragment,null,x.createElement(j,{className:"top"}),x.createElement(j,{className:"bottom"}),x.createElement(F,null,o.map(((t,r)=>x.createElement(x.Fragment,{key:r},x.createElement($,{locale:_,lang_selectedButtonText:b,lang_confirmButtonText:d,lang_cancelButtonText:s,format_startTimeFormatString:c,onCancelClicked:()=>(e=>{E(-1),a&&e.startTime.getTime()===a&&h(void 0)})(t),selected:Boolean(a&&a===t.startTime.getTime()),confirmState:r===w,startTimeEvent:t,onStartTimeSelect:()=>((t,r)=>{e||w===r?(n(t),E(-1)):E(r)})(t,r)}),r!==o.length-1&&x.createElement(R,{makeTransparent:w===r||w===r+1})))))):x.createElement(z,{className:a?"has-selection":""},o.map(((e,t)=>x.createElement(N,{key:t,type:"button",className:a&&a===e.startTime.getTime()?"is-selected":"",onClick:()=>n(e)},r(e.startTime,c,{locale:_}))))))},U=_("div")` width: 100%; display: flex; align-items: center; justify-content: center; --text-color-rgb: ${({$textColorRGB:e})=>e}; --primary-color-text-shade-rgb: ${({$calendarColoredTextRGB:e})=>e}; --background-color-rgb: ${({$backgroundColorRGB:e})=>e}; --background-color-contrast-rgb: ${({$backgroundColorContrastRGB:e})=>e}; --primary-color-rgb: ${({$primaryColorRGB:e})=>e}; --primary-color-contrast-rgb: ${({$primaryColorContrastRGB:e})=>e}; --border-radius: ${({$borderRadius:e})=>e}px; `,H=_("div")` display: flex; border-radius: var(--border-radius); background: rgba(var(--background-color-rgb), 1); box-shadow: 0 5px 22px rgba(20, 21, 21, 0.22), 0px 1px 4px rgba(20, 21, 21, 0.14); padding: 16px; margin: 16px; flex-direction: column; @media (min-width: 768px) { flex-direction: row; } @media (max-width: 768px) { padding: 8px; margin: 8px; } `,V=_("div")` width: 1px; background: rgba(0, 0, 0, 0.1); margin: 16px; @media (max-width: 768px) { width: auto; height: 1px; } `,W=_("div")` flex: 1; `,q=_("div")` flex: 1; overflow: hidden; position: relative; @media (max-width: 768px) { min-height: 301px; } `,J=_("div")` position: absolute; width: 100%; height: 100%; display: flex; flex-direction: column; `,K=_("h3")` margin: 0; padding: 0; font-weight: 700; font-size: 24px; color: rgba(var(--text-color-rgb), 1); `,P=_("div")` width: 100%; display: flex; justify-content: space-between; align-items: center; margin-bottom: 6px; `,Q=_("button")` outline: none; background: none; border: none; border-radius: var(--border-radius); cursor: pointer; display: flex; justify-content: center; align-items: center; padding: 8px; opacity: 0.4; margin: 0; color: rgba(var(--text-color-rgb), 0.7); &:hover { opacity: 0.7; background: rgba(var(--background-color-contrast-rgb), 0.06); } `,X=({availableTimeslots:e=[],backgroundColor:t="#ffffff",borderRadius:b=0,className:u,defaultDate:p,emptyListContentEl:y,eventDurationInMinutes:h=30,eventStartTimeSpreadInMinutes:_=0,format_nextFutureStartTimeAvailableFormatString:w="cccc, LLLL do",format_selectedDateDayTitleFormatString:E="cccc, LLLL do",format_selectedDateMonthTitleFormatString:S="LLLL yyyy",format_startTimeFormatString:D="h:mm a",lang_cancelButtonText:N="Cancel",lang_confirmButtonText:B="Confirm",lang_emptyListText:L="No times available",lang_goToNextAvailableDayText:$="Next Available",lang_noFutureTimesText:F="No future times available",lang_selectedButtonText:z="Selected:",locale:j,onNoFutureTimesAvailable:R,onSelectedDayChange:G,onStartTimeSelect:A,primaryColor:M="#3f5b85",scheduleMeetingStyles:I,selectedStartTime:X,skipConfirmCheck:Y=!1,startTimeListStyle:Z="grid",textColor:ee})=>{const te=f(M).rgb().array().join(","),re=f(t).rgb().array().join(","),ae=f(t).isDark(),oe=ee||(ae?"255, 255, 255":"34, 34, 34"),ne=f(M).isDark()?"255, 255, 255":"34, 34, 34",ie=ae?"255, 255, 255":"34, 34, 34",le=ae?f(M).lighten(.5).rgb().array().join(","):f(M).darken(.5).rgb().array().join(","),[ce,de]=v(X?X.getTime():void 0),[se,me]=v(new Date),[ge,be]=v([]),[ue,pe]=v([]),[xe,ve]=v(),[Te,fe]=v([]);T((()=>{de(X?X.getTime():void 0)}),[X]),T((()=>{const t=[...e];t.sort(((e,t)=>new Date(e.startTime).getTime()-new Date(t.startTime).getTime())),fe(t)}),[e]);T((()=>{const e=[];for(const t of Te){const r=a(new Date(t.endTime),new Date(t.startTime));let n=Math.floor(r/(h+_))-1;for(;n>=0;){const r={availableTimeslot:t,startTime:o(new Date(t.startTime),n*(h+_))};e.push(r),n--}}p&&me(p);const t=e.sort(((e,t)=>e.startTime.getTime()-t.startTime.getTime()));be(t)}),[Te,h,_,p]),T((()=>{var e;const t=[];for(const e of ge)n(e.startTime,se)&&0===t.filter((t=>i(t.startTime,e.startTime))).length&&(l(e.startTime)||t.push(e));const r=t.sort(((e,t)=>e.startTime.getTime()-t.startTime.getTime())),a=null===(e=ge.find((e=>c(e.startTime,se))))||void 0===e?void 0:e.startTime;ge.length>0&&R&&!a&&0===r.length&&R(se),ve(a),pe(r)}),[se,ge]);return x.createElement(U,{className:u,$primaryColorRGB:te,$borderRadius:b,style:I,$backgroundColorContrastRGB:ie,$textColorRGB:oe,$backgroundColorRGB:re,$primaryColorContrastRGB:ne,$calendarColoredTextRGB:le},x.createElement(H,null,x.createElement(W,null,x.createElement(P,null,x.createElement(Q,{type:"button",className:"rsm-arrow-button",onClick:()=>{me(d(se,1))}},x.createElement(k,{direction:"back"})),x.createElement(K,{className:"rsm-date-title"},r(se,S,{locale:j})),x.createElement(Q,{type:"button",className:"rsm-arrow-button",onClick:()=>{me(s(se,1))}},x.createElement(k,{direction:"forward"}))),x.createElement(C,{locale:j,selectedDay:se,startTimeEventsList:ge,onDaySelected:e=>{me(e),G&&G(e)}})),x.createElement(V,null),x.createElement(q,null,x.createElement(J,null,x.createElement(P,null,x.createElement(Q,{type:"button",className:"rsm-arrow-button",onClick:()=>{me(m(se,1))}},x.createElement(k,{direction:"back"})),x.createElement(K,{className:"rsm-date-title"},r(se,E,{locale:j})),x.createElement(Q,{type:"button",className:"rsm-arrow-button",onClick:()=>{me(g(se,1))}},x.createElement(k,{direction:"forward"}))),x.createElement(O,{skipConfirmCheck:Y,selectedDay:se,selectedStartTime:ce,locale:j,format_nextFutureStartTimeAvailableFormatString:w,nextFutureStartTimeAvailable:xe,lang_goToNextAvailableDayText:$,lang_noFutureTimesText:F,onGoToNextAvailableDayClick:()=>{xe&&me(xe)},lang_confirmButtonText:B,lang_cancelButtonText:N,lang_emptyListText:L,lang_selectedButtonText:z,emptyListContentEl:y,onStartTimeSelect:e=>{const t=(e=>{const t=[null,null],r=a(e.startTime,new Date(e.availableTimeslot.startTime));if(0!==r){const a={oldId:e.availableTimeslot.id,startTime:e.availableTimeslot.startTime,endTime:o(new Date(e.availableTimeslot.startTime),r)};t[0]=a}const n=o(new Date(e.availableTimeslot.startTime),r+h);if(0!==a(n,new Date(e.availableTimeslot.endTime))){const r={oldId:e.availableTimeslot.id,startTime:n,endTime:e.availableTimeslot.endTime};t[1]=r}return t})(e),r=Object.assign(Object.assign({},e),{splitTimeslot:t,resetDate:()=>me(p||new Date),resetSelectedTimeState:()=>de(void 0)});de(e.startTime.getTime()),A&&A(r)},startTimeListItems:ue,format_startTimeFormatString:D,startTimeListStyle:Z,setSelectedStartTime:de})))))};function Y(e,t){if(!e||!t)return[];const r=[...e],a=[...t];r.sort(((e,t)=>new Date(e.startTime).getTime()-new Date(t.startTime).getTime()));let o=0;for(;o<r.length;){const e=r[o];try{const t=new Date(e.startTime),n=new Date(e.endTime);"string"==typeof e.startTime&&(e.startTime=t),"string"==typeof e.endTime&&(e.endTime=n);for(const i of a)try{const a=new Date(i.startTime),l=new Date(i.endTime);if("string"==typeof i.startTime&&(i.startTime=a),"string"==typeof i.endTime&&(i.endTime=l),b(a,t)||u(a,t))b(t,l)&&(b(l,n)?e.startTime=l:(r.splice(o,1),o--));else if(b(a,n))if(b(l,n)){const t=Object.assign(Object.assign({},e),{startTime:l});e.endTime=a,r.splice(o+1,0,t),o--}else e.endTime=a}catch(e){throw console.error("Invalid Date for unavailable slot: ",i),e}}catch(t){throw console.error("Invalid Date for available slot: ",e),t}o++}return r}export{X as ScheduleMeeting,Y as timeSlotDifference};