2021-04-11 17:12:18 +00:00
import Head from 'next/head' ;
import Link from 'next/link' ;
2021-06-09 19:46:41 +00:00
import { useRouter } from 'next/router' ;
import { CalendarIcon , ClockIcon , LocationMarkerIcon } from '@heroicons/react/solid' ;
2021-04-11 17:12:18 +00:00
import prisma from '../../lib/prisma' ;
2021-05-07 17:05:33 +00:00
import { collectPageParameters , telemetryEventTypes , useTelemetry } from "../../lib/telemetry" ;
2021-06-09 19:46:41 +00:00
import { useEffect , useState } from "react" ;
2021-05-08 19:03:47 +00:00
import dayjs from 'dayjs' ;
2021-05-26 18:40:22 +00:00
import utc from 'dayjs/plugin/utc' ;
import timezone from 'dayjs/plugin/timezone' ;
2021-05-08 19:03:47 +00:00
import 'react-phone-number-input/style.css' ;
import PhoneInput from 'react-phone-number-input' ;
2021-06-09 19:46:41 +00:00
import { LocationType } from '../../lib/location' ;
2021-05-08 20:26:19 +00:00
import Avatar from '../../components/Avatar' ;
2021-05-27 20:34:02 +00:00
import Button from '../../components/ui/Button' ;
2021-03-22 13:48:48 +00:00
2021-05-26 18:40:22 +00:00
dayjs . extend ( utc ) ;
dayjs . extend ( timezone ) ;
2021-03-22 13:48:48 +00:00
export default function Book ( props ) {
2021-04-11 17:12:18 +00:00
const router = useRouter ( ) ;
2021-06-09 18:28:39 +00:00
const { date , user , rescheduleUid } = router . query ;
2021-05-08 21:53:10 +00:00
2021-05-26 18:40:22 +00:00
const [ is24h , setIs24h ] = useState ( false ) ;
const [ preferredTimeZone , setPreferredTimeZone ] = useState ( '' ) ;
2021-05-08 21:53:10 +00:00
const locations = props . eventType . locations || [ ] ;
const [ selectedLocation , setSelectedLocation ] = useState < LocationType > ( locations . length === 1 ? locations [ 0 ] . type : '' ) ;
2021-04-27 14:19:12 +00:00
const telemetry = useTelemetry ( ) ;
useEffect ( ( ) = > {
2021-05-26 18:40:22 +00:00
setPreferredTimeZone ( localStorage . getItem ( 'timeOption.preferredTimeZone' ) || dayjs . tz . guess ( ) ) ;
setIs24h ( ! ! localStorage . getItem ( 'timeOption.is24hClock' ) ) ;
2021-05-07 17:05:33 +00:00
telemetry . withJitsu ( jitsu = > jitsu . track ( telemetryEventTypes . timeSelected , collectPageParameters ( ) ) ) ;
2021-05-08 19:03:47 +00:00
} ) ;
2021-05-08 21:53:10 +00:00
const locationInfo = ( type : LocationType ) = > locations . find (
2021-05-08 19:03:47 +00:00
( location ) = > location . type === type
) ;
// TODO: Move to translations
const locationLabels = {
[ LocationType . InPerson ] : 'In-person meeting' ,
[ LocationType . Phone ] : 'Phone call' ,
} ;
2021-03-22 13:48:48 +00:00
const bookingHandler = event = > {
2021-04-11 17:12:18 +00:00
event . preventDefault ( ) ;
2021-05-08 19:03:47 +00:00
2021-05-08 21:53:10 +00:00
let payload = {
start : dayjs ( date ) . format ( ) ,
end : dayjs ( date ) . add ( props . eventType . length , 'minute' ) . format ( ) ,
name : event.target.name.value ,
email : event.target.email.value ,
2021-05-27 22:10:20 +00:00
notes : event.target.notes.value ,
timeZone : preferredTimeZone ,
eventName : props.eventType.title ,
2021-06-09 18:28:39 +00:00
rescheduleUid : rescheduleUid
2021-05-08 21:53:10 +00:00
} ;
if ( selectedLocation ) {
payload [ 'location' ] = selectedLocation === LocationType . Phone ? event.target.phone.value : locationInfo ( selectedLocation ) . address ;
}
2021-05-08 19:03:47 +00:00
2021-05-07 17:05:33 +00:00
telemetry . withJitsu ( jitsu = > jitsu . track ( telemetryEventTypes . bookingConfirmed , collectPageParameters ( ) ) ) ;
2021-03-22 13:48:48 +00:00
const res = fetch (
2021-04-07 20:41:08 +00:00
'/api/book/' + user ,
2021-03-22 13:48:48 +00:00
{
2021-05-08 21:53:10 +00:00
body : JSON.stringify ( payload ) ,
2021-03-22 13:48:48 +00:00
headers : {
'Content-Type' : 'application/json'
} ,
method : 'POST'
}
2021-04-11 17:12:18 +00:00
) ;
2021-05-08 19:03:47 +00:00
2021-06-09 18:28:39 +00:00
let successUrl = ` /success?date= ${ date } &type= ${ props . eventType . id } &user= ${ props . user . username } &reschedule=1 ` ;
2021-05-08 21:53:10 +00:00
if ( payload [ 'location' ] ) {
successUrl += "&location=" + encodeURIComponent ( payload [ 'location' ] ) ;
}
router . push ( successUrl ) ;
2021-03-22 13:48:48 +00:00
}
return (
< div >
< Head >
2021-06-09 18:28:39 +00:00
< title > { rescheduleUid ? 'Reschedule' : 'Confirm' } your { props . eventType . title } with { props . user . name || props . user . username } | Calendso < / title >
2021-03-22 13:48:48 +00:00
< link rel = "icon" href = "/favicon.ico" / >
< / Head >
< main className = "max-w-3xl mx-auto my-24" >
< div className = "bg-white overflow-hidden shadow rounded-lg" >
< div className = "sm:flex px-4 py-5 sm:p-6" >
< div className = "sm:w-1/2 sm:border-r" >
2021-05-08 20:26:19 +00:00
< Avatar user = { props . user } className = "w-16 h-16 rounded-full mb-4" / >
2021-03-22 13:48:48 +00:00
< h2 className = "font-medium text-gray-500" > { props . user . name } < / h2 >
< h1 className = "text-3xl font-semibold text-gray-800 mb-4" > { props . eventType . title } < / h1 >
< p className = "text-gray-500 mb-2" >
2021-04-21 10:10:27 +00:00
< ClockIcon className = "inline-block w-4 h-4 mr-1 -mt-1" / >
2021-03-22 13:48:48 +00:00
{ props . eventType . length } minutes
< / p >
2021-05-08 19:03:47 +00:00
{ selectedLocation === LocationType . InPerson && < p className = "text-gray-500 mb-2" >
< LocationMarkerIcon className = "inline-block w-4 h-4 mr-1 -mt-1" / >
{ locationInfo ( selectedLocation ) . address }
< / p > }
2021-03-22 13:48:48 +00:00
< p className = "text-blue-600 mb-4" >
2021-04-21 10:10:27 +00:00
< CalendarIcon className = "inline-block w-4 h-4 mr-1 -mt-1" / >
2021-05-26 18:40:22 +00:00
{ preferredTimeZone && dayjs ( date ) . tz ( preferredTimeZone ) . format ( ( is24h ? "H:mm" : "h:mma" ) + ", dddd DD MMMM YYYY" ) }
2021-03-22 13:48:48 +00:00
< / p >
< p className = "text-gray-600" > { props . eventType . description } < / p >
< / div >
< div className = "sm:w-1/2 pl-8 pr-4" >
< form onSubmit = { bookingHandler } >
< div className = "mb-4" >
< label htmlFor = "name" className = "block text-sm font-medium text-gray-700" > Your name < / label >
< div className = "mt-1" >
2021-06-09 22:50:45 +00:00
< input type = "text" name = "name" id = "name" required className = "shadow-sm focus:ring-blue-500 focus:border-blue-500 block w-full sm:text-sm border-gray-300 rounded-md" placeholder = "John Doe" defaultValue = { props . booking ? props . booking . attendees [ 0 ] . name : '' } / >
2021-03-22 13:48:48 +00:00
< / div >
< / div >
< div className = "mb-4" >
< label htmlFor = "email" className = "block text-sm font-medium text-gray-700" > Email address < / label >
< div className = "mt-1" >
2021-06-09 22:50:45 +00:00
< input type = "email" name = "email" id = "email" required className = "shadow-sm focus:ring-blue-500 focus:border-blue-500 block w-full sm:text-sm border-gray-300 rounded-md" placeholder = "you@example.com" defaultValue = { props . booking ? props . booking . attendees [ 0 ] . email : '' } / >
2021-03-22 13:48:48 +00:00
< / div >
< / div >
2021-05-08 21:53:10 +00:00
{ locations . length > 1 && (
2021-05-08 19:03:47 +00:00
< div className = "mb-4" >
< span className = "block text-sm font-medium text-gray-700" > Location < / span >
2021-05-08 21:53:10 +00:00
{ locations . map ( ( location ) = > (
2021-05-08 19:03:47 +00:00
< label key = { location . type } className = "block" >
< input type = "radio" required onChange = { ( e ) = > setSelectedLocation ( e . target . value ) } className = "location" name = "location" value = { location . type } checked = { selectedLocation === location . type } / >
< span className = "text-sm ml-2" > { locationLabels [ location . type ] } < / span >
< / label >
) ) }
< / div >
) }
{ selectedLocation === LocationType . Phone && ( < div className = "mb-4" >
< label htmlFor = "phone" className = "block text-sm font-medium text-gray-700" > Phone Number < / label >
< div className = "mt-1" >
< PhoneInput name = "phone" placeholder = "Enter phone number" id = "phone" required className = "shadow-sm focus:ring-blue-500 focus:border-blue-500 block w-full sm:text-sm border-gray-300 rounded-md" onChange = { ( ) = > { } } / >
< / div >
< / div > ) }
2021-03-22 13:48:48 +00:00
< div className = "mb-4" >
< label htmlFor = "notes" className = "block text-sm font-medium text-gray-700 mb-1" > Additional notes < / label >
2021-06-09 22:50:45 +00:00
< textarea name = "notes" id = "notes" rows = { 3 } className = "shadow-sm focus:ring-blue-500 focus:border-blue-500 block w-full sm:text-sm border-gray-300 rounded-md" placeholder = "Please share anything that will help prepare for our meeting." defaultValue = { props . booking ? props . booking . description : '' } > < / textarea >
2021-03-22 13:48:48 +00:00
< / div >
2021-06-01 18:03:13 +00:00
< div className = "flex items-start" >
2021-06-09 18:28:39 +00:00
< Button type = "submit" className = "btn btn-primary" > { rescheduleUid ? 'Reschedule' : 'Confirm' } < / Button >
< Link href = { "/" + props . user . username + "/" + props . eventType . slug + ( rescheduleUid ? "?rescheduleUid=" + rescheduleUid : "" ) } >
2021-03-22 13:48:48 +00:00
< a className = "ml-2 btn btn-white" > Cancel < / a >
< / Link >
< / div >
< / form >
< / div >
< / div >
< / div >
< / main >
< / div >
)
}
export async function getServerSideProps ( context ) {
const user = await prisma . user . findFirst ( {
where : {
username : context.query.user ,
} ,
select : {
username : true ,
name : true ,
2021-05-08 20:26:19 +00:00
email :true ,
2021-03-22 13:48:48 +00:00
bio : true ,
avatar : true ,
eventTypes : true
}
} ) ;
const eventType = await prisma . eventType . findUnique ( {
where : {
id : parseInt ( context . query . type ) ,
} ,
select : {
id : true ,
title : true ,
2021-04-30 12:06:04 +00:00
slug : true ,
2021-03-22 13:48:48 +00:00
description : true ,
2021-05-08 19:03:47 +00:00
length : true ,
locations : true ,
2021-03-22 13:48:48 +00:00
}
} ) ;
2021-06-09 19:46:41 +00:00
let booking = null ;
2021-06-09 18:28:39 +00:00
if ( context . query . rescheduleUid ) {
booking = await prisma . booking . findFirst ( {
where : {
uid : context.query.rescheduleUid
} ,
select : {
description : true ,
attendees : {
select : {
email : true ,
name : true
}
}
}
} ) ;
}
2021-03-22 13:48:48 +00:00
return {
props : {
user ,
2021-06-09 18:28:39 +00:00
eventType ,
booking
2021-03-22 13:48:48 +00:00
} ,
}
}