refactor: add next-seo (#531)
* refactor: add next-seo * refactor: change naming of seo component
This commit is contained in:
		
							parent
							
								
									fc50821282
								
							
						
					
					
						commit
						a37411b8af
					
				
					 33 changed files with 290 additions and 298 deletions
				
			
		|  | @ -3,7 +3,7 @@ import React, { Fragment, useEffect, useState } from "react"; | ||||||
| import { useRouter } from "next/router"; | import { useRouter } from "next/router"; | ||||||
| import { signOut, useSession } from "next-auth/client"; | import { signOut, useSession } from "next-auth/client"; | ||||||
| import { Menu, Transition } from "@headlessui/react"; | import { Menu, Transition } from "@headlessui/react"; | ||||||
| import { collectPageParameters, telemetryEventTypes, useTelemetry } from "../lib/telemetry"; | import { collectPageParameters, telemetryEventTypes, useTelemetry } from "@lib/telemetry"; | ||||||
| import { SelectorIcon } from "@heroicons/react/outline"; | import { SelectorIcon } from "@heroicons/react/outline"; | ||||||
| import { | import { | ||||||
|   CalendarIcon, |   CalendarIcon, | ||||||
|  | @ -20,6 +20,7 @@ import classNames from "@lib/classNames"; | ||||||
| import { Toaster } from "react-hot-toast"; | import { Toaster } from "react-hot-toast"; | ||||||
| import Avatar from "@components/Avatar"; | import Avatar from "@components/Avatar"; | ||||||
| import { User } from "@prisma/client"; | import { User } from "@prisma/client"; | ||||||
|  | import { HeadSeo } from "@components/seo/head-seo"; | ||||||
| 
 | 
 | ||||||
| export default function Shell(props) { | export default function Shell(props) { | ||||||
|   const router = useRouter(); |   const router = useRouter(); | ||||||
|  | @ -70,8 +71,18 @@ export default function Shell(props) { | ||||||
|     router.replace("/auth/login"); |     router.replace("/auth/login"); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  |   const pageTitle = typeof props.heading === "string" ? props.heading : props.title; | ||||||
|  | 
 | ||||||
|   return session ? ( |   return session ? ( | ||||||
|     <> |     <> | ||||||
|  |       <HeadSeo | ||||||
|  |         title={pageTitle} | ||||||
|  |         description={props.subtitle} | ||||||
|  |         nextSeoProps={{ | ||||||
|  |           nofollow: true, | ||||||
|  |           noindex: true, | ||||||
|  |         }} | ||||||
|  |       /> | ||||||
|       <div> |       <div> | ||||||
|         <Toaster position="bottom-right" /> |         <Toaster position="bottom-right" /> | ||||||
|       </div> |       </div> | ||||||
|  |  | ||||||
							
								
								
									
										101
									
								
								components/seo/head-seo.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										101
									
								
								components/seo/head-seo.tsx
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,101 @@ | ||||||
|  | import { NextSeo, NextSeoProps } from "next-seo"; | ||||||
|  | import React from "react"; | ||||||
|  | import { getBrowserInfo } from "@lib/core/browser/browser.utils"; | ||||||
|  | import { getSeoImage, seoConfig } from "@lib/config/next-seo.config"; | ||||||
|  | import merge from "lodash.merge"; | ||||||
|  | 
 | ||||||
|  | export type HeadSeoProps = { | ||||||
|  |   title: string; | ||||||
|  |   description: string; | ||||||
|  |   siteName?: string; | ||||||
|  |   name?: string; | ||||||
|  |   avatar?: string; | ||||||
|  |   url?: string; | ||||||
|  |   canonical?: string; | ||||||
|  |   nextSeoProps?: NextSeoProps; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Build full seo tags from title, desc, canonical and url | ||||||
|  |  */ | ||||||
|  | const buildSeoMeta = (pageProps: { | ||||||
|  |   title: string; | ||||||
|  |   description: string; | ||||||
|  |   image: string; | ||||||
|  |   siteName?: string; | ||||||
|  |   url?: string; | ||||||
|  |   canonical?: string; | ||||||
|  | }): NextSeoProps => { | ||||||
|  |   const { title, description, image, canonical, siteName = seoConfig.headSeo.siteName } = pageProps; | ||||||
|  |   return { | ||||||
|  |     title: title, | ||||||
|  |     canonical: canonical, | ||||||
|  |     openGraph: { | ||||||
|  |       site_name: siteName, | ||||||
|  |       type: "website", | ||||||
|  |       title: title, | ||||||
|  |       description: description, | ||||||
|  |       images: [ | ||||||
|  |         { | ||||||
|  |           url: image, | ||||||
|  |           //width: 1077,
 | ||||||
|  |           //height: 565,
 | ||||||
|  |           //alt: "Alt image"
 | ||||||
|  |         }, | ||||||
|  |       ], | ||||||
|  |     }, | ||||||
|  |     additionalMetaTags: [ | ||||||
|  |       { | ||||||
|  |         property: "name", | ||||||
|  |         content: title, | ||||||
|  |       }, | ||||||
|  |       { | ||||||
|  |         property: "description", | ||||||
|  |         content: description, | ||||||
|  |       }, | ||||||
|  |       { | ||||||
|  |         name: "description", | ||||||
|  |         content: description, | ||||||
|  |       }, | ||||||
|  |       { | ||||||
|  |         property: "image", | ||||||
|  |         content: image, | ||||||
|  |       }, | ||||||
|  |     ], | ||||||
|  |   }; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | const constructImage = (name: string, avatar: string, description: string): string => { | ||||||
|  |   return ( | ||||||
|  |     encodeURIComponent("Meet **" + name + "** <br>" + description).replace(/'/g, "%27") + | ||||||
|  |     ".png?md=1&images=https%3A%2F%2Fcalendso.com%2Fcalendso-logo-white.svg&images=" + | ||||||
|  |     encodeURIComponent(avatar) | ||||||
|  |   ); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | export const HeadSeo: React.FC<HeadSeoProps & { children?: never }> = (props) => { | ||||||
|  |   const defaultUrl = getBrowserInfo()?.url; | ||||||
|  |   const image = getSeoImage("default"); | ||||||
|  | 
 | ||||||
|  |   const { | ||||||
|  |     title, | ||||||
|  |     description, | ||||||
|  |     name = null, | ||||||
|  |     avatar = null, | ||||||
|  |     siteName, | ||||||
|  |     canonical = defaultUrl, | ||||||
|  |     nextSeoProps = {}, | ||||||
|  |   } = props; | ||||||
|  | 
 | ||||||
|  |   const pageTitle = title + " | Calendso"; | ||||||
|  |   let seoObject = buildSeoMeta({ title: pageTitle, image, description, canonical, siteName }); | ||||||
|  | 
 | ||||||
|  |   if (name && avatar) { | ||||||
|  |     const pageImage = getSeoImage("ogImage") + constructImage(name, avatar, description); | ||||||
|  |     seoObject = buildSeoMeta({ title: pageTitle, description, image: pageImage, canonical, siteName }); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   const seoProps: NextSeoProps = merge(nextSeoProps, seoObject); | ||||||
|  | 
 | ||||||
|  |   return <NextSeo {...seoProps} />; | ||||||
|  | }; | ||||||
							
								
								
									
										27
									
								
								lib/config/next-seo.config.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								lib/config/next-seo.config.ts
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,27 @@ | ||||||
|  | import { DefaultSeoProps } from "next-seo"; | ||||||
|  | import { HeadSeoProps } from "@components/seo/head-seo"; | ||||||
|  | 
 | ||||||
|  | const seoImages = { | ||||||
|  |   default: "https://calendso.com/og-image.png", | ||||||
|  |   ogImage: "https://og-image-one-pi.vercel.app/", | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | export const getSeoImage = (key: keyof typeof seoImages): string => { | ||||||
|  |   return seoImages[key]; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | export const seoConfig: { | ||||||
|  |   headSeo: Required<Pick<HeadSeoProps, "siteName">>; | ||||||
|  |   defaultNextSeo: DefaultSeoProps; | ||||||
|  | } = { | ||||||
|  |   headSeo: { | ||||||
|  |     siteName: "Calendso", | ||||||
|  |   }, | ||||||
|  |   defaultNextSeo: { | ||||||
|  |     twitter: { | ||||||
|  |       handle: "@calendso", | ||||||
|  |       site: "@Calendso", | ||||||
|  |       cardType: "summary_large_image", | ||||||
|  |     }, | ||||||
|  |   }, | ||||||
|  | } as const; | ||||||
							
								
								
									
										22
									
								
								lib/core/browser/browser.utils.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								lib/core/browser/browser.utils.ts
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,22 @@ | ||||||
|  | export const isBrowser = () => typeof window !== "undefined"; | ||||||
|  | 
 | ||||||
|  | type BrowserInfo = { | ||||||
|  |   url: string; | ||||||
|  |   path: string; | ||||||
|  |   referrer: string; | ||||||
|  |   title: string; | ||||||
|  |   query: string; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | export const getBrowserInfo = (): Partial<BrowserInfo> => { | ||||||
|  |   if (!isBrowser()) { | ||||||
|  |     return {}; | ||||||
|  |   } | ||||||
|  |   return { | ||||||
|  |     url: window.document.location?.href ?? undefined, | ||||||
|  |     path: window.document.location?.pathname ?? undefined, | ||||||
|  |     referrer: window.document?.referrer ?? undefined, | ||||||
|  |     title: window.document.title ?? undefined, | ||||||
|  |     query: window.document.location?.search, | ||||||
|  |   }; | ||||||
|  | }; | ||||||
|  | @ -42,6 +42,7 @@ | ||||||
|     "lodash.throttle": "^4.1.1", |     "lodash.throttle": "^4.1.1", | ||||||
|     "next": "^10.2.3", |     "next": "^10.2.3", | ||||||
|     "next-auth": "^3.28.0", |     "next-auth": "^3.28.0", | ||||||
|  |     "next-seo": "^4.26.0", | ||||||
|     "next-transpile-modules": "^8.0.0", |     "next-transpile-modules": "^8.0.0", | ||||||
|     "nodemailer": "^6.6.3", |     "nodemailer": "^6.6.3", | ||||||
|     "react": "17.0.2", |     "react": "17.0.2", | ||||||
|  |  | ||||||
|  | @ -3,7 +3,7 @@ import { BookOpenIcon, CheckIcon, CodeIcon, DocumentTextIcon } from "@heroicons/ | ||||||
| import { useRouter } from "next/router"; | import { useRouter } from "next/router"; | ||||||
| import React from "react"; | import React from "react"; | ||||||
| import Link from "next/link"; | import Link from "next/link"; | ||||||
| import Head from "next/head"; | import { HeadSeo } from "@components/seo/head-seo"; | ||||||
| 
 | 
 | ||||||
| const links = [ | const links = [ | ||||||
|   { |   { | ||||||
|  | @ -32,9 +32,14 @@ export default function Custom404() { | ||||||
| 
 | 
 | ||||||
|   return ( |   return ( | ||||||
|     <> |     <> | ||||||
|       <Head> |       <HeadSeo | ||||||
|         <title>404: This page could not be found.</title> |         title="404: This page could not be found." | ||||||
|       </Head> |         description="404: This page could not be found." | ||||||
|  |         nextSeoProps={{ | ||||||
|  |           nofollow: true, | ||||||
|  |           noindex: true, | ||||||
|  |         }} | ||||||
|  |       /> | ||||||
|       <div className="bg-white min-h-screen px-4"> |       <div className="bg-white min-h-screen px-4"> | ||||||
|         <main className="max-w-xl mx-auto pb-6 pt-16 sm:pt-24"> |         <main className="max-w-xl mx-auto pb-6 pt-16 sm:pt-24"> | ||||||
|           <div className="text-center"> |           <div className="text-center"> | ||||||
|  |  | ||||||
|  | @ -1,5 +1,5 @@ | ||||||
| import { GetServerSideProps } from "next"; | import { GetServerSideProps } from "next"; | ||||||
| import Head from "next/head"; | import { HeadSeo } from "@components/seo/head-seo"; | ||||||
| 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"; | ||||||
|  | @ -48,59 +48,12 @@ export default function User(props): User { | ||||||
|   )); |   )); | ||||||
|   return ( |   return ( | ||||||
|     <> |     <> | ||||||
|       <Head> |       <HeadSeo | ||||||
|         <title>{props.user.name || props.user.username} | Calendso</title> |         title={props.user.name || props.user.username} | ||||||
|         <link rel="icon" href="/favicon.ico" /> |         description={props.user.name || props.user.username} | ||||||
| 
 |         name={props.user.name || props.user.username} | ||||||
|         <meta name="title" content={"Meet " + (props.user.name || props.user.username) + " via Calendso"} /> |         avatar={props.user.avatar} | ||||||
|         <meta name="description" content={"Book a time with " + (props.user.name || props.user.username)} /> |       /> | ||||||
| 
 |  | ||||||
|         <meta property="og:type" content="website" /> |  | ||||||
|         <meta property="og:url" content="https://calendso/" /> |  | ||||||
|         <meta |  | ||||||
|           property="og:title" |  | ||||||
|           content={"Meet " + (props.user.name || props.user.username) + " via Calendso"} |  | ||||||
|         /> |  | ||||||
|         <meta |  | ||||||
|           property="og:description" |  | ||||||
|           content={"Book a time with " + (props.user.name || props.user.username)} |  | ||||||
|         /> |  | ||||||
|         <meta |  | ||||||
|           property="og:image" |  | ||||||
|           content={ |  | ||||||
|             "https://og-image-one-pi.vercel.app/" + |  | ||||||
|             encodeURIComponent("Meet **" + (props.user.name || props.user.username) + "** <br>").replace( |  | ||||||
|               /'/g, |  | ||||||
|               "%27" |  | ||||||
|             ) + |  | ||||||
|             ".png?md=1&images=https%3A%2F%2Fcalendso.com%2Fcalendso-logo-white.svg&images=" + |  | ||||||
|             encodeURIComponent(props.user.avatar) |  | ||||||
|           } |  | ||||||
|         /> |  | ||||||
| 
 |  | ||||||
|         <meta property="twitter:card" content="summary_large_image" /> |  | ||||||
|         <meta property="twitter:url" content="https://calendso/" /> |  | ||||||
|         <meta |  | ||||||
|           property="twitter:title" |  | ||||||
|           content={"Meet " + (props.user.name || props.user.username) + " via Calendso"} |  | ||||||
|         /> |  | ||||||
|         <meta |  | ||||||
|           property="twitter:description" |  | ||||||
|           content={"Book a time with " + (props.user.name || props.user.username)} |  | ||||||
|         /> |  | ||||||
|         <meta |  | ||||||
|           property="twitter:image" |  | ||||||
|           content={ |  | ||||||
|             "https://og-image-one-pi.vercel.app/" + |  | ||||||
|             encodeURIComponent("Meet **" + (props.user.name || props.user.username) + "** <br>").replace( |  | ||||||
|               /'/g, |  | ||||||
|               "%27" |  | ||||||
|             ) + |  | ||||||
|             ".png?md=1&images=https%3A%2F%2Fcalendso.com%2Fcalendso-logo-white.svg&images=" + |  | ||||||
|             encodeURIComponent(props.user.avatar) |  | ||||||
|           } |  | ||||||
|         /> |  | ||||||
|       </Head> |  | ||||||
|       {isReady && ( |       {isReady && ( | ||||||
|         <div className="bg-neutral-50 dark:bg-black h-screen"> |         <div className="bg-neutral-50 dark:bg-black h-screen"> | ||||||
|           <main className="max-w-3xl mx-auto py-24 px-4"> |           <main className="max-w-3xl mx-auto py-24 px-4"> | ||||||
|  |  | ||||||
|  | @ -6,16 +6,16 @@ import prisma from "@lib/prisma"; | ||||||
| import * as Collapsible from "@radix-ui/react-collapsible"; | import * as Collapsible from "@radix-ui/react-collapsible"; | ||||||
| import dayjs, { Dayjs } from "dayjs"; | import dayjs, { Dayjs } from "dayjs"; | ||||||
| import { GetServerSidePropsContext, InferGetServerSidePropsType } from "next"; | import { GetServerSidePropsContext, InferGetServerSidePropsType } from "next"; | ||||||
| import Head from "next/head"; | import { HeadSeo } from "@components/seo/head-seo"; | ||||||
| import { useRouter } from "next/router"; | import { useRouter } from "next/router"; | ||||||
| import { useEffect, useState } from "react"; | import { useEffect, useState } from "react"; | ||||||
| import Avatar from "@components/Avatar"; | import Avatar from "@components/Avatar"; | ||||||
| import AvailableTimes from "../../components/booking/AvailableTimes"; | import AvailableTimes from "@components/booking/AvailableTimes"; | ||||||
| import DatePicker from "../../components/booking/DatePicker"; | import DatePicker from "@components/booking/DatePicker"; | ||||||
| import TimeOptions from "../../components/booking/TimeOptions"; | import TimeOptions from "@components/booking/TimeOptions"; | ||||||
| import PoweredByCalendso from "../../components/ui/PoweredByCalendso"; | import PoweredByCalendso from "@components/ui/PoweredByCalendso"; | ||||||
| import { timeZone } from "../../lib/clock"; | import { timeZone } from "@lib/clock"; | ||||||
| import { collectPageParameters, telemetryEventTypes, useTelemetry } from "../../lib/telemetry"; | import { collectPageParameters, telemetryEventTypes, useTelemetry } from "@lib/telemetry"; | ||||||
| import { asStringOrNull } from "@lib/asStringOrNull"; | import { asStringOrNull } from "@lib/asStringOrNull"; | ||||||
| 
 | 
 | ||||||
| export default function Type(props: InferGetServerSidePropsType<typeof getServerSideProps>) { | export default function Type(props: InferGetServerSidePropsType<typeof getServerSideProps>) { | ||||||
|  | @ -82,53 +82,14 @@ export default function Type(props: InferGetServerSidePropsType<typeof getServer | ||||||
| 
 | 
 | ||||||
|   return ( |   return ( | ||||||
|     <> |     <> | ||||||
|       <Head> |       <HeadSeo | ||||||
|         <title> |         title={`${rescheduleUid ? "Reschedule" : ""} ${props.eventType.title} | ${ | ||||||
|           {rescheduleUid && "Reschedule"} {props.eventType.title} | {props.user.name || props.user.username} | |           props.user.name || props.user.username | ||||||
|           Calendso |         }`}
 | ||||||
|         </title> |         description={`${rescheduleUid ? "Reschedule" : ""} ${props.eventType.title}`} | ||||||
|         <meta name="title" content={"Meet " + (props.user.name || props.user.username) + " via Calendso"} /> |         name={props.user.name || props.user.username} | ||||||
|         <meta name="description" content={props.eventType.description} /> |         avatar={props.user.avatar} | ||||||
| 
 |       /> | ||||||
|         <meta property="og:type" content="website" /> |  | ||||||
|         <meta property="og:url" content="https://calendso/" /> |  | ||||||
|         <meta |  | ||||||
|           property="og:title" |  | ||||||
|           content={"Meet " + (props.user.name || props.user.username) + " via Calendso"} |  | ||||||
|         /> |  | ||||||
|         <meta property="og:description" content={props.eventType.description} /> |  | ||||||
|         <meta |  | ||||||
|           property="og:image" |  | ||||||
|           content={ |  | ||||||
|             "https://og-image-one-pi.vercel.app/" + |  | ||||||
|             encodeURIComponent( |  | ||||||
|               "Meet **" + (props.user.name || props.user.username) + "** <br>" + props.eventType.description |  | ||||||
|             ).replace(/'/g, "%27") + |  | ||||||
|             ".png?md=1&images=https%3A%2F%2Fcalendso.com%2Fcalendso-logo-white.svg&images=" + |  | ||||||
|             encodeURIComponent(props.user.avatar) |  | ||||||
|           } |  | ||||||
|         /> |  | ||||||
| 
 |  | ||||||
|         <meta property="twitter:card" content="summary_large_image" /> |  | ||||||
|         <meta property="twitter:url" content="https://calendso/" /> |  | ||||||
|         <meta |  | ||||||
|           property="twitter:title" |  | ||||||
|           content={"Meet " + (props.user.name || props.user.username) + " via Calendso"} |  | ||||||
|         /> |  | ||||||
|         <meta property="twitter:description" content={props.eventType.description} /> |  | ||||||
|         <meta |  | ||||||
|           property="twitter:image" |  | ||||||
|           content={ |  | ||||||
|             "https://og-image-one-pi.vercel.app/" + |  | ||||||
|             encodeURIComponent( |  | ||||||
|               "Meet **" + (props.user.name || props.user.username) + "** <br>" + props.eventType.description |  | ||||||
|             ).replace(/'/g, "%27") + |  | ||||||
|             ".png?md=1&images=https%3A%2F%2Fcalendso.com%2Fcalendso-logo-white.svg&images=" + |  | ||||||
|             encodeURIComponent(props.user.avatar) |  | ||||||
|           } |  | ||||||
|         /> |  | ||||||
|       </Head> |  | ||||||
| 
 |  | ||||||
|       {isReady && ( |       {isReady && ( | ||||||
|         <div> |         <div> | ||||||
|           <main |           <main | ||||||
|  |  | ||||||
|  | @ -1,16 +1,16 @@ | ||||||
| import Head from "next/head"; | import { HeadSeo } from "@components/seo/head-seo"; | ||||||
| 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 { EventTypeCustomInputType } from "@prisma/client"; | import { EventTypeCustomInputType } from "@prisma/client"; | ||||||
| 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"; | ||||||
| import utc from "dayjs/plugin/utc"; | import utc from "dayjs/plugin/utc"; | ||||||
| import timezone from "dayjs/plugin/timezone"; | import timezone from "dayjs/plugin/timezone"; | ||||||
| import PhoneInput from "@components/ui/form/PhoneInput"; | import PhoneInput from "@components/ui/form/PhoneInput"; | ||||||
| import { LocationType } from "../../lib/location"; | import { LocationType } from "@lib/location"; | ||||||
| import Avatar from "@components/Avatar"; | import Avatar from "@components/Avatar"; | ||||||
| import { Button } from "@components/ui/Button"; | import { Button } from "@components/ui/Button"; | ||||||
| import Theme from "@components/Theme"; | import Theme from "@components/Theme"; | ||||||
|  | @ -150,13 +150,14 @@ export default function Book(props: any): JSX.Element { | ||||||
|   return ( |   return ( | ||||||
|     isReady && ( |     isReady && ( | ||||||
|       <div> |       <div> | ||||||
|         <Head> |         <HeadSeo | ||||||
|           <title> |           title={`${rescheduleUid ? "Reschedule" : "Confirm"} your ${props.eventType.title} with ${ | ||||||
|             {rescheduleUid ? "Reschedule" : "Confirm"} your {props.eventType.title} with{" "} |             props.user.name || props.user.username | ||||||
|             {props.user.name || props.user.username} | Calendso |           }`}
 | ||||||
|           </title> |           description={`${rescheduleUid ? "Reschedule" : "Confirm"} your ${props.eventType.title} with ${ | ||||||
|           <link rel="icon" href="/favicon.ico" /> |             props.user.name || props.user.username | ||||||
|         </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-neutral-900 bg-white overflow-hidden border border-gray-200 dark:border-0 sm:rounded-sm"> |           <div className="dark:bg-neutral-900 bg-white overflow-hidden border border-gray-200 dark:border-0 sm:rounded-sm"> | ||||||
|  |  | ||||||
|  | @ -1,7 +1,8 @@ | ||||||
| import "../styles/globals.css"; | import "../styles/globals.css"; | ||||||
| import AppProviders from "@lib/app-providers"; | import AppProviders from "@lib/app-providers"; | ||||||
| import type { AppProps as NextAppProps } from "next/app"; | import type { AppProps as NextAppProps } from "next/app"; | ||||||
| import Head from "next/head"; | import { DefaultSeo } from "next-seo"; | ||||||
|  | import { seoConfig } from "@lib/config/next-seo.config"; | ||||||
| 
 | 
 | ||||||
| // Workaround for https://github.com/zeit/next.js/issues/8592
 | // Workaround for https://github.com/zeit/next.js/issues/8592
 | ||||||
| export type AppProps = NextAppProps & { | export type AppProps = NextAppProps & { | ||||||
|  | @ -12,9 +13,7 @@ export type AppProps = NextAppProps & { | ||||||
| function MyApp({ Component, pageProps, err }: AppProps) { | function MyApp({ Component, pageProps, err }: AppProps) { | ||||||
|   return ( |   return ( | ||||||
|     <AppProviders> |     <AppProviders> | ||||||
|       <Head> |       <DefaultSeo {...seoConfig.defaultNextSeo} /> | ||||||
|         <meta name="viewport" content="width=device-width, initial-scale=1.0" /> |  | ||||||
|       </Head> |  | ||||||
|       <Component {...pageProps} err={err} /> |       <Component {...pageProps} err={err} /> | ||||||
|     </AppProviders> |     </AppProviders> | ||||||
|   ); |   ); | ||||||
|  |  | ||||||
|  | @ -1,6 +1,6 @@ | ||||||
| import { useRouter } from "next/router"; | import { useRouter } from "next/router"; | ||||||
| import { XIcon } from "@heroicons/react/outline"; | import { XIcon } from "@heroicons/react/outline"; | ||||||
| import Head from "next/head"; | import { HeadSeo } from "@components/seo/head-seo"; | ||||||
| import Link from "next/link"; | import Link from "next/link"; | ||||||
| 
 | 
 | ||||||
| export default function Error() { | export default function Error() { | ||||||
|  | @ -13,10 +13,7 @@ export default function Error() { | ||||||
|       aria-labelledby="modal-title" |       aria-labelledby="modal-title" | ||||||
|       role="dialog" |       role="dialog" | ||||||
|       aria-modal="true"> |       aria-modal="true"> | ||||||
|       <Head> |       <HeadSeo title="Error" description="Error" /> | ||||||
|         <title>{error} - Calendso</title> |  | ||||||
|         <link rel="icon" href="/favicon.ico" /> |  | ||||||
|       </Head> |  | ||||||
|       <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="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"> |         <span className="hidden sm:inline-block sm:align-middle sm:h-screen" aria-hidden="true"> | ||||||
|           ​ |           ​ | ||||||
|  |  | ||||||
|  | @ -1,7 +1,6 @@ | ||||||
| import { getCsrfToken } from "next-auth/client"; | import { getCsrfToken } from "next-auth/client"; | ||||||
| import prisma from "../../../lib/prisma"; | import prisma from "@lib/prisma"; | ||||||
| 
 | import { HeadSeo } from "@components/seo/head-seo"; | ||||||
| import Head from "next/head"; |  | ||||||
| import React, { useMemo } from "react"; | import React, { useMemo } from "react"; | ||||||
| import debounce from "lodash.debounce"; | import debounce from "lodash.debounce"; | ||||||
| import dayjs from "dayjs"; | import dayjs from "dayjs"; | ||||||
|  | @ -122,10 +121,7 @@ export default function Page({ resetPasswordRequest, csrfToken }: Props) { | ||||||
| 
 | 
 | ||||||
|   return ( |   return ( | ||||||
|     <div className="min-h-screen bg-gray-50 flex flex-col justify-center py-12 sm:px-6 lg:px-8"> |     <div className="min-h-screen bg-gray-50 flex flex-col justify-center py-12 sm:px-6 lg:px-8"> | ||||||
|       <Head> |       <HeadSeo title="Reset Password" description="Change your password" /> | ||||||
|         <title>Reset Password</title> |  | ||||||
|         <link rel="icon" href="/favicon.ico" /> |  | ||||||
|       </Head> |  | ||||||
|       <div className="mt-8 sm:mx-auto sm:w-full sm:max-w-md"> |       <div className="mt-8 sm:mx-auto sm:w-full sm:max-w-md"> | ||||||
|         <div className="bg-white py-8 px-4 mx-2 shadow rounded-lg sm:px-10 space-y-6"> |         <div className="bg-white py-8 px-4 mx-2 shadow rounded-lg sm:px-10 space-y-6"> | ||||||
|           {isRequestExpired && <Expired />} |           {isRequestExpired && <Expired />} | ||||||
|  |  | ||||||
|  | @ -1,4 +1,4 @@ | ||||||
| import Head from "next/head"; | import { HeadSeo } from "@components/seo/head-seo"; | ||||||
| import Link from "next/link"; | import Link from "next/link"; | ||||||
| import React from "react"; | import React from "react"; | ||||||
| import { getCsrfToken, getSession } from "next-auth/client"; | import { getCsrfToken, getSession } from "next-auth/client"; | ||||||
|  | @ -71,11 +71,7 @@ export default function ForgotPassword({ csrfToken }) { | ||||||
| 
 | 
 | ||||||
|   return ( |   return ( | ||||||
|     <div className="min-h-screen bg-gray-50 flex flex-col justify-center py-12 sm:px-6 lg:px-8"> |     <div className="min-h-screen bg-gray-50 flex flex-col justify-center py-12 sm:px-6 lg:px-8"> | ||||||
|       <Head> |       <HeadSeo title="Forgot Password" description="Forgot Password" /> | ||||||
|         <title>Forgot Password</title> |  | ||||||
|         <link rel="icon" href="/favicon.ico" /> |  | ||||||
|       </Head> |  | ||||||
| 
 |  | ||||||
|       <div className="mt-8 sm:mx-auto sm:w-full sm:max-w-md"> |       <div className="mt-8 sm:mx-auto sm:w-full sm:max-w-md"> | ||||||
|         <div className="bg-white py-8 px-4 mx-2 shadow rounded-lg sm:px-10 space-y-6"> |         <div className="bg-white py-8 px-4 mx-2 shadow rounded-lg sm:px-10 space-y-6"> | ||||||
|           {success && <Success />} |           {success && <Success />} | ||||||
|  |  | ||||||
|  | @ -1,14 +1,11 @@ | ||||||
| import Head from "next/head"; | import { HeadSeo } from "@components/seo/head-seo"; | ||||||
| import Link from "next/link"; | import Link from "next/link"; | ||||||
| import { getCsrfToken, getSession } from "next-auth/client"; | import { getCsrfToken, getSession } from "next-auth/client"; | ||||||
| 
 | 
 | ||||||
| export default function Login({ csrfToken }) { | export default function Login({ csrfToken }) { | ||||||
|   return ( |   return ( | ||||||
|     <div className="min-h-screen bg-neutral-50 flex flex-col justify-center py-12 sm:px-6 lg:px-8"> |     <div className="min-h-screen bg-neutral-50 flex flex-col justify-center py-12 sm:px-6 lg:px-8"> | ||||||
|       <Head> |       <HeadSeo title="Login" description="Login" /> | ||||||
|         <title>Login</title> |  | ||||||
|         <link rel="icon" href="/favicon.ico" /> |  | ||||||
|       </Head> |  | ||||||
|       <div className="sm:mx-auto sm:w-full sm:max-w-md"> |       <div className="sm:mx-auto sm:w-full sm:max-w-md"> | ||||||
|         <img className="h-6 mx-auto" src="/calendso-logo-white-word.svg" alt="Calendso Logo" /> |         <img className="h-6 mx-auto" src="/calendso-logo-white-word.svg" alt="Calendso Logo" /> | ||||||
|         <h2 className="mt-6 text-center text-3xl font-bold text-neutral-900">Sign in to your account</h2> |         <h2 className="mt-6 text-center text-3xl font-bold text-neutral-900">Sign in to your account</h2> | ||||||
|  |  | ||||||
|  | @ -1,4 +1,4 @@ | ||||||
| import Head from "next/head"; | import { HeadSeo } from "@components/seo/head-seo"; | ||||||
| import Link from "next/link"; | import Link from "next/link"; | ||||||
| import { CheckIcon } from "@heroicons/react/outline"; | import { CheckIcon } from "@heroicons/react/outline"; | ||||||
| 
 | 
 | ||||||
|  | @ -9,10 +9,7 @@ export default function Logout() { | ||||||
|       aria-labelledby="modal-title" |       aria-labelledby="modal-title" | ||||||
|       role="dialog" |       role="dialog" | ||||||
|       aria-modal="true"> |       aria-modal="true"> | ||||||
|       <Head> |       <HeadSeo title="Logged out" description="Logged out" /> | ||||||
|         <title>Logged out - Calendso</title> |  | ||||||
|         <link rel="icon" href="/favicon.ico" /> |  | ||||||
|       </Head> |  | ||||||
|       <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="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"> |         <span className="hidden sm:inline-block sm:align-middle sm:h-screen" aria-hidden="true"> | ||||||
|           ​ |           ​ | ||||||
|  |  | ||||||
|  | @ -1,10 +1,10 @@ | ||||||
| import Head from "next/head"; | import { HeadSeo } from "@components/seo/head-seo"; | ||||||
| import { useRouter } from "next/router"; | import { useRouter } from "next/router"; | ||||||
| import { signIn } from "next-auth/client"; | import { signIn } from "next-auth/client"; | ||||||
| import ErrorAlert from "../../components/ui/alerts/Error"; | import ErrorAlert from "@components/ui/alerts/Error"; | ||||||
| import { useState } from "react"; | import { useState } from "react"; | ||||||
| import { UsernameInput } from "../../components/ui/UsernameInput"; | import { UsernameInput } from "@components/ui/UsernameInput"; | ||||||
| import prisma from "../../lib/prisma"; | import prisma from "@lib/prisma"; | ||||||
| 
 | 
 | ||||||
| export default function Signup(props) { | export default function Signup(props) { | ||||||
|   const router = useRouter(); |   const router = useRouter(); | ||||||
|  | @ -54,10 +54,7 @@ export default function Signup(props) { | ||||||
|       aria-labelledby="modal-title" |       aria-labelledby="modal-title" | ||||||
|       role="dialog" |       role="dialog" | ||||||
|       aria-modal="true"> |       aria-modal="true"> | ||||||
|       <Head> |       <HeadSeo title="Sign up" description="Sign up" /> | ||||||
|         <title>Sign up</title> |  | ||||||
|         <link rel="icon" href="/favicon.ico" /> |  | ||||||
|       </Head> |  | ||||||
|       <div className="sm:mx-auto sm:w-full sm:max-w-md"> |       <div className="sm:mx-auto sm:w-full sm:max-w-md"> | ||||||
|         <h2 className="text-center text-3xl font-extrabold text-gray-900">Create your account</h2> |         <h2 className="text-center text-3xl font-extrabold text-gray-900">Create your account</h2> | ||||||
|       </div> |       </div> | ||||||
|  |  | ||||||
|  | @ -1,8 +1,7 @@ | ||||||
| import Head from "next/head"; |  | ||||||
| import Link from "next/link"; | import Link from "next/link"; | ||||||
| import prisma from "../../lib/prisma"; | import prisma from "@lib/prisma"; | ||||||
| import Modal from "../../components/Modal"; | import Modal from "@components/Modal"; | ||||||
| import Shell from "../../components/Shell"; | import Shell from "@components/Shell"; | ||||||
| import { useRouter } from "next/router"; | import { useRouter } from "next/router"; | ||||||
| import { useRef, useState } from "react"; | import { useRef, useState } from "react"; | ||||||
| import { getSession, useSession } from "next-auth/client"; | import { getSession, useSession } from "next-auth/client"; | ||||||
|  | @ -115,15 +114,7 @@ export default function Availability(props) { | ||||||
| 
 | 
 | ||||||
|   return ( |   return ( | ||||||
|     <div> |     <div> | ||||||
|       <Head> |       <Shell heading="Availability" subtitle="Configure times when you are available for bookings."> | ||||||
|         <title>Availability | Calendso</title> |  | ||||||
|         <link rel="icon" href="/favicon.ico" /> |  | ||||||
|       </Head> |  | ||||||
|       <Shell |  | ||||||
|         heading="Availability" |  | ||||||
|         subtitle="Configure times when you are available for bookings. |  | ||||||
| 
 |  | ||||||
| "> |  | ||||||
|         <div className="flex"> |         <div className="flex"> | ||||||
|           <div className="w-1/2 mr-2 bg-white border border-gray-200 rounded-sm"> |           <div className="w-1/2 mr-2 bg-white border border-gray-200 rounded-sm"> | ||||||
|             <div className="px-4 py-5 sm:p-6"> |             <div className="px-4 py-5 sm:p-6"> | ||||||
|  |  | ||||||
|  | @ -4,9 +4,8 @@ import dayjs from "dayjs"; | ||||||
| import utc from "dayjs/plugin/utc"; | import utc from "dayjs/plugin/utc"; | ||||||
| import { GetServerSideProps } from "next"; | import { GetServerSideProps } from "next"; | ||||||
| import { getSession } from "next-auth/client"; | import { getSession } from "next-auth/client"; | ||||||
| import Head from "next/head"; |  | ||||||
| import { useEffect, useState } from "react"; | import { useEffect, useState } from "react"; | ||||||
| import Shell from "../../components/Shell"; | import Shell from "@components/Shell"; | ||||||
| 
 | 
 | ||||||
| dayjs.extend(utc); | dayjs.extend(utc); | ||||||
| 
 | 
 | ||||||
|  | @ -52,10 +51,6 @@ export default function Troubleshoot({ user }) { | ||||||
| 
 | 
 | ||||||
|   return ( |   return ( | ||||||
|     <div> |     <div> | ||||||
|       <Head> |  | ||||||
|         <title>Troubleshoot | Calendso</title> |  | ||||||
|         <link rel="icon" href="/favicon.ico" /> |  | ||||||
|       </Head> |  | ||||||
|       <Shell |       <Shell | ||||||
|         heading="Troubleshoot" |         heading="Troubleshoot" | ||||||
|         subtitle="Understand why certain times are available and others are blocked."> |         subtitle="Understand why certain times are available and others are blocked."> | ||||||
|  |  | ||||||
|  | @ -1,7 +1,6 @@ | ||||||
| import Head from "next/head"; | import prisma from "@lib/prisma"; | ||||||
| import prisma from "../../lib/prisma"; |  | ||||||
| import { getSession, useSession } from "next-auth/client"; | import { getSession, useSession } from "next-auth/client"; | ||||||
| import Shell from "../../components/Shell"; | import Shell from "@components/Shell"; | ||||||
| import { useRouter } from "next/router"; | import { useRouter } from "next/router"; | ||||||
| import dayjs from "dayjs"; | import dayjs from "dayjs"; | ||||||
| import { Fragment } from "react"; | import { Fragment } from "react"; | ||||||
|  | @ -36,10 +35,6 @@ export default function Bookings({ bookings }) { | ||||||
| 
 | 
 | ||||||
|   return ( |   return ( | ||||||
|     <div> |     <div> | ||||||
|       <Head> |  | ||||||
|         <title>Bookings | Calendso</title> |  | ||||||
|         <link rel="icon" href="/favicon.ico" /> |  | ||||||
|       </Head> |  | ||||||
|       <Shell heading="Bookings" subtitle="See upcoming and past events booked through your event type links."> |       <Shell heading="Bookings" subtitle="See upcoming and past events booked through your event type links."> | ||||||
|         <div className="-mx-4 sm:mx-auto flex flex-col"> |         <div className="-mx-4 sm:mx-auto flex flex-col"> | ||||||
|           <div className="-my-2 overflow-x-auto sm:-mx-6 lg:-mx-8"> |           <div className="-my-2 overflow-x-auto sm:-mx-6 lg:-mx-8"> | ||||||
|  |  | ||||||
|  | @ -4,11 +4,11 @@ import isBetween from "dayjs/plugin/isBetween"; | ||||||
| import isSameOrBefore from "dayjs/plugin/isSameOrBefore"; | import isSameOrBefore from "dayjs/plugin/isSameOrBefore"; | ||||||
| import timezone from "dayjs/plugin/timezone"; | import timezone from "dayjs/plugin/timezone"; | ||||||
| import utc from "dayjs/plugin/utc"; | import utc from "dayjs/plugin/utc"; | ||||||
| import Head from "next/head"; | import { HeadSeo } from "@components/seo/head-seo"; | ||||||
| import { useRouter } from "next/router"; | import { useRouter } from "next/router"; | ||||||
| import { useState } from "react"; | import { useState } from "react"; | ||||||
| import prisma from "../../lib/prisma"; | import prisma from "@lib/prisma"; | ||||||
| import { collectPageParameters, telemetryEventTypes, useTelemetry } from "../../lib/telemetry"; | import { collectPageParameters, telemetryEventTypes, useTelemetry } from "@lib/telemetry"; | ||||||
| 
 | 
 | ||||||
| dayjs.extend(isSameOrBefore); | dayjs.extend(isSameOrBefore); | ||||||
| dayjs.extend(isBetween); | dayjs.extend(isBetween); | ||||||
|  | @ -55,13 +55,12 @@ export default function Type(props) { | ||||||
| 
 | 
 | ||||||
|   return ( |   return ( | ||||||
|     <div> |     <div> | ||||||
|       <Head> |       <HeadSeo | ||||||
|         <title> |         title={`Cancel ${props.booking && props.booking.title} | ${props.user.name || props.user.username}`} | ||||||
|           Cancel {props.booking && `${props.booking.title} | ${props.user.name || props.user.username} `}| |         description={`Cancel ${props.booking && props.booking.title} | ${ | ||||||
|           Calendso |           props.user.name || props.user.username | ||||||
|         </title> |         }`}
 | ||||||
|         <link rel="icon" href="/favicon.ico" /> |       /> | ||||||
|       </Head> |  | ||||||
|       <main className="max-w-3xl mx-auto my-24"> |       <main className="max-w-3xl mx-auto my-24"> | ||||||
|         <div className="fixed z-50 inset-0 overflow-y-auto"> |         <div className="fixed z-50 inset-0 overflow-y-auto"> | ||||||
|           <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="flex items-end justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0"> | ||||||
|  |  | ||||||
|  | @ -1,4 +1,4 @@ | ||||||
| import Head from "next/head"; | import { HeadSeo } from "@components/seo/head-seo"; | ||||||
| import prisma from "../../lib/prisma"; | import prisma from "../../lib/prisma"; | ||||||
| import { useRouter } from "next/router"; | import { useRouter } from "next/router"; | ||||||
| import dayjs from "dayjs"; | import dayjs from "dayjs"; | ||||||
|  | @ -19,12 +19,10 @@ export default function Type(props) { | ||||||
| 
 | 
 | ||||||
|   return ( |   return ( | ||||||
|     <div> |     <div> | ||||||
|       <Head> |       <HeadSeo | ||||||
|         <title> |         title={`Cancelled ${props.title} | ${props.user.name || props.user.username}`} | ||||||
|           Cancelled {props.title} | {props.user.name || props.user.username} | Calendso |         description={`Cancelled ${props.title} | ${props.user.name || props.user.username}`} | ||||||
|         </title> |       /> | ||||||
|         <link rel="icon" href="/favicon.ico" /> |  | ||||||
|       </Head> |  | ||||||
|       <main className="max-w-3xl mx-auto my-24"> |       <main className="max-w-3xl mx-auto my-24"> | ||||||
|         <div className="fixed z-50 inset-0 overflow-y-auto"> |         <div className="fixed z-50 inset-0 overflow-y-auto"> | ||||||
|           <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="flex items-end justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0"> | ||||||
|  |  | ||||||
|  | @ -1,7 +1,6 @@ | ||||||
| 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 Modal from "../../components/Modal"; | import Modal from "@components/Modal"; | ||||||
| import React, { useEffect, useRef, useState } from "react"; | import React, { useEffect, useRef, useState } from "react"; | ||||||
| import Select, { OptionBase } from "react-select"; | import Select, { OptionBase } from "react-select"; | ||||||
| import prisma from "@lib/prisma"; | import prisma from "@lib/prisma"; | ||||||
|  | @ -331,11 +330,8 @@ const EventTypePage = (props: InferGetServerSidePropsType<typeof getServerSidePr | ||||||
| 
 | 
 | ||||||
|   return ( |   return ( | ||||||
|     <div> |     <div> | ||||||
|       <Head> |  | ||||||
|         <title>{eventType.title} | Event Type | Calendso</title> |  | ||||||
|         <link rel="icon" href="/favicon.ico" /> |  | ||||||
|       </Head> |  | ||||||
|       <Shell |       <Shell | ||||||
|  |         title={`${eventType.title} | Event Type`} | ||||||
|         heading={ |         heading={ | ||||||
|           <input |           <input | ||||||
|             ref={titleRef} |             ref={titleRef} | ||||||
|  |  | ||||||
|  | @ -15,7 +15,6 @@ import { | ||||||
| import classNames from "@lib/classNames"; | import classNames from "@lib/classNames"; | ||||||
| import showToast from "@lib/notification"; | import showToast from "@lib/notification"; | ||||||
| import { getSession, useSession } from "next-auth/client"; | import { getSession, useSession } from "next-auth/client"; | ||||||
| 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 React, { Fragment, useRef } from "react"; | import React, { Fragment, useRef } from "react"; | ||||||
|  | @ -193,10 +192,6 @@ const EventTypesPage = (props: InferGetServerSidePropsType<typeof getServerSideP | ||||||
| 
 | 
 | ||||||
|   return ( |   return ( | ||||||
|     <div> |     <div> | ||||||
|       <Head> |  | ||||||
|         <title>Event Types | Calendso</title> |  | ||||||
|         <link rel="icon" href="/favicon.ico" /> |  | ||||||
|       </Head> |  | ||||||
|       <Shell |       <Shell | ||||||
|         heading="Event Types" |         heading="Event Types" | ||||||
|         subtitle="Create events to share for people to book on your calendar." |         subtitle="Create events to share for people to book on your calendar." | ||||||
|  |  | ||||||
|  | @ -1,7 +1,6 @@ | ||||||
| import Head from "next/head"; | import prisma from "@lib/prisma"; | ||||||
| import prisma from "../../lib/prisma"; | import { getIntegrationName, getIntegrationType } from "@lib/integrations"; | ||||||
| import { getIntegrationName, getIntegrationType } from "../../lib/integrations"; | import Shell from "@components/Shell"; | ||||||
| import Shell from "../../components/Shell"; |  | ||||||
| import { useState } from "react"; | import { useState } from "react"; | ||||||
| import { useRouter } from "next/router"; | import { useRouter } from "next/router"; | ||||||
| import { getSession, useSession } from "next-auth/client"; | import { getSession, useSession } from "next-auth/client"; | ||||||
|  | @ -40,12 +39,9 @@ export default function Integration(props) { | ||||||
| 
 | 
 | ||||||
|   return ( |   return ( | ||||||
|     <div> |     <div> | ||||||
|       <Head> |       <Shell | ||||||
|         <title>{getIntegrationName(props.integration.type)} App | Calendso</title> |         heading={`${getIntegrationName(props.integration.type)} App`} | ||||||
|         <link rel="icon" href="/favicon.ico" /> |         subtitle="Manage and delete this app."> | ||||||
|       </Head> |  | ||||||
| 
 |  | ||||||
|       <Shell heading={getIntegrationName(props.integration.type)} subtitle="Manage and delete this app."> |  | ||||||
|         <div className="block sm:grid grid-cols-3 gap-4"> |         <div className="block sm:grid grid-cols-3 gap-4"> | ||||||
|           <div className="col-span-2 bg-white border border-gray-200 mb-6 overflow-hidden rounded-sm"> |           <div className="col-span-2 bg-white border border-gray-200 mb-6 overflow-hidden rounded-sm"> | ||||||
|             <div className="px-4 py-5 sm:px-6"> |             <div className="px-4 py-5 sm:px-6"> | ||||||
|  |  | ||||||
|  | @ -1,7 +1,6 @@ | ||||||
| import Head from "next/head"; |  | ||||||
| import Link from "next/link"; | import Link from "next/link"; | ||||||
| import prisma from "../../lib/prisma"; | import prisma from "@lib/prisma"; | ||||||
| import Shell from "../../components/Shell"; | import Shell from "@components/Shell"; | ||||||
| import { useEffect, useState, useRef, useCallback } from "react"; | import { useEffect, useState, useRef, useCallback } from "react"; | ||||||
| import { getSession, useSession } from "next-auth/client"; | import { getSession, useSession } from "next-auth/client"; | ||||||
| import { CheckCircleIcon, ChevronRightIcon, PlusIcon, XCircleIcon } from "@heroicons/react/solid"; | import { CheckCircleIcon, ChevronRightIcon, PlusIcon, XCircleIcon } from "@heroicons/react/solid"; | ||||||
|  | @ -270,11 +269,6 @@ export default function Home({ integrations }: Props) { | ||||||
| 
 | 
 | ||||||
|   return ( |   return ( | ||||||
|     <div> |     <div> | ||||||
|       <Head> |  | ||||||
|         <title>App Store | Calendso</title> |  | ||||||
|         <link rel="icon" href="/favicon.ico" /> |  | ||||||
|       </Head> |  | ||||||
| 
 |  | ||||||
|       <Shell heading="App Store" subtitle="Connect your favourite apps." CTA={<ConnectNewAppDialog />}> |       <Shell heading="App Store" subtitle="Connect your favourite apps." CTA={<ConnectNewAppDialog />}> | ||||||
|         <div className="bg-white border border-gray-200 overflow-hidden rounded-sm mb-8"> |         <div className="bg-white border border-gray-200 overflow-hidden rounded-sm mb-8"> | ||||||
|           {integrations.filter((ig) => ig.credential).length !== 0 ? ( |           {integrations.filter((ig) => ig.credential).length !== 0 ? ( | ||||||
|  |  | ||||||
|  | @ -1,15 +1,11 @@ | ||||||
| import Head from "next/head"; | import Shell from "@components/Shell"; | ||||||
| import Shell from "../../components/Shell"; | import SettingsShell from "@components/Settings"; | ||||||
| import SettingsShell from "../../components/Settings"; | import prisma from "@lib/prisma"; | ||||||
| import prisma from "../../lib/prisma"; |  | ||||||
| import { getSession } from "next-auth/client"; | import { getSession } from "next-auth/client"; | ||||||
| 
 | 
 | ||||||
| export default function Billing() { | export default function Billing() { | ||||||
|   return ( |   return ( | ||||||
|     <Shell heading="Billing" subtitle="Manage your billing information and cancel your subscription."> |     <Shell heading="Billing" subtitle="Manage your billing information and cancel your subscription."> | ||||||
|       <Head> |  | ||||||
|         <title>Billing | Calendso</title> |  | ||||||
|       </Head> |  | ||||||
|       <SettingsShell> |       <SettingsShell> | ||||||
|         <div className="py-6 lg:pb-8 lg:col-span-9"> |         <div className="py-6 lg:pb-8 lg:col-span-9"> | ||||||
|           <div className="my-6"> |           <div className="my-6"> | ||||||
|  |  | ||||||
|  | @ -1,7 +1,6 @@ | ||||||
| import Head from "next/head"; | import prisma from "@lib/prisma"; | ||||||
| import prisma from "../../lib/prisma"; | import Shell from "@components/Shell"; | ||||||
| import Shell from "../../components/Shell"; | import SettingsShell from "@components/Settings"; | ||||||
| import SettingsShell from "../../components/Settings"; |  | ||||||
| import { getSession, useSession } from "next-auth/client"; | import { getSession, useSession } from "next-auth/client"; | ||||||
| import Loader from "@components/Loader"; | import Loader from "@components/Loader"; | ||||||
| 
 | 
 | ||||||
|  | @ -15,10 +14,6 @@ export default function Embed(props) { | ||||||
| 
 | 
 | ||||||
|   return ( |   return ( | ||||||
|     <Shell heading="Embed" subtitle="Integrate with your website using our embed options."> |     <Shell heading="Embed" subtitle="Integrate with your website using our embed options."> | ||||||
|       <Head> |  | ||||||
|         <title>Embed | Calendso</title> |  | ||||||
|         <link rel="icon" href="/favicon.ico" /> |  | ||||||
|       </Head> |  | ||||||
|       <SettingsShell> |       <SettingsShell> | ||||||
|         <div className="py-6 lg:pb-8 lg:col-span-9"> |         <div className="py-6 lg:pb-8 lg:col-span-9"> | ||||||
|           <div className="mb-6"> |           <div className="mb-6"> | ||||||
|  |  | ||||||
|  | @ -1,9 +1,8 @@ | ||||||
| import Head from "next/head"; |  | ||||||
| import { useRef, useState } from "react"; | import { useRef, useState } from "react"; | ||||||
| import prisma from "../../lib/prisma"; | import prisma 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"; | ||||||
| import { getSession, useSession } from "next-auth/client"; | import { getSession, useSession } from "next-auth/client"; | ||||||
| import Loader from "@components/Loader"; | import Loader from "@components/Loader"; | ||||||
| 
 | 
 | ||||||
|  | @ -45,11 +44,7 @@ export default function Settings() { | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   return ( |   return ( | ||||||
|     <Shell heading="Password" subtitle="Change the password that you use to sign in to your account."> |     <Shell heading="Change Password" subtitle="Change the password that you use to sign in to your account."> | ||||||
|       <Head> |  | ||||||
|         <title>Change Password | Calendso</title> |  | ||||||
|         <link rel="icon" href="/favicon.ico" /> |  | ||||||
|       </Head> |  | ||||||
|       <SettingsShell> |       <SettingsShell> | ||||||
|         <form className="divide-y divide-gray-200 lg:col-span-9" onSubmit={changePasswordHandler}> |         <form className="divide-y divide-gray-200 lg:col-span-9" onSubmit={changePasswordHandler}> | ||||||
|           <div className="py-6 lg:pb-8"> |           <div className="py-6 lg:pb-8"> | ||||||
|  |  | ||||||
|  | @ -1,17 +1,16 @@ | ||||||
| import { GetServerSideProps } from "next"; | import { GetServerSideProps } from "next"; | ||||||
| import Head from "next/head"; |  | ||||||
| import { useEffect, useRef, useState } from "react"; | import { useEffect, useRef, useState } from "react"; | ||||||
| import prisma from "@lib/prisma"; | import prisma 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"; | ||||||
| import Avatar from "@components/Avatar"; | import Avatar from "@components/Avatar"; | ||||||
| import { getSession } from "next-auth/client"; | import { getSession } from "next-auth/client"; | ||||||
| import Select from "react-select"; | import Select from "react-select"; | ||||||
| import TimezoneSelect from "react-timezone-select"; | import TimezoneSelect from "react-timezone-select"; | ||||||
| import { UsernameInput } from "../../components/ui/UsernameInput"; | import { UsernameInput } from "@components/ui/UsernameInput"; | ||||||
| import ErrorAlert from "../../components/ui/alerts/Error"; | import ErrorAlert from "@components/ui/alerts/Error"; | ||||||
| import ImageUploader from "../../components/ImageUploader"; | import ImageUploader from "@components/ImageUploader"; | ||||||
| import crypto from "crypto"; | import crypto from "crypto"; | ||||||
| 
 | 
 | ||||||
| const themeOptions = [ | const themeOptions = [ | ||||||
|  | @ -107,10 +106,6 @@ export default function Settings(props) { | ||||||
| 
 | 
 | ||||||
|   return ( |   return ( | ||||||
|     <Shell heading="Profile" subtitle="Edit your profile information, which shows on your scheduling link."> |     <Shell heading="Profile" subtitle="Edit your profile information, which shows on your scheduling link."> | ||||||
|       <Head> |  | ||||||
|         <title>Profile | Calendso</title> |  | ||||||
|         <link rel="icon" href="/favicon.ico" /> |  | ||||||
|       </Head> |  | ||||||
|       <SettingsShell> |       <SettingsShell> | ||||||
|         <form className="divide-y divide-gray-200 lg:col-span-9" onSubmit={updateProfileHandler}> |         <form className="divide-y divide-gray-200 lg:col-span-9" onSubmit={updateProfileHandler}> | ||||||
|           {hasErrors && <ErrorAlert message={errorMessage} />} |           {hasErrors && <ErrorAlert message={errorMessage} />} | ||||||
|  |  | ||||||
|  | @ -1,13 +1,12 @@ | ||||||
| import { GetServerSideProps } from "next"; | import { GetServerSideProps } from "next"; | ||||||
| import Head from "next/head"; | import Shell from "@components/Shell"; | ||||||
| import Shell from "../../components/Shell"; | import SettingsShell from "@components/Settings"; | ||||||
| import SettingsShell from "../../components/Settings"; |  | ||||||
| import { useEffect, useState } from "react"; | import { useEffect, useState } from "react"; | ||||||
| import type { Session } from "next-auth"; | import type { Session } from "next-auth"; | ||||||
| import { getSession, useSession } from "next-auth/client"; | import { getSession, useSession } from "next-auth/client"; | ||||||
| import { UsersIcon } from "@heroicons/react/outline"; | import { UsersIcon } from "@heroicons/react/outline"; | ||||||
| import TeamList from "../../components/team/TeamList"; | import TeamList from "@components/team/TeamList"; | ||||||
| import TeamListItem from "../../components/team/TeamListItem"; | import TeamListItem from "@components/team/TeamListItem"; | ||||||
| import Loader from "@components/Loader"; | import Loader from "@components/Loader"; | ||||||
| 
 | 
 | ||||||
| export default function Teams() { | export default function Teams() { | ||||||
|  | @ -59,10 +58,6 @@ export default function Teams() { | ||||||
| 
 | 
 | ||||||
|   return ( |   return ( | ||||||
|     <Shell heading="Teams" subtitle="Create and manage teams to use collaborative features."> |     <Shell heading="Teams" subtitle="Create and manage teams to use collaborative features."> | ||||||
|       <Head> |  | ||||||
|         <title>Teams | Calendso</title> |  | ||||||
|         <link rel="icon" href="/favicon.ico" /> |  | ||||||
|       </Head> |  | ||||||
|       <SettingsShell> |       <SettingsShell> | ||||||
|         <div className="divide-y divide-gray-200 lg:col-span-9"> |         <div className="divide-y divide-gray-200 lg:col-span-9"> | ||||||
|           <div className="py-6 lg:pb-8"> |           <div className="py-6 lg:pb-8"> | ||||||
|  |  | ||||||
|  | @ -1,6 +1,6 @@ | ||||||
| import Head from "next/head"; | import { HeadSeo } from "@components/seo/head-seo"; | ||||||
| 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"; | ||||||
|  | @ -10,7 +10,7 @@ import utc from "dayjs/plugin/utc"; | ||||||
| import toArray from "dayjs/plugin/toArray"; | import toArray from "dayjs/plugin/toArray"; | ||||||
| import timezone from "dayjs/plugin/timezone"; | import timezone from "dayjs/plugin/timezone"; | ||||||
| import { createEvent } from "ics"; | import { createEvent } from "ics"; | ||||||
| import { getEventName } from "../lib/event"; | import { getEventName } from "@lib/event"; | ||||||
| import Theme from "@components/Theme"; | import Theme from "@components/Theme"; | ||||||
| 
 | 
 | ||||||
| dayjs.extend(utc); | dayjs.extend(utc); | ||||||
|  | @ -61,13 +61,10 @@ export default function Success(props) { | ||||||
|   return ( |   return ( | ||||||
|     isReady && ( |     isReady && ( | ||||||
|       <div className="bg-neutral-50 dark:bg-neutral-900 h-screen"> |       <div className="bg-neutral-50 dark:bg-neutral-900 h-screen"> | ||||||
|         <Head> |         <HeadSeo | ||||||
|           <title> |           title={`Booking ${props.eventType.requiresConfirmation ? "Submitted" : "Confirmed"}`} | ||||||
|             Booking {props.eventType.requiresConfirmation ? "Submitted" : "Confirmed"} | {eventName} | |           description={`Booking ${props.eventType.requiresConfirmation ? "Submitted" : "Confirmed"}`} | ||||||
|             Calendso |         /> | ||||||
|           </title> |  | ||||||
|           <link rel="icon" href="/favicon.ico" /> |  | ||||||
|         </Head> |  | ||||||
|         <main className="max-w-3xl mx-auto py-24"> |         <main className="max-w-3xl mx-auto py-24"> | ||||||
|           <div className="fixed z-50 inset-0 overflow-y-auto"> |           <div className="fixed z-50 inset-0 overflow-y-auto"> | ||||||
|             <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="flex items-end justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0"> | ||||||
|  |  | ||||||
|  | @ -1,6 +1,5 @@ | ||||||
| import { GetServerSideProps } from "next"; | import { GetServerSideProps } from "next"; | ||||||
| import Head from "next/head"; | import { HeadSeo } from "@components/seo/head-seo"; | ||||||
| 
 |  | ||||||
| import Theme from "@components/Theme"; | import Theme from "@components/Theme"; | ||||||
| import { getTeam } from "@lib/teams/getTeam"; | import { getTeam } from "@lib/teams/getTeam"; | ||||||
| import Team from "@components/team/screens/Team"; | import Team from "@components/team/screens/Team"; | ||||||
|  | @ -11,11 +10,7 @@ export default function Page(props) { | ||||||
|   return ( |   return ( | ||||||
|     isReady && ( |     isReady && ( | ||||||
|       <div> |       <div> | ||||||
|         <Head> |         <HeadSeo title={props.team.name} description={props.team.name} /> | ||||||
|           <title>{props.team.name} | Calendso</title> |  | ||||||
|           <link rel="icon" href="/favicon.ico" /> |  | ||||||
|         </Head> |  | ||||||
| 
 |  | ||||||
|         <main className="mx-auto py-24 px-4"> |         <main className="mx-auto py-24 px-4"> | ||||||
|           <Team team={props.team} /> |           <Team team={props.team} /> | ||||||
|         </main> |         </main> | ||||||
|  |  | ||||||
|  | @ -4216,6 +4216,10 @@ next-auth@^3.28.0: | ||||||
|     preact-render-to-string "^5.1.14" |     preact-render-to-string "^5.1.14" | ||||||
|     querystring "^0.2.0" |     querystring "^0.2.0" | ||||||
| 
 | 
 | ||||||
|  | next-seo@^4.26.0: | ||||||
|  |   version "4.26.0" | ||||||
|  |   resolved "https://registry.yarnpkg.com/next-seo/-/next-seo-4.26.0.tgz#4218cfae5651fdc2e330dcdf1cc1b34ce199d41c" | ||||||
|  | 
 | ||||||
| next-transpile-modules@^8.0.0: | next-transpile-modules@^8.0.0: | ||||||
|   version "8.0.0" |   version "8.0.0" | ||||||
|   resolved "https://registry.npmjs.org/next-transpile-modules/-/next-transpile-modules-8.0.0.tgz#56375cdc25ae5d23a834195f277fc2737b26cb97" |   resolved "https://registry.npmjs.org/next-transpile-modules/-/next-transpile-modules-8.0.0.tgz#56375cdc25ae5d23a834195f277fc2737b26cb97" | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue
	
	 Mihai C
						Mihai C