├── public ├── favicon.ico ├── web-shot.png ├── hero-image.png ├── favicon-16x16.png ├── favicon-32x32.png ├── apple-touch-icon.png ├── features-image.png ├── android-chrome-192x192.png ├── android-chrome-512x512.png └── site.webmanifest ├── prisma ├── migrations │ ├── 20230624223235_schema_change │ │ └── migration.sql │ ├── migration_lock.toml │ ├── 20230629195519_make_user_id_nullable │ │ └── migration.sql │ ├── 20230624043916_call_name_change │ │ └── migration.sql │ ├── 20230624043330_call_name_change │ │ └── migration.sql │ └── 20230606005725_init │ │ └── migration.sql └── schema.prisma ├── postcss.config.cjs ├── src ├── utils │ └── absoluteUrl.ts ├── lib │ ├── utils.ts │ ├── extract-id.ts │ ├── session.ts │ └── date.ts ├── schemas │ ├── invite.ts │ ├── call.ts │ └── join.ts ├── app │ ├── api │ │ ├── auth │ │ │ └── [...nextauth] │ │ │ │ └── route.ts │ │ ├── call │ │ │ ├── delete │ │ │ │ └── route.ts │ │ │ ├── code │ │ │ │ └── route.ts │ │ │ ├── join │ │ │ │ └── route.ts │ │ │ ├── leave │ │ │ │ └── route.ts │ │ │ └── create │ │ │ │ └── route.ts │ │ └── sendEmail │ │ │ └── route.ts │ ├── (calls) │ │ └── calls │ │ │ ├── history │ │ │ ├── layout.tsx │ │ │ ├── loading.tsx │ │ │ └── page.tsx │ │ │ ├── layout.tsx │ │ │ └── page.tsx │ ├── sitemap.ts │ ├── (call) │ │ └── call │ │ │ └── [[...slug]] │ │ │ ├── layout.tsx │ │ │ └── page.tsx │ ├── (preview) │ │ └── preview │ │ │ └── [[...slug]] │ │ │ ├── layout.tsx │ │ │ └── page.tsx │ ├── (home) │ │ ├── layout.tsx │ │ └── page.tsx │ ├── (auth) │ │ ├── register │ │ │ └── page.tsx │ │ └── login │ │ │ └── page.tsx │ └── layout.tsx ├── types │ ├── types.ts │ └── next-auth.d.ts ├── components │ ├── room-provider.tsx │ ├── theme-provider.tsx │ ├── ui │ │ ├── video.tsx │ │ ├── label.tsx │ │ ├── input.tsx │ │ ├── toaster.tsx │ │ ├── avatar.tsx │ │ ├── peer.tsx │ │ ├── checkbox.tsx │ │ ├── badge.tsx │ │ ├── button.tsx │ │ ├── card.tsx │ │ ├── table.tsx │ │ ├── dialog.tsx │ │ ├── use-toast.ts │ │ ├── select.tsx │ │ ├── alert-dialog.tsx │ │ ├── toast.tsx │ │ └── dropdown-menu.tsx │ ├── user-avatar-label-group.tsx │ ├── user-avatar.tsx │ ├── layout │ │ ├── full-nav.tsx │ │ ├── card-shell.tsx │ │ ├── user-account-dropdown.tsx │ │ └── footer.tsx │ ├── call │ │ ├── conference.tsx │ │ ├── pagination.tsx │ │ ├── call-history-per-page-dropdown.tsx │ │ ├── delete-call-actions.tsx │ │ ├── rejoin-call.tsx │ │ ├── join-call-dialog.tsx │ │ ├── call-footer.tsx │ │ ├── create-call-card.tsx │ │ └── invite-participants-dialog.tsx │ ├── mode-toggle.tsx │ ├── social-auth-form.tsx │ ├── delete-action-alert.tsx │ └── email-template.tsx ├── server │ ├── db.ts │ ├── management-token.ts │ └── auth.ts ├── config │ └── site-config.ts ├── context │ └── call-id-context.tsx ├── middleware.ts ├── hooks │ └── use-copy.tsx ├── env.mjs └── styles │ └── globals.css ├── prettier.config.cjs ├── components.json ├── .gitignore ├── next.config.mjs ├── tsconfig.json ├── .eslintrc.cjs ├── LICENSE.md ├── .env.example ├── tailwind.config.ts ├── package.json ├── README.md ├── CONTRIBUTING.md └── CODE_OF_CONDUCT.md /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JaleelB/callsquare/HEAD/public/favicon.ico -------------------------------------------------------------------------------- /public/web-shot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JaleelB/callsquare/HEAD/public/web-shot.png -------------------------------------------------------------------------------- /public/hero-image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JaleelB/callsquare/HEAD/public/hero-image.png -------------------------------------------------------------------------------- /public/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JaleelB/callsquare/HEAD/public/favicon-16x16.png -------------------------------------------------------------------------------- /public/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JaleelB/callsquare/HEAD/public/favicon-32x32.png -------------------------------------------------------------------------------- /public/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JaleelB/callsquare/HEAD/public/apple-touch-icon.png -------------------------------------------------------------------------------- /public/features-image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JaleelB/callsquare/HEAD/public/features-image.png -------------------------------------------------------------------------------- /public/android-chrome-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JaleelB/callsquare/HEAD/public/android-chrome-192x192.png -------------------------------------------------------------------------------- /public/android-chrome-512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JaleelB/callsquare/HEAD/public/android-chrome-512x512.png -------------------------------------------------------------------------------- /prisma/migrations/20230624223235_schema_change/migration.sql: -------------------------------------------------------------------------------- 1 | -- DropIndex 2 | DROP INDEX `Participant_callName_fkey` ON `Participant`; 3 | -------------------------------------------------------------------------------- /postcss.config.cjs: -------------------------------------------------------------------------------- 1 | const config = { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | }; 7 | 8 | module.exports = config; 9 | -------------------------------------------------------------------------------- /prisma/migrations/migration_lock.toml: -------------------------------------------------------------------------------- 1 | # Please do not edit this file manually 2 | # It should be added in your version-control system (i.e. Git) 3 | provider = "mysql" -------------------------------------------------------------------------------- /src/utils/absoluteUrl.ts: -------------------------------------------------------------------------------- 1 | import { env } from "~/env.mjs"; 2 | 3 | export function absoluteUrl(path: string) { 4 | return `${env.NEXT_PUBLIC_APP_URL}${path}` 5 | } -------------------------------------------------------------------------------- /prettier.config.cjs: -------------------------------------------------------------------------------- 1 | /** @type {import("prettier").Config} */ 2 | const config = { 3 | plugins: [require.resolve("prettier-plugin-tailwindcss")], 4 | }; 5 | 6 | module.exports = config; 7 | -------------------------------------------------------------------------------- /prisma/migrations/20230629195519_make_user_id_nullable/migration.sql: -------------------------------------------------------------------------------- 1 | -- AlterTable 2 | ALTER TABLE `Participant` MODIFY `userId` VARCHAR(191) NULL, 3 | MODIFY `email` VARCHAR(191) NULL; 4 | -------------------------------------------------------------------------------- /src/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 | -------------------------------------------------------------------------------- /src/schemas/invite.ts: -------------------------------------------------------------------------------- 1 | import { z } from 'zod'; 2 | 3 | export const inviteSchema = z.object({ 4 | email: z.string().refine(value => /\S+@\S+\.\S+/.test(value), { 5 | message: 'Please enter a valid email address', 6 | }), 7 | }); 8 | -------------------------------------------------------------------------------- /src/schemas/call.ts: -------------------------------------------------------------------------------- 1 | import { z } from "zod"; 2 | 3 | export const joinCallFormSchema = z.object({ 4 | name: z.string().optional(), 5 | meetingLink: z.string().nonempty("A meeting address link is required to join a call"), 6 | }); 7 | -------------------------------------------------------------------------------- /src/lib/extract-id.ts: -------------------------------------------------------------------------------- 1 | export function extractId(url: string): string { 2 | const urlObject = new URL(url); 3 | const urlParts = urlObject.pathname.split('/'); 4 | const id = urlParts[urlParts.length - 1]; 5 | return id as string; 6 | } -------------------------------------------------------------------------------- /src/lib/session.ts: -------------------------------------------------------------------------------- 1 | import { getServerSession } from "next-auth/next" 2 | import { authOptions } from "~/server/auth" 3 | 4 | export async function getCurrentUser() { 5 | const session = await getServerSession(authOptions) 6 | 7 | return session?.user; 8 | } -------------------------------------------------------------------------------- /public/site.webmanifest: -------------------------------------------------------------------------------- 1 | {"name":"","short_name":"","icons":[{"src":"/android-chrome-192x192.png","sizes":"192x192","type":"image/png"},{"src":"/android-chrome-512x512.png","sizes":"512x512","type":"image/png"}],"theme_color":"#ffffff","background_color":"#ffffff","display":"standalone"} -------------------------------------------------------------------------------- /src/app/api/auth/[...nextauth]/route.ts: -------------------------------------------------------------------------------- 1 | import { authOptions } from "~/server/auth"; 2 | import NextAuth from "next-auth"; 3 | 4 | // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment 5 | const handler = NextAuth(authOptions); 6 | export { handler as GET, handler as POST }; 7 | -------------------------------------------------------------------------------- /src/lib/date.ts: -------------------------------------------------------------------------------- 1 | export function formatDate(date: Date): string { 2 | const options: Intl.DateTimeFormatOptions = { 3 | weekday: 'long', 4 | month: 'long', 5 | day: 'numeric', 6 | }; 7 | 8 | return new Intl.DateTimeFormat('en-US', options).format(date); 9 | } 10 | -------------------------------------------------------------------------------- /src/types/types.ts: -------------------------------------------------------------------------------- 1 | export type RoomCodeResponse = { 2 | code: string; 3 | } 4 | 5 | export type EmailProps = { 6 | recipient: string, 7 | link: string, 8 | recipientUsername: string, 9 | senderImage: string, 10 | invitedByUsername: string, 11 | invitedByEmail: string 12 | } -------------------------------------------------------------------------------- /src/types/next-auth.d.ts: -------------------------------------------------------------------------------- 1 | import { type User } from "next-auth" 2 | 3 | type UserId = string 4 | 5 | declare module "next-auth/jwt" { 6 | interface JWT { 7 | id: UserId 8 | } 9 | } 10 | 11 | declare module "next-auth" { 12 | interface Session { 13 | user: User & { 14 | id: UserId 15 | } 16 | } 17 | } -------------------------------------------------------------------------------- /src/app/(calls)/calls/history/layout.tsx: -------------------------------------------------------------------------------- 1 | export default function HistoryLayout({ 2 | children 3 | }: { 4 | children: React.ReactNode 5 | }) { 6 | 7 | return ( 8 |
9 | {children} 10 |
11 | ); 12 | } -------------------------------------------------------------------------------- /src/components/room-provider.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | import { HMSRoomProvider } from '@100mslive/react-sdk'; 3 | import React from 'react' 4 | 5 | 6 | export default function RoomProvider({ 7 | children, 8 | }: { 9 | children: React.ReactNode; 10 | }){ 11 | return ( 12 | 13 | {children} 14 | 15 | ) 16 | } 17 | -------------------------------------------------------------------------------- /src/components/theme-provider.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import * as React from "react"; 4 | import { ThemeProvider as NextThemesProvider } from "next-themes"; 5 | import { type ThemeProviderProps } from "next-themes/dist/types"; 6 | 7 | export function ThemeProvider({ children, ...props }: ThemeProviderProps) { 8 | return {children}; 9 | } 10 | -------------------------------------------------------------------------------- /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": "src/styles/globals.css", 9 | "baseColor": "slate", 10 | "cssVariables": true 11 | }, 12 | "aliases": { 13 | "components": "~/components", 14 | "utils": "~/lib/utils" 15 | } 16 | } -------------------------------------------------------------------------------- /src/components/ui/video.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | function Video(_: object, ref: React.Ref) { 4 | return ( 5 |