├── bun.lockb ├── app ├── icon1.png ├── icon2.png ├── favicon.ico ├── apple-icon.png ├── (auth) │ ├── sign-in │ │ └── [[...sign-in]] │ │ │ └── page.tsx │ └── sign-up │ │ └── [[...sign-up]] │ │ └── page.tsx ├── (root) │ ├── (home) │ │ ├── previous │ │ │ └── page.tsx │ │ ├── upcoming │ │ │ └── page.tsx │ │ ├── recordings │ │ │ └── page.tsx │ │ ├── layout.tsx │ │ ├── page.tsx │ │ └── personal-room │ │ │ └── page.tsx │ ├── layout.tsx │ └── meeting │ │ └── [id] │ │ └── page.tsx ├── layout.tsx └── globals.css ├── .github ├── images │ ├── img1.png │ ├── img2.png │ ├── img3.png │ ├── img4.png │ ├── img_main.png │ └── stats.svg ├── dependabot.yml ├── ISSUE_TEMPLATE │ ├── feature_request.md │ └── bug_report.md └── workflows │ └── update-bun-lockfile.yml ├── public ├── images │ ├── avatar-3.png │ ├── avatar-4.png │ ├── avatar-5.png │ ├── avatar-1.jpeg │ ├── avatar-2.jpeg │ └── hero-background.png └── icons │ ├── three-dots.svg │ ├── home.svg │ ├── hamburger.svg │ ├── play.svg │ ├── video.svg │ ├── recordings.svg │ ├── add-meeting.svg │ ├── add-personal.svg │ ├── github.svg │ ├── loading-circle.svg │ ├── schedule.svg │ ├── copy.svg │ ├── previous.svg │ ├── upcoming.svg │ ├── share.svg │ ├── join-meeting.svg │ ├── call-ended.svg │ ├── logo.svg │ ├── yoom-logo.svg │ └── checked.svg ├── next.config.mjs ├── .eslintrc.json ├── postcss.config.mjs ├── .prettierrc.json ├── lib └── utils.ts ├── components ├── loader.tsx ├── ui │ ├── textarea.tsx │ ├── input.tsx │ ├── toaster.tsx │ ├── button.tsx │ ├── dialog.tsx │ ├── sheet.tsx │ ├── use-toast.ts │ ├── toast.tsx │ └── dropdown-menu.tsx ├── end-call-button.tsx ├── home-card.tsx ├── navbar.tsx ├── sidebar.tsx ├── modals │ └── meeting-modal.tsx ├── meeting-setup.tsx ├── mobile-nav.tsx ├── meeting-card.tsx ├── call-list.tsx ├── meeting-room.tsx └── meeting-type-list.tsx ├── environment.d.ts ├── components.json ├── middleware.ts ├── .gitignore ├── .env.example ├── tsconfig.json ├── SECURITY.md ├── constants └── index.ts ├── hooks ├── use-get-call-by-id.ts └── use-get-calls.ts ├── actions └── stream.actions.ts ├── config └── index.ts ├── LICENSE ├── providers └── stream-client-provider.tsx ├── tailwind.config.ts ├── package.json ├── CODE_OF_CONDUCT.md └── README.md /bun.lockb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kamillm/ts-zoom/HEAD/bun.lockb -------------------------------------------------------------------------------- /app/icon1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kamillm/ts-zoom/HEAD/app/icon1.png -------------------------------------------------------------------------------- /app/icon2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kamillm/ts-zoom/HEAD/app/icon2.png -------------------------------------------------------------------------------- /app/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kamillm/ts-zoom/HEAD/app/favicon.ico -------------------------------------------------------------------------------- /app/apple-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kamillm/ts-zoom/HEAD/app/apple-icon.png -------------------------------------------------------------------------------- /.github/images/img1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kamillm/ts-zoom/HEAD/.github/images/img1.png -------------------------------------------------------------------------------- /.github/images/img2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kamillm/ts-zoom/HEAD/.github/images/img2.png -------------------------------------------------------------------------------- /.github/images/img3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kamillm/ts-zoom/HEAD/.github/images/img3.png -------------------------------------------------------------------------------- /.github/images/img4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kamillm/ts-zoom/HEAD/.github/images/img4.png -------------------------------------------------------------------------------- /public/images/avatar-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kamillm/ts-zoom/HEAD/public/images/avatar-3.png -------------------------------------------------------------------------------- /public/images/avatar-4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kamillm/ts-zoom/HEAD/public/images/avatar-4.png -------------------------------------------------------------------------------- /public/images/avatar-5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kamillm/ts-zoom/HEAD/public/images/avatar-5.png -------------------------------------------------------------------------------- /.github/images/img_main.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kamillm/ts-zoom/HEAD/.github/images/img_main.png -------------------------------------------------------------------------------- /public/images/avatar-1.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kamillm/ts-zoom/HEAD/public/images/avatar-1.jpeg -------------------------------------------------------------------------------- /public/images/avatar-2.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kamillm/ts-zoom/HEAD/public/images/avatar-2.jpeg -------------------------------------------------------------------------------- /public/images/hero-background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kamillm/ts-zoom/HEAD/public/images/hero-background.png -------------------------------------------------------------------------------- /next.config.mjs: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = {}; 3 | 4 | export default nextConfig; 5 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "next/core-web-vitals", 3 | "plugins": ["unused-imports"], 4 | "rules": { 5 | "unused-imports/no-unused-imports": "error" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /.prettierrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "trailingComma": "es5", 3 | "semi": true, 4 | "tabWidth": 2, 5 | "singleQuote": false, 6 | "jsxSingleQuote": false, 7 | "plugins": ["prettier-plugin-tailwindcss"] 8 | } 9 | -------------------------------------------------------------------------------- /lib/utils.ts: -------------------------------------------------------------------------------- 1 | import { type ClassValue, clsx } from "clsx"; 2 | import { twMerge } from "tailwind-merge"; 3 | 4 | export function cn(...inputs: ClassValue[]) { 5 | return twMerge(clsx(inputs)); 6 | } 7 | -------------------------------------------------------------------------------- /app/(auth)/sign-in/[[...sign-in]]/page.tsx: -------------------------------------------------------------------------------- 1 | import { SignIn } from "@clerk/nextjs"; 2 | 3 | const SignInPage = () => { 4 | return ( 5 |
6 | 7 |
8 | ); 9 | }; 10 | 11 | export default SignInPage; 12 | -------------------------------------------------------------------------------- /app/(auth)/sign-up/[[...sign-up]]/page.tsx: -------------------------------------------------------------------------------- 1 | import { SignUp } from "@clerk/nextjs"; 2 | 3 | const SignUpPage = () => { 4 | return ( 5 |
6 | 7 |
8 | ); 9 | }; 10 | 11 | export default SignUpPage; 12 | -------------------------------------------------------------------------------- /components/loader.tsx: -------------------------------------------------------------------------------- 1 | import Image from "next/image"; 2 | 3 | export const Loader = () => { 4 | return ( 5 |
6 | Loading 12 |
13 | ); 14 | }; 15 | -------------------------------------------------------------------------------- /public/icons/three-dots.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /app/(root)/(home)/previous/page.tsx: -------------------------------------------------------------------------------- 1 | import { CallList } from "@/components/call-list"; 2 | 3 | const PreviousPage = () => { 4 | return ( 5 |
6 |

Previous

7 | 8 | 9 |
10 | ); 11 | }; 12 | 13 | export default PreviousPage; 14 | -------------------------------------------------------------------------------- /app/(root)/layout.tsx: -------------------------------------------------------------------------------- 1 | import type { PropsWithChildren } from "react"; 2 | 3 | import { StreamClientProvider } from "@/providers/stream-client-provider"; 4 | 5 | const RootLayout = ({ children }: PropsWithChildren) => { 6 | return ( 7 |
8 | {children} 9 |
10 | ); 11 | }; 12 | 13 | export default RootLayout; 14 | -------------------------------------------------------------------------------- /environment.d.ts: -------------------------------------------------------------------------------- 1 | // This file is needed to support autocomplete for process.env 2 | export {}; 3 | 4 | declare global { 5 | namespace NodeJS { 6 | interface ProcessEnv { 7 | // stream api keys 8 | NEXT_PUBLIC_STREAM_API_KEY: string; 9 | STREAM_SECRET_KEY: string; 10 | 11 | // app base url 12 | NEXT_PUBLIC_BASE_URL: string; 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /app/(root)/(home)/upcoming/page.tsx: -------------------------------------------------------------------------------- 1 | import { CallList } from "@/components/call-list"; 2 | 3 | const UpcomingPage = () => { 4 | return ( 5 |
6 |

