Skip to content
Open
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
63 changes: 63 additions & 0 deletions app/(protected)/in-process/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
// <project root>/app/(protected)/in-process/page.tsx
import React from "react";
import { Metadata } from "next";
import DealCard from "@/components/DealCard";
import Pagination from "@/components/pagination";
import SearchDeals from "@/components/SearchDeal";
import getCurrentUserRole from "../../../lib/data/current-user-role";
import prismaDB from "../../../lib/prisma";

export const metadata: Metadata = {
title: "In Process Deals",
description: "Deals you’ve moved into processing",
};

// Strictly type your props so TS knows what searchParams contains
type Props = {
searchParams: {
page?: string;
[key: string]: string | undefined;
};
};

const LIMIT = 20;

export default async function InProcessPage({ searchParams }: Props) {
// parse page number
const currentPage = Number(searchParams.page ?? "1");
const offset = (currentPage - 1) * LIMIT;

// fetch only deals with status = IN_PROCESS
const [data, totalCount] = await Promise.all([
prismaDB.deal.findMany({
where: { status: "IN_PROCESS" },
orderBy: { createdAt: "desc" },
skip: offset,
take: LIMIT,
}),
prismaDB.deal.count({ where: { status: "IN_PROCESS" } }),
]);

const totalPages = Math.ceil(totalCount / LIMIT);

// getCurrentUserRole can return undefined; assert non-null
const userRole = (await getCurrentUserRole())!;

return (
<section className="block-space container">
<h1 className="mb-6 text-center">In Process Deals</h1>
<h4>Total: {totalCount}</h4>

<div className="mb-4 flex flex-wrap gap-4">
<SearchDeals />
<Pagination totalPages={totalPages} />
</div>

<div className="grid grid-cols-1 gap-6 sm:grid-cols-2 lg:grid-cols-3">
{data.map((deal) => (
<DealCard key={deal.id} deal={deal} userRole={userRole} />
))}
</div>
</section>
);
}
2 changes: 2 additions & 0 deletions app/(protected)/raw-deals/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import DealTypeFilter from "@/components/DealTypeFilter";
import { DealType } from "@prisma/client";
import SearchDealsSkeleton from "@/components/skeletons/SearchDealsSkeleton";
import SearchEbitdaDeals from "@/components/SearchEbitdaDeals";
import { DealStatus } from "@prisma/client";

export const metadata: Metadata = {
title: "Inferred Deals",
Expand Down Expand Up @@ -45,6 +46,7 @@ const RawDealsPage = async (props: { searchParams: SearchParams }) => {
limit,
dealTypes: dealTypes as DealType[],
ebitda,
status: DealStatus.RAW,
});

const currentUserRole = await getCurrentUserRole();
Expand Down
7 changes: 5 additions & 2 deletions app/actions/get-deal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import "server-only";

import prismaDB from "@/lib/prisma";
import { Deal, DealType } from "@prisma/client";
import { Deal, DealType, DealStatus } from "@prisma/client";
import { unstable_cache } from "next/cache";

