mirror of
https://github.com/Sosokker/B2D-Ventures.git
synced 2025-12-18 13:34:06 +01:00
feat: add page to view schedule meeting for business
This commit is contained in:
parent
bf1226a704
commit
af351aa481
101
src/app/calendar/manage/ManageMeetDialog.tsx
Normal file
101
src/app/calendar/manage/ManageMeetDialog.tsx
Normal file
@ -0,0 +1,101 @@
|
||||
"use client";
|
||||
|
||||
import React from "react";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import {
|
||||
Dialog,
|
||||
DialogClose,
|
||||
DialogContent,
|
||||
DialogDescription,
|
||||
DialogFooter,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
} from "@/components/ui/dialog";
|
||||
import { Table, TableBody, TableCell, TableFooter, TableHead, TableHeader, TableRow } from "@/components/ui/table";
|
||||
import { Clock } from "lucide-react";
|
||||
import { createSupabaseClient } from "@/lib/supabase/clientComponentClient";
|
||||
|
||||
import getMeetingLog from "./actions";
|
||||
import { useQuery } from "@supabase-cache-helpers/postgrest-react-query";
|
||||
import { LegacyLoader } from "@/components/loading/LegacyLoader";
|
||||
|
||||
interface DialogProps {
|
||||
children?: React.ReactNode;
|
||||
open?: boolean;
|
||||
defaultOpen?: boolean;
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
onOpenChange?(open: boolean): void;
|
||||
modal?: boolean;
|
||||
projectId: number;
|
||||
}
|
||||
|
||||
export function ManageMeetDialog(props: DialogProps) {
|
||||
const supabase = createSupabaseClient();
|
||||
const {
|
||||
data: meetingLog,
|
||||
error: meetingLogError,
|
||||
isLoading: isLoadingMeetingLog,
|
||||
} = useQuery(getMeetingLog(supabase, props.projectId), {
|
||||
enabled: !!props.projectId,
|
||||
});
|
||||
|
||||
return (
|
||||
<Dialog {...props}>
|
||||
<DialogContent className="sm:max-w-md overflow-y-auto h-[80%]">
|
||||
<DialogHeader>
|
||||
<DialogTitle className="flex gap-2 items-center">
|
||||
<Clock />
|
||||
Meeting Request
|
||||
</DialogTitle>
|
||||
<DialogDescription>List of meeting you need to attend.</DialogDescription>
|
||||
</DialogHeader>
|
||||
|
||||
{meetingLogError ? (
|
||||
<div>Error Loading data</div>
|
||||
) : isLoadingMeetingLog ? (
|
||||
<LegacyLoader />
|
||||
) : meetingLog && meetingLog.length > 0 ? (
|
||||
<Table>
|
||||
<TableHeader>
|
||||
<TableRow>
|
||||
<TableHead className="w-[100px]">Date</TableHead>
|
||||
<TableHead>Start Time</TableHead>
|
||||
<TableHead>End Time</TableHead>
|
||||
<TableHead>User</TableHead>
|
||||
<TableHead>Note</TableHead>
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
{meetingLog.map((log) => (
|
||||
<TableRow key={log.id}>
|
||||
<TableCell className="font-medium">{log.meet_date}</TableCell>
|
||||
<TableCell>{log.start_time}</TableCell>
|
||||
<TableCell>{log.end_time}</TableCell>
|
||||
<TableCell>{log.user_id}</TableCell>
|
||||
<TableCell>{log.note || "No note provided"}</TableCell>
|
||||
</TableRow>
|
||||
))}
|
||||
</TableBody>
|
||||
<TableFooter>
|
||||
<TableRow>
|
||||
<TableCell colSpan={5} className="text-right">
|
||||
Total Meetings: {meetingLog.length}
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
</TableFooter>
|
||||
</Table>
|
||||
) : (
|
||||
<div>No meeting logs available</div>
|
||||
)}
|
||||
|
||||
<DialogFooter className="sm:justify-start mt-4">
|
||||
<DialogClose asChild>
|
||||
<Button type="button" variant="secondary">
|
||||
Close
|
||||
</Button>
|
||||
</DialogClose>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
);
|
||||
}
|
||||
63
src/app/calendar/manage/ProjectCardSection.tsx
Normal file
63
src/app/calendar/manage/ProjectCardSection.tsx
Normal file
@ -0,0 +1,63 @@
|
||||
"use client";
|
||||
|
||||
import { useState } from "react";
|
||||
import { Separator } from "@/components/ui/separator";
|
||||
import { Card, CardContent, CardDescription, CardTitle, CardHeader, CardFooter } from "@/components/ui/card";
|
||||
import { Tooltip, TooltipProvider, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip";
|
||||
import { ManageMeetDialog } from "./ManageMeetDialog";
|
||||
import { Button } from "@/components/ui/button";
|
||||
|
||||
type ProjectCardSectionProps = {
|
||||
id: number;
|
||||
project_name: string;
|
||||
project_short_description: string;
|
||||
business_id: {
|
||||
user_id: string;
|
||||
};
|
||||
dataroom_id: number | null;
|
||||
};
|
||||
|
||||
type ProjectCardCalendarManageSectionProps = {
|
||||
projectData: ProjectCardSectionProps[] | null;
|
||||
};
|
||||
export default function ProjectCardCalendarManageSection({ projectData }: ProjectCardCalendarManageSectionProps) {
|
||||
const [showMeetModal, setShowMeetModal] = useState<boolean>(false);
|
||||
const [currentProjectId, setCurrentProjectId] = useState<number | undefined>(undefined);
|
||||
|
||||
return (
|
||||
<div id="content" className="grid grid-cols-2 space-x-2">
|
||||
{projectData != null ? (
|
||||
projectData.map((project) => (
|
||||
<Card key={project.id} className="mb-3">
|
||||
<CardHeader className="h-[55%]">
|
||||
<CardTitle>{project.project_name}</CardTitle>
|
||||
<TooltipProvider>
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<CardDescription className="line-clamp-1">{project.project_short_description}</CardDescription>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>{project.project_short_description}</TooltipContent>
|
||||
</Tooltip>
|
||||
</TooltipProvider>
|
||||
</CardHeader>
|
||||
<Separator className="mb-3" />
|
||||
<CardContent>
|
||||
<Button
|
||||
onClick={() => {
|
||||
setCurrentProjectId(project.id);
|
||||
setTimeout(() => setShowMeetModal(true), 0);
|
||||
}}
|
||||
>
|
||||
Meeting List
|
||||
</Button>
|
||||
</CardContent>
|
||||
<CardFooter></CardFooter>
|
||||
</Card>
|
||||
))
|
||||
) : (
|
||||
<div>No data</div>
|
||||
)}
|
||||
<ManageMeetDialog open={showMeetModal} onOpenChange={setShowMeetModal} projectId={currentProjectId!} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
20
src/app/calendar/manage/actions.ts
Normal file
20
src/app/calendar/manage/actions.ts
Normal file
@ -0,0 +1,20 @@
|
||||
import { Database } from "@/types/database.types";
|
||||
import { SupabaseClient } from "@supabase/supabase-js";
|
||||
|
||||
export default function getMeetingLog(client: SupabaseClient<Database>, projectId: number) {
|
||||
return client
|
||||
.from("meeting_log")
|
||||
.select(
|
||||
`
|
||||
id,
|
||||
meet_date,
|
||||
start_time,
|
||||
end_time,
|
||||
note,
|
||||
user_id,
|
||||
project_id,
|
||||
created_at
|
||||
`
|
||||
)
|
||||
.eq("project_id", projectId);
|
||||
}
|
||||
62
src/app/calendar/manage/page.tsx
Normal file
62
src/app/calendar/manage/page.tsx
Normal file
@ -0,0 +1,62 @@
|
||||
import { Separator } from "@/components/ui/separator";
|
||||
import { Clock } from "lucide-react";
|
||||
import { createSupabaseClient } from "@/lib/supabase/serverComponentClient";
|
||||
import { getProjectByUserId } from "@/lib/data/projectQuery";
|
||||
import { Suspense } from "react";
|
||||
import { LegacyLoader } from "@/components/loading/LegacyLoader";
|
||||
import { getUserRole } from "@/lib/data/userQuery";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import Link from "next/link";
|
||||
import ProjectCardCalendarManageSection from "./ProjectCardSection";
|
||||
|
||||
export default async function ManageMeetingPage() {
|
||||
const supabase = createSupabaseClient();
|
||||
const { data: user, error: userError } = await supabase.auth.getUser();
|
||||
|
||||
if (userError) {
|
||||
throw "Can't get user data!";
|
||||
}
|
||||
|
||||
const userId = user.user?.id;
|
||||
|
||||
const { data: roleData, error: roleDataError } = await getUserRole(supabase, userId);
|
||||
|
||||
if (roleDataError) {
|
||||
throw "Error fetching user data";
|
||||
}
|
||||
|
||||
if (!roleData || roleData.role != "business") {
|
||||
return (
|
||||
<div className="container max-w-screen-xl">
|
||||
<span className="flex gap-2 items-center mt-4">
|
||||
<Clock />
|
||||
<p className="text-2xl font-bold">Manage Meeting Request</p>
|
||||
</span>
|
||||
<Separator className="my-3" />
|
||||
<div className="mb-3 mt-2">Please apply for business first to access functionalities of busienss account</div>
|
||||
<Link href="/business/apply">
|
||||
<Button>Apply for business</Button>
|
||||
</Link>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
const { data: projectData, error: projectDataError } = await getProjectByUserId(supabase, userId);
|
||||
|
||||
if (projectDataError) {
|
||||
throw "Can't get project data";
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="container max-w-screen-xl">
|
||||
<span className="flex gap-2 items-center mt-4">
|
||||
<Clock />
|
||||
<p className="text-2xl font-bold">Manage Meeting Request</p>
|
||||
</span>
|
||||
<Separator className="my-3" />
|
||||
<Suspense fallback={<LegacyLoader />}>
|
||||
<ProjectCardCalendarManageSection projectData={projectData} />
|
||||
</Suspense>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user