diff --git a/base_files/after_issue_3/server/src/controller.js b/base_files/after_issue_3/server/src/controller.js new file mode 100644 index 0000000..6e25368 --- /dev/null +++ b/base_files/after_issue_3/server/src/controller.js @@ -0,0 +1,40 @@ +import {Subscription} from "./models/Subscription.js"; + +const addSubscription= async (req, res) => { + const {userId, name, amount, billingCycle, renewalDate, isTrial, source} = req.body; + + if(!userId || !name || !amount || !billingCycle || !renewalDate || !isTrial || !source){ + return res.json({error: "Missing fields!"}); + } + + const data= await Subscription.create(req.body); + console.log(data); + + return res.json({success: "Subscription added successfully!"}); + +} + +const fetchSubscriptions= async (req, res) => { + const {userId} = req.body; + + if(!userId){ + return res.json({error: "UserID required!"}); + } + + const subs= await Subscription.find( + {userId: userId}, + {name:1, amount:1, billingCycle:1, renewalDate:1, _id: 0} + ); + + if(!subs){ + return res.json({error: "Failes to fetch subscriptions!"}); + } + + if(subs.length == 0){ + return res.json({error: "No data found!"}); + } + + return res.json(subs); +} + +export {addSubscription, fetchSubscriptions}; \ No newline at end of file diff --git a/base_files/after_issue_3/server/src/middleware/authConfirm.js b/base_files/after_issue_3/server/src/middleware/authConfirm.js new file mode 100644 index 0000000..e69de29 diff --git a/base_files/after_issue_3/server/src/route.js b/base_files/after_issue_3/server/src/route.js new file mode 100644 index 0000000..3b97e54 --- /dev/null +++ b/base_files/after_issue_3/server/src/route.js @@ -0,0 +1,14 @@ +import express from 'express'; +import { addSubscription, fetchSubscriptions } from './controller.js'; +const router = express.Router(); + +router.get("/healthCheck", (req, res) => { + + return res.json({health: "Working fine!"}) + +}) + +router.get("/subscriptions", fetchSubscriptions); +router.post("/subscriptions", addSubscription); + +export default router; \ No newline at end of file diff --git a/contributors/Anshdeep-Singh-9/client/.gitignore b/contributors/Anshdeep-Singh-9/client/.gitignore new file mode 100644 index 0000000..e2764f9 --- /dev/null +++ b/contributors/Anshdeep-Singh-9/client/.gitignore @@ -0,0 +1,44 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +/node_modules +/.pnp +.pnp.* +.yarn/* +!.yarn/patches +!.yarn/plugins +!.yarn/releases +!.yarn/versions + +# testing +/coverage + +# next.js +/.next/ +/out/ + +# production +/build + +# misc +.DS_Store +*.pem + +# debug +npm-debug.log* +yarn-debug.log* +yarn-error.log* +.pnpm-debug.log* + +# env files (can opt-in for committing if needed) +.env* + +# vercel +.vercel + +# typescript +*.tsbuildinfo +next-env.d.ts + +# clerk configuration (can include secrets) +/.clerk/ diff --git a/contributors/Anshdeep-Singh-9/client/README.md b/contributors/Anshdeep-Singh-9/client/README.md new file mode 100644 index 0000000..e215bc4 --- /dev/null +++ b/contributors/Anshdeep-Singh-9/client/README.md @@ -0,0 +1,36 @@ +This is a [Next.js](https://nextjs.org) project bootstrapped with [`create-next-app`](https://nextjs.org/docs/app/api-reference/cli/create-next-app). + +## Getting Started + +First, run the development server: + +```bash +npm run dev +# or +yarn dev +# or +pnpm dev +# or +bun dev +``` + +Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. + +You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file. + +This project uses [`next/font`](https://nextjs.org/docs/app/building-your-application/optimizing/fonts) to automatically optimize and load [Geist](https://vercel.com/font), a new font family for Vercel. + +## Learn More + +To learn more about Next.js, take a look at the following resources: + +- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API. +- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial. + +You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js) - your feedback and contributions are welcome! + +## Deploy on Vercel + +The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js. + +Check out our [Next.js deployment documentation](https://nextjs.org/docs/app/building-your-application/deploying) for more details. diff --git a/contributors/Anshdeep-Singh-9/client/envExample b/contributors/Anshdeep-Singh-9/client/envExample new file mode 100644 index 0000000..6d7b26a --- /dev/null +++ b/contributors/Anshdeep-Singh-9/client/envExample @@ -0,0 +1,2 @@ +NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=pk_test_PLACEHOLDER +CLERK_SECRET_KEY=sk_test_PLACEHOLDER diff --git a/contributors/Anshdeep-Singh-9/client/eslint.config.mjs b/contributors/Anshdeep-Singh-9/client/eslint.config.mjs new file mode 100644 index 0000000..05e726d --- /dev/null +++ b/contributors/Anshdeep-Singh-9/client/eslint.config.mjs @@ -0,0 +1,18 @@ +import { defineConfig, globalIgnores } from "eslint/config"; +import nextVitals from "eslint-config-next/core-web-vitals"; +import nextTs from "eslint-config-next/typescript"; + +const eslintConfig = defineConfig([ + ...nextVitals, + ...nextTs, + // Override default ignores of eslint-config-next. + globalIgnores([ + // Default ignores of eslint-config-next: + ".next/**", + "out/**", + "build/**", + "next-env.d.ts", + ]), +]); + +export default eslintConfig; diff --git a/contributors/Anshdeep-Singh-9/client/next.config.ts b/contributors/Anshdeep-Singh-9/client/next.config.ts new file mode 100644 index 0000000..e9ffa30 --- /dev/null +++ b/contributors/Anshdeep-Singh-9/client/next.config.ts @@ -0,0 +1,7 @@ +import type { NextConfig } from "next"; + +const nextConfig: NextConfig = { + /* config options here */ +}; + +export default nextConfig; diff --git a/contributors/Anshdeep-Singh-9/client/package.json b/contributors/Anshdeep-Singh-9/client/package.json new file mode 100644 index 0000000..e447189 --- /dev/null +++ b/contributors/Anshdeep-Singh-9/client/package.json @@ -0,0 +1,27 @@ +{ + "name": "client", + "version": "0.1.0", + "private": true, + "scripts": { + "dev": "next dev", + "build": "next build", + "start": "next start", + "lint": "eslint" + }, + "dependencies": { + "@clerk/nextjs": "^6.36.5", + "next": "16.1.1", + "react": "19.2.3", + "react-dom": "19.2.3" + }, + "devDependencies": { + "@tailwindcss/postcss": "^4", + "@types/node": "^20", + "@types/react": "^19", + "@types/react-dom": "^19", + "eslint": "^9", + "eslint-config-next": "16.1.1", + "tailwindcss": "^4", + "typescript": "^5" + } +} diff --git a/contributors/Anshdeep-Singh-9/client/postcss.config.mjs b/contributors/Anshdeep-Singh-9/client/postcss.config.mjs new file mode 100644 index 0000000..61e3684 --- /dev/null +++ b/contributors/Anshdeep-Singh-9/client/postcss.config.mjs @@ -0,0 +1,7 @@ +const config = { + plugins: { + "@tailwindcss/postcss": {}, + }, +}; + +export default config; diff --git a/contributors/Anshdeep-Singh-9/client/public/file.svg b/contributors/Anshdeep-Singh-9/client/public/file.svg new file mode 100644 index 0000000..004145c --- /dev/null +++ b/contributors/Anshdeep-Singh-9/client/public/file.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/contributors/Anshdeep-Singh-9/client/public/globe.svg b/contributors/Anshdeep-Singh-9/client/public/globe.svg new file mode 100644 index 0000000..567f17b --- /dev/null +++ b/contributors/Anshdeep-Singh-9/client/public/globe.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/contributors/Anshdeep-Singh-9/client/public/next.svg b/contributors/Anshdeep-Singh-9/client/public/next.svg new file mode 100644 index 0000000..5174b28 --- /dev/null +++ b/contributors/Anshdeep-Singh-9/client/public/next.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/contributors/Anshdeep-Singh-9/client/public/vercel.svg b/contributors/Anshdeep-Singh-9/client/public/vercel.svg new file mode 100644 index 0000000..7705396 --- /dev/null +++ b/contributors/Anshdeep-Singh-9/client/public/vercel.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/contributors/Anshdeep-Singh-9/client/public/window.svg b/contributors/Anshdeep-Singh-9/client/public/window.svg new file mode 100644 index 0000000..b2b2a44 --- /dev/null +++ b/contributors/Anshdeep-Singh-9/client/public/window.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/contributors/Anshdeep-Singh-9/client/src/app/dashboard/page.tsx b/contributors/Anshdeep-Singh-9/client/src/app/dashboard/page.tsx new file mode 100644 index 0000000..7c79306 --- /dev/null +++ b/contributors/Anshdeep-Singh-9/client/src/app/dashboard/page.tsx @@ -0,0 +1,40 @@ +import { UserButton } from '@clerk/nextjs'; +import { currentUser } from '@clerk/nextjs/server'; +import { redirect } from 'next/navigation'; + +export default async function DashboardPage() { + const user = await currentUser(); + + if (!user) { + redirect('/sign-in'); + } + + return ( +
+
+
+

+ Dashboard +

+ + +
+ +
+

+ Welcome, {user.firstName ?? 'User'} 👋 +

+ +
+

+ Email: {user.emailAddresses[0]?.emailAddress} +

+

+ User ID: {user.id} +

+
+
+
+
+ ); +} diff --git a/contributors/Anshdeep-Singh-9/client/src/app/favicon.ico b/contributors/Anshdeep-Singh-9/client/src/app/favicon.ico new file mode 100644 index 0000000..718d6fe Binary files /dev/null and b/contributors/Anshdeep-Singh-9/client/src/app/favicon.ico differ diff --git a/contributors/Anshdeep-Singh-9/client/src/app/globals.css b/contributors/Anshdeep-Singh-9/client/src/app/globals.css new file mode 100644 index 0000000..a2dc41e --- /dev/null +++ b/contributors/Anshdeep-Singh-9/client/src/app/globals.css @@ -0,0 +1,26 @@ +@import "tailwindcss"; + +:root { + --background: #ffffff; + --foreground: #171717; +} + +@theme inline { + --color-background: var(--background); + --color-foreground: var(--foreground); + --font-sans: var(--font-geist-sans); + --font-mono: var(--font-geist-mono); +} + +@media (prefers-color-scheme: dark) { + :root { + --background: #0a0a0a; + --foreground: #ededed; + } +} + +body { + background: var(--background); + color: var(--foreground); + font-family: Arial, Helvetica, sans-serif; +} diff --git a/contributors/Anshdeep-Singh-9/client/src/app/layout.tsx b/contributors/Anshdeep-Singh-9/client/src/app/layout.tsx new file mode 100644 index 0000000..a923b7e --- /dev/null +++ b/contributors/Anshdeep-Singh-9/client/src/app/layout.tsx @@ -0,0 +1,37 @@ +import type { Metadata } from "next"; +import { Geist, Geist_Mono } from "next/font/google"; +import "./globals.css"; +import { ClerkProvider } from "@clerk/nextjs"; + +const geistSans = Geist({ + variable: "--font-geist-sans", + subsets: ["latin"], +}); + +const geistMono = Geist_Mono({ + variable: "--font-geist-mono", + subsets: ["latin"], +}); + +export const metadata: Metadata = { + title: "Create Next App", + description: "Generated by create next app", +}; + +export default function RootLayout({ + children, +}: Readonly<{ + children: React.ReactNode; +}>) { + return ( + + + + {children} + + + + ); +} diff --git a/contributors/Anshdeep-Singh-9/client/src/app/page.tsx b/contributors/Anshdeep-Singh-9/client/src/app/page.tsx new file mode 100644 index 0000000..ccf4300 --- /dev/null +++ b/contributors/Anshdeep-Singh-9/client/src/app/page.tsx @@ -0,0 +1,42 @@ +import { SignedIn, SignedOut, SignInButton } from '@clerk/nextjs'; +import Link from 'next/link'; + +export default function Home() { + return ( +
+
+

SubSentry

+ +

+ Secure subscription management with industry-grade authentication. +

+ +
+ + + + + + + Sign Up + + + + + + Go to Dashboard + + +
+
+
+ ); +} diff --git a/contributors/Anshdeep-Singh-9/client/src/middleware.ts b/contributors/Anshdeep-Singh-9/client/src/middleware.ts new file mode 100644 index 0000000..8c40de4 --- /dev/null +++ b/contributors/Anshdeep-Singh-9/client/src/middleware.ts @@ -0,0 +1,23 @@ +import { clerkMiddleware, createRouteMatcher } from '@clerk/nextjs/server'; + +const isPublicRoute = createRouteMatcher([ + '/', + '/sign-in(.*)', // sign-in routes + '/sign-up(.*)', +]); + +export default clerkMiddleware(async (auth, request) => { + if (!isPublicRoute(request)) { + await auth.protect(); + } +}); + +export const config = { + matcher: [ + // Skip _next, static files, images, fonts, etc. + '/((?!_next|[^?]*\\.(?:html?|css|js(?!on)|jpe?g|png|webp|gif|svg|ttf|woff2?|ico|csv|docx?|xlsx?|zip|webmanifest)).*)', + + // Always run middleware for API & tRPC routes + '/(api|trpc)(.*)', + ], +}; diff --git a/contributors/Anshdeep-Singh-9/client/tsconfig.json b/contributors/Anshdeep-Singh-9/client/tsconfig.json new file mode 100644 index 0000000..cf9c65d --- /dev/null +++ b/contributors/Anshdeep-Singh-9/client/tsconfig.json @@ -0,0 +1,34 @@ +{ + "compilerOptions": { + "target": "ES2017", + "lib": ["dom", "dom.iterable", "esnext"], + "allowJs": true, + "skipLibCheck": true, + "strict": true, + "noEmit": true, + "esModuleInterop": true, + "module": "esnext", + "moduleResolution": "bundler", + "resolveJsonModule": true, + "isolatedModules": true, + "jsx": "react-jsx", + "incremental": true, + "plugins": [ + { + "name": "next" + } + ], + "paths": { + "@/*": ["./src/*"] + } + }, + "include": [ + "next-env.d.ts", + "**/*.ts", + "**/*.tsx", + ".next/types/**/*.ts", + ".next/dev/types/**/*.ts", + "**/*.mts" + ], + "exclude": ["node_modules"] +} diff --git a/contributors/Anshdeep-Singh-9/server/.gitignore b/contributors/Anshdeep-Singh-9/server/.gitignore new file mode 100644 index 0000000..4c49bd7 --- /dev/null +++ b/contributors/Anshdeep-Singh-9/server/.gitignore @@ -0,0 +1 @@ +.env diff --git a/contributors/Anshdeep-Singh-9/server/envExample b/contributors/Anshdeep-Singh-9/server/envExample new file mode 100644 index 0000000..c361fab --- /dev/null +++ b/contributors/Anshdeep-Singh-9/server/envExample @@ -0,0 +1,2 @@ +PORT=5000 +MONGO_URI=mongodb://localhost:27017/subsentry diff --git a/contributors/Anshdeep-Singh-9/server/package.json b/contributors/Anshdeep-Singh-9/server/package.json new file mode 100644 index 0000000..2855186 --- /dev/null +++ b/contributors/Anshdeep-Singh-9/server/package.json @@ -0,0 +1,18 @@ +{ + "name": "server", + "version": "1.0.0", + "description": "SubSentry Backend Server", + "scripts": { + "start": "node src/server.js", + "dev": "nodemon src/server.js" + }, + "type": "module", + "dependencies": { + "cors": "^2.8.5", + "dotenv": "^16.0.0", + "express": "^4.17.1", + "mongodb": "^7.0.0", + "mongoose": "^6.0.0", + "nodemon": "^3.1.11" + } +} diff --git a/contributors/Anshdeep-Singh-9/server/src/app.js b/contributors/Anshdeep-Singh-9/server/src/app.js new file mode 100644 index 0000000..b13614d --- /dev/null +++ b/contributors/Anshdeep-Singh-9/server/src/app.js @@ -0,0 +1,18 @@ +2; +import cors from 'cors'; +import express from 'express'; + +const app = express(); + +app.use(cors()); +app.use(express.json()); + +import routes from "./route.js"; + +app.get('/', (_, res) => { + res.send('SubSentry API running'); +}); + +app.use("/api", routes); + +export default app; diff --git a/contributors/Anshdeep-Singh-9/server/src/config/db.js b/contributors/Anshdeep-Singh-9/server/src/config/db.js new file mode 100644 index 0000000..9fb8b29 --- /dev/null +++ b/contributors/Anshdeep-Singh-9/server/src/config/db.js @@ -0,0 +1,33 @@ +import mongoose from 'mongoose'; + +const MONGO_URI = process.env.MONGO_URI; + +if (!MONGO_URI) { + throw new Error('❌ Please define MONGO_URI in environment variables'); +} + +mongoose.set('strictQuery', false); + +let cached = global.mongoose; + +if (!cached) { + cached = global.mongoose = { conn: null, promise: null }; +} + +export async function connectDB() { + if (cached.conn) return cached.conn; + + if (!cached.promise) { + cached.promise = mongoose.connect(MONGO_URI); + } + + try { + cached.conn = await cached.promise; + console.log('MongoDB connected'); + return cached.conn; + } catch (err) { + cached.promise = null; + console.error('MongoDB connection failed', err); + throw err; + } +} diff --git a/contributors/Anshdeep-Singh-9/server/src/controller.js b/contributors/Anshdeep-Singh-9/server/src/controller.js new file mode 100644 index 0000000..6e25368 --- /dev/null +++ b/contributors/Anshdeep-Singh-9/server/src/controller.js @@ -0,0 +1,40 @@ +import {Subscription} from "./models/Subscription.js"; + +const addSubscription= async (req, res) => { + const {userId, name, amount, billingCycle, renewalDate, isTrial, source} = req.body; + + if(!userId || !name || !amount || !billingCycle || !renewalDate || !isTrial || !source){ + return res.json({error: "Missing fields!"}); + } + + const data= await Subscription.create(req.body); + console.log(data); + + return res.json({success: "Subscription added successfully!"}); + +} + +const fetchSubscriptions= async (req, res) => { + const {userId} = req.body; + + if(!userId){ + return res.json({error: "UserID required!"}); + } + + const subs= await Subscription.find( + {userId: userId}, + {name:1, amount:1, billingCycle:1, renewalDate:1, _id: 0} + ); + + if(!subs){ + return res.json({error: "Failes to fetch subscriptions!"}); + } + + if(subs.length == 0){ + return res.json({error: "No data found!"}); + } + + return res.json(subs); +} + +export {addSubscription, fetchSubscriptions}; \ No newline at end of file diff --git a/contributors/Anshdeep-Singh-9/server/src/middleware/authConfirm.js b/contributors/Anshdeep-Singh-9/server/src/middleware/authConfirm.js new file mode 100644 index 0000000..e69de29 diff --git a/contributors/Anshdeep-Singh-9/server/src/models/Subscription.js b/contributors/Anshdeep-Singh-9/server/src/models/Subscription.js new file mode 100644 index 0000000..7bc4180 --- /dev/null +++ b/contributors/Anshdeep-Singh-9/server/src/models/Subscription.js @@ -0,0 +1,39 @@ +import { Schema, model } from 'mongoose'; + +const subscriptionSchema = new Schema( + { + userId: { + type: String, + required: true, + }, + name: { + type: String, + required: true, + }, + amount: { + type: Number, + required: true, + }, + billingCycle: { + type: String, + enum: ['monthly', 'yearly'], + required: true, + }, + renewalDate: { + type: Date, + required: true, + }, + isTrial: { + type: Boolean, + default: false, + }, + source: { + type: String, + enum: ['manual', 'email'], + default: 'manual', + }, + }, + { timestamps: true } +); + +export const Subscription = model('Subscription', subscriptionSchema, "Subscriptions"); diff --git a/contributors/Anshdeep-Singh-9/server/src/route.js b/contributors/Anshdeep-Singh-9/server/src/route.js new file mode 100644 index 0000000..3b97e54 --- /dev/null +++ b/contributors/Anshdeep-Singh-9/server/src/route.js @@ -0,0 +1,14 @@ +import express from 'express'; +import { addSubscription, fetchSubscriptions } from './controller.js'; +const router = express.Router(); + +router.get("/healthCheck", (req, res) => { + + return res.json({health: "Working fine!"}) + +}) + +router.get("/subscriptions", fetchSubscriptions); +router.post("/subscriptions", addSubscription); + +export default router; \ No newline at end of file diff --git a/contributors/Anshdeep-Singh-9/server/src/server.js b/contributors/Anshdeep-Singh-9/server/src/server.js new file mode 100644 index 0000000..ffa41e4 --- /dev/null +++ b/contributors/Anshdeep-Singh-9/server/src/server.js @@ -0,0 +1,16 @@ +import 'dotenv/config'; + +import app from './app.js'; +import { connectDB } from './config/db.js'; + +const PORT = process.env.PORT || 5000; + +async function startServer() { + await connectDB(); + + app.listen(PORT, () => { + console.log(`SubSentry API running on port ${PORT}`); + }); +} + +startServer();