Skip to content
Merged
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
60 changes: 60 additions & 0 deletions contributors/dwivediprashant/client/app/api/subscriptions/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,66 @@ export async function GET() {
}
}

export async function POST(request: Request) {
try {
const body = await request.json();

// Validate required fields
const requiredFields = [
"name",
"amount",
"billingCycle",
"renewalDate",
"category",
];
const missingFields = requiredFields.filter((field) => !body[field]);

if (missingFields.length > 0) {
return NextResponse.json(
{
success: false,
message: `Missing required fields: ${missingFields.join(", ")}`,
},
{ status: 400 }
);
}

// Forward the request to your backend server
const response = await fetch("http://localhost:5000/api/subscriptions", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(body),
});

const result = await response.json();

if (!response.ok) {
return NextResponse.json(result, {
status: response.status,
});
}

// Return the backend response
return NextResponse.json(result, {
status: 201,
headers: {
"Content-Type": "application/json",
},
});
} catch (error) {
console.error("API Error:", error);
return NextResponse.json(
{
success: false,
message: "Failed to create subscription",
},
{ status: 500 }
);
}
}

// Helper functions to map backend data to frontend format
function getCategoryFromName(serviceName: string): string {
const categories: { [key: string]: string } = {
Expand Down
81 changes: 81 additions & 0 deletions contributors/dwivediprashant/client/app/components/Modal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
"use client";

import { useEffect } from "react";

interface ModalProps {
isOpen: boolean;
onClose: () => void;
title: string;
children: React.ReactNode;
}

export default function Modal({
isOpen,
onClose,
title,
children,
}: ModalProps) {
useEffect(() => {
const handleEscape = (e: KeyboardEvent) => {
if (e.key === "Escape") {
onClose();
}
};

if (isOpen) {
document.addEventListener("keydown", handleEscape);
document.body.style.overflow = "hidden";
}

return () => {
document.removeEventListener("keydown", handleEscape);
document.body.style.overflow = "unset";
};
}, [isOpen, onClose]);

if (!isOpen) return null;

return (
<div className="fixed inset-0 z-50 overflow-y-auto">
{/* Backdrop */}
<div
className="fixed inset-0 bg-gradient-to-br from-[#191919] to-[#282828] transition-opacity"
onClick={onClose}
/>

{/* Modal Container */}
<div className="flex min-h-full items-center justify-center p-4">
<div
className="relative bg-black rounded-xl shadow-xl max-w-2xl w-full max-h-[90vh] overflow-y-auto border border-[#2A2A2A]/50 backdrop-blur-sm"
onClick={(e) => e.stopPropagation()}
>
{/* Header */}
<div className="flex items-center justify-between p-6 border-b border-[#2A2A2A]/50">
<h2 className="text-2xl font-bold text-white">{title}</h2>
<button
onClick={onClose}
className="p-2 text-gray-400 hover:text-white hover:bg-white/10 rounded-lg transition-colors"
>
<svg
className="w-5 h-5"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
d="M6 18L18 6M6 6l12 12"
/>
</svg>
</button>
</div>

{/* Content */}
<div className="p-6">{children}</div>
</div>
</div>
</div>
);
}
35 changes: 0 additions & 35 deletions contributors/dwivediprashant/client/app/components/Sidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,6 @@ export default function Sidebar({ activePage }: SidebarProperties) {
{ name: "Analytics", href: "/analytics" },
];

const accountItems = [
{ name: "Settings", href: "/settings" },
{ name: "Profile", href: "/profile" },
];

return (
<>
{/* Mobile backdrop */}
Expand Down Expand Up @@ -96,37 +91,7 @@ export default function Sidebar({ activePage }: SidebarProperties) {
<span>{item.name}</span>
</Link>
))}

<div className="border-t border-[#2A2A2A]/50 pt-4 mt-6">
{accountItems.map((item) => (
<Link
key={item.name}
href={item.href}
className={`
flex items-center gap-3 px-3 py-3 rounded-lg text-sm font-medium
transition-all duration-200 mb-1
${getActiveStateClasses(item.name)}
`}
onClick={() => setSidebarOpen(false)}
>
<span>{item.name}</span>
</Link>
))}
</div>
</nav>

{/* User Section */}
<div className="px-6 py-4 border-t border-[#2A2A2A]/50">
<div className="flex items-center gap-3">
<div className="w-10 h-10 bg-[#282828] rounded-full flex items-center justify-center border border-[#2A2A2A]">
<span className="text-[#B3B3B3] text-sm font-medium">U</span>
</div>
<div className="flex-1">
<div className="text-sm font-medium text-[#FFFFFF]">User</div>
<div className="text-xs text-[#B3B3B3]">[email protected]</div>
</div>
</div>
</div>
</aside>

{/* Mobile menu button */}
Expand Down
Loading