feat: add arrange meeting page

This commit is contained in:
Sosokker 2024-11-13 08:16:44 +07:00
parent 0b76ed64da
commit c79bc4229e
5 changed files with 308 additions and 13 deletions

View File

@ -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<Date | undefined>(undefined);
const [startTime, setStartTime] = useState<Date | undefined>(undefined);
const [endTime, setEndTime] = useState<Date | undefined>(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<string>("");
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 (
<Dialog {...props}>
<DialogContent className="sm:max-w-md">
<DialogHeader>
<DialogTitle className="flex gap-2 items-center">
<Clock />
Arrange Meeting
</DialogTitle>
<DialogDescription>
Arrange a meeting with the business you&apos;re interested in for more information.
</DialogDescription>
</DialogHeader>
<div className="space-y-4 w-[90%]">
<div>
<Label htmlFor="eventName">Event Name</Label>
<Input
id="eventName"
placeholder="Enter event name"
value={eventName}
onChange={(e) => setEventName(e.target.value)}
/>
</div>
<div>
<Label htmlFor="eventDescription">Event Description</Label>
<Input
id="eventDescription"
placeholder="Enter event description"
value={eventDescription}
onChange={(e) => setEventDescription(e.target.value)}
/>
</div>
<div>
<Label htmlFor="eventDescription">Event Description</Label>
<Input
id="note"
placeholder="Your note to business"
value={noteToBusiness}
onChange={(e) => setNoteToBusiness(e.target.value)}
/>
</div>
<div>
<Label>Date</Label>
<DateTimePicker granularity="day" hourCycle={24} value={eventDate} onChange={setEventDate} />
</div>
<div>
<div>
<Label>Start Time</Label>
<TimePicker date={startTime} onChange={setStartTime} />
</div>
<div>
<Label>End Time</Label>
<TimePicker date={endTime} onChange={setEndTime} />
</div>
</div>
</div>
<DialogFooter className="sm:justify-start mt-4">
<Button type="button" onClick={handleCreateEvent} className="mr-2">
Create Event
</Button>
<DialogClose asChild>
<Button type="button" variant="secondary">
Close
</Button>
</DialogClose>
</DialogFooter>
</DialogContent>
</Dialog>
);
}

View File

@ -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.");
}
}

View File

@ -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<Date | undefined>(undefined);
const [date24, setDate24] = useState<Date | undefined>(undefined);
const supabase = createSupabaseClient();
const [showModal, setShowModal] = useState<boolean>(false);
const [currentProjectName, setCurrentProjectName] = useState<string>("");
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 <LegacyLoader />;
}
if (!session || !session?.user.id) {
throw "Can't load session!";
}
if (isLoadingInvestments) {
return <LegacyLoader />;
}
return (
<div className="flex flex-col gap-3 lg:flex-row">
<div className="flex w-72 flex-col gap-2">
<Label>12 Hour</Label>
<DateTimePicker hourCycle={12} value={date12} onChange={setDate12} />
</div>
<div className="flex w-72 flex-col gap-2">
<Label>24 Hour</Label>
<DateTimePicker hourCycle={24} value={date24} onChange={setDate24} />
<div className="container max-w-screen-xl">
<span className="flex gap-2 items-center mt-4">
<Clock />
<p className="text-2xl font-bold">Schedule Meeting</p>
</span>
<Separator className="my-3" />
<div className="space-y-2">
{Object.entries(projectInvestments).map(([projectId, projectInvestments]) => (
<Card key={projectId}>
<CardHeader>
<CardTitle className="text-xl">{projectInvestments[0].project_name}</CardTitle>
<CardDescription>{projectInvestments[0].project_short_description}</CardDescription>
</CardHeader>
<CardContent>
<Table>
<TableCaption>Investments for this project</TableCaption>
<TableHeader>
<TableRow>
<TableHead className="w-[100px]">Investment Id</TableHead>
<TableHead>Invested At</TableHead>
<TableHead className="text-right">Amount</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{projectInvestments.map((investment) => (
<TableRow key={investment.id}>
<TableCell className="font-medium">{investment.id}</TableCell>
<TableCell>{investment.created_time}</TableCell>
<TableCell className="text-right">{investment.deal_amount}</TableCell>
</TableRow>
))}
</TableBody>
<TableFooter>
<TableRow>
<TableCell colSpan={2}>Total</TableCell>
<TableCell className="text-right">
{projectInvestments
.reduce((total, investment) => total + (parseFloat(investment.deal_amount) || 0), 0)
.toLocaleString("en-US", { style: "currency", currency: "USD" })}
</TableCell>
</TableRow>
</TableFooter>
</Table>
</CardContent>
<CardFooter>
<Button
onClick={() => {
setCurrentProjectName(projectInvestments[0].project_name);
setShowModal(true);
}}
>
Schedule Meeting
</Button>
</CardFooter>
</Card>
))}
</div>
<MeetEventDialog
open={showModal}
onOpenChange={setShowModal}
session={session}
projectName={currentProjectName}
/>
</div>
);
};

View File

@ -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",
},
});
};

View File

@ -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",
},
});
};