├── .env ├── public ├── java.png ├── python.png ├── javascript.png └── screenshot-for-readme.png ├── src ├── app │ ├── favicon.ico │ ├── fonts │ │ ├── GeistVF.woff │ │ └── GeistMonoVF.woff │ ├── (root) │ │ ├── layout.tsx │ │ ├── schedule │ │ │ ├── page.tsx │ │ │ └── InterviewScheduleUI.tsx │ │ ├── meeting │ │ │ └── [id] │ │ │ │ └── page.tsx │ │ ├── recordings │ │ │ └── page.tsx │ │ └── (home) │ │ │ └── page.tsx │ ├── layout.tsx │ ├── globals.css │ └── (admin) │ │ └── dashboard │ │ └── page.tsx ├── components │ ├── LoaderUI.tsx │ ├── providers │ │ ├── ThemeProvider.tsx │ │ ├── ConvexClerkProvider.tsx │ │ └── StreamClientProvider.tsx │ ├── DasboardBtn.tsx │ ├── UserInfo.tsx │ ├── ui │ │ ├── textarea.tsx │ │ ├── label.tsx │ │ ├── input.tsx │ │ ├── switch.tsx │ │ ├── badge.tsx │ │ ├── avatar.tsx │ │ ├── scroll-area.tsx │ │ ├── resizable.tsx │ │ ├── button.tsx │ │ ├── card.tsx │ │ ├── calendar.tsx │ │ ├── dialog.tsx │ │ ├── select.tsx │ │ └── dropdown-menu.tsx │ ├── Navbar.tsx │ ├── ModeToggle.tsx │ ├── EndCallButton.tsx │ ├── ActionCard.tsx │ ├── MeetingModal.tsx │ ├── MeetingCard.tsx │ ├── RecordingCard.tsx │ ├── MeetingRoom.tsx │ ├── MeetingSetup.tsx │ ├── CommentDialog.tsx │ └── CodeEditor.tsx ├── actions │ └── stream.actions.ts ├── hooks │ ├── useUserRole.ts │ ├── useGetCallById.ts │ ├── useMeetingActions.ts │ └── useGetCalls.ts ├── middleware.ts ├── lib │ └── utils.ts └── constants │ └── index.ts ├── next.config.mjs ├── postcss.config.mjs ├── convex ├── auth.config.ts ├── _generated │ ├── api.js │ ├── api.d.ts │ ├── dataModel.d.ts │ ├── server.js │ └── server.d.ts ├── tsconfig.json ├── comments.ts ├── schema.ts ├── users.ts ├── interviews.ts ├── http.ts └── README.md ├── .vscode └── tasks.json ├── components.json ├── .gitignore ├── tsconfig.json ├── LICENSE ├── package.json ├── tailwind.config.ts └── README.md /.env: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /public/java.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/its-pratyushpandey/Codivue/HEAD/public/java.png -------------------------------------------------------------------------------- /public/python.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/its-pratyushpandey/Codivue/HEAD/public/python.png -------------------------------------------------------------------------------- /src/app/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/its-pratyushpandey/Codivue/HEAD/src/app/favicon.ico -------------------------------------------------------------------------------- /public/javascript.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/its-pratyushpandey/Codivue/HEAD/public/javascript.png -------------------------------------------------------------------------------- /src/app/fonts/GeistVF.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/its-pratyushpandey/Codivue/HEAD/src/app/fonts/GeistVF.woff -------------------------------------------------------------------------------- /next.config.mjs: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = {}; 3 | 4 | export default nextConfig; 5 | -------------------------------------------------------------------------------- /src/app/fonts/GeistMonoVF.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/its-pratyushpandey/Codivue/HEAD/src/app/fonts/GeistMonoVF.woff -------------------------------------------------------------------------------- /public/screenshot-for-readme.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/its-pratyushpandey/Codivue/HEAD/public/screenshot-for-readme.png -------------------------------------------------------------------------------- /postcss.config.mjs: -------------------------------------------------------------------------------- 1 | /** @type {import('postcss-load-config').Config} */ 2 | const config = { 3 | plugins: { 4 | tailwindcss: {}, 5 | }, 6 | }; 7 | 8 | export default config; 9 | -------------------------------------------------------------------------------- /convex/auth.config.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | providers: [ 3 | { 4 | domain: "https://climbing-cattle-3.clerk.accounts.dev/", 5 | applicationID: "convex", 6 | }, 7 | ], 8 | }; 9 | -------------------------------------------------------------------------------- /src/app/(root)/layout.tsx: -------------------------------------------------------------------------------- 1 | import StreamClientProvider from "@/components/providers/StreamClientProvider"; 2 | 3 | function Layout({ children }: { children: React.ReactNode }) { 4 | return {children}; 5 | } 6 | export default Layout; 7 | -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "2.0.0", 3 | "tasks": [ 4 | { 5 | "type": "shell", 6 | "label": "Run Next.js App", 7 | "command": "npm run dev", 8 | "isBackground": true, 9 | "problemMatcher": [ 10 | "$tsc" 11 | ], 12 | "group": "build" 13 | } 14 | ] 15 | } -------------------------------------------------------------------------------- /src/components/LoaderUI.tsx: -------------------------------------------------------------------------------- 1 | import { LoaderIcon } from "lucide-react"; 2 | function LoaderUI() { 3 | // h-16 + 1 for border in navbar => 65px 4 | return ( 5 |
6 | 7 |
8 | ); 9 | } 10 | export default LoaderUI; 11 | -------------------------------------------------------------------------------- /src/components/providers/ThemeProvider.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import * as React from "react"; 4 | import { ThemeProvider as NextThemesProvider } from "next-themes"; 5 | 6 | 7 | export function ThemeProvider({ 8 | children, 9 | ...props 10 | }: React.ComponentProps) { 11 | return {children}; 12 | } 13 | -------------------------------------------------------------------------------- /convex/_generated/api.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | /** 3 | * Generated `api` utility. 4 | * 5 | * THIS CODE IS AUTOMATICALLY GENERATED. 6 | * 7 | * To regenerate, run `npx convex dev`. 8 | * @module 9 | */ 10 | 11 | import { anyApi } from "convex/server"; 12 | 13 | /** 14 | * A utility for referencing Convex functions in your app's API. 15 | * 16 | * Usage: 17 | * ```js 18 | * const myFunctionReference = api.myModule.myFunction; 19 | * ``` 20 | */ 21 | export const api = anyApi; 22 | export const internal = anyApi; 23 | -------------------------------------------------------------------------------- /components.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://ui.shadcn.com/schema.json", 3 | "style": "new-york", 4 | "rsc": true, 5 | "tsx": true, 6 | "tailwind": { 7 | "config": "tailwind.config.ts", 8 | "css": "src/app/globals.css", 9 | "baseColor": "neutral", 10 | "cssVariables": true, 11 | "prefix": "" 12 | }, 13 | "aliases": { 14 | "components": "@/components", 15 | "utils": "@/lib/utils", 16 | "ui": "@/components/ui", 17 | "lib": "@/lib", 18 | "hooks": "@/hooks" 19 | }, 20 | "iconLibrary": "lucide" 21 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | .yarn/install-state.gz 8 | 9 | # testing 10 | /coverage 11 | 12 | # next.js 13 | /.next/ 14 | /out/ 15 | 16 | # production 17 | /build 18 | 19 | # misc 20 | .DS_Store 21 | *.pem 22 | 23 | # debug 24 | npm-debug.log* 25 | yarn-debug.log* 26 | yarn-error.log* 27 | 28 | # local env files 29 | .env*.local 30 | 31 | # vercel 32 | .vercel 33 | 34 | # typescript 35 | *.tsbuildinfo 36 | next-env.d.ts 37 | -------------------------------------------------------------------------------- /src/app/(root)/schedule/page.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import LoaderUI from "@/components/LoaderUI"; 4 | import { useUserRole } from "@/hooks/useUserRole"; 5 | import { useRouter } from "next/navigation"; 6 | import InterviewScheduleUI from "./InterviewScheduleUI"; 7 | 8 | function SchedulePage() { 9 | const router = useRouter(); 10 | 11 | const { isInterviewer, isLoading } = useUserRole(); 12 | 13 | if (isLoading) return ; 14 | if (!isInterviewer) return router.push("/"); 15 | 16 | return ; 17 | } 18 | export default SchedulePage; 19 | -------------------------------------------------------------------------------- /src/actions/stream.actions.ts: -------------------------------------------------------------------------------- 1 | "use server"; 2 | import { currentUser } from "@clerk/nextjs/server"; 3 | import { StreamClient } from "@stream-io/node-sdk"; 4 | 5 | export const streamTokenProvider = async () => { 6 | const user = await currentUser(); 7 | 8 | if (!user) throw new Error("User not authenticated"); 9 | 10 | const streamClient = new StreamClient( 11 | process.env.NEXT_PUBLIC_STREAM_API_KEY!, 12 | process.env.STREAM_SECRET_KEY! 13 | ); 14 | 15 | 16 | 17 | const token = streamClient.generateUserToken({ user_id: user.id }); 18 | 19 | return token; 20 | }; 21 | -------------------------------------------------------------------------------- /src/hooks/useUserRole.ts: -------------------------------------------------------------------------------- 1 | import { useUser } from "@clerk/nextjs"; 2 | import { useQuery } from "convex/react"; 3 | import { api } from "../../convex/_generated/api"; 4 | 5 | export const useUserRole = () => { 6 | const { user } = useUser(); 7 | 8 | const userData = useQuery(api.users.getUserByClerkId, { 9 | clerkId: user?.id || "", 10 | }); 11 | 12 | const isLoading = userData === undefined; 13 | return { 14 | isLoading, 15 | isInterviewer: userData?.role === "interviewer", 16 | isCandidate: userData?.role === "candidate", 17 | userNotFound: userData === null, 18 | }; 19 | }; 20 | -------------------------------------------------------------------------------- /src/components/DasboardBtn.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import Link from "next/link"; 4 | import { Button } from "./ui/button"; 5 | import { SparklesIcon } from "lucide-react"; 6 | import { useUserRole } from "@/hooks/useUserRole"; 7 | 8 | function DasboardBtn() { 9 | const { isCandidate, isLoading } = useUserRole(); 10 | 11 | if (isCandidate || isLoading) return null; 12 | 13 | return ( 14 | 15 | 19 | 20 | ); 21 | } 22 | export default DasboardBtn; 23 | -------------------------------------------------------------------------------- /src/middleware.ts: -------------------------------------------------------------------------------- 1 | import { clerkMiddleware } from "@clerk/nextjs/server"; 2 | import type { NextRequest, NextFetchEvent } from "next/server"; 3 | export default async function middleware(req: NextRequest, ev: NextFetchEvent) { 4 | console.log("Middleware executed for:", req.url); 5 | return clerkMiddleware()(req, ev); 6 | } 7 | 8 | export const config = { 9 | matcher: [ 10 | // Skip Next.js internals and all static files, unless found in search params 11 | "/((?!_next|[^?]*\\.(?:html?|css|js(?!on)|jpe?g|webp|png|gif|svg|ttf|woff2?|ico|csv|docx?|xlsx?|zip|webmanifest)).*)", 12 | // Always run for API routes 13 | "/(api|trpc)(.*)", 14 | ], 15 | }; 16 | -------------------------------------------------------------------------------- /src/components/UserInfo.tsx: -------------------------------------------------------------------------------- 1 | import { UserCircleIcon } from "lucide-react"; 2 | import { Doc } from "../../convex/_generated/dataModel"; 3 | import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"; 4 | 5 | type User = Doc<"users">; 6 | 7 | function UserInfo({ user }: { user: User }) { 8 | return ( 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 | {user.name} 17 |
18 | ); 19 | } 20 | export default UserInfo; 21 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "lib": ["dom", "dom.iterable", "esnext"], 4 | "allowJs": true, 5 | "skipLibCheck": true, 6 | "strict": true, 7 | "noEmit": true, 8 | "esModuleInterop": true, 9 | "module": "esnext", 10 | "moduleResolution": "bundler", 11 | "resolveJsonModule": true, 12 | "isolatedModules": true, 13 | "jsx": "preserve", 14 | "incremental": true, 15 | "plugins": [ 16 | { 17 | "name": "next" 18 | } 19 | ], 20 | "paths": { 21 | "@/*": ["./src/*"] 22 | } 23 | }, 24 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], 25 | "exclude": ["node_modules"] 26 | } 27 | -------------------------------------------------------------------------------- /src/components/providers/ConvexClerkProvider.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import { ClerkProvider, useAuth } from "@clerk/nextjs"; 4 | import { ConvexReactClient } from "convex/react"; 5 | import { ConvexProviderWithClerk } from "convex/react-clerk"; 6 | 7 | const convex = new ConvexReactClient(process.env.NEXT_PUBLIC_CONVEX_URL!); 8 | function ConvexClerkProvider({ children }: { children: React.ReactNode }) { 9 | return ( 10 | 11 | 12 | {children} 13 | 14 | 15 | ); 16 | } 17 | 18 | export default ConvexClerkProvider; 19 | -------------------------------------------------------------------------------- /src/components/ui/textarea.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react" 2 | 3 | import { cn } from "@/lib/utils" 4 | 5 | const Textarea = React.forwardRef< 6 | HTMLTextAreaElement, 7 | React.ComponentProps<"textarea"> 8 | >(({ className, ...props }, ref) => { 9 | return ( 10 |