Moved DatePicker and PoweredByCalendso to seperate components
This commit is contained in:
		
							parent
							
								
									f99729c392
								
							
						
					
					
						commit
						b50fe16566
					
				
					 3 changed files with 149 additions and 130 deletions
				
			
		
							
								
								
									
										109
									
								
								components/booking/DatePicker.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										109
									
								
								components/booking/DatePicker.tsx
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,109 @@ | |||
| import dayjs from "dayjs"; | ||||
| import {ChevronLeftIcon, ChevronRightIcon} from "@heroicons/react/solid"; | ||||
| import {useEffect, useState} from "react"; | ||||
| 
 | ||||
| const DatePicker = ({ weekStart, onDatePicked }) => { | ||||
| 
 | ||||
|   const [selectedMonth, setSelectedMonth] = useState(dayjs().month()); | ||||
|   const [selectedDay, setSelectedDay] = useState(dayjs().date()); | ||||
|   const [hasPickedDate, setHasPickedDate] = useState(false); | ||||
| 
 | ||||
|   useEffect(() => { | ||||
|     if (hasPickedDate) { | ||||
|       onDatePicked(dayjs().month(selectedMonth).date(selectedDay)); | ||||
|     } | ||||
|   }, [hasPickedDate, selectedDay]); | ||||
| 
 | ||||
|   // Handle month changes
 | ||||
|   const incrementMonth = () => { | ||||
|     setSelectedMonth(selectedMonth + 1); | ||||
|   } | ||||
| 
 | ||||
|   const decrementMonth = () => { | ||||
|     setSelectedMonth(selectedMonth - 1); | ||||
|   } | ||||
| 
 | ||||
|   // Set up calendar
 | ||||
|   var daysInMonth = dayjs().month(selectedMonth).daysInMonth(); | ||||
|   var days = []; | ||||
|   for (let i = 1; i <= daysInMonth; i++) { | ||||
|     days.push(i); | ||||
|   } | ||||
| 
 | ||||
|   // Create placeholder elements for empty days in first week
 | ||||
|   let weekdayOfFirst = dayjs().month(selectedMonth).date(1).day(); | ||||
|   if (weekStart === 'Monday') { | ||||
|     weekdayOfFirst -= 1; | ||||
|     if (weekdayOfFirst < 0) | ||||
|       weekdayOfFirst = 6; | ||||
|   } | ||||
|   const emptyDays = Array(weekdayOfFirst).fill(null).map((day, i) => | ||||
|     <div key={`e-${i}`} className={"text-center w-10 h-10 rounded-full mx-auto"}> | ||||
|       {null} | ||||
|     </div> | ||||
|   ); | ||||
| 
 | ||||
|   // Combine placeholder days with actual days
 | ||||
|   const calendar = [...emptyDays, ...days.map((day) => | ||||
|     <button key={day} | ||||
|             onClick={() => { setHasPickedDate(true); setSelectedDay(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().date(selectedDay).month(selectedMonth).format("D") == day ? ' bg-blue-600 text-white-important' : '' | ||||
|               ) | ||||
|             }> | ||||
|       {day} | ||||
|     </button> | ||||
|   )]; | ||||
| 
 | ||||
|   return ( | ||||
|     <div | ||||
|       className={ | ||||
|         "mt-8 sm:mt-0 " + | ||||
|         (hasPickedDate | ||||
|           ? "sm:w-1/3 border-r sm:px-4" | ||||
|           : "sm:w-1/2 sm:pl-4") | ||||
|       } | ||||
|     > | ||||
|       <div className="flex text-gray-600 font-light text-xl mb-4 ml-2"> | ||||
|                   <span className="w-1/2"> | ||||
|                     {dayjs().month(selectedMonth).format("MMMM YYYY")} | ||||
|                   </span> | ||||
|         <div className="w-1/2 text-right"> | ||||
|           <button | ||||
|             onClick={decrementMonth} | ||||
|             className={ | ||||
|               "mr-4 " + | ||||
|               (selectedMonth < parseInt(dayjs().format("MM")) && | ||||
|                 "text-gray-400") | ||||
|             } | ||||
|             disabled={selectedMonth < parseInt(dayjs().format("MM"))} | ||||
|           > | ||||
|             <ChevronLeftIcon className="w-5 h-5" /> | ||||
|           </button> | ||||
|           <button onClick={incrementMonth}> | ||||
|             <ChevronRightIcon className="w-5 h-5" /> | ||||
|           </button> | ||||
|         </div> | ||||
|       </div> | ||||
|       <div className="grid grid-cols-7 gap-y-4 text-center"> | ||||
|         { | ||||
|           ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'] | ||||
|             .sort( (a, b) => weekStart.startsWith(a) ? -1 : weekStart.startsWith(b) ? 1 : 0 ) | ||||
|             .map( (weekDay) => | ||||
|               <div key={weekDay} className="uppercase text-gray-400 text-xs tracking-widest">{weekDay}</div> | ||||
|             ) | ||||
|         } | ||||
|         {calendar} | ||||
|       </div> | ||||
|     </div> | ||||
|   ); | ||||
| } | ||||
| 
 | ||||
| export default DatePicker; | ||||
							
								
								
									
										22
									
								
								components/ui/PoweredByCalendso.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								components/ui/PoweredByCalendso.tsx
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,22 @@ | |||
| import Link from "next/link"; | ||||
| 
 | ||||
| const PoweredByCalendso = (props) => ( | ||||
|   <div className="text-xs text-right pt-1"> | ||||
|     <Link href="https://calendso.com"> | ||||
|       <a | ||||
|         style={{ color: "#104D86" }} | ||||
|         className="opacity-50 hover:opacity-100" | ||||
|       > | ||||
|         powered by{" "} | ||||
|         <img | ||||
|           style={{ top: -2 }} | ||||
|           className="w-auto inline h-3 relative" | ||||
|           src="/calendso-logo-word.svg" | ||||
|           alt="Calendso Logo" | ||||
|         /> | ||||
|       </a> | ||||
|     </Link> | ||||
|   </div> | ||||
| ); | ||||
| 
 | ||||
| export default PoweredByCalendso; | ||||
|  | @ -2,7 +2,6 @@ import {useEffect, useState, useMemo} from 'react'; | |||
| import Head from 'next/head'; | ||||
| import Link from 'next/link'; | ||||
| import prisma from '../../lib/prisma'; | ||||
| import { useRouter } from 'next/router'; | ||||
| import dayjs, { Dayjs } from 'dayjs'; | ||||
| import { ClockIcon, GlobeIcon, ChevronDownIcon, ChevronLeftIcon, ChevronRightIcon } from '@heroicons/react/solid'; | ||||
| import isSameOrBefore from 'dayjs/plugin/isSameOrBefore'; | ||||
|  | @ -17,16 +16,16 @@ import AvailableTimes from "../../components/booking/AvailableTimes"; | |||
| import TimeOptions from "../../components/booking/TimeOptions" | ||||
| import Avatar from '../../components/Avatar'; | ||||
| import {timeZone} from "../../lib/clock"; | ||||
| import DatePicker from "../../components/booking/DatePicker"; | ||||
| import PoweredByCalendso from "../../components/ui/PoweredByCalendso"; | ||||
| import {useRouter} from "next/router"; | ||||
| 
 | ||||
| export default function Type(props) { | ||||
| 
 | ||||
|   // Get router variables
 | ||||
|   const router = useRouter(); | ||||
|   const { rescheduleUid } = router.query; | ||||
| 
 | ||||
|   // Initialise state
 | ||||
|   const [selectedDate, setSelectedDate] = useState<Dayjs>(); | ||||
|   const [selectedMonth, setSelectedMonth] = useState(dayjs().month()); | ||||
|   const [isTimeOptionsOpen, setIsTimeOptionsOpen] = useState(false); | ||||
|   const [timeFormat, setTimeFormat] = useState('hh:mm'); | ||||
|   const telemetry = useTelemetry(); | ||||
|  | @ -35,47 +34,11 @@ export default function Type(props) { | |||
|     telemetry.withJitsu((jitsu) => jitsu.track(telemetryEventTypes.pageView, collectPageParameters())) | ||||
|   }, []); | ||||
| 
 | ||||
|   // Handle month changes
 | ||||
|   const incrementMonth = () => { | ||||
|       setSelectedMonth(selectedMonth + 1); | ||||
|   } | ||||
| 
 | ||||
|   const decrementMonth = () => { | ||||
|       setSelectedMonth(selectedMonth - 1); | ||||
|   } | ||||
| 
 | ||||
|   // Set up calendar
 | ||||
|   var daysInMonth = dayjs().month(selectedMonth).daysInMonth(); | ||||
|   var days = []; | ||||
|   for (let i = 1; i <= daysInMonth; i++) { | ||||
|       days.push(i); | ||||
|   } | ||||
| 
 | ||||
|   // Create placeholder elements for empty days in first week
 | ||||
|   let weekdayOfFirst = dayjs().month(selectedMonth).date(1).day(); | ||||
|   if (props.user.weekStart === 'Monday') { | ||||
|     weekdayOfFirst -= 1; | ||||
|     if (weekdayOfFirst < 0) | ||||
|       weekdayOfFirst = 6; | ||||
|   } | ||||
|   const emptyDays = Array(weekdayOfFirst).fill(null).map((day, i) => | ||||
|       <div key={`e-${i}`} className={"text-center w-10 h-10 rounded-full mx-auto"}> | ||||
|           {null} | ||||
|       </div> | ||||
|   ); | ||||
| 
 | ||||
|   const changeDate = (day) => { | ||||
|   const changeDate = (date: Dayjs) => { | ||||
|     telemetry.withJitsu((jitsu) => jitsu.track(telemetryEventTypes.dateSelected, collectPageParameters())) | ||||
|     setSelectedDate(dayjs().month(selectedMonth).date(day)) | ||||
|     setSelectedDate(date); | ||||
|   }; | ||||
| 
 | ||||
|   // Combine placeholder days with actual days
 | ||||
|   const calendar = [...emptyDays, ...days.map((day) => | ||||
|       <button key={day} onClick={() => changeDate(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> | ||||
|   )]; | ||||
| 
 | ||||
|   const handleSelectTimeZone = (selectedTimeZone: string) => { | ||||
|     if (selectedDate) { | ||||
|       setSelectedDate(selectedDate.tz(selectedTimeZone)) | ||||
|  | @ -120,102 +83,27 @@ export default function Type(props) { | |||
|                 {props.eventType.length} minutes | ||||
|               </p> | ||||
|               <button | ||||
|                 onClick={() => setIsTimeOptionsOpen(!isTimeOptionsOpen)} | ||||
|                 onClick={() => setIsTimeOptionsOpen(true)} | ||||
|                 className="text-gray-500 mb-1 px-2 py-1 -ml-2" | ||||
|               > | ||||
|                 <GlobeIcon className="inline-block w-4 h-4 mr-1 -mt-1" /> | ||||
|                 {timeZone()} | ||||
|                 <ChevronDownIcon className="inline-block w-4 h-4 ml-1 -mt-1" /> | ||||
|               </button> | ||||
|               { isTimeOptionsOpen && <TimeOptions onSelectTimeZone={handleSelectTimeZone} | ||||
|                                                   onToggle24hClock={handleToggle24hClock} />} | ||||
|               <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") | ||||
|               } | ||||
|             > | ||||
|               <div className="flex text-gray-600 font-light text-xl mb-4 ml-2"> | ||||
|                 <span className="w-1/2"> | ||||
|                   {dayjs().month(selectedMonth).format("MMMM YYYY")} | ||||
|                 </span> | ||||
|                 <div className="w-1/2 text-right"> | ||||
|                   <button | ||||
|                     onClick={decrementMonth} | ||||
|                     className={ | ||||
|                       "mr-4 " + | ||||
|                       (selectedMonth < parseInt(dayjs().format("MM")) && | ||||
|                         "text-gray-400") | ||||
|                     } | ||||
|                     disabled={selectedMonth < parseInt(dayjs().format("MM"))} | ||||
|                   > | ||||
|                     <ChevronLeftIcon className="w-5 h-5" /> | ||||
|                   </button> | ||||
|                   <button onClick={incrementMonth}> | ||||
|                     <ChevronRightIcon className="w-5 h-5" /> | ||||
|                   </button> | ||||
|                 </div> | ||||
|               </div> | ||||
|               <div className="grid grid-cols-7 gap-y-4 text-center"> | ||||
|                 {props.user.weekStart !== 'Monday' ? ( | ||||
|                   <div className="uppercase text-gray-400 text-xs tracking-widest"> | ||||
|                   Sun | ||||
|                 </div> | ||||
|                 ) : null} | ||||
|                 <div className="uppercase text-gray-400 text-xs tracking-widest"> | ||||
|                   Mon | ||||
|                 </div> | ||||
|                 <div className="uppercase text-gray-400 text-xs tracking-widest"> | ||||
|                   Tue | ||||
|                 </div> | ||||
|                 <div className="uppercase text-gray-400 text-xs tracking-widest"> | ||||
|                   Wed | ||||
|                 </div> | ||||
|                 <div className="uppercase text-gray-400 text-xs tracking-widest"> | ||||
|                   Thu | ||||
|                 </div> | ||||
|                 <div className="uppercase text-gray-400 text-xs tracking-widest"> | ||||
|                   Fri | ||||
|                 </div> | ||||
|                 <div className="uppercase text-gray-400 text-xs tracking-widest"> | ||||
|                   Sat | ||||
|                 </div> | ||||
|                 {props.user.weekStart === 'Monday' ? ( | ||||
|                   <div className="uppercase text-gray-400 text-xs tracking-widest"> | ||||
|                   Sun | ||||
|                 </div> | ||||
|                 ) : null} | ||||
|                 {calendar} | ||||
|               </div> | ||||
|             </div> | ||||
|               <GlobeIcon className="inline-block w-4 h-4 mr-1 -mt-1" /> | ||||
|               {timeZone()} | ||||
|               <ChevronDownIcon className="inline-block w-4 h-4 ml-1 -mt-1" /> | ||||
|             </button> | ||||
|             { isTimeOptionsOpen && <TimeOptions onSelectTimeZone={handleSelectTimeZone} | ||||
|                                                 onToggle24hClock={handleToggle24hClock} />} | ||||
|             <p className="text-gray-600 mt-3 mb-8"> | ||||
|               {props.eventType.description} | ||||
|             </p> | ||||
|           </div> | ||||
|             <DatePicker weekStart={props.user.weekStart} onDatePicked={changeDate} /> | ||||
|             {selectedDate && <AvailableTimes timeFormat={timeFormat} user={props.user} eventType={props.eventType} date={selectedDate} />} | ||||
|           </div> | ||||
|         </div> | ||||
|         {/* note(peer): | ||||
|           you can remove calendso branding here, but we'd also appreciate it, if you don't <3 | ||||
|         */} | ||||
|         <div className="text-xs text-right pt-1"> | ||||
|           <Link href="https://calendso.com"> | ||||
|             <a | ||||
|               style={{ color: "#104D86" }} | ||||
|               className="opacity-50 hover:opacity-100" | ||||
|             > | ||||
|               powered by{" "} | ||||
|               <img | ||||
|                 style={{ top: -2 }} | ||||
|                 className="w-auto inline h-3 relative" | ||||
|                 src="/calendso-logo-word.svg" | ||||
|                 alt="Calendso Logo" | ||||
|               /> | ||||
|             </a> | ||||
|           </Link> | ||||
|         </div> | ||||
|         <PoweredByCalendso /> | ||||
|       </main> | ||||
|     </div> | ||||
|   ); | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue
	
	 Alex van Andel
						Alex van Andel