interface GetDealsResult {
Expand Down Expand Up @@ -55,21 +55,24 @@ export const GetAllDeals = async ({
limit = 20,
dealTypes,
ebitda,
status,
}: {
search?: string | undefined;
offset?: number;
limit?: number;
dealTypes?: DealType[];
ebitda?: string;
status?: DealStatus;
}): Promise<GetDealsResult> => {
const ebitdaValue = ebitda ? parseFloat(ebitda) : undefined;

const whereClause = {
const whereClause: any = {
...(search ? { dealCaption: { contains: search } } : {}),
...(dealTypes && dealTypes.length > 0
? { dealType: { in: dealTypes } }
: {}),
...(ebitdaValue !== undefined ? { ebitda: { gte: ebitdaValue } } : {}),
...(status ? { status } : {}),
};

console.log("whereClause", whereClause);
Expand Down
76 changes: 61 additions & 15 deletions components/DealCard.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// components/DealCard.tsx
"use client";

import React from "react";
Expand Down Expand Up @@ -29,6 +30,9 @@ import { useToast } from "@/hooks/use-toast";
import DeleteDealFromDB from "@/app/actions/delete-deal";
import { cn } from "@/lib/utils";

import moveToInProcess from "@/app/actions/move-to-in-process";
import { exportDealToBitrix } from "@/app/actions/upload-bitrix";

const DealCard = ({
deal,
userRole,
Expand All @@ -42,19 +46,27 @@ const DealCard = ({
showActions?: boolean;
showScreenButton?: boolean;
}) => {
const editLink = `/raw-deals/${deal.id}/edit`;
const editLink = `/raw-deals/${deal.id}/edit`;
const detailLink = `/raw-deals/${deal.id}`;
const screenLink = `/raw-deals/${deal.id}/screen`;

const { toast } = useToast();
const formatCurrency = (amount: number) => {
return new Intl.NumberFormat("en-US", {

// Wrapper that Next.js expects for <form action={…}>
const handleMove = async (_formData: FormData): Promise<void> => {
await moveToInProcess(deal.id);
};

const handleExport = async (_formData: FormData): Promise<void> => {
await exportDealToBitrix(deal);
};

const formatCurrency = (amount: number) =>
new Intl.NumberFormat("en-US", {
style: "currency",
currency: "USD",
notation: "compact",
maximumFractionDigits: 1,
}).format(amount);
};

const handleDelete = async () => {
try {
Expand All @@ -64,7 +76,7 @@ const DealCard = ({
description: response.message,
variant: response.type === "success" ? "default" : "destructive",
});
} catch (error) {
} catch {
toast({
title: "Error",
description: "Failed to delete deal",
Expand All @@ -77,7 +89,7 @@ const DealCard = ({
<Card
className={cn(
"group w-full transition-all duration-300 hover:scale-[1.02] hover:shadow-xl",
className,
className
)}
>
<CardHeader className="pb-3">
Expand All @@ -87,6 +99,7 @@ const DealCard = ({
</CardTitle>
{showActions && (
<div className="flex space-x-2">
{/* Edit */}
<TooltipProvider>
<Tooltip>
<TooltipTrigger asChild>
Expand All @@ -106,6 +119,7 @@ const DealCard = ({
</TooltipContent>
</Tooltip>
</TooltipProvider>
{/* Delete */}
{userRole === "ADMIN" && (
<TooltipProvider>
<Tooltip>
Expand All @@ -129,6 +143,7 @@ const DealCard = ({
)}
</div>
</CardHeader>

<CardContent className="grid gap-3">
<InfoItem
icon={<DollarSign className="h-4 w-4 text-emerald-500" />}
Expand All @@ -150,7 +165,7 @@ const DealCard = ({
label="Industry"
value={deal.industry}
/>
{deal.askingPrice && (
{deal.askingPrice != null && (
<InfoItem
icon={<DollarSign className="h-4 w-4 text-amber-500" />}
label="Asking Price"
Expand All @@ -165,19 +180,50 @@ const DealCard = ({
/>
)}
</CardContent>

<CardFooter className="flex flex-col gap-2 pt-3">
{/* View Details */}
<Button className="w-full bg-primary/90 hover:bg-primary" asChild>
<Link href={detailLink}>View Details</Link>
</Button>

{showScreenButton && (
<Button
className="w-full border-primary/20 hover:bg-primary/10 hover:text-primary"
asChild
variant="outline"
>
<Link href={screenLink}>Screen Deal</Link>
</Button>
<>
{/* Screen Deal */}
<Button
className="w-full border-primary/20 hover:bg-primary/10 hover:text-primary"
asChild
variant="outline"
>
<Link href={screenLink}>Screen Deal</Link>
</Button>

{/* RAW → Move to In Process */}
{deal.status === "RAW" && (
<form action={handleMove} className="w-full">
<Button
type="submit"
className="w-full border-yellow-500 hover:bg-yellow-100 hover:text-yellow-800"
variant="outline"
>
Move to In Process
</Button>
</form>
)}

{/* IN_PROCESS → Publish to Bitrix */}
{deal.status === "IN_PROCESS" && (
<form action={handleExport} className="w-full">
<Button
type="submit"
className="w-full border-green-500 hover:bg-green-100 hover:text-green-800"
variant="outline"
>
Publish to Bitrix
</Button>
</form>
)}
</>
)}
</CardFooter>
</Card>
Expand Down
3 changes: 2 additions & 1 deletion components/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,9 @@ type NavLinkType = {
export const NavLinks: NavLinkType = [
{ navlink: "/new-deal", navlabel: "New", icon: FiPlus },
{ navlink: "/raw-deals", navlabel: "Raw", icon: FiList },
{ navlink: "/in-process", navlabel: "In Process", icon: FiTrendingUp },
{ navlink: "/published-deals", navlabel: "Published", icon: FiCheckSquare },
{ navlink: "/infer", navlabel: "Infer", icon: FiSearch },
{ navlink: "/infer", navlabel: "Screened", icon: FiSearch },
];

const Header = ({ className, session }: HeaderProps) => {
Expand Down