Skip to content

Commit

Permalink
add special treatment for interview phases
Browse files Browse the repository at this point in the history
  • Loading branch information
Simon Huang committed Oct 9, 2024
1 parent 386a31e commit 35f4629
Show file tree
Hide file tree
Showing 9 changed files with 208 additions and 119 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,13 @@ import { type ColumnDef } from "@tanstack/react-table";
import { ArrowUpDown, MoreHorizontal, UserCheck, UserX } from "lucide-react";
import { type PhaseApplication } from "../page";
import { Badge } from "@components/ui/badge";
import {
Tooltip,
TooltipContent,
TooltipTrigger,
} from "@components/ui/tooltip";
import Link from "next/link";
import { Avatar, AvatarImage } from "@components/ui/avatar";

export const columns: ColumnDef<PhaseApplication>[] = [
{
Expand Down Expand Up @@ -48,7 +55,7 @@ export const columns: ColumnDef<PhaseApplication>[] = [
variant="ghost"
onClick={() => column.toggleSorting(column.getIsSorted() === "asc")}
>
In Phase
Invited
<ArrowUpDown className="ml-2 h-4 w-4" />
</Button>
);
Expand All @@ -58,18 +65,60 @@ export const columns: ColumnDef<PhaseApplication>[] = [
return (
<Badge variant="default">
<UserCheck className="mr-2" />
In phase
Invited
</Badge>
);

return (
<Badge variant="outline">
<UserX className="mr-2" />
Not in phase
Not invited
</Badge>
);
},
},
{
id: "questionnaires",
header: "Questionnaires",
cell: ({ row }) => {
const questionnaires = row.original.questionnaires;
return (
<div className="flex gap-2">
{questionnaires.map((questionnaire) => (
<Badge
variant={questionnaire.phase.isCurrent ? "default" : "outline"}
>
{questionnaire.name}
</Badge>
))}
</div>
);
},
},
{
id: "reviews",
header: () => "Reviews",
cell: ({ row }) => {
return (
<div className="flex -space-x-3 overflow-hidden">
{row.original.reviews.map((review, i) => (
<Tooltip key={i}>
<TooltipTrigger>
<Link href={`review/${review.id}`}>
<Avatar className="border">
<AvatarImage src={review.user.image ?? undefined} />
</Avatar>
</Link>
</TooltipTrigger>
<TooltipContent>
<p>{review.user.name}</p>
</TooltipContent>
</Tooltip>
))}
</div>
);
},
},
{
id: "actions",
cell: ({ row }) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,11 @@ export type PhaseApplication = {
questionnaires: {
id: string;
name: string;
phaseId: string;
phase: {
id: string;
name: string;
isCurrent: boolean;
};
}[];
inPhase: boolean;
};
Expand All @@ -38,7 +42,7 @@ export default async function PhasePage({ params }: Props) {
},
});

if (!phase) redirect("/404");
if (!phase || !phase.isInterview) redirect("/404");

const opportunity = await db.opportunity.findUnique({
where: { id: phase.opportunityId },
Expand Down Expand Up @@ -71,16 +75,31 @@ export default async function PhasePage({ params }: Props) {
select: {
id: true,
name: true,
phaseId: true,
phase: {
select: {
id: true,
name: true,
},
},
},
},
},
});

const applicationsWithInPhase = applications.map((application) => ({
...application,
inPhase: application.questionnaires.some((q) => q.phaseId === phase.id),
}));
const applicationsWithInPhase: PhaseApplication[] = applications.map(
(application) => ({
...application,
questionnaires: application.questionnaires.map((q) => ({
id: q.id,
name: q.name,
phase: {
...q.phase,
isCurrent: q.phase.id === phase.id,
},
})),
inPhase: application.questionnaires.some((q) => q.phase.id === phase.id),
}),
);

