"use client"; import { useState } from "react"; import { useRouter } from "next/navigation"; import { useAuthGuard } from "@/hooks/useAuthGuard"; import { useDocumentTitle } from "@/hooks/useDocumentTitle"; import { useResource } from "@/hooks/useResource"; import { useDeleteResource } from "@/hooks/useDeleteResource"; import { useReturnTo, useWithReturnTo } from "@/hooks/useReturnTo"; import { useRecordByUuid } from "@/hooks/useRecordByUuid"; import { contactsAPI } from "@/lib/api/contacts"; import { usePeopleByUuid } from "@/hooks/usePeopleByUuid"; import { splitCourseInstructor } from "@/lib/people"; import { coursesAPI, Course } from "@/lib/api/courses"; import { certificationAgencyLabel } from "@/lib/api/certifications"; import { courseStatusLabel } from "@/lib/course"; import { formatTripDateRange } from "@/lib/date-time"; import { cn } from "@/lib/utils"; import { RecentDivesCard } from "@/components/dives/recent-dives-card"; import { CourseCertificationsCard } from "@/components/courses/course-certifications-card"; import { CourseDialog } from "@/components/courses/course-dialog"; import { PeopleList } from "@/components/people/people-list"; import { Button, ButtonLink } from "@/components/ui/button"; import { DeleteMenuItem, ItemActionsMenu, } from "@/components/ui/item-actions-menu"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { ConfirmDialog } from "@/components/ui/confirm-dialog"; import { HERO_BODY, HERO_CONTROL, MapHeroPageSkeleton, PAGE_COLUMN, PlainHero, } from "@/components/ui/map-hero"; import { NotFoundState } from "@/components/ui/not-found-state"; import { BadgeCheck, Edit, Plus, GraduationCap } from "lucide-react"; import Link from "next/link"; import { PageSpinner } from "@/components/ui/page-spinner"; import { InfoRow } from "@/components/ui/info-row"; export function CourseDetailPageContent() { const router = useRouter(); const { user, isAuthenticated, isLoading: isAuthLoading } = useAuthGuard(); const [isEditOpen, setIsEditOpen] = useState(false); // Held here rather than in the certifications card, because the sidebar's // button opens the same dialog the card's empty state does. const [isAddingCertification, setIsAddingCertification] = useState(false); const back = useReturnTo({ href: "/courses", label: "Back to courses" }); const withReturnTo = useWithReturnTo(); const { resource: course, setResource: setCourse, isLoading: isLoadingCourse, } = useResource(coursesAPI.getCourse, { enabled: !!user, errorMessage: "Failed to load course details. Please try again.", redirectTo: "/courses", }); useDocumentTitle(course?.name, "Courses"); const del = useDeleteResource(coursesAPI.deleteCourse, { // A plain confirm, no reassign offer: deleting a course unlinks it from the // dives and cards that named it, and there is nothing to hand them to. confirmMessage: "Are you sure you want to delete this course? The dives and certifications on it are kept, but they will no longer name it.", successMessage: "Course deleted successfully.", errorMessage: "Failed to delete course. Please try again.", onDeleted: () => router.push(back.href), }); const isDeleting = del.deletingId !== null; const contact = useRecordByUuid(contactsAPI.getContact, course?.contact_uuid); // The instructor on a row of their own, as the dialog holds them, and everyone // else on the course under it. const { instructorUuid, others } = splitCourseInstructor(course?.people); const people = usePeopleByUuid( (course?.people ?? []).map((reference) => reference.person_uuid), ); const instructor = instructorUuid ? people[instructorUuid] : undefined; if (isAuthLoading) { return ; } if (!isAuthenticated) { return null; // Will redirect to signin } if (isLoadingCourse) { return ( ); } if (!course) { return (
); } // In its card's formats, so a course reads the same on its page as in the // list. const subtitle = [ certificationAgencyLabel(course.agency, course.agency_other), formatTripDateRange( course.start_date ?? undefined, course.end_date ?? undefined, ), courseStatusLabel(course.status), ]; return (
del.requestDelete(course.uuid)} disabled={isDeleting} /> } /> !open && del.cancelDelete()} title="Delete course" description={del.confirmMessage} confirmText="Delete" isLoading={isDeleting} onConfirm={del.confirmDelete} />
Course Information {contact && {contact.name}} {instructor && ( {instructor.name} )} {course.instructor_number && ( {course.instructor_number} )} {others.some((reference) => people[reference.person_uuid]) && (
People
)} {course.notes && ( {course.notes} )} {/* Two columns exactly where the sidebar is wide: it is the full content width until `lg`, where it becomes a third of it and the pair no longer fits across. */}
Log a dive
); }