Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 66 additions & 0 deletions src/app/dashboard/dashboard-content.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
"use client";

import { useState } from "react";
import type * as React from "react";
import { cn } from "@/components/lib/utils";
import CoachingSessionList from "@/components/ui/dashboard/coaching-session-list";
import AddEntities from "@/components/ui/dashboard/add-entities";
import { CoachingSessionDialog } from "@/components/ui/dashboard/coaching-session-dialog";
import type { CoachingSession } from "@/types/coaching-session";

function DashboardContainer({
className,
...props
}: React.HTMLAttributes<HTMLDivElement>) {
return (
<div
className={cn(
// Base styles
"p-4",
// Mobile: stack vertically
"flex flex-col gap-6",
// Never grow wider than the site-header
"max-w-screen-2xl",
// Ensure full width for children
"[&>*]:w-full",
className
)}
{...props}
/>
);
}

export function DashboardContent() {
const [dialogOpen, setDialogOpen] = useState(false);
const [sessionToEdit, setSessionToEdit] = useState<
CoachingSession | undefined
>();

const handleOpenDialog = (session?: CoachingSession) => {
setSessionToEdit(session);
setDialogOpen(true);
};

const handleCloseDialog = () => {
setDialogOpen(false);
setSessionToEdit(undefined);
};

return (
<>
<DashboardContainer>
<AddEntities
className="mb-8"
onCreateSession={() => handleOpenDialog()}
/>
<CoachingSessionList onUpdateSession={handleOpenDialog} />
</DashboardContainer>

<CoachingSessionDialog
open={dialogOpen}
onOpenChange={handleCloseDialog}
coachingSessionToEdit={sessionToEdit}
/>
</>
);
}
44 changes: 2 additions & 42 deletions src/app/dashboard/page.tsx
Original file line number Diff line number Diff line change
@@ -1,51 +1,11 @@
import type { Metadata } from "next";
import type * as React from "react";
import { cn } from "@/components/lib/utils";
import SelectCoachingRelationship from "@/components/ui/dashboard/select-coaching-relationship";
import CoachingSessionList from "@/components/ui/dashboard/coaching-session-list";
import AddEntities from "@/components/ui/dashboard/add-entities";
import { DashboardContent } from "./dashboard-content";

export const metadata: Metadata = {
title: "Dashboard",
description: "Coaching dashboard",
};

function DashboardContainer({
className,
...props
}: React.HTMLAttributes<HTMLDivElement>) {
return (
<div
className={cn(
// Base styles
"p-4",
// Mobile: stack vertically
"flex flex-col gap-6",
// Tablet and up (640px+): side by side
"sm:grid sm:grid-cols-2",
// Never grow wider than the site-header
"max-w-screen-2xl",
// Ensure full width for children
"[&>*]:w-full",
className
)}
{...props}
/>
);
}

export default function DashboardPage() {
return (
<>
<div className="p-4 max-w-screen-2xl">
<div className="mb-8 w-full">
<AddEntities />
</div>
</div>
<DashboardContainer>
<SelectCoachingRelationship />
<CoachingSessionList />
</DashboardContainer>
</>
);
return <DashboardContent />;
}
55 changes: 28 additions & 27 deletions src/components/ui/coaching-relationship-selector.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,10 @@ import { useEffect } from "react";
import { useAuthStore } from "@/lib/providers/auth-store-provider";
import { useCoachingRelationshipStateStore } from "@/lib/providers/coaching-relationship-state-store-provider";
import { useCoachingSessionStateStore } from "@/lib/providers/coaching-session-state-store-provider";
import { cn } from "../lib/utils";