Upcoming

7 | 8 | 9 |
10 | ); 11 | }; 12 | 13 | export default UpcomingPage; 14 | -------------------------------------------------------------------------------- /app/(root)/(home)/recordings/page.tsx: -------------------------------------------------------------------------------- 1 | import { CallList } from "@/components/call-list"; 2 | 3 | const RecordingsPage = () => { 4 | return ( 5 |
6 |

Recordings

7 | 8 | 9 |
10 | ); 11 | }; 12 | 13 | export default RecordingsPage; 14 | -------------------------------------------------------------------------------- /components.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://ui.shadcn.com/schema.json", 3 | "style": "default", 4 | "rsc": true, 5 | "tsx": true, 6 | "tailwind": { 7 | "config": "tailwind.config.ts", 8 | "css": "app/globals.css", 9 | "baseColor": "slate", 10 | "cssVariables": true, 11 | "prefix": "" 12 | }, 13 | "aliases": { 14 | "components": "@/components", 15 | "utils": "@/lib/utils" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /public/icons/home.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /middleware.ts: -------------------------------------------------------------------------------- 1 | import { clerkMiddleware, createRouteMatcher } from "@clerk/nextjs/server"; 2 | 3 | const protectedRoutes = createRouteMatcher([ 4 | "/", 5 | "/upcoming", 6 | "/previous", 7 | "/recordings", 8 | "/personal-room", 9 | "/meeting(.*)", 10 | ]); 11 | 12 | export default clerkMiddleware((auth, req) => { 13 | if (protectedRoutes(req)) auth().protect(); 14 | }); 15 | 16 | export const config = { 17 | matcher: ["/((?!.*\\..*|_next).*)", "/", "/(api|trpc)(.*)"], 18 | }; 19 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # To get started with Dependabot version updates, you'll need to specify which 2 | # package ecosystems to update and where the package manifests are located. 3 | # Please see the documentation for all configuration options: 4 | # https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file 5 | 6 | version: 2 7 | updates: 8 | - package-ecosystem: "npm" # See documentation for possible values 9 | directory: "/" # Location of package manifests 10 | schedule: 11 | interval: "monthly" 12 | versioning-strategy: increase 13 | -------------------------------------------------------------------------------- /.env.example: -------------------------------------------------------------------------------- 1 | # .env.local 2 | 3 | # disabled next.js telemetry 4 | NEXT_TELEMETRY_DISABLED=1 5 | 6 | # clerk auth keys 7 | NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=pk_test_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX 8 | CLERK_SECRET_KEY=sk_test_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX 9 | 10 | # clerk auth redirect urls 11 | NEXT_PUBLIC_CLERK_SIGN_IN_URL=/sign-in 12 | NEXT_PUBLIC_CLERK_SIGN_UP_URL=/sign-up 13 | 14 | # stream api keys 15 | NEXT_PUBLIC_STREAM_API_KEY=xxxxxxxxxxxxxxxxxxxxxx 16 | STREAM_SECRET_KEY=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX 17 | 18 | # app base url 19 | NEXT_PUBLIC_BASE_URL=http://localhost:3000 20 | -------------------------------------------------------------------------------- /app/(root)/(home)/layout.tsx: -------------------------------------------------------------------------------- 1 | import type { PropsWithChildren } from "react"; 2 | 3 | import { Navbar } from "@/components/navbar"; 4 | import { Sidebar } from "@/components/sidebar"; 5 | 6 | const HomeLayout = ({ children }: PropsWithChildren) => { 7 | return ( 8 |
9 | 10 | 11 |
12 | 13 | 14 |
15 |
{children}
16 |
17 |
18 |
19 | ); 20 | }; 21 | 22 | export default HomeLayout; 23 | -------------------------------------------------------------------------------- /public/icons/hamburger.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /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 | "@/*": ["./*"] 22 | } 23 | }, 24 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], 25 | "exclude": ["node_modules"] 26 | } 27 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: "" 5 | labels: "" 6 | assignees: "" 7 | --- 8 | 9 | **Is your feature request related to a problem? Please describe.** 10 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 11 | 12 | **Describe the solution you'd like** 13 | A clear and concise description of what you want to happen. 14 | 15 | **Describe alternatives you've considered** 16 | A clear and concise description of any alternative solutions or features you've considered. 17 | 18 | **Additional context** 19 | Add any other context or screenshots about the feature request here. 20 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | ## Supported Versions 4 | 5 | Use this section to tell people about which versions of your project are 6 | currently being supported with security updates. 7 | 8 | | Version | Supported | 9 | | ------- | ------------------ | 10 | | 5.1.x | :white_check_mark: | 11 | | 5.0.x | :x: | 12 | | 4.0.x | :white_check_mark: | 13 | | < 4.0 | :x: | 14 | 15 | ## Reporting a Vulnerability 16 | 17 | Use this section to tell people how to report a vulnerability. 18 | 19 | Tell them where to go, how often they can expect to get an update on a 20 | reported vulnerability, what to expect if the vulnerability is accepted or 21 | declined, etc. 22 | -------------------------------------------------------------------------------- /constants/index.ts: -------------------------------------------------------------------------------- 1 | export const SIDEBAR_LINKS = [ 2 | { 3 | label: "Home", 4 | route: "/", 5 | imgUrl: "/icons/home.svg", 6 | }, 7 | { 8 | label: "Upcoming", 9 | route: "/upcoming", 10 | imgUrl: "/icons/upcoming.svg", 11 | }, 12 | { 13 | label: "Previous", 14 | route: "/previous", 15 | imgUrl: "/icons/previous.svg", 16 | }, 17 | { 18 | label: "Recordings", 19 | route: "/recordings", 20 | imgUrl: "/icons/video.svg", 21 | }, 22 | { 23 | label: "Personal Room", 24 | route: "/personal-room", 25 | imgUrl: "/icons/add-personal.svg", 26 | }, 27 | ] as const; 28 | 29 | export const avatarImages = [ 30 | "/images/avatar-1.jpeg", 31 | "/images/avatar-2.jpeg", 32 | "/images/avatar-3.png", 33 | "/images/avatar-4.png", 34 | "/images/avatar-5.png", 35 | ] as const; 36 | -------------------------------------------------------------------------------- /public/icons/play.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /.github/workflows/update-bun-lockfile.yml: -------------------------------------------------------------------------------- 1 | name: 'Dependabot: Update bun.lockb' 2 | 3 | on: 4 | pull_request: 5 | paths: 6 | - "package.json" 7 | 8 | permissions: 9 | contents: write 10 | 11 | jobs: 12 | update-bun-lockb: 13 | name: "Update bun.lockb" 14 | if: github.actor == 'dependabot[bot]' 15 | runs-on: ubuntu-latest 16 | steps: 17 | - uses: oven-sh/setup-bun@v1 18 | - uses: actions/checkout@v4 19 | with: 20 | fetch-depth: 0 21 | ref: ${{ github.event.pull_request.head.ref }} 22 | - run: | 23 | bun install 24 | git add bun.lockb 25 | git config --global user.name 'dependabot[bot]' 26 | git config --global user.email 'dependabot[bot]@users.noreply.github.com' 27 | git commit --amend --no-edit 28 | git push --force 29 | -------------------------------------------------------------------------------- /hooks/use-get-call-by-id.ts: -------------------------------------------------------------------------------- 1 | import { useStreamVideoClient, type Call } from "@stream-io/video-react-sdk"; 2 | import { useEffect, useState } from "react"; 3 | 4 | export const useGetCallById = (id: string | string[]) => { 5 | const [call, setCall] = useState(); 6 | const [isCallLoading, setIsCallLoading] = useState(true); 7 | 8 | const streamClient = useStreamVideoClient(); 9 | 10 | useEffect(() => { 11 | if (!streamClient) return; 12 | 13 | const loadCall = async () => { 14 | const { calls } = await streamClient.queryCalls({ 15 | filter_conditions: { 16 | id, 17 | }, 18 | }); 19 | 20 | if (calls.length > 0) setCall(calls[0]); 21 | 22 | setIsCallLoading(false); 23 | }; 24 | 25 | loadCall(); 26 | }, [streamClient, id]); 27 | 28 | return { call, isCallLoading }; 29 | }; 30 | -------------------------------------------------------------------------------- /public/icons/video.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /components/ui/textarea.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | 3 | import { cn } from "@/lib/utils"; 4 | 5 | export interface TextareaProps 6 | extends React.TextareaHTMLAttributes {} 7 | 8 | const Textarea = React.forwardRef( 9 | ({ className, ...props }, ref) => { 10 | return ( 11 |