async function assignToQuestionnaire(
isAdd: boolean,
Expand Down Expand Up @@ -109,8 +128,11 @@ export default async function PhasePage({ params }: Props) {
<div className="flex flex-col gap-3">
<Breadcrumbs title={`${phase.name}`} />
<h1 className="scroll-m-20 text-4xl font-extrabold tracking-tight lg:text-5xl">
Phase {phase.name}
{phase.name}
</h1>
<p className="text-muted-foreground">
Invite applicants to interviews
</p>
</div>
</div>

Expand Down
76 changes: 39 additions & 37 deletions app/opportunities/_components/opportunityCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import { Card, CardHeader, CardContent, CardTitle } from "@components/ui/card";
import { Button } from "@components/ui/button";
import { CalendarIcon } from "@radix-ui/react-icons";
import Link from "next/link";
import { type Opportunity } from "@prisma/client";
import { format } from "date-fns";
import { BarChart2, Edit, Ellipsis, Eye, Users } from "lucide-react";
import {
Expand All @@ -12,9 +11,10 @@ import {
DropdownMenuTrigger,
} from "@components/ui/dropdown-menu";
import { cn } from "@lib/utils";
import { OverviewOpportunity } from "../page";

interface OpportunityCardProps {
opportunity: Opportunity;
opportunity: OverviewOpportunity;
onClick?: () => void;
className?: string;
}
Expand All @@ -30,42 +30,44 @@ export default function OpportunityCard({
<div className="flex justify-between gap-2">
<CardTitle className="text-lg">{opportunity.title}</CardTitle>

<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button
type="button"
size="icon-sm"
variant="ghost"
className="text-muted-foreground"
>
<Ellipsis />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent>
<DropdownMenuItem asChild>
<Link
href={"opportunities/" + +opportunity.id + "/leaderboard"}
{opportunity.isAdmin && (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button
type="button"
size="icon-sm"
variant="ghost"
className="text-muted-foreground"
>
<BarChart2 className="mr-2 h-4 w-4" />
<span>Leaderboard</span>
</Link>
</DropdownMenuItem>
<DropdownMenuItem asChild>
<Link
href={"opportunities/" + +opportunity.id + "/applications"}
>
<Users className="mr-2 h-4 w-4" />
<span>Applications</span>
</Link>
</DropdownMenuItem>
<DropdownMenuItem asChild>
<Link href={"opportunities/" + +opportunity.id + "/edit"}>
<Edit className="mr-2 h-4 w-4" />
<span>Edit </span>
</Link>
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
<Ellipsis />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent>
<DropdownMenuItem asChild>
<Link
href={"opportunities/" + +opportunity.id + "/leaderboard"}
>
<BarChart2 className="mr-2 h-4 w-4" />
<span>Leaderboard</span>
</Link>
</DropdownMenuItem>
<DropdownMenuItem asChild>
<Link
href={"opportunities/" + +opportunity.id + "/applications"}
>
<Users className="mr-2 h-4 w-4" />
<span>Applications</span>
</Link>
</DropdownMenuItem>
<DropdownMenuItem asChild>
<Link href={"opportunities/" + +opportunity.id + "/edit"}>
<Edit className="mr-2 h-4 w-4" />
<span>Edit </span>
</Link>
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
)}
</div>
</CardHeader>

Expand Down
62 changes: 26 additions & 36 deletions app/opportunities/_components/opportunityOverview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,34 +19,11 @@ import { Avatar, AvatarFallback, AvatarImage } from "@components/ui/avatar";
import { ScrollArea, ScrollBar } from "@components/ui/scroll-area";
import Link from "next/link";
import { Button } from "@components/ui/button";
import { Plus } from "lucide-react";
import { Handshake, Plus } from "lucide-react";
import { OverviewOpportunity } from "../page";

interface Props {
opportunities: Prisma.OpportunityGetPayload<{
include: {
phases: {
include: {
questionnaires: {
include: {
applications: {
select: {
id: true;
name: true;
reviews: { select: { user: true; id: true } };
};
};
reviewers: true;
};
};
};
};
admins: {
select: {
id: true;
};
};
};
}>[];
opportunities: OverviewOpportunity[];
}

export const OpportunityOverview = ({ opportunities }: Props) => {
Expand Down Expand Up @@ -77,7 +54,10 @@ export const OpportunityOverview = ({ opportunities }: Props) => {

return (
<Card className="flex h-full min-h-0">
<ResizablePanelGroup direction={"horizontal"}>
<ResizablePanelGroup
direction={"horizontal"}
autoSaveId="opportunities-overview"
>
<ResizablePanel defaultSize={25} className="p-4">
<div className="group flex h-full flex-col gap-4">
{opportunities.map((item) => {
Expand Down Expand Up @@ -117,17 +97,27 @@ export const OpportunityOverview = ({ opportunities }: Props) => {
<div className="flex h-full flex-col gap-2">
{selectedOpportunity?.phases.map((phase) => (
<div key={`phase-${phase.id}`} className="space-y-2">
<Button
variant="link"
className="font-semi pl-0 text-sm"
asChild
>
<Link
href={`opportunities/${selectedOpportunity.id}/phase/${phase.id}`}
{selectedOpportunity?.isAdmin && phase.isInterview ? (
<Button
variant="link"
className="font-semi h-min p-0 text-sm"
asChild
>
<Link
href={`opportunities/${selectedOpportunity.id}/interview/${phase.id}`}
>
<Handshake className="mr-2 h-4 w-4" />
{phase.name}
</Link>
</Button>
) : (
<span className="font-semi text-sm">
{phase.isInterview && (
<Handshake className="mr-2 h-4 w-4" />
)}
{phase.name}
</Link>
</Button>
</span>
)}
<div className="flex flex-col gap-2">
{phase.questionnaires.map((questionnaire) => (
<Card
Expand Down
Loading

0 comments on commit 35f4629

Please sign in to comment.