interface CoachingRelationshipsSelectorProps extends PopoverProps {
className?: string;
/// The Organization's Id for which to get a list of associated CoachingRelationships
organizationId: Id;
/// Disable the component from interaction with the user
Expand All @@ -38,18 +40,13 @@ function CoachingRelationshipsSelectItems({
// Be sure to cache the list of current coaching relationships in the CoachingRelationshipStateStore
useEffect(() => {
if (!relationships.length) return;
console.debug(
`relationships (useEffect): ${JSON.stringify(relationships)}`
);
setCurrentCoachingRelationships(relationships);
}, [relationships, setCurrentCoachingRelationships]);

if (isLoading) return <div>Loading...</div>;
if (isError) return <div>Error loading coaching relationships</div>;
if (!relationships?.length) return <div>No coaching relationships found</div>;

console.debug(`relationships: ${JSON.stringify(relationships)}`);

return (
<>
{relationships.map((rel) => (
Expand All @@ -63,6 +60,7 @@ function CoachingRelationshipsSelectItems({
}

export default function CoachingRelationshipSelector({
className,
organizationId,
disabled,
onSelect,
Expand Down Expand Up @@ -101,29 +99,32 @@ export default function CoachingRelationshipSelector({
? getCurrentCoachingRelationship(currentCoachingRelationshipId)
: null;

const displayValue = currentRelationship ? (
<>
{currentRelationship.coach_first_name}{" "}
{currentRelationship.coach_last_name} -&gt;{" "}
{currentRelationship.coachee_first_name}{" "}
{currentRelationship.coachee_last_name}
</>
) : undefined;
const displayValue =
currentRelationship && currentRelationship.id ? (
<>
{currentRelationship.coach_first_name}{" "}
{currentRelationship.coach_last_name} -&gt;{" "}
{currentRelationship.coachee_first_name}{" "}
{currentRelationship.coachee_last_name}
</>
) : undefined;

return (
<Select
disabled={disabled}
value={currentCoachingRelationshipId ?? undefined}
onValueChange={handleSetCoachingRelationship}
>
<SelectTrigger id="coaching-relationship-selector">
<SelectValue placeholder="Select coaching relationship">
{displayValue}
</SelectValue>
</SelectTrigger>
<SelectContent>
<CoachingRelationshipsSelectItems organizationId={organizationId} />
</SelectContent>
</Select>
<div className={cn("font-normal", className)}>
<Select
disabled={disabled}
value={currentCoachingRelationshipId ?? undefined}
onValueChange={handleSetCoachingRelationship}
>
<SelectTrigger id="coaching-relationship-selector">
<SelectValue placeholder="Select coaching relationship">
{displayValue}
</SelectValue>
</SelectTrigger>
<SelectContent>
<CoachingRelationshipsSelectItems organizationId={organizationId} />
</SelectContent>
</Select>
</div>
);
}
56 changes: 43 additions & 13 deletions src/components/ui/coaching-session.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,31 @@ import Link from "next/link";
import { useCoachingSessionStateStore } from "@/lib/providers/coaching-session-state-store-provider";
import { useOverarchingGoalBySession } from "@/lib/api/overarching-goals";
import { Id } from "@/types/general";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
import { MoreHorizontal } from "lucide-react";
import { CoachingSession as CoachingSessionType } from "@/types/coaching-session";
import { useAuthStore } from "@/lib/providers/auth-store-provider";

interface CoachingSessionProps {
coachingSession: {
id: Id;
date: string;
};
coachingSession: CoachingSessionType;
onUpdate: () => void;
onDelete: () => void;
}

const CoachingSession: React.FC<CoachingSessionProps> = ({
coachingSession,
onUpdate,
onDelete,
}) => {
const { setCurrentCoachingSessionId } = useCoachingSessionStateStore(
(state) => state
);
const { isCoach } = useAuthStore((state) => state);

return (
<Card>
Expand All @@ -33,15 +44,34 @@ const CoachingSession: React.FC<CoachingSessionProps> = ({
{format(new Date(coachingSession.date), "MMMM d, yyyy h:mm a")}
</div>
</div>
<Link href={`/coaching-sessions/${coachingSession.id}`} passHref>
<Button
size="sm"
className="w-full sm:w-auto mt-2 sm:mt-0"
onClick={() => setCurrentCoachingSessionId(coachingSession.id)}
>
Join Session
</Button>
</Link>
<div className="flex items-center gap-2">
<Link href={`/coaching-sessions/${coachingSession.id}`} passHref>
<Button
size="sm"
className="w-full sm:w-auto mt-2 sm:mt-0 text-sm px-3 py-1"
onClick={() => setCurrentCoachingSessionId(coachingSession.id)}
>
Join Session
</Button>
</Link>
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="ghost" size="icon">
<MoreHorizontal className="h-4 w-4" />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end">
<DropdownMenuItem onClick={onUpdate}>
Edit
</DropdownMenuItem>
{isCoach && (
<DropdownMenuItem onClick={onDelete} className="text-destructive">
Delete
</DropdownMenuItem>
)}
</DropdownMenuContent>
</DropdownMenu>
</div>
</div>
</CardHeader>
</Card>
Expand Down
Loading
Loading