Skip to content

Commit

Permalink
Merge branch 'add/googleCalendar' of https://github.com/UTDNebula/jup…
Browse files Browse the repository at this point in the history
…iter into add/googleCalendar
  • Loading branch information
MistahSanta committed Aug 26, 2024
2 parents d912ab5 + deb3d4b commit 28d015c
Show file tree
Hide file tree
Showing 11 changed files with 294 additions and 18 deletions.
10 changes: 0 additions & 10 deletions .env.example

This file was deleted.

Binary file added public/images/google_calendar_icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/images/microsoft-outlook-icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
10 changes: 10 additions & 0 deletions src/app/api/googleCalendar.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { getSession } from "next-auth/react";

export const createGoogleCalenderEvent = () => {
const session = getSession();

if(!session ) {
console.log(session);
return
}
}
14 changes: 12 additions & 2 deletions src/components/events/EventCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ import EventTimeAlert from './EventTimeAlert';
import { type RouterOutputs } from '@src/trpc/shared';
import EventLikeButton from '../EventLikeButton';
import { getServerAuthSession } from '@src/server/auth';
import AddToCalendarButton from './calendar/AddToCalendarButton';
import AddToCalendarAuthorizedButton from './calendar/AddToCalendarAuthorizedButton';


type EventCardProps = {
event: RouterOutputs['event']['findByFilters']['events'][number];
Expand Down Expand Up @@ -58,10 +61,15 @@ const HorizontalCard = async ({
{event.description}
</p>
</div>
<div className="ml-auto flex flex-row space-x-4">
<div className="ml-auto flex flex-row space-x-4 ">
{session && (
<EventLikeButton liked={event.liked} eventId={event.id} />

)}
{ session
? <AddToCalendarAuthorizedButton event={event} session={session} />
: <AddToCalendarButton event={event} /> }

<Link
className=" h-10 w-10 rounded-full bg-blue-primary p-1.5 shadow-lg transition-colors hover:bg-blue-700 active:bg-blue-800"
href={`/event/${event.id}`}
Expand Down Expand Up @@ -122,14 +130,16 @@ const VerticalCard = async ({
</div>
</h4>
</div>
<div className="mt-auto flex flex-row space-x-4">
<div className="mt-auto flex flex-row space-x-4 ">
<Link
className=" h-10 w-10 rounded-full bg-blue-primary p-1.5 shadow-lg transition-colors hover:bg-blue-700 active:bg-blue-800"
href={`/event/${event.id}`}
passHref
>
<MoreIcon fill="fill-white" />
</Link>
<AddToCalendarButton event={event} />

{session && (
<EventLikeButton liked={event.liked} eventId={event.id} />
)}
Expand Down
71 changes: 71 additions & 0 deletions src/components/events/calendar/AddToCalendarAuthorizedButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
"use client";
import { type RouterOutputs } from '@src/trpc/shared';
import { CalendarButton } from '@src/icons/Icons';
import { type Session } from 'next-auth';
import { useState } from 'react'




export const AddToCalendarAuthorizedButton = ({
event, session
}: {
event: RouterOutputs['event']['findByFilters']['events'][number];
session: Session;
}) => {
const [status, setStatus] = useState('')

// This function will check if the user is authenticated and auto add the desired event to their google calendara
const createGoogleCalenderEvent = async(session: Session, event : RouterOutputs['event']['findByFilters']['events'][number] ) => {
// Assume that session is already active since the user was able to reach this button
if (session.user && session.user.access_token ) {

const {name, startTime, endTime, description, location} = event
try {
const response = await fetch('/api/calendaar/add-event', {
method:'POST',
headers: {
'Content-Type': 'applicaation/json',
'Authorization': `Bearer ${session.user.access_token}`
},
body: JSON.stringify({
name,
startTime,
endTime,
description,
location
})
})

if (!response.ok) {
throw new Error("failed to add event to calendar!")
}

const data = await response.json();
setStatus("Event added successfully!")
console.log("Event added successfully!")
} catch( e ) {

setStatus(`Error when trying to add event: ${e}`)
console.log(`Error when trying to add event: ${e}`)
}
} else
{ // TODO redirect to the regular button sign in or ask if user want to sign in
setStatus("User is not authenticated!")
console.log("User is not authenicated!")
}
}


// TODO onClick error with async function - incompatible types.
return (
<main className="relative flex h-10 w-10 cursor-pointer items-center justify-center rounded-full shadow-md inset-0 overflow-visible">

<button onClick={createGoogleCalenderEvent(session, event)}>
<CalendarButton /> auth
</button>
</main>
);
}

export default AddToCalendarAuthorizedButton;
30 changes: 30 additions & 0 deletions src/components/events/calendar/AddToCalendarButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
"use client";

import { CalendarButton } from '@src/icons/Icons';
import {useState} from 'react';
import CalendarPopUp from './CalendarPopUp';
import { type RouterOutputs } from '@src/trpc/shared';

export default function AddToCalendarButton( {
event,
}: {
event: RouterOutputs['event']['findByFilters']['events'][number];
})
{

const [isOpen, setIsOpen] = useState(false);

const handlePopUp = () => { setIsOpen(!isOpen); }

return (

<main className="relative flex h-10 w-10 cursor-pointer items-center justify-center rounded-full shadow-md inset-0 overflow-visible">

<button onClick={handlePopUp} >
<CalendarButton />
</button>
<CalendarPopUp isOpen={isOpen} onClose={handlePopUp} event={event} />

</main>
);
}
82 changes: 82 additions & 0 deletions src/components/events/calendar/CalendarPopUp.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
import * as Dialog from '@radix-ui/react-dialog';
import {CloseIcon} from '@src/icons/Icons';
import { CalendarButton } from '@src/icons/Icons';
import googleCalendarIcon from "public/images/google_calendar_icon.png"
import outlookCalendarIcon from "public/images/microsoft-outlook-icon.png";
import Image from 'next/image';
import { type RouterOutputs } from '@src/trpc/shared';

type CalendarPopUpProps = {
isOpen: boolean,
onClose: () => void
event: RouterOutputs['event']['findByFilters']['events'][number];
}

const CalendarPopUp: React.FC<CalendarPopUpProps> = ({isOpen, onClose, event}) => {
const generateGoogleCalendarLink = () => {
const startTime = event.startTime.toISOString().replace(/-|:|\.\d+/g, '');
const endTime = event.endTime.toISOString().replace(/-|:|\.\d+/g, '');
const googleCalendarLink = `https://calendar.google.com/calendar/render?action=TEMPLATE&text=${event.name}&dates=${startTime}/${endTime}&details=${event.description}&location=${event.location}`;

window.open(googleCalendarLink, '_blank');
}

const generateOutlookCalendarLink = () => {
const startTime = event.startTime.toISOString().split('.')[0] + "Z";
const endTime = event.endTime.toISOString().split('.')[0] + "Z";

const outlookCalendarLink = `https://outlook.live.com/owa/?path=/calendar/action/compose&rru=addevent&subject=${event.name}&startdt=${startTime}&enddt=${endTime}&location=${event.location}&body=${event.description}`;
window.open(outlookCalendarLink, '_blank');
}

return (
<Dialog.Root open={isOpen} onOpenChange={onClose}>
<Dialog.Portal>
<Dialog.Overlay className="fixed inset-0 z-20 bg-black bg-opacity-50" />
<Dialog.Content className="fixed inset-0 z-20 h-1/3 w-1/2 max-w-screen-sm transform self-center justify-self-center rounded-md bg-white p-10 text-center shadow-lg">
<Dialog.Title className="mt-4 border-b-2 border-slate-200 pb-4 text-center font-bold text-slate-700 md:text-4xl">
Add to Calendar
</Dialog.Title>

<Dialog.Description className="mt-8 md:mt-8 md:font-semibold flex justify-center space-x-6">
<button className="relative z-10 cursor-pointer shadow-md" onClick={ generateGoogleCalendarLink } >
<Image
src={googleCalendarIcon}
alt="Google Calendar Icon"
width={50}
height={50}
/>
</button>
<button className="relative z-10 cursor-pointer shadow-md" onClick={ generateOutlookCalendarLink } >
<Image
src={outlookCalendarIcon}
alt="Outlook Calendar Icon"
width={50}
height={50}
/>
</button>
</Dialog.Description>

<Dialog.Close className="absolute right-0 top-0 z-50 m-2" onClick={onClose}>
<CloseIcon />
</Dialog.Close>

<div className="absolute inset-0 flex justify-center">
<div className="absolute -top-16 flex h-24 w-24 transform items-center justify-center rounded-full bg-blue-500 text-white shadow-lg">
<div >
<CalendarButton />
</div>
</div>
</div>


</Dialog.Content>
</Dialog.Portal>
</Dialog.Root>
)


}


export default CalendarPopUp;
17 changes: 17 additions & 0 deletions src/icons/Icons.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -368,6 +368,23 @@ export const CloseIcon = () => (
</svg>
);

export const CalendarButton = () => (
<svg
xmlns="http://www.w3.org/2000/svg"
fill="white"
viewBox="0 0 24 24"
strokeWidth={1.5}
stroke="currentColor"
className="h-6 w-6"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
d="M6.75 3v2.25M17.25 3v2.25M3 18.75V7.5a2.25 2.25 0 0 1 2.25-2.25h13.5A2.25 2.25 0 0 1 21 7.5v11.25m-18 0A2.25 2.25 0 0 0 5.25 21h13.5A2.25 2.25 0 0 0 21 18.75m-18 0v-7.5A2.25 2.25 0 0 1 5.25 9h13.5A2.25 2.25 0 0 1 21 11.25v7.5"
/>
</svg>
);

export const UploadIcon = () => (
<svg
xmlns="http://www.w3.org/2000/svg"
Expand Down
Loading

0 comments on commit 28d015c

Please sign in to comment.