From c79bc4229e2e87f5d55f08b2be289048811b3209 Mon Sep 17 00:00:00 2001 From: Sosokker Date: Wed, 13 Nov 2024 08:16:44 +0700 Subject: [PATCH] feat: add arrange meeting page --- src/app/calendar/MeetEventDialog.tsx | 128 +++++++++++++++++++++++ src/app/calendar/actions.ts | 41 ++++++++ src/app/calendar/page.tsx | 150 ++++++++++++++++++++++++--- src/components/auth/loginButton.tsx | 1 + src/components/auth/signupButton.tsx | 1 + 5 files changed, 308 insertions(+), 13 deletions(-) create mode 100644 src/app/calendar/MeetEventDialog.tsx create mode 100644 src/app/calendar/actions.ts diff --git a/src/app/calendar/MeetEventDialog.tsx b/src/app/calendar/MeetEventDialog.tsx new file mode 100644 index 0000000..f3b2bd0 --- /dev/null +++ b/src/app/calendar/MeetEventDialog.tsx @@ -0,0 +1,128 @@ +"use client"; + +import React, { useState } from "react"; +import { Button } from "@/components/ui/button"; +import { + Dialog, + DialogClose, + DialogContent, + DialogDescription, + DialogFooter, + DialogHeader, + DialogTitle, +} from "@/components/ui/dialog"; +import { Input } from "@/components/ui/input"; +import { Clock } from "lucide-react"; +import { DateTimePicker, TimePicker } from "@/components/ui/datetime-picker"; +import { Label } from "@/components/ui/label"; +import { createCalendarEvent } from "./actions"; +import { Session } from "@supabase/supabase-js"; + +interface DialogProps { + children?: React.ReactNode; + open?: boolean; + defaultOpen?: boolean; + // eslint-disable-next-line no-unused-vars + onOpenChange?(open: boolean): void; + modal?: boolean; + session: Session; + projectName: string; +} + +export function MeetEventDialog(props: DialogProps) { + const [eventDate, setEventDate] = useState(undefined); + const [startTime, setStartTime] = useState(undefined); + const [endTime, setEndTime] = useState(undefined); + const [eventName, setEventName] = useState(`Meet with ${props.projectName}`); + const [eventDescription, setEventDescription] = useState( + "Meet and gather more information on business in B2DVentures" + ); + const [noteToBusiness, setNoteToBusiness] = useState(""); + const session = props.session; + + const handleCreateEvent = async () => { + if (!session || !eventDate || !startTime || !endTime || !eventName) { + alert("Please fill in all event details."); + return; + } + + const startDate = new Date(eventDate); + startDate.setHours(startTime.getHours(), startTime.getMinutes()); + + const endDate = new Date(eventDate); + endDate.setHours(endTime.getHours(), endTime.getMinutes()); + await createCalendarEvent(session, startDate, endDate, eventName, eventDescription); + props.onOpenChange?.(false); + }; + + return ( + + + + + + Arrange Meeting + + + Arrange a meeting with the business you're interested in for more information. + + + +
+
+ + setEventName(e.target.value)} + /> +
+
+ + setEventDescription(e.target.value)} + /> +
+
+ + setNoteToBusiness(e.target.value)} + /> +
+
+ + +
+
+
+ + +
+
+ + +
+
+
+ + + + + + + +
+
+ ); +} diff --git a/src/app/calendar/actions.ts b/src/app/calendar/actions.ts new file mode 100644 index 0000000..9d9bed6 --- /dev/null +++ b/src/app/calendar/actions.ts @@ -0,0 +1,41 @@ +import { Session } from "@supabase/supabase-js"; + +export async function createCalendarEvent( + session: Session, + start: Date, + end: Date, + eventName: string, + eventDescription: string +) { + console.log("Creating calendar event"); + + const event = { + summary: eventName, + description: eventDescription, + start: { + dateTime: start.toISOString(), + timeZone: Intl.DateTimeFormat().resolvedOptions().timeZone, + }, + end: { + dateTime: end.toISOString(), + timeZone: Intl.DateTimeFormat().resolvedOptions().timeZone, + }, + }; + + try { + const response = await fetch("https://www.googleapis.com/calendar/v3/calendars/primary/events", { + method: "POST", + headers: { + Authorization: "Bearer " + session.provider_token, + }, + body: JSON.stringify(event), + }); + + const data = await response.json(); + console.log(data); + alert("Event created, check your Google Calendar!"); + } catch (error) { + console.error("Error creating calendar event:", error); + alert("Failed to create the event."); + } +} diff --git a/src/app/calendar/page.tsx b/src/app/calendar/page.tsx index 88e8ca8..2babbbe 100644 --- a/src/app/calendar/page.tsx +++ b/src/app/calendar/page.tsx @@ -1,21 +1,145 @@ "use client"; -import React, { useState } from "react"; -import { DateTimePicker } from "@/components/ui/datetime-picker"; -import { Label } from "@/components/ui/label"; + +import React, { useMemo, useState } from "react"; +import useSession from "@/lib/supabase/useSession"; +import { MeetEventDialog } from "./MeetEventDialog"; +import { Clock } from "lucide-react"; +import { Separator } from "@/components/ui/separator"; +import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from "@/components/ui/card"; +import { + Table, + TableBody, + TableCaption, + TableCell, + TableHeader, + TableHead, + TableRow, + TableFooter, +} from "@/components/ui/table"; +import { Button } from "@/components/ui/button"; +import { useQuery } from "@supabase-cache-helpers/postgrest-react-query"; +import { getInvestmentByUserId } from "@/lib/data/investmentQuery"; +import { LegacyLoader } from "@/components/loading/LegacyLoader"; +import { createSupabaseClient } from "@/lib/supabase/clientComponentClient"; + +interface Investment { + id: any; + project_id: any; + project_name: any; + project_short_description: any; + dataroom_id: any; + deal_amount: any; + investor_id: any; + created_time: any; +} const DatetimePickerHourCycle = () => { - const [date12, setDate12] = useState(undefined); - const [date24, setDate24] = useState(undefined); + const supabase = createSupabaseClient(); + const [showModal, setShowModal] = useState(false); + const [currentProjectName, setCurrentProjectName] = useState(""); + const { session, loading } = useSession(); + + const { + data: investments = [], + error: investmentsError, + isLoading: isLoadingInvestments, + } = useQuery(getInvestmentByUserId(supabase, session?.user.id ?? ""), { + enabled: !!session?.user.id, + }); + + if (investmentsError) { + throw "Error load investment data"; + } + + const projectInvestments = useMemo(() => { + if (!investments) return {}; + + return investments.reduce((acc: { [key: string]: Investment[] }, investment: Investment) => { + const projectId = investment.project_id; + if (!acc[projectId]) { + acc[projectId] = []; + } + acc[projectId].push(investment); + return acc; + }, {}); + }, [investments]); + + if (loading) { + return ; + } + + if (!session || !session?.user.id) { + throw "Can't load session!"; + } + + if (isLoadingInvestments) { + return ; + } + return ( -
-
- - -
-
- - +
+ + +

Schedule Meeting

+
+ +
+ {Object.entries(projectInvestments).map(([projectId, projectInvestments]) => ( + + + {projectInvestments[0].project_name} + {projectInvestments[0].project_short_description} + + + + Investments for this project + + + Investment Id + Invested At + Amount + + + + {projectInvestments.map((investment) => ( + + {investment.id} + {investment.created_time} + {investment.deal_amount} + + ))} + + + + Total + + {projectInvestments + .reduce((total, investment) => total + (parseFloat(investment.deal_amount) || 0), 0) + .toLocaleString("en-US", { style: "currency", currency: "USD" })} + + + +
+
+ + + +
+ ))}
+
); }; diff --git a/src/components/auth/loginButton.tsx b/src/components/auth/loginButton.tsx index 9c7c8ba..abca970 100644 --- a/src/components/auth/loginButton.tsx +++ b/src/components/auth/loginButton.tsx @@ -12,6 +12,7 @@ export function LoginButton(props: { nextUrl?: string }) { provider: "google", options: { redirectTo: `${location.origin}/auth/callback?next=${props.nextUrl || ""}`, + scopes: "https://www.googleapis.com/auth/calendar", }, }); }; diff --git a/src/components/auth/signupButton.tsx b/src/components/auth/signupButton.tsx index 4e7e339..fae586e 100644 --- a/src/components/auth/signupButton.tsx +++ b/src/components/auth/signupButton.tsx @@ -12,6 +12,7 @@ export function SignupButton(props: { nextUrl?: string }) { provider: "google", options: { redirectTo: `${location.origin}/auth/callback?next=${props.nextUrl || ""}`, + scopes: "https://www.googleapis.com/auth/calendar", }, }); };