Fixes some linting + codacy issues
This commit is contained in:
		
							parent
							
								
									5206fb4f88
								
							
						
					
					
						commit
						4d7427ad91
					
				
					 7 changed files with 563 additions and 556 deletions
				
			
		|  | @ -1,8 +1,8 @@ | ||||||
| import {useEffect, useState} from "react"; | import { useEffect, useState } from "react"; | ||||||
| 
 | 
 | ||||||
| const Theme = (theme?: string) => { | export default function Theme(theme?: string) { | ||||||
|   const [isReady, setIsReady] = useState(false); |   const [isReady, setIsReady] = useState(false); | ||||||
|   useEffect( () => { |   useEffect(() => { | ||||||
|     if (!theme && window.matchMedia("(prefers-color-scheme: dark)").matches) { |     if (!theme && window.matchMedia("(prefers-color-scheme: dark)").matches) { | ||||||
|       document.documentElement.classList.add("dark"); |       document.documentElement.classList.add("dark"); | ||||||
|     } else { |     } else { | ||||||
|  | @ -12,8 +12,6 @@ const Theme = (theme?: string) => { | ||||||
|   }, []); |   }, []); | ||||||
| 
 | 
 | ||||||
|   return { |   return { | ||||||
|     isReady |     isReady, | ||||||
|   } |   }; | ||||||
| }; | } | ||||||
| 
 |  | ||||||
| export default Theme; |  | ||||||
|  |  | ||||||
|  | @ -1,12 +1,11 @@ | ||||||
| import { GetServerSideProps } from "next"; | import { GetServerSideProps } from "next"; | ||||||
| import Head from "next/head"; | import Head from "next/head"; | ||||||
| import Link from "next/link"; | import Link from "next/link"; | ||||||
| import prisma, {whereAndSelect} from "@lib/prisma"; | import prisma, { whereAndSelect } from "@lib/prisma"; | ||||||
| import Avatar from "../components/Avatar"; | import Avatar from "../components/Avatar"; | ||||||
| import Theme from "@components/Theme"; | import Theme from "@components/Theme"; | ||||||
| 
 | 
 | ||||||
| export default function User(props): User { | export default function User(props): User { | ||||||
| 
 |  | ||||||
|   const { isReady } = Theme(props.user.theme); |   const { isReady } = Theme(props.user.theme); | ||||||
| 
 | 
 | ||||||
|   const eventTypes = props.eventTypes.map((type) => ( |   const eventTypes = props.eventTypes.map((type) => ( | ||||||
|  | @ -24,42 +23,44 @@ export default function User(props): User { | ||||||
|       </Link> |       </Link> | ||||||
|     </li> |     </li> | ||||||
|   )); |   )); | ||||||
|   return isReady && ( |   return ( | ||||||
|     <div> |     isReady && ( | ||||||
|       <Head> |       <div> | ||||||
|         <title>{props.user.name || props.user.username} | Calendso</title> |         <Head> | ||||||
|         <link rel="icon" href="/favicon.ico" /> |           <title>{props.user.name || props.user.username} | Calendso</title> | ||||||
|       </Head> |           <link rel="icon" href="/favicon.ico" /> | ||||||
|  |         </Head> | ||||||
| 
 | 
 | ||||||
|       <main className="max-w-2xl mx-auto my-24"> |         <main className="max-w-2xl mx-auto my-24"> | ||||||
|         <div className="mb-8 text-center"> |           <div className="mb-8 text-center"> | ||||||
|           <Avatar user={props.user} className="mx-auto w-24 h-24 rounded-full mb-4" /> |             <Avatar user={props.user} className="mx-auto w-24 h-24 rounded-full mb-4" /> | ||||||
|           <h1 className="text-3xl font-semibold text-gray-800 dark:text-white mb-1"> |             <h1 className="text-3xl font-semibold text-gray-800 dark:text-white mb-1"> | ||||||
|             {props.user.name || props.user.username} |               {props.user.name || props.user.username} | ||||||
|           </h1> |             </h1> | ||||||
|           <p className="text-gray-600 dark:text-white">{props.user.bio}</p> |             <p className="text-gray-600 dark:text-white">{props.user.bio}</p> | ||||||
|         </div> |           </div> | ||||||
|         <div className="shadow overflow-hidden rounded-md"> |           <div className="shadow overflow-hidden rounded-md"> | ||||||
|           <ul className="divide-y divide-gray-200 dark:divide-gray-900">{eventTypes}</ul> |             <ul className="divide-y divide-gray-200 dark:divide-gray-900">{eventTypes}</ul> | ||||||
|           {eventTypes.length == 0 && ( |             {eventTypes.length == 0 && ( | ||||||
|             <div className="p-8 text-center text-gray-400 dark:text-white"> |               <div className="p-8 text-center text-gray-400 dark:text-white"> | ||||||
|               <h2 className="font-semibold text-3xl text-gray-600">Uh oh!</h2> |                 <h2 className="font-semibold text-3xl text-gray-600">Uh oh!</h2> | ||||||
|               <p className="max-w-md mx-auto">This user hasn't set up any event types yet.</p> |                 <p className="max-w-md mx-auto">This user hasn't set up any event types yet.</p> | ||||||
|             </div> |               </div> | ||||||
|           )} |             )} | ||||||
|         </div> |           </div> | ||||||
|       </main> |         </main> | ||||||
|     </div> |       </div> | ||||||
|  |     ) | ||||||
|   ); |   ); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export const getServerSideProps: GetServerSideProps = async (context) => { | export const getServerSideProps: GetServerSideProps = async (context) => { | ||||||
| 
 |   const user = await whereAndSelect( | ||||||
|   const user = await whereAndSelect(prisma.user.findFirst, { |     prisma.user.findFirst, | ||||||
|  |     { | ||||||
|       username: context.query.user.toLowerCase(), |       username: context.query.user.toLowerCase(), | ||||||
|     }, [ |     }, | ||||||
|       "id", "username", "email", "name", "bio", "avatar", "eventTypes", "theme" |     ["id", "username", "email", "name", "bio", "avatar", "eventTypes", "theme"] | ||||||
|     ] |  | ||||||
|   ); |   ); | ||||||
|   if (!user) { |   if (!user) { | ||||||
|     return { |     return { | ||||||
|  |  | ||||||
|  | @ -47,113 +47,115 @@ export default function Type(props): Type { | ||||||
|     setTimeFormat(is24hClock ? "HH:mm" : "h:mma"); |     setTimeFormat(is24hClock ? "HH:mm" : "h:mma"); | ||||||
|   }; |   }; | ||||||
| 
 | 
 | ||||||
|   return isReady && ( |   return ( | ||||||
|     <div> |     isReady && ( | ||||||
|       <Head> |       <div> | ||||||
|         <title> |         <Head> | ||||||
|           {rescheduleUid && "Reschedule"} {props.eventType.title} | {props.user.name || props.user.username} | |           <title> | ||||||
|           Calendso |             {rescheduleUid && "Reschedule"} {props.eventType.title} | {props.user.name || props.user.username}{" "} | ||||||
|         </title> |             | Calendso | ||||||
|         <meta name="title" content={"Meet " + (props.user.name || props.user.username) + " via Calendso"} /> |           </title> | ||||||
|         <meta name="description" content={props.eventType.description} /> |           <meta name="title" content={"Meet " + (props.user.name || props.user.username) + " via Calendso"} /> | ||||||
|  |           <meta name="description" content={props.eventType.description} /> | ||||||
| 
 | 
 | ||||||
|         <meta property="og:type" content="website" /> |           <meta property="og:type" content="website" /> | ||||||
|         <meta property="og:url" content="https://calendso/" /> |           <meta property="og:url" content="https://calendso/" /> | ||||||
|         <meta |           <meta | ||||||
|           property="og:title" |             property="og:title" | ||||||
|           content={"Meet " + (props.user.name || props.user.username) + " via Calendso"} |             content={"Meet " + (props.user.name || props.user.username) + " via Calendso"} | ||||||
|         /> |           /> | ||||||
|         <meta property="og:description" content={props.eventType.description} /> |           <meta property="og:description" content={props.eventType.description} /> | ||||||
|         <meta |           <meta | ||||||
|           property="og:image" |             property="og:image" | ||||||
|           content={ |             content={ | ||||||
|             "https://og-image-one-pi.vercel.app/" + |               "https://og-image-one-pi.vercel.app/" + | ||||||
|             encodeURIComponent( |               encodeURIComponent( | ||||||
|               "Meet **" + (props.user.name || props.user.username) + "** <br>" + props.eventType.description |                 "Meet **" + (props.user.name || props.user.username) + "** <br>" + props.eventType.description | ||||||
|             ).replace(/'/g, "%27") + |               ).replace(/'/g, "%27") + | ||||||
|             ".png?md=1&images=https%3A%2F%2Fcalendso.com%2Fcalendso-logo-white.svg&images=" + |               ".png?md=1&images=https%3A%2F%2Fcalendso.com%2Fcalendso-logo-white.svg&images=" + | ||||||
|             encodeURIComponent(props.user.avatar) |               encodeURIComponent(props.user.avatar) | ||||||
|           } |             } | ||||||
|         /> |           /> | ||||||
| 
 | 
 | ||||||
|         <meta property="twitter:card" content="summary_large_image" /> |           <meta property="twitter:card" content="summary_large_image" /> | ||||||
|         <meta property="twitter:url" content="https://calendso/" /> |           <meta property="twitter:url" content="https://calendso/" /> | ||||||
|         <meta |           <meta | ||||||
|           property="twitter:title" |             property="twitter:title" | ||||||
|           content={"Meet " + (props.user.name || props.user.username) + " via Calendso"} |             content={"Meet " + (props.user.name || props.user.username) + " via Calendso"} | ||||||
|         /> |           /> | ||||||
|         <meta property="twitter:description" content={props.eventType.description} /> |           <meta property="twitter:description" content={props.eventType.description} /> | ||||||
|         <meta |           <meta | ||||||
|           property="twitter:image" |             property="twitter:image" | ||||||
|           content={ |             content={ | ||||||
|             "https://og-image-one-pi.vercel.app/" + |               "https://og-image-one-pi.vercel.app/" + | ||||||
|             encodeURIComponent( |               encodeURIComponent( | ||||||
|               "Meet **" + (props.user.name || props.user.username) + "** <br>" + props.eventType.description |                 "Meet **" + (props.user.name || props.user.username) + "** <br>" + props.eventType.description | ||||||
|             ).replace(/'/g, "%27") + |               ).replace(/'/g, "%27") + | ||||||
|             ".png?md=1&images=https%3A%2F%2Fcalendso.com%2Fcalendso-logo-white.svg&images=" + |               ".png?md=1&images=https%3A%2F%2Fcalendso.com%2Fcalendso-logo-white.svg&images=" + | ||||||
|             encodeURIComponent(props.user.avatar) |               encodeURIComponent(props.user.avatar) | ||||||
|           } |             } | ||||||
|         /> |           /> | ||||||
|       </Head> |         </Head> | ||||||
|       <main |         <main | ||||||
|         className={ |           className={ | ||||||
|           "mx-auto my-0 sm:my-24 transition-max-width ease-in-out duration-500 " + |             "mx-auto my-0 sm:my-24 transition-max-width ease-in-out duration-500 " + | ||||||
|           (selectedDate ? "max-w-6xl" : "max-w-3xl") |             (selectedDate ? "max-w-6xl" : "max-w-3xl") | ||||||
|         }> |           }> | ||||||
|         <div className="dark:bg-gray-800 bg-white sm:shadow sm:rounded-lg"> |           <div className="dark:bg-gray-800 bg-white sm:shadow sm:rounded-lg"> | ||||||
|           <div className="sm:flex px-4 py-5 sm:p-4"> |             <div className="sm:flex px-4 py-5 sm:p-4"> | ||||||
|             <div |               <div | ||||||
|               className={ |                 className={ | ||||||
|                 "pr-8 sm:border-r sm:dark:border-gray-900 " + (selectedDate ? "sm:w-1/3" : "sm:w-1/2") |                   "pr-8 sm:border-r sm:dark:border-gray-900 " + (selectedDate ? "sm:w-1/3" : "sm:w-1/2") | ||||||
|               }> |                 }> | ||||||
|               <Avatar user={props.user} className="w-16 h-16 rounded-full mb-4" /> |                 <Avatar user={props.user} className="w-16 h-16 rounded-full mb-4" /> | ||||||
|               <h2 className="font-medium dark:text-gray-300 text-gray-500">{props.user.name}</h2> |                 <h2 className="font-medium dark:text-gray-300 text-gray-500">{props.user.name}</h2> | ||||||
|               <h1 className="text-3xl font-semibold dark:text-white text-gray-800 mb-4"> |                 <h1 className="text-3xl font-semibold dark:text-white text-gray-800 mb-4"> | ||||||
|                 {props.eventType.title} |                   {props.eventType.title} | ||||||
|               </h1> |                 </h1> | ||||||
|               <p className="text-gray-500 mb-1 px-2 py-1 -ml-2"> |                 <p className="text-gray-500 mb-1 px-2 py-1 -ml-2"> | ||||||
|                 <ClockIcon className="inline-block w-4 h-4 mr-1 -mt-1" /> |                   <ClockIcon className="inline-block w-4 h-4 mr-1 -mt-1" /> | ||||||
|                 {props.eventType.length} minutes |                   {props.eventType.length} minutes | ||||||
|               </p> |                 </p> | ||||||
|               <button |                 <button | ||||||
|                 onClick={() => setIsTimeOptionsOpen(!isTimeOptionsOpen)} |                   onClick={() => setIsTimeOptionsOpen(!isTimeOptionsOpen)} | ||||||
|                 className="text-gray-500 mb-1 px-2 py-1 -ml-2"> |                   className="text-gray-500 mb-1 px-2 py-1 -ml-2"> | ||||||
|                 <GlobeIcon className="inline-block w-4 h-4 mr-1 -mt-1" /> |                   <GlobeIcon className="inline-block w-4 h-4 mr-1 -mt-1" /> | ||||||
|                 {timeZone()} |                   {timeZone()} | ||||||
|                 <ChevronDownIcon className="inline-block w-4 h-4 ml-1 -mt-1" /> |                   <ChevronDownIcon className="inline-block w-4 h-4 ml-1 -mt-1" /> | ||||||
|               </button> |                 </button> | ||||||
|               {isTimeOptionsOpen && ( |                 {isTimeOptionsOpen && ( | ||||||
|                 <TimeOptions |                   <TimeOptions | ||||||
|                   onSelectTimeZone={handleSelectTimeZone} |                     onSelectTimeZone={handleSelectTimeZone} | ||||||
|                   onToggle24hClock={handleToggle24hClock} |                     onToggle24hClock={handleToggle24hClock} | ||||||
|  |                   /> | ||||||
|  |                 )} | ||||||
|  |                 <p className="dark:text-gray-200 text-gray-600 mt-3 mb-8">{props.eventType.description}</p> | ||||||
|  |               </div> | ||||||
|  |               <DatePicker | ||||||
|  |                 weekStart={props.user.weekStart} | ||||||
|  |                 onDatePicked={changeDate} | ||||||
|  |                 workingHours={props.workingHours} | ||||||
|  |                 organizerTimeZone={props.eventType.timeZone || props.user.timeZone} | ||||||
|  |                 inviteeTimeZone={timeZone()} | ||||||
|  |                 eventLength={props.eventType.length} | ||||||
|  |               /> | ||||||
|  |               {selectedDate && ( | ||||||
|  |                 <AvailableTimes | ||||||
|  |                   workingHours={props.workingHours} | ||||||
|  |                   timeFormat={timeFormat} | ||||||
|  |                   organizerTimeZone={props.eventType.timeZone || props.user.timeZone} | ||||||
|  |                   eventLength={props.eventType.length} | ||||||
|  |                   eventTypeId={props.eventType.id} | ||||||
|  |                   date={selectedDate} | ||||||
|  |                   user={props.user} | ||||||
|                 /> |                 /> | ||||||
|               )} |               )} | ||||||
|               <p className="dark:text-gray-200 text-gray-600 mt-3 mb-8">{props.eventType.description}</p> |  | ||||||
|             </div> |             </div> | ||||||
|             <DatePicker |  | ||||||
|               weekStart={props.user.weekStart} |  | ||||||
|               onDatePicked={changeDate} |  | ||||||
|               workingHours={props.workingHours} |  | ||||||
|               organizerTimeZone={props.eventType.timeZone || props.user.timeZone} |  | ||||||
|               inviteeTimeZone={timeZone()} |  | ||||||
|               eventLength={props.eventType.length} |  | ||||||
|             /> |  | ||||||
|             {selectedDate && ( |  | ||||||
|               <AvailableTimes |  | ||||||
|                 workingHours={props.workingHours} |  | ||||||
|                 timeFormat={timeFormat} |  | ||||||
|                 organizerTimeZone={props.eventType.timeZone || props.user.timeZone} |  | ||||||
|                 eventLength={props.eventType.length} |  | ||||||
|                 eventTypeId={props.eventType.id} |  | ||||||
|                 date={selectedDate} |  | ||||||
|                 user={props.user} |  | ||||||
|               /> |  | ||||||
|             )} |  | ||||||
|           </div> |           </div> | ||||||
|         </div> |           {!props.user.hideBranding && <PoweredByCalendso />} | ||||||
|         {!props.user.hideBranding && <PoweredByCalendso />} |         </main> | ||||||
|       </main> |       </div> | ||||||
|     </div> |     ) | ||||||
|   ); |   ); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -2,7 +2,7 @@ import Head from "next/head"; | ||||||
| import Link from "next/link"; | import Link from "next/link"; | ||||||
| import { useRouter } from "next/router"; | import { useRouter } from "next/router"; | ||||||
| import { CalendarIcon, ClockIcon, ExclamationIcon, LocationMarkerIcon } from "@heroicons/react/solid"; | import { CalendarIcon, ClockIcon, ExclamationIcon, LocationMarkerIcon } from "@heroicons/react/solid"; | ||||||
| import prisma, {whereAndSelect} from "../../lib/prisma"; | import prisma, { whereAndSelect } from "../../lib/prisma"; | ||||||
| import { collectPageParameters, telemetryEventTypes, useTelemetry } from "../../lib/telemetry"; | import { collectPageParameters, telemetryEventTypes, useTelemetry } from "../../lib/telemetry"; | ||||||
| import { useEffect, useState } from "react"; | import { useEffect, useState } from "react"; | ||||||
| import dayjs from "dayjs"; | import dayjs from "dayjs"; | ||||||
|  | @ -141,247 +141,247 @@ export default function Book(props: any): JSX.Element { | ||||||
|     book(); |     book(); | ||||||
|   }; |   }; | ||||||
| 
 | 
 | ||||||
|   return isReady && ( |   return ( | ||||||
|     <div> |     isReady && ( | ||||||
|       <Head> |       <div> | ||||||
|         <title> |         <Head> | ||||||
|           {rescheduleUid ? "Reschedule" : "Confirm"} your {props.eventType.title} with{" "} |           <title> | ||||||
|           {props.user.name || props.user.username} | Calendso |             {rescheduleUid ? "Reschedule" : "Confirm"} your {props.eventType.title} with{" "} | ||||||
|         </title> |             {props.user.name || props.user.username} | Calendso | ||||||
|         <link rel="icon" href="/favicon.ico" /> |           </title> | ||||||
|       </Head> |           <link rel="icon" href="/favicon.ico" /> | ||||||
|  |         </Head> | ||||||
| 
 | 
 | ||||||
|       <main className="max-w-3xl mx-auto my-0 sm:my-24"> |         <main className="max-w-3xl mx-auto my-0 sm:my-24"> | ||||||
|         <div className="dark:bg-gray-800 bg-white overflow-hidden sm:shadow sm:rounded-lg"> |           <div className="dark:bg-gray-800 bg-white overflow-hidden sm:shadow sm:rounded-lg"> | ||||||
|           <div className="sm:flex px-4 py-5 sm:p-4"> |             <div className="sm:flex px-4 py-5 sm:p-4"> | ||||||
|             <div className="sm:w-1/2 sm:border-r sm:dark:border-gray-900"> |               <div className="sm:w-1/2 sm:border-r sm:dark:border-gray-900"> | ||||||
|               <Avatar user={props.user} className="w-16 h-16 rounded-full mb-4" /> |                 <Avatar user={props.user} className="w-16 h-16 rounded-full mb-4" /> | ||||||
|               <h2 className="font-medium dark:text-gray-300 text-gray-500">{props.user.name}</h2> |                 <h2 className="font-medium dark:text-gray-300 text-gray-500">{props.user.name}</h2> | ||||||
|               <h1 className="text-3xl font-semibold dark:text-white text-gray-800 mb-4"> |                 <h1 className="text-3xl font-semibold dark:text-white text-gray-800 mb-4"> | ||||||
|                 {props.eventType.title} |                   {props.eventType.title} | ||||||
|               </h1> |                 </h1> | ||||||
|               <p className="text-gray-500 mb-2"> |  | ||||||
|                 <ClockIcon className="inline-block w-4 h-4 mr-1 -mt-1" /> |  | ||||||
|                 {props.eventType.length} minutes |  | ||||||
|               </p> |  | ||||||
|               {selectedLocation === LocationType.InPerson && ( |  | ||||||
|                 <p className="text-gray-500 mb-2"> |                 <p className="text-gray-500 mb-2"> | ||||||
|                   <LocationMarkerIcon className="inline-block w-4 h-4 mr-1 -mt-1" /> |                   <ClockIcon className="inline-block w-4 h-4 mr-1 -mt-1" /> | ||||||
|                   {locationInfo(selectedLocation).address} |                   {props.eventType.length} minutes | ||||||
|                 </p> |                 </p> | ||||||
|               )} |                 {selectedLocation === LocationType.InPerson && ( | ||||||
|               <p className="text-blue-600 mb-4"> |                   <p className="text-gray-500 mb-2"> | ||||||
|                 <CalendarIcon className="inline-block w-4 h-4 mr-1 -mt-1" /> |                     <LocationMarkerIcon className="inline-block w-4 h-4 mr-1 -mt-1" /> | ||||||
|                 {preferredTimeZone && |                     {locationInfo(selectedLocation).address} | ||||||
|                   dayjs(date) |                   </p> | ||||||
|                     .tz(preferredTimeZone) |  | ||||||
|                     .format((is24h ? "H:mm" : "h:mma") + ", dddd DD MMMM YYYY")} |  | ||||||
|               </p> |  | ||||||
|               <p className="dark:text-white text-gray-600 mb-8">{props.eventType.description}</p> |  | ||||||
|             </div> |  | ||||||
|             <div className="sm:w-1/2 sm:pl-8 sm:pr-4"> |  | ||||||
|               <form onSubmit={bookingHandler}> |  | ||||||
|                 <div className="mb-4"> |  | ||||||
|                   <label htmlFor="name" className="block text-sm font-medium dark:text-white text-gray-700"> |  | ||||||
|                     Your name |  | ||||||
|                   </label> |  | ||||||
|                   <div className="mt-1"> |  | ||||||
|                     <input |  | ||||||
|                       type="text" |  | ||||||
|                       name="name" |  | ||||||
|                       id="name" |  | ||||||
|                       required |  | ||||||
|                       className="shadow-sm dark:bg-gray-700 dark:text-white dark:border-gray-900 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 : ""} |  | ||||||
|                     /> |  | ||||||
|                   </div> |  | ||||||
|                 </div> |  | ||||||
|                 <div className="mb-4"> |  | ||||||
|                   <label htmlFor="email" className="block text-sm font-medium dark:text-white text-gray-700"> |  | ||||||
|                     Email address |  | ||||||
|                   </label> |  | ||||||
|                   <div className="mt-1"> |  | ||||||
|                     <input |  | ||||||
|                       type="email" |  | ||||||
|                       name="email" |  | ||||||
|                       id="email" |  | ||||||
|                       required |  | ||||||
|                       className="shadow-sm dark:bg-gray-700 dark:text-white dark:border-gray-900 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 : ""} |  | ||||||
|                     /> |  | ||||||
|                   </div> |  | ||||||
|                 </div> |  | ||||||
|                 {locations.length > 1 && ( |  | ||||||
|                   <div className="mb-4"> |  | ||||||
|                     <span className="block text-sm font-medium text-gray-700">Location</span> |  | ||||||
|                     {locations.map((location) => ( |  | ||||||
|                       <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 && ( |                 <p className="text-blue-600 mb-4"> | ||||||
|  |                   <CalendarIcon className="inline-block w-4 h-4 mr-1 -mt-1" /> | ||||||
|  |                   {preferredTimeZone && | ||||||
|  |                     dayjs(date) | ||||||
|  |                       .tz(preferredTimeZone) | ||||||
|  |                       .format((is24h ? "H:mm" : "h:mma") + ", dddd DD MMMM YYYY")} | ||||||
|  |                 </p> | ||||||
|  |                 <p className="dark:text-white text-gray-600 mb-8">{props.eventType.description}</p> | ||||||
|  |               </div> | ||||||
|  |               <div className="sm:w-1/2 sm:pl-8 sm:pr-4"> | ||||||
|  |                 <form onSubmit={bookingHandler}> | ||||||
|                   <div className="mb-4"> |                   <div className="mb-4"> | ||||||
|                     <label |                     <label htmlFor="name" className="block text-sm font-medium dark:text-white text-gray-700"> | ||||||
|                       htmlFor="phone" |                       Your name | ||||||
|                       className="block text-sm font-medium dark:text-white text-gray-700"> |  | ||||||
|                       Phone Number |  | ||||||
|                     </label> |                     </label> | ||||||
|                     <div className="mt-1"> |                     <div className="mt-1"> | ||||||
|                       <PhoneInput |                       <input | ||||||
|                         name="phone" |                         type="text" | ||||||
|                         placeholder="Enter phone number" |                         name="name" | ||||||
|                         id="phone" |                         id="name" | ||||||
|                         required |                         required | ||||||
|                         className="shadow-sm dark:bg-gray-700 dark:text-white dark:border-gray-900 focus:ring-blue-500 focus:border-blue-500 block w-full sm:text-sm border-gray-300 rounded-md" |                         className="shadow-sm dark:bg-gray-700 dark:text-white dark:border-gray-900 focus:ring-blue-500 focus:border-blue-500 block w-full sm:text-sm border-gray-300 rounded-md" | ||||||
|                         onChange={() => { |                         placeholder="John Doe" | ||||||
|                           /* DO NOT REMOVE: Callback required by PhoneInput, comment added to satisfy eslint:no-empty-function */ |                         defaultValue={props.booking ? props.booking.attendees[0].name : ""} | ||||||
|                         }} |  | ||||||
|                       /> |                       /> | ||||||
|                     </div> |                     </div> | ||||||
|                   </div> |                   </div> | ||||||
|                 )} |                   <div className="mb-4"> | ||||||
|                 {props.eventType.customInputs && |                     <label | ||||||
|                   props.eventType.customInputs |                       htmlFor="email" | ||||||
|                     .sort((a, b) => a.id - b.id) |                       className="block text-sm font-medium dark:text-white text-gray-700"> | ||||||
|                     .map((input) => ( |                       Email address | ||||||
|                       <div className="mb-4" key={"input-" + input.label.toLowerCase}> |                     </label> | ||||||
|                         {input.type !== EventTypeCustomInputType.Bool && ( |                     <div className="mt-1"> | ||||||
|                           <label |                       <input | ||||||
|                             htmlFor={input.label} |                         type="email" | ||||||
|                             className="block text-sm font-medium text-gray-700 mb-1"> |                         name="email" | ||||||
|                             {input.label} |                         id="email" | ||||||
|                           </label> |                         required | ||||||
|                         )} |                         className="shadow-sm dark:bg-gray-700 dark:text-white dark:border-gray-900 focus:ring-blue-500 focus:border-blue-500 block w-full sm:text-sm border-gray-300 rounded-md" | ||||||
|                         {input.type === EventTypeCustomInputType.TextLong && ( |                         placeholder="you@example.com" | ||||||
|                           <textarea |                         defaultValue={props.booking ? props.booking.attendees[0].email : ""} | ||||||
|                             name={"custom_" + input.id} |                       /> | ||||||
|                             id={"custom_" + input.id} |  | ||||||
|                             required={input.required} |  | ||||||
|                             rows={3} |  | ||||||
|                             className="shadow-sm dark:bg-gray-700 dark:text-white dark:border-gray-900 focus:ring-blue-500 focus:border-blue-500 block w-full sm:text-sm border-gray-300 rounded-md" |  | ||||||
|                             placeholder="" |  | ||||||
|                           /> |  | ||||||
|                         )} |  | ||||||
|                         {input.type === EventTypeCustomInputType.Text && ( |  | ||||||
|                           <input |  | ||||||
|                             type="text" |  | ||||||
|                             name={"custom_" + input.id} |  | ||||||
|                             id={"custom_" + input.id} |  | ||||||
|                             required={input.required} |  | ||||||
|                             className="shadow-sm dark:bg-gray-700 dark:border-gray-900 focus:ring-blue-500 focus:border-blue-500 block w-full sm:text-sm border-gray-300 rounded-md" |  | ||||||
|                             placeholder="" |  | ||||||
|                           /> |  | ||||||
|                         )} |  | ||||||
|                         {input.type === EventTypeCustomInputType.Number && ( |  | ||||||
|                           <input |  | ||||||
|                             type="number" |  | ||||||
|                             name={"custom_" + input.id} |  | ||||||
|                             id={"custom_" + input.id} |  | ||||||
|                             required={input.required} |  | ||||||
|                             className="shadow-sm dark:bg-gray-700 dark:border-gray-900 focus:ring-blue-500 focus:border-blue-500 block w-full sm:text-sm border-gray-300 rounded-md" |  | ||||||
|                             placeholder="" |  | ||||||
|                           /> |  | ||||||
|                         )} |  | ||||||
|                         {input.type === EventTypeCustomInputType.Bool && ( |  | ||||||
|                           <div className="flex items-center h-5"> |  | ||||||
|                             <input |  | ||||||
|                               type="checkbox" |  | ||||||
|                               name={"custom_" + input.id} |  | ||||||
|                               id={"custom_" + input.id} |  | ||||||
|                               className="focus:ring-blue-500 h-4 w-4 text-blue-600 border-gray-300 rounded mr-2" |  | ||||||
|                               placeholder="" |  | ||||||
|                             /> |  | ||||||
|                             <label htmlFor={input.label} className="block text-sm font-medium text-gray-700"> |  | ||||||
|                               {input.label} |  | ||||||
|                             </label> |  | ||||||
|                           </div> |  | ||||||
|                         )} |  | ||||||
|                       </div> |  | ||||||
|                     ))} |  | ||||||
|                 <div className="mb-4"> |  | ||||||
|                   <label |  | ||||||
|                     htmlFor="notes" |  | ||||||
|                     className="block text-sm font-medium dark:text-white text-gray-700 mb-1"> |  | ||||||
|                     Additional notes |  | ||||||
|                   </label> |  | ||||||
|                   <textarea |  | ||||||
|                     name="notes" |  | ||||||
|                     id="notes" |  | ||||||
|                     rows={3} |  | ||||||
|                     className="shadow-sm dark:bg-gray-700 dark:text-white dark:border-gray-900 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 : ""} |  | ||||||
|                   /> |  | ||||||
|                 </div> |  | ||||||
|                 <div className="flex items-start"> |  | ||||||
|                   <Button type="submit" loading={loading} className="btn btn-primary"> |  | ||||||
|                     {rescheduleUid ? "Reschedule" : "Confirm"} |  | ||||||
|                   </Button> |  | ||||||
|                   <Link |  | ||||||
|                     href={ |  | ||||||
|                       "/" + |  | ||||||
|                       props.user.username + |  | ||||||
|                       "/" + |  | ||||||
|                       props.eventType.slug + |  | ||||||
|                       (rescheduleUid ? "?rescheduleUid=" + rescheduleUid : "") |  | ||||||
|                     }> |  | ||||||
|                     <a className="ml-2 btn btn-white">Cancel</a> |  | ||||||
|                   </Link> |  | ||||||
|                 </div> |  | ||||||
|               </form> |  | ||||||
|               {error && ( |  | ||||||
|                 <div className="bg-yellow-50 border-l-4 border-yellow-400 p-4 mt-2"> |  | ||||||
|                   <div className="flex"> |  | ||||||
|                     <div className="flex-shrink-0"> |  | ||||||
|                       <ExclamationIcon className="h-5 w-5 text-yellow-400" aria-hidden="true" /> |  | ||||||
|                     </div> |  | ||||||
|                     <div className="ml-3"> |  | ||||||
|                       <p className="text-sm text-yellow-700"> |  | ||||||
|                         Could not {rescheduleUid ? "reschedule" : "book"} the meeting. Please try again or{" "} |  | ||||||
|                         <a |  | ||||||
|                           href={"mailto:" + props.user.email} |  | ||||||
|                           className="font-medium underline text-yellow-700 hover:text-yellow-600"> |  | ||||||
|                           Contact {props.user.name} via e-mail |  | ||||||
|                         </a> |  | ||||||
|                       </p> |  | ||||||
|                     </div> |                     </div> | ||||||
|                   </div> |                   </div> | ||||||
|                 </div> |                   {locations.length > 1 && ( | ||||||
|               )} |                     <div className="mb-4"> | ||||||
|  |                       <span className="block text-sm font-medium text-gray-700">Location</span> | ||||||
|  |                       {locations.map((location) => ( | ||||||
|  |                         <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 dark:text-white text-gray-700"> | ||||||
|  |                         Phone Number | ||||||
|  |                       </label> | ||||||
|  |                       <div className="mt-1"> | ||||||
|  |                         <PhoneInput | ||||||
|  |                           name="phone" | ||||||
|  |                           placeholder="Enter phone number" | ||||||
|  |                           id="phone" | ||||||
|  |                           required | ||||||
|  |                           className="shadow-sm dark:bg-gray-700 dark:text-white dark:border-gray-900 focus:ring-blue-500 focus:border-blue-500 block w-full sm:text-sm border-gray-300 rounded-md" | ||||||
|  |                           onChange={() => { | ||||||
|  |                             /* DO NOT REMOVE: Callback required by PhoneInput, comment added to satisfy eslint:no-empty-function */ | ||||||
|  |                           }} | ||||||
|  |                         /> | ||||||
|  |                       </div> | ||||||
|  |                     </div> | ||||||
|  |                   )} | ||||||
|  |                   {props.eventType.customInputs && | ||||||
|  |                     props.eventType.customInputs | ||||||
|  |                       .sort((a, b) => a.id - b.id) | ||||||
|  |                       .map((input) => ( | ||||||
|  |                         <div className="mb-4" key={"input-" + input.label.toLowerCase}> | ||||||
|  |                           {input.type !== EventTypeCustomInputType.Bool && ( | ||||||
|  |                             <label | ||||||
|  |                               htmlFor={input.label} | ||||||
|  |                               className="block text-sm font-medium text-gray-700 mb-1"> | ||||||
|  |                               {input.label} | ||||||
|  |                             </label> | ||||||
|  |                           )} | ||||||
|  |                           {input.type === EventTypeCustomInputType.TextLong && ( | ||||||
|  |                             <textarea | ||||||
|  |                               name={"custom_" + input.id} | ||||||
|  |                               id={"custom_" + input.id} | ||||||
|  |                               required={input.required} | ||||||
|  |                               rows={3} | ||||||
|  |                               className="shadow-sm dark:bg-gray-700 dark:text-white dark:border-gray-900 focus:ring-blue-500 focus:border-blue-500 block w-full sm:text-sm border-gray-300 rounded-md" | ||||||
|  |                               placeholder="" | ||||||
|  |                             /> | ||||||
|  |                           )} | ||||||
|  |                           {input.type === EventTypeCustomInputType.Text && ( | ||||||
|  |                             <input | ||||||
|  |                               type="text" | ||||||
|  |                               name={"custom_" + input.id} | ||||||
|  |                               id={"custom_" + input.id} | ||||||
|  |                               required={input.required} | ||||||
|  |                               className="shadow-sm dark:bg-gray-700 dark:border-gray-900 focus:ring-blue-500 focus:border-blue-500 block w-full sm:text-sm border-gray-300 rounded-md" | ||||||
|  |                               placeholder="" | ||||||
|  |                             /> | ||||||
|  |                           )} | ||||||
|  |                           {input.type === EventTypeCustomInputType.Number && ( | ||||||
|  |                             <input | ||||||
|  |                               type="number" | ||||||
|  |                               name={"custom_" + input.id} | ||||||
|  |                               id={"custom_" + input.id} | ||||||
|  |                               required={input.required} | ||||||
|  |                               className="shadow-sm dark:bg-gray-700 dark:border-gray-900 focus:ring-blue-500 focus:border-blue-500 block w-full sm:text-sm border-gray-300 rounded-md" | ||||||
|  |                               placeholder="" | ||||||
|  |                             /> | ||||||
|  |                           )} | ||||||
|  |                           {input.type === EventTypeCustomInputType.Bool && ( | ||||||
|  |                             <div className="flex items-center h-5"> | ||||||
|  |                               <input | ||||||
|  |                                 type="checkbox" | ||||||
|  |                                 name={"custom_" + input.id} | ||||||
|  |                                 id={"custom_" + input.id} | ||||||
|  |                                 className="focus:ring-blue-500 h-4 w-4 text-blue-600 border-gray-300 rounded mr-2" | ||||||
|  |                                 placeholder="" | ||||||
|  |                               /> | ||||||
|  |                               <label | ||||||
|  |                                 htmlFor={input.label} | ||||||
|  |                                 className="block text-sm font-medium text-gray-700"> | ||||||
|  |                                 {input.label} | ||||||
|  |                               </label> | ||||||
|  |                             </div> | ||||||
|  |                           )} | ||||||
|  |                         </div> | ||||||
|  |                       ))} | ||||||
|  |                   <div className="mb-4"> | ||||||
|  |                     <label | ||||||
|  |                       htmlFor="notes" | ||||||
|  |                       className="block text-sm font-medium dark:text-white text-gray-700 mb-1"> | ||||||
|  |                       Additional notes | ||||||
|  |                     </label> | ||||||
|  |                     <textarea | ||||||
|  |                       name="notes" | ||||||
|  |                       id="notes" | ||||||
|  |                       rows={3} | ||||||
|  |                       className="shadow-sm dark:bg-gray-700 dark:text-white dark:border-gray-900 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 : ""} | ||||||
|  |                     /> | ||||||
|  |                   </div> | ||||||
|  |                   <div className="flex items-start"> | ||||||
|  |                     <Button type="submit" loading={loading} className="btn btn-primary"> | ||||||
|  |                       {rescheduleUid ? "Reschedule" : "Confirm"} | ||||||
|  |                     </Button> | ||||||
|  |                     <Link | ||||||
|  |                       href={ | ||||||
|  |                         "/" + | ||||||
|  |                         props.user.username + | ||||||
|  |                         "/" + | ||||||
|  |                         props.eventType.slug + | ||||||
|  |                         (rescheduleUid ? "?rescheduleUid=" + rescheduleUid : "") | ||||||
|  |                       }> | ||||||
|  |                       <a className="ml-2 btn btn-white">Cancel</a> | ||||||
|  |                     </Link> | ||||||
|  |                   </div> | ||||||
|  |                 </form> | ||||||
|  |                 {error && ( | ||||||
|  |                   <div className="bg-yellow-50 border-l-4 border-yellow-400 p-4 mt-2"> | ||||||
|  |                     <div className="flex"> | ||||||
|  |                       <div className="flex-shrink-0"> | ||||||
|  |                         <ExclamationIcon className="h-5 w-5 text-yellow-400" aria-hidden="true" /> | ||||||
|  |                       </div> | ||||||
|  |                       <div className="ml-3"> | ||||||
|  |                         <p className="text-sm text-yellow-700"> | ||||||
|  |                           Could not {rescheduleUid ? "reschedule" : "book"} the meeting. Please try again or{" "} | ||||||
|  |                           <a | ||||||
|  |                             href={"mailto:" + props.user.email} | ||||||
|  |                             className="font-medium underline text-yellow-700 hover:text-yellow-600"> | ||||||
|  |                             Contact {props.user.name} via e-mail | ||||||
|  |                           </a> | ||||||
|  |                         </p> | ||||||
|  |                       </div> | ||||||
|  |                     </div> | ||||||
|  |                   </div> | ||||||
|  |                 )} | ||||||
|  |               </div> | ||||||
|             </div> |             </div> | ||||||
|           </div> |           </div> | ||||||
|         </div> |         </main> | ||||||
|       </main> |       </div> | ||||||
|     </div> |     ) | ||||||
|   ); |   ); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export async function getServerSideProps(context) { | export async function getServerSideProps(context) { | ||||||
| 
 |   const user = await whereAndSelect( | ||||||
|   const user = await whereAndSelect(prisma.user.findFirst, { |     prisma.user.findFirst, | ||||||
|  |     { | ||||||
|       username: context.query.user, |       username: context.query.user, | ||||||
|     }, [ |     }, | ||||||
|       "username", |     ["username", "name", "email", "bio", "avatar", "eventTypes", "theme"] | ||||||
|       "name", |  | ||||||
|       "email", |  | ||||||
|       "bio", |  | ||||||
|       "avatar", |  | ||||||
|       "eventTypes", |  | ||||||
|       "theme", |  | ||||||
|     ] |  | ||||||
|   ); |   ); | ||||||
| 
 | 
 | ||||||
|   const eventType = await prisma.eventType.findUnique({ |   const eventType = await prisma.eventType.findUnique({ | ||||||
|  |  | ||||||
|  | @ -1,23 +1,28 @@ | ||||||
| import type { NextApiRequest, NextApiResponse } from 'next'; | import type { NextApiRequest, NextApiResponse } from "next"; | ||||||
| import { getSession } from 'next-auth/client'; | import { getSession } from "next-auth/client"; | ||||||
| import prisma, {whereAndSelect} from '@lib/prisma'; | import prisma, { whereAndSelect } from "@lib/prisma"; | ||||||
| 
 | 
 | ||||||
| export default async function handler(req: NextApiRequest, res: NextApiResponse) { | export default async function handler(req: NextApiRequest, res: NextApiResponse) { | ||||||
|   const session = await getSession({req: req}); |   const session = await getSession({ req: req }); | ||||||
| 
 | 
 | ||||||
|   if (!session) { |   if (!session) { | ||||||
|       res.status(401).json({message: "Not authenticated"}); |     res.status(401).json({ message: "Not authenticated" }); | ||||||
|       return; |     return; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   // Get user
 |   // Get user
 | ||||||
|   const user = await whereAndSelect(prisma.user.findUnique, { |   const user = await whereAndSelect( | ||||||
|  |     prisma.user.findUnique, | ||||||
|  |     { | ||||||
|       id: session.user.id, |       id: session.user.id, | ||||||
|     }, |     }, | ||||||
|     [ "id", "password" ] |     ["id", "password"] | ||||||
|   ); |   ); | ||||||
| 
 | 
 | ||||||
|   if (!user) { res.status(404).json({message: 'User not found'}); return; } |   if (!user) { | ||||||
|  |     res.status(404).json({ message: "User not found" }); | ||||||
|  |     return; | ||||||
|  |   } | ||||||
| 
 | 
 | ||||||
|   const username = req.body.username; |   const username = req.body.username; | ||||||
|   // username is changed: username is optional but it is necessary to be unique, enforce here
 |   // username is changed: username is optional but it is necessary to be unique, enforce here
 | ||||||
|  | @ -25,10 +30,10 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) | ||||||
|     const userConflict = await prisma.user.findFirst({ |     const userConflict = await prisma.user.findFirst({ | ||||||
|       where: { |       where: { | ||||||
|         username, |         username, | ||||||
|       } |       }, | ||||||
|     }); |     }); | ||||||
|     if (userConflict) { |     if (userConflict) { | ||||||
|       return res.status(409).json({ message: 'Username already taken' }); |       return res.status(409).json({ message: "Username already taken" }); | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  | @ -40,7 +45,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) | ||||||
|   const hideBranding = req.body.hideBranding; |   const hideBranding = req.body.hideBranding; | ||||||
|   const theme = req.body.theme; |   const theme = req.body.theme; | ||||||
| 
 | 
 | ||||||
|   const updateUser = await prisma.user.update({ |   await prisma.user.update({ | ||||||
|     where: { |     where: { | ||||||
|       id: user.id, |       id: user.id, | ||||||
|     }, |     }, | ||||||
|  | @ -56,5 +61,5 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) | ||||||
|     }, |     }, | ||||||
|   }); |   }); | ||||||
| 
 | 
 | ||||||
|   return res.status(200).json({message: 'Profile updated successfully'}); |   return res.status(200).json({ message: "Profile updated successfully" }); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -1,7 +1,7 @@ | ||||||
| import { GetServerSideProps } from "next"; | import { GetServerSideProps } from "next"; | ||||||
| import Head from "next/head"; | import Head from "next/head"; | ||||||
| import {useEffect, useRef, useState} from "react"; | import { useEffect, useRef, useState } from "react"; | ||||||
| import prisma, {whereAndSelect} from "@lib/prisma"; | import prisma, { whereAndSelect } from "@lib/prisma"; | ||||||
| import Modal from "../../components/Modal"; | import Modal from "../../components/Modal"; | ||||||
| import Shell from "../../components/Shell"; | import Shell from "../../components/Shell"; | ||||||
| import SettingsShell from "../../components/Settings"; | import SettingsShell from "../../components/Settings"; | ||||||
|  | @ -27,12 +27,14 @@ export default function Settings(props) { | ||||||
|   const [errorMessage, setErrorMessage] = useState(""); |   const [errorMessage, setErrorMessage] = useState(""); | ||||||
| 
 | 
 | ||||||
|   const themeOptions = [ |   const themeOptions = [ | ||||||
|     {value: 'light', label: 'Light'}, |     { value: "light", label: "Light" }, | ||||||
|     {value: 'dark', label: 'Dark'} |     { value: "dark", label: "Dark" }, | ||||||
|   ]; |   ]; | ||||||
| 
 | 
 | ||||||
|   useEffect( () => { |   useEffect(() => { | ||||||
|     setSelectedTheme(props.user.theme ? themeOptions.find( (theme) => theme.value === props.user.theme ) : null); |     setSelectedTheme( | ||||||
|  |       props.user.theme ? themeOptions.find((theme) => theme.value === props.user.theme) : null | ||||||
|  |     ); | ||||||
|     setSelectedWeekStartDay({ value: props.user.weekStart, label: props.user.weekStart }); |     setSelectedWeekStartDay({ value: props.user.weekStart, label: props.user.weekStart }); | ||||||
|   }, []); |   }, []); | ||||||
| 
 | 
 | ||||||
|  | @ -138,8 +140,7 @@ export default function Settings(props) { | ||||||
|                       placeholder="A little something about yourself." |                       placeholder="A little something about yourself." | ||||||
|                       rows={3} |                       rows={3} | ||||||
|                       defaultValue={props.user.bio} |                       defaultValue={props.user.bio} | ||||||
|                       className="shadow-sm focus:ring-blue-500 focus:border-blue-500 mt-1 block w-full sm:text-sm border-gray-300 rounded-md"> |                       className="shadow-sm focus:ring-blue-500 focus:border-blue-500 mt-1 block w-full sm:text-sm border-gray-300 rounded-md"></textarea> | ||||||
|                     </textarea> |  | ||||||
|                   </div> |                   </div> | ||||||
|                 </div> |                 </div> | ||||||
|                 <div> |                 <div> | ||||||
|  | @ -166,9 +167,10 @@ export default function Settings(props) { | ||||||
|                       onChange={setSelectedWeekStartDay} |                       onChange={setSelectedWeekStartDay} | ||||||
|                       className="shadow-sm focus:ring-blue-500 focus:border-blue-500 mt-1 block w-full sm:text-sm border-gray-300 rounded-md" |                       className="shadow-sm focus:ring-blue-500 focus:border-blue-500 mt-1 block w-full sm:text-sm border-gray-300 rounded-md" | ||||||
|                       options={[ |                       options={[ | ||||||
|                         { value:'Sunday', label:'Sunday' }, |                         { value: "Sunday", label: "Sunday" }, | ||||||
|                         { value:'Monday', label:'Monday' } |                         { value: "Monday", label: "Monday" }, | ||||||
|                       ]} /> |                       ]} | ||||||
|  |                     /> | ||||||
|                   </div> |                   </div> | ||||||
|                 </div> |                 </div> | ||||||
|                 <div> |                 <div> | ||||||
|  | @ -182,7 +184,8 @@ export default function Settings(props) { | ||||||
|                       defaultValue={selectedTheme || themeOptions[0]} |                       defaultValue={selectedTheme || themeOptions[0]} | ||||||
|                       onChange={setSelectedTheme} |                       onChange={setSelectedTheme} | ||||||
|                       className="shadow-sm focus:ring-blue-500 focus:border-blue-500 mt-1 block w-full sm:text-sm border-gray-300 rounded-md" |                       className="shadow-sm focus:ring-blue-500 focus:border-blue-500 mt-1 block w-full sm:text-sm border-gray-300 rounded-md" | ||||||
|                       options={themeOptions} /> |                       options={themeOptions} | ||||||
|  |                     /> | ||||||
|                   </div> |                   </div> | ||||||
|                   <div className="relative flex items-start"> |                   <div className="relative flex items-start"> | ||||||
|                     <div className="flex items-center h-5"> |                     <div className="flex items-center h-5"> | ||||||
|  | @ -302,20 +305,13 @@ export const getServerSideProps: GetServerSideProps = async (context) => { | ||||||
|     return { redirect: { permanent: false, destination: "/auth/login" } }; |     return { redirect: { permanent: false, destination: "/auth/login" } }; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   const user = await whereAndSelect(prisma.user.findFirst, { |   const user = await whereAndSelect( | ||||||
|  |     prisma.user.findFirst, | ||||||
|  |     { | ||||||
|       id: session.user.id, |       id: session.user.id, | ||||||
|     }, [ |     }, | ||||||
|       "id", |     ["id", "username", "name", "email", "bio", "avatar", "timeZone", "weekStart", "hideBranding", "theme"] | ||||||
|     "username", |   ); | ||||||
|     "name", |  | ||||||
|     "email", |  | ||||||
|     "bio", |  | ||||||
|     "avatar", |  | ||||||
|     "timeZone", |  | ||||||
|     "weekStart", |  | ||||||
|     "hideBranding", |  | ||||||
|     "theme" |  | ||||||
|   ]); |  | ||||||
| 
 | 
 | ||||||
|   return { |   return { | ||||||
|     props: { user }, // will be passed to the page component as props
 |     props: { user }, // will be passed to the page component as props
 | ||||||
|  |  | ||||||
|  | @ -1,6 +1,6 @@ | ||||||
| import Head from "next/head"; | import Head from "next/head"; | ||||||
| import Link from "next/link"; | import Link from "next/link"; | ||||||
| import prisma, {whereAndSelect} from "../lib/prisma"; | import prisma, { whereAndSelect } from "../lib/prisma"; | ||||||
| import { useEffect, useState } from "react"; | import { useEffect, useState } from "react"; | ||||||
| import { useRouter } from "next/router"; | import { useRouter } from "next/router"; | ||||||
| import { CheckIcon } from "@heroicons/react/outline"; | import { CheckIcon } from "@heroicons/react/outline"; | ||||||
|  | @ -33,7 +33,7 @@ export default function Success(props) { | ||||||
|   const eventName = getEventName(name, props.eventType.title, props.eventType.eventName); |   const eventName = getEventName(name, props.eventType.title, props.eventType.eventName); | ||||||
| 
 | 
 | ||||||
|   function eventLink(): string { |   function eventLink(): string { | ||||||
|     let optional = {}; |     const optional = {}; | ||||||
|     if (location) { |     if (location) { | ||||||
|       optional["location"] = location; |       optional["location"] = location; | ||||||
|     } |     } | ||||||
|  | @ -58,169 +58,173 @@ export default function Success(props) { | ||||||
|     return encodeURIComponent(event.value); |     return encodeURIComponent(event.value); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   return isReady && ( |   return ( | ||||||
|     <div> |     isReady && ( | ||||||
|       <Head> |       <div> | ||||||
|         <title>Booking Confirmed | {eventName} | Calendso</title> |         <Head> | ||||||
|         <link rel="icon" href="/favicon.ico" /> |           <title>Booking Confirmed | {eventName} | Calendso</title> | ||||||
|       </Head> |           <link rel="icon" href="/favicon.ico" /> | ||||||
|       <main className="max-w-3xl mx-auto my-24"> |         </Head> | ||||||
|         <div className="fixed z-10 inset-0 overflow-y-auto"> |         <main className="max-w-3xl mx-auto my-24"> | ||||||
|           <div className="flex items-end justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0"> |           <div className="fixed z-10 inset-0 overflow-y-auto"> | ||||||
|             <div className="fixed inset-0 my-4 sm:my-0 transition-opacity" aria-hidden="true"> |             <div className="flex items-end justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0"> | ||||||
|               <span className="hidden sm:inline-block sm:align-middle sm:h-screen" aria-hidden="true"> |               <div className="fixed inset-0 my-4 sm:my-0 transition-opacity" aria-hidden="true"> | ||||||
|                 ​ |                 <span className="hidden sm:inline-block sm:align-middle sm:h-screen" aria-hidden="true"> | ||||||
|               </span> |                   ​ | ||||||
|               <div |                 </span> | ||||||
|                 className="inline-block align-bottom dark:bg-gray-800 bg-white rounded-lg px-4 pt-5 pb-4 text-left overflow-hidden shadow-xl transform transition-all sm:my-8 sm:align-middle sm:max-w-sm sm:w-full sm:p-6" |                 <div | ||||||
|                 role="dialog" |                   className="inline-block align-bottom dark:bg-gray-800 bg-white rounded-lg px-4 pt-5 pb-4 text-left overflow-hidden shadow-xl transform transition-all sm:my-8 sm:align-middle sm:max-w-sm sm:w-full sm:p-6" | ||||||
|                 aria-modal="true" |                   role="dialog" | ||||||
|                 aria-labelledby="modal-headline"> |                   aria-modal="true" | ||||||
|                 <div> |                   aria-labelledby="modal-headline"> | ||||||
|                   <div className="mx-auto flex items-center justify-center h-12 w-12 rounded-full bg-green-100"> |                   <div> | ||||||
|                     <CheckIcon className="h-6 w-6 text-green-600" /> |                     <div className="mx-auto flex items-center justify-center h-12 w-12 rounded-full bg-green-100"> | ||||||
|                   </div> |                       <CheckIcon className="h-6 w-6 text-green-600" /> | ||||||
|                   <div className="mt-3 text-center sm:mt-5"> |  | ||||||
|                     <h3 |  | ||||||
|                       className="text-lg leading-6 font-medium dark:text-white text-gray-900" |  | ||||||
|                       id="modal-headline"> |  | ||||||
|                       Booking confirmed |  | ||||||
|                     </h3> |  | ||||||
|                     <div className="mt-2"> |  | ||||||
|                       <p className="text-sm text-gray-500 dark:text-gray-300"> |  | ||||||
|                         You are scheduled in with {props.user.name || props.user.username}. |  | ||||||
|                       </p> |  | ||||||
|                     </div> |                     </div> | ||||||
|                     <div className="mt-4 border-t border-b dark:border-gray-900 py-4"> |                     <div className="mt-3 text-center sm:mt-5"> | ||||||
|                       <h2 className="text-lg font-medium text-gray-600 dark:text-gray-100 mb-2"> |                       <h3 | ||||||
|                         {eventName} |                         className="text-lg leading-6 font-medium dark:text-white text-gray-900" | ||||||
|                       </h2> |                         id="modal-headline"> | ||||||
|                       <p className="text-gray-500 dark:text-gray-50 mb-1"> |                         Booking confirmed | ||||||
|                         <ClockIcon className="inline-block w-4 h-4 mr-1 -mt-1" /> |                       </h3> | ||||||
|                         {props.eventType.length} minutes |                       <div className="mt-2"> | ||||||
|                       </p> |                         <p className="text-sm text-gray-500 dark:text-gray-300"> | ||||||
|                       {location && ( |                           You are scheduled in with {props.user.name || props.user.username}. | ||||||
|                         <p className="text-gray-500 mb-1"> |  | ||||||
|                           <LocationMarkerIcon className="inline-block w-4 h-4 mr-1 -mt-1" /> |  | ||||||
|                           {location} |  | ||||||
|                         </p> |                         </p> | ||||||
|                       )} |                       </div> | ||||||
|                       <p className="text-gray-500 dark:text-gray-50"> |                       <div className="mt-4 border-t border-b dark:border-gray-900 py-4"> | ||||||
|                         <CalendarIcon className="inline-block w-4 h-4 mr-1 -mt-1" /> |                         <h2 className="text-lg font-medium text-gray-600 dark:text-gray-100 mb-2"> | ||||||
|                         {date.format((is24h ? "H:mm" : "h:mma") + ", dddd DD MMMM YYYY")} |                           {eventName} | ||||||
|                       </p> |                         </h2> | ||||||
|  |                         <p className="text-gray-500 dark:text-gray-50 mb-1"> | ||||||
|  |                           <ClockIcon className="inline-block w-4 h-4 mr-1 -mt-1" /> | ||||||
|  |                           {props.eventType.length} minutes | ||||||
|  |                         </p> | ||||||
|  |                         {location && ( | ||||||
|  |                           <p className="text-gray-500 mb-1"> | ||||||
|  |                             <LocationMarkerIcon className="inline-block w-4 h-4 mr-1 -mt-1" /> | ||||||
|  |                             {location} | ||||||
|  |                           </p> | ||||||
|  |                         )} | ||||||
|  |                         <p className="text-gray-500 dark:text-gray-50"> | ||||||
|  |                           <CalendarIcon className="inline-block w-4 h-4 mr-1 -mt-1" /> | ||||||
|  |                           {date.format((is24h ? "H:mm" : "h:mma") + ", dddd DD MMMM YYYY")} | ||||||
|  |                         </p> | ||||||
|  |                       </div> | ||||||
|                     </div> |                     </div> | ||||||
|                   </div> |                   </div> | ||||||
|                 </div> |                   <div className="mt-5 sm:mt-0 pt-2 text-center"> | ||||||
|                 <div className="mt-5 sm:mt-0 pt-2 text-center"> |                     <span className="font-medium text-gray-500 dark:text-gray-50">Add to your calendar</span> | ||||||
|                   <span className="font-medium text-gray-500 dark:text-gray-50">Add to your calendar</span> |                     <div className="flex mt-2"> | ||||||
|                   <div className="flex mt-2"> |                       <Link | ||||||
|                     <Link |                         href={ | ||||||
|                       href={ |                           `https://calendar.google.com/calendar/r/eventedit?dates=${date | ||||||
|                         `https://calendar.google.com/calendar/r/eventedit?dates=${date |                             .utc() | ||||||
|                           .utc() |                             .format("YYYYMMDDTHHmmss[Z]")}/${date | ||||||
|                           .format("YYYYMMDDTHHmmss[Z]")}/${date |                             .add(props.eventType.length, "minute") | ||||||
|                           .add(props.eventType.length, "minute") |                             .utc() | ||||||
|                           .utc() |                             .format("YYYYMMDDTHHmmss[Z]")}&text=${eventName}&details=${ | ||||||
|                           .format("YYYYMMDDTHHmmss[Z]")}&text=${eventName}&details=${ |                             props.eventType.description | ||||||
|                           props.eventType.description |                           }` + (location ? "&location=" + encodeURIComponent(location) : "")
 | ||||||
|                         }` + (location ? "&location=" + encodeURIComponent(location) : "")
 |                         }> | ||||||
|                       }> |                         <a className="mx-2 btn-wide btn-white"> | ||||||
|                       <a className="mx-2 btn-wide btn-white"> |                           <svg | ||||||
|                         <svg |                             className="inline-block w-4 h-4 mr-1 -mt-1" | ||||||
|                           className="inline-block w-4 h-4 mr-1 -mt-1" |                             fill="currentColor" | ||||||
|                           fill="currentColor" |                             xmlns="http://www.w3.org/2000/svg" | ||||||
|                           xmlns="http://www.w3.org/2000/svg" |                             viewBox="0 0 24 24"> | ||||||
|                           viewBox="0 0 24 24"> |                             <title>Google</title> | ||||||
|                           <title>Google</title> |                             <path d="M12.48 10.92v3.28h7.84c-.24 1.84-.853 3.187-1.787 4.133-1.147 1.147-2.933 2.4-6.053 2.4-4.827 0-8.6-3.893-8.6-8.72s3.773-8.72 8.6-8.72c2.6 0 4.507 1.027 5.907 2.347l2.307-2.307C18.747 1.44 16.133 0 12.48 0 5.867 0 .307 5.387.307 12s5.56 12 12.173 12c3.573 0 6.267-1.173 8.373-3.36 2.16-2.16 2.84-5.213 2.84-7.667 0-.76-.053-1.467-.173-2.053H12.48z" /> | ||||||
|                           <path d="M12.48 10.92v3.28h7.84c-.24 1.84-.853 3.187-1.787 4.133-1.147 1.147-2.933 2.4-6.053 2.4-4.827 0-8.6-3.893-8.6-8.72s3.773-8.72 8.6-8.72c2.6 0 4.507 1.027 5.907 2.347l2.307-2.307C18.747 1.44 16.133 0 12.48 0 5.867 0 .307 5.387.307 12s5.56 12 12.173 12c3.573 0 6.267-1.173 8.373-3.36 2.16-2.16 2.84-5.213 2.84-7.667 0-.76-.053-1.467-.173-2.053H12.48z" /> |                           </svg> | ||||||
|                         </svg> |                         </a> | ||||||
|                       </a> |                       </Link> | ||||||
|                     </Link> |                       <Link | ||||||
|                     <Link |                         href={ | ||||||
|                       href={ |                           encodeURI( | ||||||
|                         encodeURI( |                             "https://outlook.live.com/calendar/0/deeplink/compose?body=" + | ||||||
|                           "https://outlook.live.com/calendar/0/deeplink/compose?body=" + |                               props.eventType.description + | ||||||
|                             props.eventType.description + |                               "&enddt=" + | ||||||
|                             "&enddt=" + |                               date.add(props.eventType.length, "minute").format() + | ||||||
|                             date.add(props.eventType.length, "minute").format() + |                               "&path=%2Fcalendar%2Faction%2Fcompose&rru=addevent&startdt=" + | ||||||
|                             "&path=%2Fcalendar%2Faction%2Fcompose&rru=addevent&startdt=" + |                               date.format() + | ||||||
|                             date.format() + |                               "&subject=" + | ||||||
|                             "&subject=" + |                               eventName | ||||||
|                             eventName |                           ) + (location ? "&location=" + location : "") | ||||||
|                         ) + (location ? "&location=" + location : "") |                         }> | ||||||
|                       }> |                         <a className="mx-2 btn-wide btn-white"> | ||||||
|                       <a className="mx-2 btn-wide btn-white"> |                           <svg | ||||||
|                         <svg |                             className="inline-block w-4 h-4 mr-1 -mt-1" | ||||||
|                           className="inline-block w-4 h-4 mr-1 -mt-1" |                             fill="currentColor" | ||||||
|                           fill="currentColor" |                             xmlns="http://www.w3.org/2000/svg" | ||||||
|                           xmlns="http://www.w3.org/2000/svg" |                             viewBox="0 0 24 24"> | ||||||
|                           viewBox="0 0 24 24"> |                             <title>Microsoft Outlook</title> | ||||||
|                           <title>Microsoft Outlook</title> |                             <path d="M7.88 12.04q0 .45-.11.87-.1.41-.33.74-.22.33-.58.52-.37.2-.87.2t-.85-.2q-.35-.21-.57-.55-.22-.33-.33-.75-.1-.42-.1-.86t.1-.87q.1-.43.34-.76.22-.34.59-.54.36-.2.87-.2t.86.2q.35.21.57.55.22.34.31.77.1.43.1.88zM24 12v9.38q0 .46-.33.8-.33.32-.8.32H7.13q-.46 0-.8-.33-.32-.33-.32-.8V18H1q-.41 0-.7-.3-.3-.29-.3-.7V7q0-.41.3-.7Q.58 6 1 6h6.5V2.55q0-.44.3-.75.3-.3.75-.3h12.9q.44 0 .75.3.3.3.3.75V10.85l1.24.72h.01q.1.07.18.18.07.12.07.25zm-6-8.25v3h3v-3zm0 4.5v3h3v-3zm0 4.5v1.83l3.05-1.83zm-5.25-9v3h3.75v-3zm0 4.5v3h3.75v-3zm0 4.5v2.03l2.41 1.5 1.34-.8v-2.73zM9 3.75V6h2l.13.01.12.04v-2.3zM5.98 15.98q.9 0 1.6-.3.7-.32 1.19-.86.48-.55.73-1.28.25-.74.25-1.61 0-.83-.25-1.55-.24-.71-.71-1.24t-1.15-.83q-.68-.3-1.55-.3-.92 0-1.64.3-.71.3-1.2.85-.5.54-.75 1.3-.25.74-.25 1.63 0 .85.26 1.56.26.72.74 1.23.48.52 1.17.81.69.3 1.56.3zM7.5 21h12.39L12 16.08V17q0 .41-.3.7-.29.3-.7.3H7.5zm15-.13v-7.24l-5.9 3.54Z" /> | ||||||
|                           <path d="M7.88 12.04q0 .45-.11.87-.1.41-.33.74-.22.33-.58.52-.37.2-.87.2t-.85-.2q-.35-.21-.57-.55-.22-.33-.33-.75-.1-.42-.1-.86t.1-.87q.1-.43.34-.76.22-.34.59-.54.36-.2.87-.2t.86.2q.35.21.57.55.22.34.31.77.1.43.1.88zM24 12v9.38q0 .46-.33.8-.33.32-.8.32H7.13q-.46 0-.8-.33-.32-.33-.32-.8V18H1q-.41 0-.7-.3-.3-.29-.3-.7V7q0-.41.3-.7Q.58 6 1 6h6.5V2.55q0-.44.3-.75.3-.3.75-.3h12.9q.44 0 .75.3.3.3.3.75V10.85l1.24.72h.01q.1.07.18.18.07.12.07.25zm-6-8.25v3h3v-3zm0 4.5v3h3v-3zm0 4.5v1.83l3.05-1.83zm-5.25-9v3h3.75v-3zm0 4.5v3h3.75v-3zm0 4.5v2.03l2.41 1.5 1.34-.8v-2.73zM9 3.75V6h2l.13.01.12.04v-2.3zM5.98 15.98q.9 0 1.6-.3.7-.32 1.19-.86.48-.55.73-1.28.25-.74.25-1.61 0-.83-.25-1.55-.24-.71-.71-1.24t-1.15-.83q-.68-.3-1.55-.3-.92 0-1.64.3-.71.3-1.2.85-.5.54-.75 1.3-.25.74-.25 1.63 0 .85.26 1.56.26.72.74 1.23.48.52 1.17.81.69.3 1.56.3zM7.5 21h12.39L12 16.08V17q0 .41-.3.7-.29.3-.7.3H7.5zm15-.13v-7.24l-5.9 3.54Z" /> |                           </svg> | ||||||
|                         </svg> |                         </a> | ||||||
|                       </a> |                       </Link> | ||||||
|                     </Link> |                       <Link | ||||||
|                     <Link |                         href={ | ||||||
|                       href={ |                           encodeURI( | ||||||
|                         encodeURI( |                             "https://outlook.office.com/calendar/0/deeplink/compose?body=" + | ||||||
|                           "https://outlook.office.com/calendar/0/deeplink/compose?body=" + |                               props.eventType.description + | ||||||
|                             props.eventType.description + |                               "&enddt=" + | ||||||
|                             "&enddt=" + |                               date.add(props.eventType.length, "minute").format() + | ||||||
|                             date.add(props.eventType.length, "minute").format() + |                               "&path=%2Fcalendar%2Faction%2Fcompose&rru=addevent&startdt=" + | ||||||
|                             "&path=%2Fcalendar%2Faction%2Fcompose&rru=addevent&startdt=" + |                               date.format() + | ||||||
|                             date.format() + |                               "&subject=" + | ||||||
|                             "&subject=" + |                               eventName | ||||||
|                             eventName |                           ) + (location ? "&location=" + location : "") | ||||||
|                         ) + (location ? "&location=" + location : "") |                         }> | ||||||
|                       }> |                         <a className="mx-2 btn-wide btn-white"> | ||||||
|                       <a className="mx-2 btn-wide btn-white"> |                           <svg | ||||||
|                         <svg |                             className="inline-block w-4 h-4 mr-1 -mt-1" | ||||||
|                           className="inline-block w-4 h-4 mr-1 -mt-1" |                             fill="currentColor" | ||||||
|                           fill="currentColor" |                             xmlns="http://www.w3.org/2000/svg" | ||||||
|                           xmlns="http://www.w3.org/2000/svg" |                             viewBox="0 0 24 24"> | ||||||
|                           viewBox="0 0 24 24"> |                             <title>Microsoft Office</title> | ||||||
|                           <title>Microsoft Office</title> |                             <path d="M21.53 4.306v15.363q0 .807-.472 1.433-.472.627-1.253.85l-6.888 1.974q-.136.037-.29.055-.156.019-.293.019-.396 0-.72-.105-.321-.106-.656-.292l-4.505-2.544q-.248-.137-.391-.366-.143-.23-.143-.515 0-.434.304-.738.304-.305.739-.305h5.831V4.964l-4.38 1.563q-.533.187-.856.658-.322.472-.322 1.03v8.078q0 .496-.248.912-.25.416-.683.651l-2.072 1.13q-.286.148-.571.148-.497 0-.844-.347-.348-.347-.348-.844V6.563q0-.62.33-1.19.328-.571.874-.881L11.07.285q.248-.136.534-.21.285-.075.57-.075.211 0 .38.031.166.031.364.093l6.888 1.899q.384.11.7.329.317.217.547.52.23.305.353.67.125.367.125.764zm-1.588 15.363V4.306q0-.273-.16-.478-.163-.204-.423-.28l-3.388-.93q-.397-.111-.794-.23-.397-.117-.794-.216v19.68l4.976-1.427q.26-.074.422-.28.161-.204.161-.477z" /> | ||||||
|                           <path d="M21.53 4.306v15.363q0 .807-.472 1.433-.472.627-1.253.85l-6.888 1.974q-.136.037-.29.055-.156.019-.293.019-.396 0-.72-.105-.321-.106-.656-.292l-4.505-2.544q-.248-.137-.391-.366-.143-.23-.143-.515 0-.434.304-.738.304-.305.739-.305h5.831V4.964l-4.38 1.563q-.533.187-.856.658-.322.472-.322 1.03v8.078q0 .496-.248.912-.25.416-.683.651l-2.072 1.13q-.286.148-.571.148-.497 0-.844-.347-.348-.347-.348-.844V6.563q0-.62.33-1.19.328-.571.874-.881L11.07.285q.248-.136.534-.21.285-.075.57-.075.211 0 .38.031.166.031.364.093l6.888 1.899q.384.11.7.329.317.217.547.52.23.305.353.67.125.367.125.764zm-1.588 15.363V4.306q0-.273-.16-.478-.163-.204-.423-.28l-3.388-.93q-.397-.111-.794-.23-.397-.117-.794-.216v19.68l4.976-1.427q.26-.074.422-.28.161-.204.161-.477z" /> |                           </svg> | ||||||
|                         </svg> |                         </a> | ||||||
|                       </a> |                       </Link> | ||||||
|                     </Link> |                       <Link href={"data:text/calendar," + eventLink()}> | ||||||
|                     <Link href={"data:text/calendar," + eventLink()}> |                         <a className="mx-2 btn-wide btn-white" download={props.eventType.title + ".ics"}> | ||||||
|                       <a className="mx-2 btn-wide btn-white" download={props.eventType.title + ".ics"}> |                           <svg | ||||||
|                         <svg |                             version="1.1" | ||||||
|                           version="1.1" |                             xmlns="http://www.w3.org/2000/svg" | ||||||
|                           xmlns="http://www.w3.org/2000/svg" |                             viewBox="0 0 1000 1000" | ||||||
|                           viewBox="0 0 1000 1000" |                             className="inline-block w-4 h-4 mr-1 -mt-1"> | ||||||
|                           className="inline-block w-4 h-4 mr-1 -mt-1"> |                             <title>Other</title> | ||||||
|                           <title>Other</title> |                             <path d="M971.3,154.9c0-34.7-28.2-62.9-62.9-62.9H611.7c-1.3,0-2.6,0.1-3.9,0.2V10L28.7,87.3v823.4L607.8,990v-84.6c1.3,0.1,2.6,0.2,3.9,0.2h296.7c34.7,0,62.9-28.2,62.9-62.9V154.9z M607.8,636.1h44.6v-50.6h-44.6v-21.9h44.6v-50.6h-44.6v-92h277.9v230.2c0,3.8-3.1,7-7,7H607.8V636.1z M117.9,644.7l-50.6-2.4V397.5l50.6-2.2V644.7z M288.6,607.3c17.6,0.6,37.3-2.8,49.1-7.2l9.1,48c-11,5.1-35.6,9.9-66.9,8.3c-85.4-4.3-127.5-60.7-127.5-132.6c0-86.2,57.8-136.7,133.2-140.1c30.3-1.3,53.7,4,64.3,9.2l-12.2,48.9c-12.1-4.9-28.8-9.2-49.5-8.6c-45.3,1.2-79.5,30.1-79.5,87.4C208.8,572.2,237.8,605.7,288.6,607.3z M455.5,665.2c-32.4-1.6-63.7-11.3-79.1-20.5l12.6-50.7c16.8,9.1,42.9,18.5,70.4,19.4c30.1,1,46.3-10.7,46.3-29.3c0-17.8-14-28.1-48.8-40.6c-46.9-16.4-76.8-41.7-76.8-81.5c0-46.6,39.3-84.1,106.8-87.1c33.3-1.5,58.3,4.2,76.5,11.2l-15.4,53.3c-12.1-5.3-33.5-12.8-62.3-12c-28.3,0.8-41.9,13.6-41.9,28.1c0,17.8,16.1,25.5,53.6,39c52.9,18.5,78.4,45.3,78.4,86.4C575.6,629.7,536.2,669.2,455.5,665.2z M935.3,842.7c0,14.9-12.1,27-27,27H611.7c-1.3,0-2.6-0.2-3.9-0.4V686.2h270.9c19.2,0,34.9-15.6,34.9-34.9V398.4c0-19.2-15.6-34.9-34.9-34.9h-47.1v-32.3H808v32.3h-44.8v-32.3h-22.7v32.3h-43.3v-32.3h-22.7v32.3H628v-32.3h-20.2v-203c1.31.2,2.6-0.4,3.9-0.4h296.7c14.9,0,27,12.1,27,27L935.3,842.7L935.3,842.7z" /> | ||||||
|                           <path d="M971.3,154.9c0-34.7-28.2-62.9-62.9-62.9H611.7c-1.3,0-2.6,0.1-3.9,0.2V10L28.7,87.3v823.4L607.8,990v-84.6c1.3,0.1,2.6,0.2,3.9,0.2h296.7c34.7,0,62.9-28.2,62.9-62.9V154.9z M607.8,636.1h44.6v-50.6h-44.6v-21.9h44.6v-50.6h-44.6v-92h277.9v230.2c0,3.8-3.1,7-7,7H607.8V636.1z M117.9,644.7l-50.6-2.4V397.5l50.6-2.2V644.7z M288.6,607.3c17.6,0.6,37.3-2.8,49.1-7.2l9.1,48c-11,5.1-35.6,9.9-66.9,8.3c-85.4-4.3-127.5-60.7-127.5-132.6c0-86.2,57.8-136.7,133.2-140.1c30.3-1.3,53.7,4,64.3,9.2l-12.2,48.9c-12.1-4.9-28.8-9.2-49.5-8.6c-45.3,1.2-79.5,30.1-79.5,87.4C208.8,572.2,237.8,605.7,288.6,607.3z M455.5,665.2c-32.4-1.6-63.7-11.3-79.1-20.5l12.6-50.7c16.8,9.1,42.9,18.5,70.4,19.4c30.1,1,46.3-10.7,46.3-29.3c0-17.8-14-28.1-48.8-40.6c-46.9-16.4-76.8-41.7-76.8-81.5c0-46.6,39.3-84.1,106.8-87.1c33.3-1.5,58.3,4.2,76.5,11.2l-15.4,53.3c-12.1-5.3-33.5-12.8-62.3-12c-28.3,0.8-41.9,13.6-41.9,28.1c0,17.8,16.1,25.5,53.6,39c52.9,18.5,78.4,45.3,78.4,86.4C575.6,629.7,536.2,669.2,455.5,665.2z M935.3,842.7c0,14.9-12.1,27-27,27H611.7c-1.3,0-2.6-0.2-3.9-0.4V686.2h270.9c19.2,0,34.9-15.6,34.9-34.9V398.4c0-19.2-15.6-34.9-34.9-34.9h-47.1v-32.3H808v32.3h-44.8v-32.3h-22.7v32.3h-43.3v-32.3h-22.7v32.3H628v-32.3h-20.2v-203c1.31.2,2.6-0.4,3.9-0.4h296.7c14.9,0,27,12.1,27,27L935.3,842.7L935.3,842.7z" /> |                           </svg> | ||||||
|                         </svg> |                         </a> | ||||||
|                       </a> |                       </Link> | ||||||
|                     </Link> |                     </div> | ||||||
|                   </div> |                   </div> | ||||||
|  |                   {!props.user.hideBranding && ( | ||||||
|  |                     <div className="mt-4 pt-4 border-t dark:border-gray-900  text-gray-400 text-center text-xs dark:text-white"> | ||||||
|  |                       <a href="https://checkout.calendso.com">Create your own booking link with Calendso</a> | ||||||
|  |                     </div> | ||||||
|  |                   )} | ||||||
|                 </div> |                 </div> | ||||||
|                 {!props.user.hideBranding && ( |  | ||||||
|                   <div className="mt-4 pt-4 border-t dark:border-gray-900  text-gray-400 text-center text-xs dark:text-white"> |  | ||||||
|                     <a href="https://checkout.calendso.com">Create your own booking link with Calendso</a> |  | ||||||
|                   </div> |  | ||||||
|                 )} |  | ||||||
|               </div> |               </div> | ||||||
|             </div> |             </div> | ||||||
|           </div> |           </div> | ||||||
|         </div> |         </main> | ||||||
|       </main> |       </div> | ||||||
|     </div> |     ) | ||||||
|   ); |   ); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export async function getServerSideProps(context) { | export async function getServerSideProps(context) { | ||||||
| 
 |   const user = context.query.user | ||||||
|   const user = (context.query.user) ? await whereAndSelect(prisma.user.findFirst, { |     ? await whereAndSelect( | ||||||
|       username: context.query.user, |         prisma.user.findFirst, | ||||||
|     }, [ |         { | ||||||
|       "username", "name", "bio", "avatar", "eventTypes", "hideBranding", "theme" |           username: context.query.user, | ||||||
|     ] |         }, | ||||||
|   ) : null; |         ["username", "name", "bio", "avatar", "eventTypes", "hideBranding", "theme"] | ||||||
|  |       ) | ||||||
|  |     : null; | ||||||
| 
 | 
 | ||||||
|   if (!user) { |   if (!user) { | ||||||
|     return { |     return { | ||||||
|  | @ -228,11 +232,12 @@ export async function getServerSideProps(context) { | ||||||
|     }; |     }; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   const eventType = await whereAndSelect(prisma.eventType.findUnique, { |   const eventType = await whereAndSelect( | ||||||
|  |     prisma.eventType.findUnique, | ||||||
|  |     { | ||||||
|       id: parseInt(context.query.type), |       id: parseInt(context.query.type), | ||||||
|     }, [ |     }, | ||||||
|       "id", "title", "description", "length", "eventName" |     ["id", "title", "description", "length", "eventName"] | ||||||
|     ] |  | ||||||
|   ); |   ); | ||||||
| 
 | 
 | ||||||
|   return { |   return { | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue
	
	 Alex van Andel
						Alex van Andel