2021-03-30 15:15:55 +00:00
import Head from 'next/head' ;
import Link from 'next/link' ;
import prisma from '../lib/prisma' ;
import Shell from '../components/Shell' ;
import { signIn , useSession , getSession } from 'next-auth/client' ;
2021-05-11 13:11:17 +00:00
import { ClockIcon , CheckIcon , InformationCircleIcon } from '@heroicons/react/outline' ;
2021-05-13 14:44:48 +00:00
import DonateBanner from '../components/DonateBanner' ;
2021-05-11 13:11:17 +00:00
function classNames ( . . . classes ) {
return classes . filter ( Boolean ) . join ( ' ' )
}
2021-03-22 13:48:48 +00:00
2021-03-30 15:15:55 +00:00
export default function Home ( props ) {
2021-05-11 13:11:17 +00:00
const [ session , loading ] = useSession ( ) ;
2021-03-30 15:15:55 +00:00
if ( loading ) {
return < p className = "text-gray-400" > Loading . . . < / p > ;
2021-04-17 20:13:42 +00:00
}
2021-03-24 15:03:04 +00:00
2021-05-11 13:11:17 +00:00
function convertMinsToHrsMins ( mins ) {
let h = Math . floor ( mins / 60 ) ;
let m = mins % 60 ;
h = h < 10 ? '0' + h : h ;
m = m < 10 ? '0' + m : m ;
return ` ${ h } : ${ m } ` ;
}
const stats = [
{ name : 'Event Types' , stat : props.eventTypeCount } ,
{ name : 'Integrations' , stat : props.integrationCount } ,
2021-05-25 20:34:18 +00:00
{ name : 'Available Hours' , stat : Math.round ( ( ( props . user . endTime - props . user . startTime ) / 60 ) * 100 ) / 100 + ' hours' } ,
2021-05-11 13:11:17 +00:00
] ;
let timeline = [ ] ;
if ( session ) {
timeline = [
{
id : 1 ,
content : 'Add your first' ,
target : 'integration' ,
href : '/integrations' ,
icon : props.integrationCount != 0 ? CheckIcon : InformationCircleIcon ,
iconBackground : props.integrationCount != 0 ? 'bg-green-400' : 'bg-gray-400' ,
} ,
{
id : 2 ,
content : 'Add one or more' ,
target : 'event types' ,
href : '/availability' ,
icon : props.eventTypeCount != 0 ? CheckIcon : InformationCircleIcon ,
iconBackground : props.eventTypeCount != 0 ? 'bg-green-400' : 'bg-gray-400' ,
} ,
{
id : 3 ,
content : 'Complete your' ,
target : 'profile' ,
href : '/settings/profile' ,
icon : session.user.image ? CheckIcon : InformationCircleIcon ,
iconBackground : session.user.image ? 'bg-green-400' : 'bg-gray-400' ,
} ,
] ;
} else {
timeline = [ ] ;
}
return (
2021-03-30 15:15:55 +00:00
< div >
< Head >
< title > Calendso < / title >
< link rel = "icon" href = "/favicon.ico" / >
< / Head >
< Shell heading = "Dashboard" >
2021-05-26 19:47:06 +00:00
< div className = "md:grid grid-cols-3 gap-4" >
2021-03-30 15:15:55 +00:00
< div className = "col-span-2" >
2021-05-11 13:11:17 +00:00
< div className = "rounded-lg bg-white shadow" >
< div className = "pt-5 pb-2 px-6 sm:flex sm:items-center sm:justify-between" >
< h3 className = "text-lg leading-6 font-medium text-gray-900" >
Your stats
< / h3 >
< / div >
< dl className = "grid grid-cols-1 overflow-hidden divide-y divide-gray-200 md:grid-cols-3 md:divide-y-0 md:divide-x" >
{ stats . map ( ( item ) = > (
< div key = { item . name } className = "px-4 py-5 sm:p-6" >
< dt className = "text-base font-normal text-gray-900" > { item . name } < / dt >
< dd className = "mt-1 flex justify-between items-baseline md:block lg:flex" >
< div className = "flex items-baseline text-2xl font-semibold text-blue-600" >
{ item . stat }
< / div >
< / dd >
< / div >
) ) }
< / dl >
< / div >
2021-05-26 19:47:06 +00:00
< div className = "mt-8 bg-white shadow overflow-hidden rounded-md" >
2021-05-11 13:11:17 +00:00
< div className = "pt-5 pb-2 px-6 sm:flex sm:items-center sm:justify-between" >
2021-03-30 15:15:55 +00:00
< h3 className = "text-lg leading-6 font-medium text-gray-900" >
2021-05-11 13:11:17 +00:00
Your event types
2021-03-30 15:15:55 +00:00
< / h3 >
2021-05-11 13:11:17 +00:00
< / div >
< ul className = "divide-y divide-gray-200" >
{ props . eventTypes . map ( ( type ) = > (
< li key = { type . id } >
< div className = "px-4 py-4 flex items-center sm:px-6" >
< div className = "min-w-0 flex-1 sm:flex sm:items-center sm:justify-between" >
< div className = "truncate" >
< div className = "flex text-sm" >
< p className = "font-medium text-blue-600 truncate" > { type . title } < / p >
< p className = "ml-1 flex-shrink-0 font-normal text-gray-500" > in { type . description } < / p >
< / div >
< div className = "mt-2 flex" >
< div className = "flex items-center text-sm text-gray-500" >
< ClockIcon className = "flex-shrink-0 mr-1.5 h-5 w-5 text-gray-400" aria - hidden = "true" / >
< p >
{ type . length } minutes
< / p >
< / div >
< / div >
< / div >
< / div >
< div className = "ml-5 flex-shrink-0" >
< Link href = { "/" + session . user . username + "/" + type . slug } > < a target = "_blank" className = "text-blue-600 hover:text-blue-900 mr-2 font-medium" > View < / a > < / Link >
< / div >
< / div >
< / li >
) ) }
< / ul >
< / div >
2021-05-26 19:47:06 +00:00
< div className = "mt-8 bg-white shadow overflow-hidden rounded-md p-6 mb-8 md:mb-0" >
< div className = "md:flex" >
< div className = "md:w-1/2 self-center mb-8 md:mb-0" >
2021-05-11 13:11:17 +00:00
< h2 className = "text-2xl font-semibold" > Getting started < / h2 >
< p className = "text-gray-600 text-sm" > Steps you should take to get started with Calendso . < / p >
2021-03-29 21:01:12 +00:00
< / div >
2021-05-26 19:47:06 +00:00
< div className = "md:w-1/2" >
2021-05-11 13:11:17 +00:00
< div className = "flow-root" >
< ul className = "-mb-8" >
{ timeline . map ( ( event , eventIdx ) = > (
< li key = { event . id } >
< div className = "relative pb-8" >
{ eventIdx !== timeline . length - 1 ? (
< span className = "absolute top-4 left-4 -ml-px h-full w-0.5 bg-gray-200" aria - hidden = "true" / >
) : null }
< div className = "relative flex space-x-3" >
< div >
< span
className = { classNames (
event . iconBackground ,
'h-8 w-8 rounded-full flex items-center justify-center ring-8 ring-white'
) }
>
< event.icon className = "h-5 w-5 text-white" aria - hidden = "true" / >
< / span >
< / div >
< div className = "min-w-0 flex-1 pt-1.5 flex justify-between space-x-4" >
< div >
< p className = "text-sm text-gray-500" >
{ event . content } { ' ' }
< Link href = { event . href } >
< a className = "font-medium text-gray-900" >
{ event . target }
< / a >
< / Link >
< / p >
< / div >
< / div >
< / div >
< / div >
< / li >
) ) }
< / ul >
< / div >
2021-03-29 21:01:12 +00:00
< / div >
< / div >
< / div >
< / div >
2021-03-30 15:15:55 +00:00
< div >
2021-04-19 17:36:39 +00:00
< div className = "bg-white rounded-lg shadow px-5 py-6 md:py-7 sm:px-6" >
2021-05-11 13:11:17 +00:00
< div className = "mb-4 sm:flex sm:items-center sm:justify-between" >
< h3 className = "text-lg leading-6 font-medium text-gray-900" >
Your day
< / h3 >
< div className = "mt-3 sm:mt-0 sm:ml-4" >
< Link href = "/availability" >
< a className = "text-sm text-gray-400" > Configure < / a >
< / Link >
< / div >
< / div >
< div >
< p className = "text-2xl font-semibold text-gray-600" > Offering time slots between < span className = "text-blue-600" > { convertMinsToHrsMins ( props . user . startTime ) } < / span > and < span className = "text-blue-600" > { convertMinsToHrsMins ( props . user . endTime ) } < / span > < / p >
< / div >
< / div >
< div className = "mt-8 bg-white rounded-lg shadow px-5 py-6 md:py-7 sm:px-6" >
2021-03-30 15:15:55 +00:00
< div className = "mb-8 sm:flex sm:items-center sm:justify-between" >
< h3 className = "text-lg leading-6 font-medium text-gray-900" >
Your integrations
< / h3 >
< div className = "mt-3 sm:mt-0 sm:ml-4" >
< Link href = "/integrations" >
< a className = "text-sm text-gray-400" > View more < / a >
< / Link >
< / div >
< / div >
< ul className = "divide-y divide-gray-200" >
2021-04-21 22:10:48 +00:00
{ props . credentials . map ( ( integration ) = >
2021-03-30 15:15:55 +00:00
< li className = "pb-4 flex" >
{ integration . type == 'google_calendar' && < img className = "h-10 w-10 mr-2" src = "integrations/google-calendar.png" alt = "Google Calendar" / > }
2021-04-21 22:10:48 +00:00
{ integration . type == 'office365_calendar' && < img className = "h-10 w-10 mr-2" src = "integrations/office-365.png" alt = "Office 365 / Outlook.com Calendar" / > }
2021-03-30 15:15:55 +00:00
< div className = "ml-3" >
2021-04-21 22:10:48 +00:00
{ integration . type == 'office365_calendar' && < p className = "text-sm font-medium text-gray-900" > Office 365 / Outlook . com Calendar < / p > }
2021-03-30 15:15:55 +00:00
{ integration . type == 'google_calendar' && < p className = "text-sm font-medium text-gray-900" > Google Calendar < / p > }
2021-04-21 22:10:48 +00:00
< p className = "text-sm text-gray-500" > Calendar Integration < / p >
2021-03-30 15:15:55 +00:00
< / div >
< / li >
) }
2021-04-21 22:10:48 +00:00
{ props . credentials . length == 0 &&
2021-03-31 20:10:53 +00:00
< div className = "text-center text-gray-400 py-2" >
< p > You haven ' t added any integrations . < / p >
< / div >
}
2021-03-30 15:15:55 +00:00
< / ul >
< / div >
2021-05-11 13:11:17 +00:00
< div className = "mt-8 bg-white rounded-lg shadow px-5 py-6 md:py-7 sm:px-6" >
< div className = "mb-4 sm:flex sm:items-center sm:justify-between" >
< h3 className = "text-lg leading-6 font-medium text-gray-900" >
Your event types
< / h3 >
< div className = "mt-3 sm:mt-0 sm:ml-4" >
< Link href = "/availability" >
< a className = "text-sm text-gray-400" > View more < / a >
< / Link >
< / div >
< / div >
< ul className = "divide-y divide-gray-200" >
{ props . eventTypes . map ( ( type ) = > (
< li
key = { type . id }
className = "relative bg-white py-5 hover:bg-gray-50 focus-within:ring-2 focus-within:ring-inset focus-within:ring-indigo-600"
>
< div className = "flex justify-between space-x-3" >
< div className = "min-w-0 flex-1" >
< a href = "#" className = "block focus:outline-none" >
< span className = "absolute inset-0" aria - hidden = "true" / >
< p className = "text-sm font-medium text-gray-900 truncate" > { type . title } < / p >
< p className = "text-sm text-gray-500 truncate" > { type . description } < / p >
< / a >
< / div >
< span className = "flex-shrink-0 whitespace-nowrap text-sm text-gray-500" >
{ type . length } minutes
< / span >
< / div >
< / li >
) ) }
< / ul >
< / div >
2021-03-30 15:15:55 +00:00
< / div >
< / div >
2021-05-13 13:07:27 +00:00
< DonateBanner / >
2021-03-30 15:15:55 +00:00
< / Shell >
< / div >
) ;
2021-03-22 13:48:48 +00:00
}
2021-03-30 15:15:55 +00:00
export async function getServerSideProps ( context ) {
const session = await getSession ( context ) ;
2021-05-11 13:11:17 +00:00
let user = [ ] ;
2021-03-30 15:15:55 +00:00
let credentials = [ ] ;
2021-05-11 13:11:17 +00:00
let eventTypes = [ ] ;
2021-03-30 15:15:55 +00:00
if ( session ) {
2021-05-11 13:11:17 +00:00
user = await prisma . user . findFirst ( {
2021-03-30 15:15:55 +00:00
where : {
email : session.user.email ,
} ,
select : {
2021-05-11 13:11:17 +00:00
id : true ,
startTime : true ,
endTime : true
2021-03-30 15:15:55 +00:00
}
} ) ;
2021-04-21 22:10:48 +00:00
2021-03-30 15:15:55 +00:00
credentials = await prisma . credential . findMany ( {
where : {
2021-05-22 19:12:06 +00:00
userId : session.user.id ,
2021-03-30 15:15:55 +00:00
} ,
select : {
type : true
}
} ) ;
2021-05-11 13:11:17 +00:00
eventTypes = await prisma . eventType . findMany ( {
where : {
2021-05-22 19:12:06 +00:00
userId : session.user.id ,
2021-05-11 13:11:17 +00:00
}
} ) ;
2021-03-30 15:15:55 +00:00
}
return {
2021-05-22 19:12:06 +00:00
props : { user , credentials , eventTypes , eventTypeCount : eventTypes.length , integrationCount : credentials.length } , // will be passed to the page component as props
2021-03-30 15:15:55 +00:00
}
}