Merge pull request #163 from 50bbx/feature/add-timezone-select-in-calendar-view
Add timezone select in calendar view
This commit is contained in:
		
						commit
						60d7351eeb
					
				
					 4 changed files with 62 additions and 54 deletions
				
			
		|  | @ -23,7 +23,7 @@ const getSlots = ({ | |||
| 
 | ||||
|   if(!selectedDate) return [] | ||||
|    | ||||
|   const lowerBound = selectedDate.startOf("day"); | ||||
|   const lowerBound = selectedDate.tz(selectedTimeZone).startOf("day"); | ||||
| 
 | ||||
|   // Simple case, same timezone
 | ||||
|   if (calendarTimeZone === selectedTimeZone) { | ||||
|  | @ -42,7 +42,7 @@ const getSlots = ({ | |||
|     return slots; | ||||
|   } | ||||
| 
 | ||||
|   const upperBound = selectedDate.endOf("day"); | ||||
|   const upperBound = selectedDate.tz(selectedTimeZone).endOf("day"); | ||||
| 
 | ||||
|   // We need to start generating slots from the start of the calendarTimeZone day
 | ||||
|   const startDateTime = lowerBound | ||||
|  |  | |||
|  | @ -23,7 +23,7 @@ | |||
|     "next-transpile-modules": "^7.0.0", | ||||
|     "react": "17.0.1", | ||||
|     "react-dom": "17.0.1", | ||||
|     "react-timezone-select": "^0.10.10" | ||||
|     "react-timezone-select": "^1.0.2" | ||||
|   }, | ||||
|   "devDependencies": { | ||||
|     "@types/node": "^14.14.33", | ||||
|  |  | |||
|  | @ -5,6 +5,7 @@ import prisma from '../../lib/prisma'; | |||
| import { useRouter } from 'next/router'; | ||||
| import dayjs, { Dayjs } from 'dayjs'; | ||||
| import { Switch } from '@headlessui/react'; | ||||
| import TimezoneSelect from 'react-timezone-select'; | ||||
| import { ClockIcon, GlobeIcon, ChevronDownIcon, ChevronLeftIcon, ChevronRightIcon } from '@heroicons/react/solid'; | ||||
| import isSameOrBefore from 'dayjs/plugin/isSameOrBefore'; | ||||
| import isBetween from 'dayjs/plugin/isBetween'; | ||||
|  | @ -32,6 +33,14 @@ export default function Type(props) { | |||
|     const [busy, setBusy] = useState([]); | ||||
|     const telemetry = useTelemetry(); | ||||
| 
 | ||||
|     const [selectedTimeZone, setSelectedTimeZone] = useState(''); | ||||
| 
 | ||||
|     useEffect(() => { | ||||
|       // Setting timezone only client-side
 | ||||
|       setSelectedTimeZone(dayjs.tz.guess()) | ||||
|     }, []) | ||||
| 
 | ||||
| 
 | ||||
|     // Get router variables
 | ||||
|     const router = useRouter(); | ||||
|     const { user } = router.query; | ||||
|  | @ -81,13 +90,13 @@ export default function Type(props) { | |||
|     const calendar = [...emptyDays, ...days.map((day) => | ||||
|         <button key={day} onClick={(e) => { | ||||
|             telemetry.withJitsu((jitsu) => jitsu.track('date_selected', {page_title: "", source_ip: ""})) | ||||
|             setSelectedDate(dayjs().tz(dayjs.tz.guess()).month(selectedMonth).date(day)) | ||||
|             setSelectedDate(dayjs().tz(selectedTimeZone).month(selectedMonth).date(day)) | ||||
|         }} disabled={selectedMonth < parseInt(dayjs().format('MM')) && dayjs().month(selectedMonth).format("D") > day} className={"text-center w-10 h-10 rounded-full mx-auto " + (dayjs().isSameOrBefore(dayjs().date(day).month(selectedMonth)) ? 'bg-blue-50 text-blue-600 font-medium' : 'text-gray-400 font-light') + (dayjs(selectedDate).month(selectedMonth).format("D") == day ? ' bg-blue-600 text-white-important' : '')}> | ||||
|             {day} | ||||
|         </button> | ||||
|     )]; | ||||
| 
 | ||||
|     // Handle date change
 | ||||
|     // Handle date change and timezone change
 | ||||
|     useEffect(() => { | ||||
|         const changeDate = async () => { | ||||
|             if (!selectedDate) { | ||||
|  | @ -101,17 +110,18 @@ export default function Type(props) { | |||
|             setLoading(false); | ||||
|         } | ||||
|         changeDate(); | ||||
|     }, [selectedDate]); | ||||
|     }, [selectedDate, selectedTimeZone]); | ||||
| 
 | ||||
| 
 | ||||
|     const times = getSlots({ | ||||
|     const times = useMemo(() => | ||||
|       getSlots({ | ||||
|         calendarTimeZone: props.user.timeZone, | ||||
|       selectedTimeZone: dayjs.tz.guess(), | ||||
|         selectedTimeZone: selectedTimeZone, | ||||
|         eventLength: props.eventType.length, | ||||
|         selectedDate: selectedDate, | ||||
|         dayStartTime: props.user.startTime, | ||||
|         dayEndTime: props.user.endTime, | ||||
|       }) | ||||
|     , [selectedDate, selectedTimeZone]) | ||||
| 
 | ||||
|     // Check for conflicts
 | ||||
|     for(let i = times.length - 1; i >= 0; i -= 1) { | ||||
|  | @ -135,7 +145,7 @@ export default function Type(props) { | |||
|     const availableTimes = times.map((time) => | ||||
|         <div key={dayjs(time).utc().format()}> | ||||
|             <Link href={`/${props.user.username}/book?date=${dayjs(time).utc().format()}&type=${props.eventType.id}`}> | ||||
|                 <a key={dayjs(time).format("hh:mma")} className="block font-medium mb-4 text-blue-600 border border-blue-600 rounded hover:text-white hover:bg-blue-600 py-4">{dayjs(time).tz(dayjs.tz.guess()).format(is24h ? "HH:mm" : "hh:mma")}</a> | ||||
|                 <a key={dayjs(time).format("hh:mma")} className="block font-medium mb-4 text-blue-600 border border-blue-600 rounded hover:text-white hover:bg-blue-600 py-4">{dayjs(time).tz(selectedTimeZone).format(is24h ? "HH:mm" : "hh:mma")}</a> | ||||
|             </Link> | ||||
|         </div> | ||||
|     ); | ||||
|  | @ -158,13 +168,9 @@ export default function Type(props) { | |||
|                                 <ClockIcon className="inline-block w-4 h-4 mr-1 -mt-1" /> | ||||
|                                 {props.eventType.length} minutes | ||||
|                             </p> | ||||
|                             <button onClick={toggleTimeOptions} className="text-gray-500 mb-1 hover:bg-gray-100 rounded-full px-2 -ml-2 cursor-pointer"> | ||||
|                             <p  className="text-gray-500 mb-1 px-2 py-1 -ml-2"> | ||||
|                             <GlobeIcon className="inline-block w-4 h-4 mr-1 -mt-1"/> | ||||
|                                 {dayjs.tz.guess()} <ChevronDownIcon className="inline-block w-4 h-4 mb-1" /> | ||||
|                             </button> | ||||
|                             { isTimeOptionsOpen && | ||||
|                             <div className="bg-white rounded shadow p-4 absolute w-72"> | ||||
|                                 <Switch.Group as="div" className="flex items-center"> | ||||
|                             <Switch.Group as="span" className=""> | ||||
|                               <Switch.Label as="span" className="mr-3"> | ||||
|                                   <span className="text-sm text-gray-500">am/pm</span> | ||||
|                               </Switch.Label> | ||||
|  | @ -189,8 +195,10 @@ export default function Type(props) { | |||
|                                   <span className="text-sm text-gray-500">24h</span> | ||||
|                               </Switch.Label> | ||||
|                             </Switch.Group> | ||||
|                             </div> | ||||
|                             } | ||||
|                             </p> | ||||
|                             <p className="mt-1 text-gray-500"> | ||||
|                                 <TimezoneSelect id="timeZone" value={selectedTimeZone} onChange={({ value }) =>setSelectedTimeZone(value)} className="shadow-sm focus:ring-blue-500 focus:border-blue-500 mt-1 block w-full sm:text-sm border-gray-300 rounded-md" /> | ||||
|                             </p> | ||||
|                             <p className="text-gray-600 mt-3 mb-8">{props.eventType.description}</p> | ||||
|                         </div> | ||||
|                         <div className={"mt-8 sm:mt-0 " + (selectedDate ? 'sm:w-1/3 border-r sm:px-4' : 'sm:w-1/2 sm:pl-4')}> | ||||
|  |  | |||
|  | @ -2625,10 +2625,10 @@ react-select@^4.2.1: | |||
|     react-input-autosize "^3.0.0" | ||||
|     react-transition-group "^4.3.0" | ||||
| 
 | ||||
| react-timezone-select@^0.10.10: | ||||
|   version "0.10.10" | ||||
|   resolved "https://registry.yarnpkg.com/react-timezone-select/-/react-timezone-select-0.10.10.tgz#853aeb73e84fcf00bd01eb57c35f2df1b84e1cc0" | ||||
|   integrity sha512-PEEQQkiL+fFW3940MmhrX6xNf2VMz16BW2UyF6Mu7jzCv89McwJ93Bp5mqE6ouhLPZSsyTnhjILifsEFUUMuFg== | ||||
| react-timezone-select@^1.0.2: | ||||
|   version "1.0.2" | ||||
|   resolved "https://registry.yarnpkg.com/react-timezone-select/-/react-timezone-select-1.0.2.tgz#37e6d99bc15372bd3f9ebc7541bda6f3a10c852b" | ||||
|   integrity sha512-MDv4rmDkop3nZcIH27tLwIuIVovJE6ushmr9r0kR1SSzVErdydV01vI1ch8u4JAAFpnR5lYDt5PBqQW/lUS+Jg== | ||||
|   dependencies: | ||||
|     react-select "^4.2.1" | ||||
|     spacetime "^6.14.0" | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue
	
	 Bailey Pumfleet
						Bailey Pumfleet