├── netlify.toml
├── bun.lockb
├── app
├── favicon.ico
├── assets
│ ├── stars.png
│ ├── avatar-1.png
│ ├── avatar-2.png
│ ├── avatar-3.png
│ ├── avatar-4.png
│ ├── grid-lines.png
│ ├── logo-acme.png
│ ├── logo-apex.png
│ ├── logo-echo.png
│ ├── logo-pulse.png
│ ├── logo-quantum.png
│ ├── product-image.png
│ ├── logo-celestial.png
│ ├── logo.svg
│ ├── icon-guage.svg
│ ├── icon-stars.svg
│ ├── icon-click.svg
│ ├── icon-menu.svg
│ ├── social-x.svg
│ ├── social-youtube.svg
│ └── social-instagram.svg
├── fonts
│ ├── GeistVF.woff
│ └── GeistMonoVF.woff
├── api
│ ├── auth
│ │ ├── [...nextauth]
│ │ │ └── route.ts
│ │ └── route.ts
│ ├── uploadthing
│ │ ├── route.ts
│ │ └── core.ts
│ └── oauth
│ │ └── exchange
│ │ └── route.ts
├── lib
│ ├── hooks.ts
│ ├── auth.ts
│ ├── uploadthing.ts
│ ├── db.ts
│ ├── nylas.ts
│ ├── times.ts
│ └── zodSchemas.ts
├── components
│ ├── landingPage
│ │ ├── AuthButton.tsx
│ │ ├── girdtabs.tsx
│ │ ├── animation-container.tsx
│ │ ├── LampDiv.tsx
│ │ ├── Cards
│ │ │ ├── cardsfeatures.tsx
│ │ │ ├── features-list.tsx
│ │ │ ├── icons.tsx
│ │ │ └── feature-card.tsx
│ │ ├── Cta.tsx
│ │ ├── ui
│ │ │ └── marquee.tsx
│ │ ├── AuthModal.tsx
│ │ ├── Newsletter.tsx
│ │ ├── Cards.tsx
│ │ ├── Logos.tsx
│ │ ├── Reviews.tsx
│ │ ├── Tools.tsx
│ │ ├── offerings.tsx
│ │ └── Stats.tsx
│ ├── dashboard
│ │ ├── ThemeProvider.tsx
│ │ ├── CopyLinkMenuItem.tsx
│ │ ├── EmptyState.tsx
│ │ ├── EventTypeSwitcher.tsx
│ │ ├── ThemeToggle.tsx
│ │ ├── DasboardLinks.tsx
│ │ └── settingsForm.tsx
│ ├── demo
│ │ ├── CalendarButton.tsx
│ │ ├── Calendar.tsx
│ │ ├── RenderCalendar.tsx
│ │ ├── CalendarHeader.tsx
│ │ ├── CalendarGrid.tsx
│ │ └── CalendarCell.tsx
│ └── SubmitButton.tsx
├── utils
│ └── colors.ts
├── test
│ └── page.tsx
├── dashboard
│ ├── settings
│ │ └── page.tsx
│ ├── event
│ │ └── [eventTypeId]
│ │ │ ├── page.tsx
│ │ │ └── delete
│ │ │ └── page.tsx
│ ├── availability
│ │ └── page.tsx
│ ├── meetings
│ │ └── page.tsx
│ └── layout.tsx
├── layout.tsx
├── onboarding
│ ├── grant-id
│ │ └── page.tsx
│ └── page.tsx
├── page.tsx
├── success
│ └── page.tsx
└── globals.css
├── public
├── canva.png
├── face.jpeg
├── hero.png
├── logo.png
├── meet.png
├── teams.png
├── ailogo.png
├── better.png
├── heroimg.png
├── nylas-logo.png
├── scheduling.png
├── assests
│ ├── logo.png
│ ├── tube.png
│ ├── Visual.png
│ ├── flare.png
│ ├── pyramid.png
│ ├── avatar-1.png
│ ├── avatar-2.png
│ ├── avatar-3.png
│ ├── avatar-4.png
│ ├── avatar-5.png
│ ├── avatar-6.png
│ ├── avatar-7.png
│ ├── avatar-8.png
│ ├── avatar-9.png
│ ├── cylinder.png
│ ├── helix2 1.png
│ ├── logo-acme.png
│ ├── logo-apex.png
│ ├── logo-echo.png
│ ├── cube-helix 1.png
│ ├── cube-helix.png
│ ├── emojistar 1.png
│ ├── half-torus.png
│ ├── logo-pulse.png
│ ├── logo-quantum.png
│ ├── Product Image.png
│ └── logo-celestial.png
├── scheduling2.png
├── scheduling3.png
├── dashboard-new.png
├── typescript-logo.png
├── work-is-almost-over-happy.gif
├── google.svg
├── vercel.svg
├── github.svg
├── producthunt.svg
├── nextjs-logo.svg
└── supabase.svg
├── .vscode
└── settings.json
├── postcss.config.mjs
├── lib
├── utils.ts
└── prisma.ts
├── .eslintrc.json
├── components.json
├── .gitignore
├── .github
└── workflows
│ ├── npm-grunt.yml
│ └── generator-generic-ossf-slsa3-publish.yml
├── next.config.mjs
├── components
└── ui
│ ├── label.tsx
│ ├── textarea.tsx
│ ├── input.tsx
│ ├── separator.tsx
│ ├── sonner.tsx
│ ├── ButtonGroup.tsx
│ ├── animated-gradient-text.tsx
│ ├── animated-shiny-text.tsx
│ ├── gradual-spacing.tsx
│ ├── tooltip.tsx
│ ├── switch.tsx
│ ├── badge.tsx
│ ├── avatar.tsx
│ ├── border-beam.tsx
│ ├── number-ticker.tsx
│ ├── word-pull-up.tsx
│ ├── letter-pullup.tsx
│ ├── button.tsx
│ ├── spotlight.tsx
│ ├── card.tsx
│ ├── flip-words.tsx
│ ├── calendar.tsx
│ ├── card-hover-effect.tsx
│ ├── dialog.tsx
│ ├── lamp.tsx
│ └── sheet.tsx
├── tsconfig.json
├── ai.tsx
├── README.md
├── package.json
├── tailwind.config.ts
└── prisma
└── schema.prisma
/netlify.toml:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/bun.lockb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duggal1/dayflow/HEAD/bun.lockb
--------------------------------------------------------------------------------
/app/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duggal1/dayflow/HEAD/app/favicon.ico
--------------------------------------------------------------------------------
/public/canva.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duggal1/dayflow/HEAD/public/canva.png
--------------------------------------------------------------------------------
/public/face.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duggal1/dayflow/HEAD/public/face.jpeg
--------------------------------------------------------------------------------
/public/hero.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duggal1/dayflow/HEAD/public/hero.png
--------------------------------------------------------------------------------
/public/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duggal1/dayflow/HEAD/public/logo.png
--------------------------------------------------------------------------------
/public/meet.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duggal1/dayflow/HEAD/public/meet.png
--------------------------------------------------------------------------------
/public/teams.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duggal1/dayflow/HEAD/public/teams.png
--------------------------------------------------------------------------------
/public/ailogo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duggal1/dayflow/HEAD/public/ailogo.png
--------------------------------------------------------------------------------
/public/better.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duggal1/dayflow/HEAD/public/better.png
--------------------------------------------------------------------------------
/public/heroimg.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duggal1/dayflow/HEAD/public/heroimg.png
--------------------------------------------------------------------------------
/app/assets/stars.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duggal1/dayflow/HEAD/app/assets/stars.png
--------------------------------------------------------------------------------
/public/nylas-logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duggal1/dayflow/HEAD/public/nylas-logo.png
--------------------------------------------------------------------------------
/public/scheduling.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duggal1/dayflow/HEAD/public/scheduling.png
--------------------------------------------------------------------------------
/app/assets/avatar-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duggal1/dayflow/HEAD/app/assets/avatar-1.png
--------------------------------------------------------------------------------
/app/assets/avatar-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duggal1/dayflow/HEAD/app/assets/avatar-2.png
--------------------------------------------------------------------------------
/app/assets/avatar-3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duggal1/dayflow/HEAD/app/assets/avatar-3.png
--------------------------------------------------------------------------------
/app/assets/avatar-4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duggal1/dayflow/HEAD/app/assets/avatar-4.png
--------------------------------------------------------------------------------
/app/fonts/GeistVF.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duggal1/dayflow/HEAD/app/fonts/GeistVF.woff
--------------------------------------------------------------------------------
/public/assests/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duggal1/dayflow/HEAD/public/assests/logo.png
--------------------------------------------------------------------------------
/public/assests/tube.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duggal1/dayflow/HEAD/public/assests/tube.png
--------------------------------------------------------------------------------
/public/scheduling2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duggal1/dayflow/HEAD/public/scheduling2.png
--------------------------------------------------------------------------------
/public/scheduling3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duggal1/dayflow/HEAD/public/scheduling3.png
--------------------------------------------------------------------------------
/app/assets/grid-lines.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duggal1/dayflow/HEAD/app/assets/grid-lines.png
--------------------------------------------------------------------------------
/app/assets/logo-acme.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duggal1/dayflow/HEAD/app/assets/logo-acme.png
--------------------------------------------------------------------------------
/app/assets/logo-apex.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duggal1/dayflow/HEAD/app/assets/logo-apex.png
--------------------------------------------------------------------------------
/app/assets/logo-echo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duggal1/dayflow/HEAD/app/assets/logo-echo.png
--------------------------------------------------------------------------------
/app/assets/logo-pulse.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duggal1/dayflow/HEAD/app/assets/logo-pulse.png
--------------------------------------------------------------------------------
/app/fonts/GeistMonoVF.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duggal1/dayflow/HEAD/app/fonts/GeistMonoVF.woff
--------------------------------------------------------------------------------
/public/assests/Visual.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duggal1/dayflow/HEAD/public/assests/Visual.png
--------------------------------------------------------------------------------
/public/assests/flare.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duggal1/dayflow/HEAD/public/assests/flare.png
--------------------------------------------------------------------------------
/public/assests/pyramid.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duggal1/dayflow/HEAD/public/assests/pyramid.png
--------------------------------------------------------------------------------
/public/dashboard-new.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duggal1/dayflow/HEAD/public/dashboard-new.png
--------------------------------------------------------------------------------
/public/typescript-logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duggal1/dayflow/HEAD/public/typescript-logo.png
--------------------------------------------------------------------------------
/app/assets/logo-quantum.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duggal1/dayflow/HEAD/app/assets/logo-quantum.png
--------------------------------------------------------------------------------
/app/assets/product-image.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duggal1/dayflow/HEAD/app/assets/product-image.png
--------------------------------------------------------------------------------
/public/assests/avatar-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duggal1/dayflow/HEAD/public/assests/avatar-1.png
--------------------------------------------------------------------------------
/public/assests/avatar-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duggal1/dayflow/HEAD/public/assests/avatar-2.png
--------------------------------------------------------------------------------
/public/assests/avatar-3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duggal1/dayflow/HEAD/public/assests/avatar-3.png
--------------------------------------------------------------------------------
/public/assests/avatar-4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duggal1/dayflow/HEAD/public/assests/avatar-4.png
--------------------------------------------------------------------------------
/public/assests/avatar-5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duggal1/dayflow/HEAD/public/assests/avatar-5.png
--------------------------------------------------------------------------------
/public/assests/avatar-6.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duggal1/dayflow/HEAD/public/assests/avatar-6.png
--------------------------------------------------------------------------------
/public/assests/avatar-7.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duggal1/dayflow/HEAD/public/assests/avatar-7.png
--------------------------------------------------------------------------------
/public/assests/avatar-8.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duggal1/dayflow/HEAD/public/assests/avatar-8.png
--------------------------------------------------------------------------------
/public/assests/avatar-9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duggal1/dayflow/HEAD/public/assests/avatar-9.png
--------------------------------------------------------------------------------
/public/assests/cylinder.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duggal1/dayflow/HEAD/public/assests/cylinder.png
--------------------------------------------------------------------------------
/public/assests/helix2 1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duggal1/dayflow/HEAD/public/assests/helix2 1.png
--------------------------------------------------------------------------------
/public/assests/logo-acme.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duggal1/dayflow/HEAD/public/assests/logo-acme.png
--------------------------------------------------------------------------------
/public/assests/logo-apex.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duggal1/dayflow/HEAD/public/assests/logo-apex.png
--------------------------------------------------------------------------------
/public/assests/logo-echo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duggal1/dayflow/HEAD/public/assests/logo-echo.png
--------------------------------------------------------------------------------
/app/assets/logo-celestial.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duggal1/dayflow/HEAD/app/assets/logo-celestial.png
--------------------------------------------------------------------------------
/public/assests/cube-helix 1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duggal1/dayflow/HEAD/public/assests/cube-helix 1.png
--------------------------------------------------------------------------------
/public/assests/cube-helix.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duggal1/dayflow/HEAD/public/assests/cube-helix.png
--------------------------------------------------------------------------------
/public/assests/emojistar 1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duggal1/dayflow/HEAD/public/assests/emojistar 1.png
--------------------------------------------------------------------------------
/public/assests/half-torus.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duggal1/dayflow/HEAD/public/assests/half-torus.png
--------------------------------------------------------------------------------
/public/assests/logo-pulse.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duggal1/dayflow/HEAD/public/assests/logo-pulse.png
--------------------------------------------------------------------------------
/public/assests/logo-quantum.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duggal1/dayflow/HEAD/public/assests/logo-quantum.png
--------------------------------------------------------------------------------
/public/assests/Product Image.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duggal1/dayflow/HEAD/public/assests/Product Image.png
--------------------------------------------------------------------------------
/public/assests/logo-celestial.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duggal1/dayflow/HEAD/public/assests/logo-celestial.png
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "WillLuke.nextjs.addTypesOnSave": true,
3 | "WillLuke.nextjs.hasPrompted": true
4 | }
--------------------------------------------------------------------------------
/public/work-is-almost-over-happy.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duggal1/dayflow/HEAD/public/work-is-almost-over-happy.gif
--------------------------------------------------------------------------------
/app/api/auth/[...nextauth]/route.ts:
--------------------------------------------------------------------------------
1 | import { handlers } from "@/app/lib/auth";
2 |
3 | export const { GET, POST } = handlers;
4 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/lib/utils.ts:
--------------------------------------------------------------------------------
1 | import { clsx, type ClassValue } from "clsx"
2 | import { twMerge } from "tailwind-merge"
3 |
4 | export function cn(...inputs: ClassValue[]) {
5 | return twMerge(clsx(inputs))
6 | }
7 |
--------------------------------------------------------------------------------
/app/lib/hooks.ts:
--------------------------------------------------------------------------------
1 | import { redirect } from "next/navigation";
2 | import { auth } from "./auth";
3 |
4 | export async function requireUser() {
5 | const session = await auth();
6 |
7 | if (!session?.user?.id) {
8 | return redirect("/");
9 | }
10 |
11 | return session;
12 | }
13 |
--------------------------------------------------------------------------------
/app/assets/logo.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": ["next/core-web-vitals", "next/typescript"],
3 | "rules": {
4 | "@typescript-eslint/no-unused-vars": "warn", // Change to 'error' if you want it to be an error
5 | "react-hooks/exhaustive-deps": "warn" // Change to 'error' if you want it to be an error
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/app/components/landingPage/AuthButton.tsx:
--------------------------------------------------------------------------------
1 | import { AuthModal } from "./AuthModal";
2 | export function AuthButton() {
3 | return (
4 |
5 |
6 |
10 |
11 | );
12 | }
--------------------------------------------------------------------------------
/app/lib/auth.ts:
--------------------------------------------------------------------------------
1 | import NextAuth from "next-auth";
2 | import GitHub from "next-auth/providers/github";
3 | import prisma from "./db";
4 | import { PrismaAdapter } from "@auth/prisma-adapter";
5 |
6 | export const { handlers, signIn, signOut, auth } = NextAuth({
7 | adapter: PrismaAdapter(prisma),
8 |
9 | providers: [GitHub],
10 | });
11 |
--------------------------------------------------------------------------------
/app/api/uploadthing/route.ts:
--------------------------------------------------------------------------------
1 | import { createRouteHandler } from "uploadthing/next";
2 |
3 | import { ourFileRouter } from "./core";
4 |
5 | // Export routes for Next App Router
6 | export const { GET, POST } = createRouteHandler({
7 | router: ourFileRouter,
8 |
9 | // Apply an (optional) custom config:
10 | // config: { ... },
11 | });
12 |
--------------------------------------------------------------------------------
/app/lib/uploadthing.ts:
--------------------------------------------------------------------------------
1 | import {
2 | generateUploadButton,
3 | generateUploadDropzone,
4 | } from "@uploadthing/react";
5 |
6 | import type { OurFileRouter } from "@/app/api/uploadthing/core";
7 |
8 | export const UploadButton = generateUploadButton();
9 | export const UploadDropzone = generateUploadDropzone();
10 |
--------------------------------------------------------------------------------
/app/api/auth/route.ts:
--------------------------------------------------------------------------------
1 | import { nylas, nylasConfig } from "@/app/lib/nylas";
2 | import { redirect } from "next/navigation";
3 |
4 | export async function GET() {
5 | const authUrl = nylas.auth.urlForOAuth2({
6 | clientId: nylasConfig.clientId as string,
7 | redirectUri: nylasConfig.callbackUri,
8 | });
9 | return redirect(authUrl);
10 | }
11 |
--------------------------------------------------------------------------------
/app/components/dashboard/ThemeProvider.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 |
--------------------------------------------------------------------------------
/app/utils/colors.ts:
--------------------------------------------------------------------------------
1 | export const StargateColors = {
2 | primary: "linear-gradient(90deg, #f72585, #7209b7)",
3 |
4 | secondary: "linear-gradient(90deg, #ff00ff, #800080)", // Fuchsia to Purple
5 | grey: "#656f7e",
6 | black: "#09090b",
7 | darkBg: "#262626",
8 | white: "#FFFFFF",
9 | lightBg: "#d9d9d9",
10 | lightGrey: "#f2f2f2",
11 | darker: "#e340bf",
12 | lighter: "#a440e3",
13 | }; // Blue to Cyan
14 |
--------------------------------------------------------------------------------
/app/lib/db.ts:
--------------------------------------------------------------------------------
1 | import { PrismaClient } from "@prisma/client";
2 |
3 | const prismaClientSingleton = () => {
4 | return new PrismaClient();
5 | };
6 |
7 | declare const globalThis: {
8 | prismaGlobal: ReturnType;
9 | } & typeof global;
10 |
11 | const prisma = globalThis.prismaGlobal ?? prismaClientSingleton();
12 |
13 | export default prisma;
14 |
15 | if (process.env.NODE_ENV !== "production") globalThis.prismaGlobal = prisma;
16 |
--------------------------------------------------------------------------------
/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": "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 | }
--------------------------------------------------------------------------------
/lib/prisma.ts:
--------------------------------------------------------------------------------
1 | import { PrismaClient } from "@prisma/client";
2 |
3 | const prismaClientSingleton = () => {
4 | return new PrismaClient();
5 | };
6 |
7 | type PrismaClientSingleton = ReturnType;
8 |
9 | const globalForPrisma = globalThis as unknown as {
10 | prisma: PrismaClientSingleton | undefined;
11 | };
12 |
13 | const prisma = globalForPrisma.prisma ?? prismaClientSingleton();
14 |
15 | export default prisma;
16 |
17 | if (process.env.NODE_ENV !== "production") globalForPrisma.prisma = prisma;
18 |
--------------------------------------------------------------------------------
/.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 | .env
31 |
32 | # vercel
33 | .vercel
34 |
35 | # typescript
36 | *.tsbuildinfo
37 | next-env.d.ts
38 |
--------------------------------------------------------------------------------
/app/assets/icon-guage.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.github/workflows/npm-grunt.yml:
--------------------------------------------------------------------------------
1 | name: NodeJS with Grunt
2 |
3 | on:
4 | push:
5 | branches: [ "main" ]
6 | pull_request:
7 | branches: [ "main" ]
8 |
9 | jobs:
10 | build:
11 | runs-on: ubuntu-latest
12 |
13 | strategy:
14 | matrix:
15 | node-version: [18.x, 20.x, 22.x]
16 |
17 | steps:
18 | - uses: actions/checkout@v4
19 |
20 | - name: Use Node.js ${{ matrix.node-version }}
21 | uses: actions/setup-node@v4
22 | with:
23 | node-version: ${{ matrix.node-version }}
24 |
25 | - name: Build
26 | run: |
27 | npm install
28 | grunt
29 |
--------------------------------------------------------------------------------
/app/components/landingPage/girdtabs.tsx:
--------------------------------------------------------------------------------
1 | "use client"
2 |
3 | import Tabs from '@/app/components/Tabs';
4 | import { Cover } from '@/components/ui/cover';
5 |
6 | const GridTabs = () => {
7 | return (
8 |
9 |
10 |
11 | The Solutions
12 | We Offers
13 |
14 |
15 |
16 |
17 | );
18 | }
19 |
20 | export default GridTabs;
21 |
22 |
--------------------------------------------------------------------------------
/app/lib/nylas.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable @typescript-eslint/no-unused-vars */
2 | import Nylas from "nylas";
3 |
4 | export const nylasConfig = {
5 | clientId: process.env.NYLAS_CLIENT_ID,
6 | callbackUri: process.env.NEXT_PUBLIC_URL + "/api/oauth/exchange",
7 | apiKey: process.env.NYLAS_API_SECRET_KEY,
8 | apiUri: process.env.NYLAS_API_URL,
9 | };
10 |
11 | export const nylas = new Nylas({
12 | apiKey: process.env.NYLAS_API_SECRET_KEY!,
13 | apiUri: process.env.NYLAS_API_URL,
14 | });
15 |
16 | // Export AuthConfig if it's needed elsewhere in your application
17 | export const AuthConfig = {
18 | clientId: process.env.NYLAS_CLIENT_ID as string,
19 | redirectUri: "http://localhost:3000/oauth/exchange",
20 | };
--------------------------------------------------------------------------------
/next.config.mjs:
--------------------------------------------------------------------------------
1 | import { fileURLToPath } from 'url';
2 | import { dirname } from 'path';
3 | 'build/types/**/*.ts'
4 |
5 | /** @type {import('next').NextConfig} */
6 | const nextConfig = {
7 |
8 | experimental: {
9 | outputFileTracingRoot: dirname(fileURLToPath(import.meta.url)), // Use this to get the directory name
10 | },
11 | images: {
12 | remotePatterns: [
13 | { hostname: "avatar.vercel.sh", port: "", protocol: "https" },
14 | { hostname: "utfs.io", port: "", protocol: "https" },
15 | { hostname: "avatars.githubusercontent.com", port: "", protocol: "https" },
16 | ],
17 | },
18 | distDir: 'build', // Netlify can cache this directory
19 | };
20 |
21 | export default nextConfig;
22 |
--------------------------------------------------------------------------------
/app/assets/icon-stars.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/components/ui/label.tsx:
--------------------------------------------------------------------------------
1 | "use client"
2 |
3 | import * as React from "react"
4 | import * as LabelPrimitive from "@radix-ui/react-label"
5 | import { cva, type VariantProps } from "class-variance-authority"
6 |
7 | import { cn } from "@/lib/utils"
8 |
9 | const labelVariants = cva(
10 | "text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
11 | )
12 |
13 | const Label = React.forwardRef<
14 | React.ElementRef,
15 | React.ComponentPropsWithoutRef &
16 | VariantProps
17 | >(({ className, ...props }, ref) => (
18 |
23 | ))
24 | Label.displayName = LabelPrimitive.Root.displayName
25 |
26 | export { Label }
27 |
--------------------------------------------------------------------------------
/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 |
19 | )
20 | }
21 | )
22 | Textarea.displayName = "Textarea"
23 |
24 | export { Textarea }
25 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "lib": [
4 | "dom",
5 | "dom.iterable",
6 | "esnext"
7 | ],
8 | "allowJs": true,
9 | "skipLibCheck": true,
10 | "strict": true,
11 | "noEmit": true,
12 | "esModuleInterop": true,
13 | "module": "esnext",
14 | "moduleResolution": "bundler",
15 | "resolveJsonModule": true,
16 | "isolatedModules": true,
17 | "jsx": "preserve",
18 | "incremental": true,
19 | "plugins": [
20 | {
21 | "name": "next"
22 | }
23 | ],
24 | "paths": {
25 | "@/*": [
26 | "./*"
27 | ]
28 | }
29 | },
30 | "include": [
31 | "next-env.d.ts",
32 | "**/*.ts",
33 | "**/*.tsx",
34 | ".next/types/**/*.ts",
35 | "build/types/**/*.ts"
36 | ],
37 | "exclude": [
38 | "node_modules"
39 | ]
40 | }
41 |
--------------------------------------------------------------------------------
/app/components/dashboard/CopyLinkMenuItem.tsx:
--------------------------------------------------------------------------------
1 | "use client";
2 |
3 | import { DropdownMenuItem } from "@/components/ui/dropdown-menu";
4 | import { Link2 } from "lucide-react";
5 | import { toast } from "sonner";
6 |
7 | interface CopyLinkMenuItemProps {
8 | meetingUrl: string;
9 | }
10 |
11 | export function CopyLinkMenuItem({ meetingUrl }: CopyLinkMenuItemProps) {
12 | const handleCopy = async () => {
13 | try {
14 | await navigator.clipboard.writeText(meetingUrl);
15 | toast.success("URL copied to clipboard");
16 | } catch (err) {
17 | console.error("Could not copy text: ", err);
18 | toast.error("Failed to copy URL");
19 | }
20 | };
21 |
22 | return (
23 |
24 |
25 | Copy
26 |
27 | );
28 | }
29 |
--------------------------------------------------------------------------------
/app/components/landingPage/animation-container.tsx:
--------------------------------------------------------------------------------
1 | "use client";
2 |
3 | import { motion } from 'framer-motion';
4 |
5 | interface AnimationContainerProps {
6 | children: React.ReactNode;
7 | delay?: number;
8 | reverse?: boolean;
9 | className?: string;
10 | };
11 |
12 | const AnimationContainer = ({ children, className, reverse, delay = 0.2 }: AnimationContainerProps) => {
13 | return (
14 |
21 | {children}
22 |
23 | )
24 | };
25 |
26 | export default AnimationContainer
--------------------------------------------------------------------------------
/app/assets/icon-click.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/app/test/page.tsx:
--------------------------------------------------------------------------------
1 | "use client";
2 |
3 | import { NylasDatePicker } from "@nylas/react";
4 | import { NylasLocaleSwitch } from "@nylas/react";
5 |
6 | const TesTpage = () => {
7 | // Define the selectable dates (e.g., the next 30 days)
8 | const generateSelectableDates = () => {
9 | const today = new Date();
10 | const dates = [];
11 | for (let i = 0; i < 30; i++) {
12 | const date = new Date();
13 | date.setDate(today.getDate() + i);
14 | dates.push(date);
15 | }
16 | return dates;
17 | };
18 |
19 | return (
20 |
21 |
22 |
28 |
29 | );
30 | };
31 |
32 | export default TesTpage;
33 |
--------------------------------------------------------------------------------
/components/ui/input.tsx:
--------------------------------------------------------------------------------
1 | import * as React from "react"
2 |
3 | import { cn } from "@/lib/utils"
4 |
5 | export interface InputProps
6 | extends React.InputHTMLAttributes {}
7 |
8 | const Input = React.forwardRef(
9 | ({ className, type, ...props }, ref) => {
10 | return (
11 |
20 | )
21 | }
22 | )
23 | Input.displayName = "Input"
24 |
25 | export { Input }
26 |
--------------------------------------------------------------------------------
/components/ui/separator.tsx:
--------------------------------------------------------------------------------
1 | "use client"
2 |
3 | import * as React from "react"
4 | import * as SeparatorPrimitive from "@radix-ui/react-separator"
5 |
6 | import { cn } from "@/lib/utils"
7 |
8 | const Separator = React.forwardRef<
9 | React.ElementRef,
10 | React.ComponentPropsWithoutRef
11 | >(
12 | (
13 | { className, orientation = "horizontal", decorative = true, ...props },
14 | ref
15 | ) => (
16 |
27 | )
28 | )
29 | Separator.displayName = SeparatorPrimitive.Root.displayName
30 |
31 | export { Separator }
32 |
--------------------------------------------------------------------------------
/app/components/demo/CalendarButton.tsx:
--------------------------------------------------------------------------------
1 | import { Button } from "@/components/ui/button";
2 | import { type AriaButtonProps, useButton } from "@react-aria/button";
3 | import { useFocusRing } from "@react-aria/focus";
4 | import { mergeProps } from "@react-aria/utils";
5 | import type { CalendarState } from "@react-stately/calendar";
6 | import { useRef } from "react";
7 |
8 | export function CalendarButton(
9 | props: AriaButtonProps<"button"> & {
10 | state?: CalendarState;
11 | side?: "left" | "right";
12 | }
13 | ) {
14 | const ref = useRef(null);
15 | const { buttonProps } = useButton(props, ref);
16 | const { focusProps } = useFocusRing();
17 | return (
18 |
25 | {props.children}
26 |
27 | );
28 | }
29 |
--------------------------------------------------------------------------------
/app/dashboard/settings/page.tsx:
--------------------------------------------------------------------------------
1 | import { SettingsForm } from "@/app/components/dashboard/settingsForm";
2 |
3 | import prisma from "@/app/lib/db";
4 | import { requireUser } from "@/app/lib/hooks";
5 |
6 | import { notFound } from "next/navigation";
7 | import React from "react";
8 |
9 | async function getData(id: string) {
10 | const data = await prisma.user.findUnique({
11 | where: {
12 | id: id,
13 | },
14 | select: {
15 | name: true,
16 | email: true,
17 | image: true,
18 | },
19 | });
20 |
21 | if (!data) {
22 | return notFound();
23 | }
24 |
25 | return data;
26 | }
27 |
28 | const SettingsPage = async () => {
29 | const session = await requireUser();
30 | const data = await getData(session.user?.id as string);
31 | return (
32 |
37 | );
38 | };
39 |
40 | export default SettingsPage;
41 |
--------------------------------------------------------------------------------
/public/google.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/components/ui/sonner.tsx:
--------------------------------------------------------------------------------
1 | "use client"
2 |
3 | import { useTheme } from "next-themes"
4 | import { Toaster as Sonner } from "sonner"
5 |
6 | type ToasterProps = React.ComponentProps
7 |
8 | const Toaster = ({ ...props }: ToasterProps) => {
9 | const { theme = "system" } = useTheme()
10 |
11 | return (
12 |
28 | )
29 | }
30 |
31 | export { Toaster }
32 |
--------------------------------------------------------------------------------
/components/ui/ButtonGroup.tsx:
--------------------------------------------------------------------------------
1 | "use client";
2 |
3 | import { Children, ReactElement, cloneElement } from "react";
4 |
5 | import { ButtonProps } from "@/components/ui/button";
6 | import { cn } from "@/lib/utils";
7 |
8 | interface ButtonGroupProps {
9 | className?: string;
10 | children: ReactElement[];
11 | }
12 |
13 | export const ButtonGroup = ({
14 | className,
15 |
16 | children,
17 | }: ButtonGroupProps) => {
18 | const totalButtons = Children.count(children);
19 |
20 | return (
21 |
22 | {Children.map(children, (child, index) => {
23 | const isFirst = index === 0;
24 | const isLast = index === totalButtons - 1;
25 |
26 | return cloneElement(child, {
27 | className: cn(
28 | {
29 | "rounded-l-none": !isFirst,
30 | "rounded-r-none": !isLast,
31 | "border-l-0": !isFirst,
32 | },
33 | child.props.className
34 | ),
35 | });
36 | })}
37 |
38 | );
39 | };
40 |
--------------------------------------------------------------------------------
/components/ui/animated-gradient-text.tsx:
--------------------------------------------------------------------------------
1 | import { ReactNode } from "react";
2 |
3 | import { cn } from "@/lib/utils";
4 |
5 | export default function AnimatedGradientText({
6 | children,
7 | className,
8 | }: {
9 | children: ReactNode;
10 | className?: string;
11 | }) {
12 | return (
13 |
19 |
22 |
23 | {children}
24 |
25 | );
26 | }
27 |
--------------------------------------------------------------------------------
/public/vercel.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/app/assets/icon-menu.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/app/components/landingPage/LampDiv.tsx:
--------------------------------------------------------------------------------
1 | "use client";
2 |
3 | import { LampContainer } from "@/components/ui/lamp";
4 | import React from "react";
5 | import { SparklesCore } from "@/components/ui/sparkles";
6 | import { motion } from "framer-motion";
7 |
8 | export function LampDemo() {
9 | return (
10 |
11 |
21 |
29 | Build lamps the right way
30 |
31 |
32 | );
33 | }
34 |
35 |
--------------------------------------------------------------------------------
/app/components/dashboard/EmptyState.tsx:
--------------------------------------------------------------------------------
1 | import { Button } from "@/components/ui/button";
2 | import { Ban, PlusCircle } from "lucide-react";
3 | import Link from "next/link";
4 |
5 | interface iAppProps {
6 | title: string;
7 | description: string;
8 | buttonText: string;
9 | href: string;
10 | }
11 |
12 | export function EmptyState({
13 | buttonText,
14 | description,
15 | href,
16 | title,
17 | }: iAppProps) {
18 | return (
19 |
20 |
21 |
22 |
23 |
{title}
24 |
25 | {description}
26 |
27 |
28 |
29 |
30 | {buttonText}
31 |
32 |
33 |
34 | );
35 | }
36 |
--------------------------------------------------------------------------------
/components/ui/animated-shiny-text.tsx:
--------------------------------------------------------------------------------
1 | import { CSSProperties, FC, ReactNode } from "react";
2 |
3 | import { cn } from "@/lib/utils";
4 |
5 | interface AnimatedShinyTextProps {
6 | children: ReactNode;
7 | className?: string;
8 | shimmerWidth?: number;
9 | }
10 |
11 | const AnimatedShinyText: FC = ({
12 | children,
13 | className,
14 | shimmerWidth = 100,
15 | }) => {
16 | return (
17 |
35 | {children}
36 |
37 | );
38 | };
39 |
40 | export default AnimatedShinyText;
41 |
--------------------------------------------------------------------------------
/app/dashboard/event/[eventTypeId]/page.tsx:
--------------------------------------------------------------------------------
1 | import { EditEventTypeForm } from "@/app/components/dashboard/EditEventTypeForm";
2 | import prisma from "@/app/lib/db";
3 | import { notFound } from "next/navigation";
4 | import React from "react";
5 |
6 | async function getData(eventTypeId: string) {
7 | const data = await prisma.eventType.findUnique({
8 | where: {
9 | id: eventTypeId,
10 | },
11 | select: {
12 | title: true,
13 | description: true,
14 | duration: true,
15 | url: true,
16 | id: true,
17 | videoCallSoftware: true,
18 | },
19 | });
20 |
21 | if (!data) {
22 | return notFound();
23 | }
24 |
25 | return data;
26 | }
27 | const EditEventTypePage = async ({
28 | params,
29 | }: {
30 | params: { eventTypeId: string };
31 | }) => {
32 | const data = await getData(params.eventTypeId);
33 |
34 | return (
35 |
44 | );
45 | };
46 |
47 | export default EditEventTypePage;
48 |
--------------------------------------------------------------------------------
/app/components/dashboard/EventTypeSwitcher.tsx:
--------------------------------------------------------------------------------
1 | "use client";
2 |
3 | import { updateEventTypeStatusAction } from "@/app/actions";
4 | import { Switch } from "@/components/ui/switch";
5 | import React, { useEffect, useTransition } from "react";
6 | import { useFormState } from "react-dom";
7 | import { toast } from "sonner";
8 |
9 | export function MenuActiveSwitcher({
10 | initialChecked,
11 | eventTypeId,
12 | }: {
13 | eventTypeId: string;
14 | initialChecked: boolean;
15 | }) {
16 | const [isPending, startTransition] = useTransition();
17 | const [state, action] = useFormState(updateEventTypeStatusAction, undefined);
18 |
19 | useEffect(() => {
20 | if (state?.status === "success") {
21 | toast.success(state.message);
22 | } else if (state?.status === "error") {
23 | toast.error(state.message);
24 | }
25 | }, [state]);
26 |
27 | return (
28 | {
32 | startTransition(() => {
33 | action({
34 | isChecked: isChecked,
35 | eventTypeId,
36 | });
37 | });
38 | }}
39 | />
40 | );
41 | }
42 |
--------------------------------------------------------------------------------
/app/components/landingPage/Cards/cardsfeatures.tsx:
--------------------------------------------------------------------------------
1 | import { FeatureCard } from './feature-card';
2 | import { featuresList } from './features-list';
3 |
4 | export function FeaturesGrid() {
5 | return (
6 |
7 |
8 |
9 | everything you need to know
10 |
11 |
12 |
13 | Enjoy customizable lists, team work tools, and smart tracking all in
14 | one place. Set tasks, get reminders, and see your progress simply
15 | and quickly.
16 |
17 |
18 |
19 | {featuresList.map((feature) => (
20 |
21 | ))}
22 |
23 |
24 |
25 | );
26 | }
27 |
28 | export default FeaturesGrid;
--------------------------------------------------------------------------------
/app/assets/social-x.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/components/ui/gradual-spacing.tsx:
--------------------------------------------------------------------------------
1 | "use client";
2 |
3 | import { AnimatePresence, motion, Variants } from "framer-motion";
4 |
5 | import { cn } from "@/lib/utils";
6 |
7 | interface GradualSpacingProps {
8 | text: string;
9 | duration?: number;
10 | delayMultiple?: number;
11 | framerProps?: Variants;
12 | className?: string;
13 | }
14 |
15 | export default function GradualSpacing({
16 | text,
17 | duration = 0.5,
18 | delayMultiple = 0.04,
19 | framerProps = {
20 | hidden: { opacity: 0, x: -20 },
21 | visible: { opacity: 1, x: 0 },
22 | },
23 | className,
24 | }: GradualSpacingProps) {
25 | return (
26 |
27 |
28 | {text.split("").map((char, i) => (
29 |
38 | {char === " " ? : char}
39 |
40 | ))}
41 |
42 |
43 | );
44 | }
45 |
--------------------------------------------------------------------------------
/app/components/demo/Calendar.tsx:
--------------------------------------------------------------------------------
1 | import { createCalendar } from "@internationalized/date";
2 | import { CalendarProps, DateValue, useCalendar, useLocale } from "react-aria";
3 | import { useCalendarState } from "react-stately";
4 | import { CalendarHeader } from "./CalendarHeader";
5 | import { CalendarGrid } from "./CalendarGrid";
6 |
7 | export function Calendar(
8 | props: CalendarProps & {
9 | isDateUnavailable?: (date: DateValue) => boolean;
10 | }
11 | ) {
12 | const { locale } = useLocale();
13 | const state = useCalendarState({
14 | ...props,
15 | visibleDuration: { months: 1 },
16 | locale,
17 | createCalendar,
18 | });
19 |
20 | const { calendarProps, prevButtonProps, nextButtonProps } = useCalendar(
21 | props,
22 | state
23 | );
24 | return (
25 |
39 | );
40 | }
41 |
--------------------------------------------------------------------------------
/components/ui/tooltip.tsx:
--------------------------------------------------------------------------------
1 | "use client";
2 |
3 | import * as React from "react";
4 | import * as TooltipPrimitive from "@radix-ui/react-tooltip";
5 |
6 | import { cn } from "@/lib/utils";
7 |
8 | const TooltipProvider = TooltipPrimitive.Provider;
9 |
10 | const Tooltip = TooltipPrimitive.Root;
11 |
12 | const TooltipTrigger = TooltipPrimitive.Trigger;
13 |
14 | const TooltipContent = React.forwardRef<
15 | React.ElementRef,
16 | React.ComponentPropsWithoutRef
17 | >(({ className, sideOffset = 4, ...props }, ref) => (
18 |
27 | ));
28 | TooltipContent.displayName = TooltipPrimitive.Content.displayName;
29 |
30 | export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider };
31 |
--------------------------------------------------------------------------------
/components/ui/switch.tsx:
--------------------------------------------------------------------------------
1 | "use client"
2 |
3 | import * as React from "react"
4 | import * as SwitchPrimitives from "@radix-ui/react-switch"
5 |
6 | import { cn } from "@/lib/utils"
7 |
8 | const Switch = React.forwardRef<
9 | React.ElementRef,
10 | React.ComponentPropsWithoutRef
11 | >(({ className, ...props }, ref) => (
12 |
20 |
25 |
26 | ))
27 | Switch.displayName = SwitchPrimitives.Root.displayName
28 |
29 | export { Switch }
30 |
--------------------------------------------------------------------------------
/components/ui/badge.tsx:
--------------------------------------------------------------------------------
1 | import * as React from "react"
2 | import { cva, type VariantProps } from "class-variance-authority"
3 |
4 | import { cn } from "@/lib/utils"
5 |
6 | const badgeVariants = cva(
7 | "inline-flex items-center rounded-md border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2",
8 | {
9 | variants: {
10 | variant: {
11 | default:
12 | "border-transparent bg-primary text-primary-foreground shadow hover:bg-primary/80",
13 | secondary:
14 | "border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80",
15 | destructive:
16 | "border-transparent bg-destructive text-destructive-foreground shadow hover:bg-destructive/80",
17 | outline: "text-foreground",
18 | },
19 | },
20 | defaultVariants: {
21 | variant: "default",
22 | },
23 | }
24 | )
25 |
26 | export interface BadgeProps
27 | extends React.HTMLAttributes,
28 | VariantProps {}
29 |
30 | function Badge({ className, variant, ...props }: BadgeProps) {
31 | return (
32 |
33 | )
34 | }
35 |
36 | export { Badge, badgeVariants }
37 |
--------------------------------------------------------------------------------
/app/dashboard/event/[eventTypeId]/delete/page.tsx:
--------------------------------------------------------------------------------
1 | import { DeleteEventTypeAction } from "@/app/actions";
2 | import { Button } from "@/components/ui/button";
3 | import {
4 | Card,
5 | CardDescription,
6 | CardFooter,
7 | CardHeader,
8 | CardTitle,
9 | } from "@/components/ui/card";
10 | import Link from "next/link";
11 | import React from "react";
12 |
13 | const DeleteEventType = ({ params }: { params: { eventTypeId: string } }) => {
14 | return (
15 |
16 |
17 |
18 | Delete Event Type
19 |
20 | Are you sure you want to delete this event type?⚠️
21 | You could never recover your data then ‼️
22 |
23 |
24 |
25 |
26 | Cancel
27 |
28 |
32 |
33 |
34 |
35 | );
36 | };
37 |
38 | export default DeleteEventType;
39 |
--------------------------------------------------------------------------------
/app/api/oauth/exchange/route.ts:
--------------------------------------------------------------------------------
1 | import prisma from "@/app/lib/db";
2 | import { requireUser } from "@/app/lib/hooks";
3 | import { nylas, nylasConfig } from "@/app/lib/nylas";
4 |
5 | import { redirect } from "next/navigation";
6 | import { NextRequest } from "next/server";
7 |
8 | export async function GET(req: NextRequest) {
9 | console.log("Received callback from Nylas");
10 | const session = await requireUser();
11 | const url = new URL(req.url as string);
12 | const code = url.searchParams.get("code");
13 |
14 | if (!code) {
15 | return Response.json("No authorization code returned from Nylas", {
16 | status: 400,
17 | });
18 | }
19 | const codeExchangePayload = {
20 | clientSecret: nylasConfig.apiKey,
21 | clientId: nylasConfig.clientId as string,
22 | redirectUri: nylasConfig.callbackUri,
23 | code,
24 | };
25 |
26 | try {
27 | const response = await nylas.auth.exchangeCodeForToken(codeExchangePayload);
28 | const { grantId, email } = response;
29 |
30 | await prisma.user.update({
31 | where: {
32 | id: session.user?.id as string,
33 | },
34 | data: {
35 | grantId: grantId,
36 | grantEmail: email,
37 | },
38 | });
39 |
40 | console.log({ grantId });
41 | } catch (error) {
42 | console.error("Error exchanging code for token:", error);
43 | }
44 |
45 | redirect("/dashboard");
46 | }
47 |
--------------------------------------------------------------------------------
/app/components/dashboard/ThemeToggle.tsx:
--------------------------------------------------------------------------------
1 | "use client";
2 |
3 | import * as React from "react";
4 | import { Moon, Sun } from "lucide-react";
5 | import { useTheme } from "next-themes";
6 |
7 | import { Button } from "@/components/ui/button";
8 | import {
9 | DropdownMenu,
10 | DropdownMenuContent,
11 | DropdownMenuItem,
12 | DropdownMenuTrigger,
13 | } from "@/components/ui/dropdown-menu";
14 |
15 | export function ThemeToggle() {
16 | const { setTheme } = useTheme();
17 |
18 | return (
19 |
20 |
21 |
22 |
23 |
24 | Toggle theme
25 |
26 |
27 |
28 | setTheme("light")}>
29 | Light
30 |
31 | setTheme("dark")}>
32 | Dark
33 |
34 | setTheme("system")}>
35 | System
36 |
37 |
38 |
39 | );
40 | }
41 |
--------------------------------------------------------------------------------
/app/assets/social-youtube.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/layout.tsx:
--------------------------------------------------------------------------------
1 | import type { Metadata } from "next";
2 | import localFont from "next/font/local";
3 | import "./globals.css";
4 | import { ThemeProvider } from "./components/dashboard/ThemeProvider";
5 | import { ourFileRouter } from "@/app/api/uploadthing/core";
6 | import { NextSSRPlugin } from "@uploadthing/react/next-ssr-plugin";
7 | import { extractRouterConfig } from "uploadthing/server";
8 |
9 | const geistSans = localFont({
10 | src: "./fonts/GeistVF.woff",
11 | variable: "--font-geist-sans",
12 | weight: "100 900",
13 | });
14 | const geistMono = localFont({
15 | src: "./fonts/GeistMonoVF.woff",
16 | variable: "--font-geist-mono",
17 | weight: "100 900",
18 | });
19 |
20 | export const metadata: Metadata = {
21 | title: "Dayflow.io",
22 | description: "Dayflow.io is your next gen AI backed Sheduling software ",
23 | };
24 |
25 | export default function RootLayout({
26 | children,
27 | }: Readonly<{
28 | children: React.ReactNode;
29 | }>) {
30 | return (
31 |
32 |
35 |
41 |
42 | {children}
43 |
44 |
45 |
46 | );
47 | }
48 |
--------------------------------------------------------------------------------
/ai.tsx:
--------------------------------------------------------------------------------
1 | // NotFound.js
2 | import React from 'react';
3 | import { useHistory } from 'react-router-dom';
4 | import './NotFound.css'; // Assuming you have a CSS file for styles
5 |
6 | const NotFound = () => {
7 | const history = useHistory();
8 |
9 | const handleGoHome = () => {
10 | history.push('/');
11 | };
12 |
13 | return (
14 |
15 |
404 - Page Not Found
16 |
17 | Oops! The page you're looking for doesn't exist.
18 |
19 |
24 |
25 | Go to Homepage
26 |
27 |
28 |
Here are some links that may help:
29 |
35 |
36 |
37 | );
38 | };
39 |
40 | export default NotFound;
41 |
--------------------------------------------------------------------------------
/app/components/dashboard/DasboardLinks.tsx:
--------------------------------------------------------------------------------
1 | "use client";
2 |
3 | import { cn } from "@/lib/utils";
4 | import { CalendarCheck, HomeIcon, Settings, Users2 } from "lucide-react";
5 | import Link from "next/link";
6 | import { usePathname } from "next/navigation";
7 | import React from "react";
8 |
9 | export const dashboardLinks = [
10 | {
11 | id: 0,
12 | name: "Event Types",
13 | href: "/dashboard",
14 | icon: HomeIcon,
15 | },
16 | {
17 | id: 1,
18 | name: "Meetings",
19 | href: "/dashboard/meetings",
20 | icon: Users2,
21 | },
22 | {
23 | id: 2,
24 | name: "Availablity",
25 | href: "/dashboard/availability",
26 | icon: CalendarCheck,
27 | },
28 | {
29 | id: 3,
30 | name: "Settings",
31 | href: "/dashboard/settings",
32 | icon: Settings,
33 | },
34 | ];
35 |
36 | export function DasboardLinks() {
37 | const pathname = usePathname();
38 | return (
39 | <>
40 | {dashboardLinks.map((link) => (
41 |
51 |
52 | {link.name}
53 |
54 | ))}
55 | >
56 | );
57 | }
58 |
--------------------------------------------------------------------------------
/app/api/uploadthing/core.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable @typescript-eslint/no-unused-vars */
2 | import { createUploadthing, type FileRouter } from "uploadthing/next";
3 | import { UploadThingError } from "uploadthing/server";
4 |
5 | const f = createUploadthing();
6 |
7 | const auth = (_req: Request) => ({ id: "fakeId" }); // Fake auth function
8 |
9 | // FileRouter for your app, can contain multiple FileRoutes
10 | export const ourFileRouter = {
11 | // Define as many FileRoutes as you like, each with a unique routeSlug
12 | imageUploader: f({ image: { maxFileSize: "4MB" } })
13 | // Set permissions and file types for this FileRoute
14 | .middleware(async ({ req }) => {
15 | // This code runs on your server before upload
16 | const user = await auth(req);
17 |
18 | // If you throw, the user will not be able to upload
19 | if (!user) throw new UploadThingError("Unauthorized");
20 |
21 | // Whatever is returned here is accessible in onUploadComplete as `metadata`
22 | return { userId: user.id };
23 | })
24 | .onUploadComplete(async ({ metadata, file }) => {
25 | // This code RUNS ON YOUR SERVER after upload
26 | console.log("Upload complete for userId:", metadata.userId);
27 |
28 | console.log("file url", file.url);
29 |
30 | // !!! Whatever is returned here is sent to the clientside `onClientUploadComplete` callback
31 | return { uploadedBy: metadata.userId };
32 | }),
33 | } satisfies FileRouter;
34 |
35 | export type OurFileRouter = typeof ourFileRouter;
36 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | 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).
2 |
3 | ## Getting Started
4 |
5 | First, run the development server:
6 |
7 | ```bash
8 | npm run dev
9 | # or
10 | yarn dev
11 | # or
12 | pnpm dev
13 | # or
14 | bun dev
15 | ```
16 |
17 | Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
18 |
19 | You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.
20 |
21 | 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.
22 |
23 | ## Learn More
24 |
25 | To learn more about Next.js, take a look at the following resources:
26 |
27 | - [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
28 | - [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
29 |
30 | You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js) - your feedback and contributions are welcome!
31 |
32 | ## Deploy on Vercel
33 |
34 | 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.
35 |
36 | Check out our [Next.js deployment documentation](https://nextjs.org/docs/app/building-your-application/deploying) for more details.
37 |
--------------------------------------------------------------------------------
/components/ui/avatar.tsx:
--------------------------------------------------------------------------------
1 | "use client"
2 |
3 | import * as React from "react"
4 | import * as AvatarPrimitive from "@radix-ui/react-avatar"
5 |
6 | import { cn } from "@/lib/utils"
7 |
8 | const Avatar = React.forwardRef<
9 | React.ElementRef,
10 | React.ComponentPropsWithoutRef
11 | >(({ className, ...props }, ref) => (
12 |
20 | ))
21 | Avatar.displayName = AvatarPrimitive.Root.displayName
22 |
23 | const AvatarImage = React.forwardRef<
24 | React.ElementRef,
25 | React.ComponentPropsWithoutRef
26 | >(({ className, ...props }, ref) => (
27 |
32 | ))
33 | AvatarImage.displayName = AvatarPrimitive.Image.displayName
34 |
35 | const AvatarFallback = React.forwardRef<
36 | React.ElementRef,
37 | React.ComponentPropsWithoutRef
38 | >(({ className, ...props }, ref) => (
39 |
47 | ))
48 | AvatarFallback.displayName = AvatarPrimitive.Fallback.displayName
49 |
50 | export { Avatar, AvatarImage, AvatarFallback }
51 |
--------------------------------------------------------------------------------
/app/components/landingPage/Cta.tsx:
--------------------------------------------------------------------------------
1 | import { Button } from "@/components/ui/button";
2 |
3 | export function CTA() {
4 | return (
5 |
6 |
7 |
8 | Start using CalMarshal Now!
9 |
10 |
11 | CalMarshal makes it easy for your clients to scheduale a meeting with
12 | you clients.
13 |
14 | < div className="mt-8 flex items-center justify-center gap-x-6">
15 | Get Started Today
16 |
17 | {/* gradient svg */}
18 |
23 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 | );
40 | }
41 |
--------------------------------------------------------------------------------
/app/components/landingPage/ui/marquee.tsx:
--------------------------------------------------------------------------------
1 | import { cn } from "@/lib/utils";
2 |
3 | interface MarqueeProps {
4 | className?: string;
5 | reverse?: boolean;
6 | pauseOnHover?: boolean;
7 | children?: React.ReactNode;
8 | vertical?: boolean;
9 | repeat?: number;
10 | [key: string]: unknown;
11 | }
12 |
13 | export default function Marquee({
14 | className,
15 | reverse,
16 | pauseOnHover = false,
17 | children,
18 | vertical = false,
19 | repeat = 4,
20 | ...props
21 | }: MarqueeProps) {
22 | return (
23 |
34 | {Array(repeat)
35 | .fill(0)
36 | .map((_, i) => (
37 |
46 | {children}
47 |
48 | ))}
49 |
50 | );
51 | };
--------------------------------------------------------------------------------
/components/ui/border-beam.tsx:
--------------------------------------------------------------------------------
1 | import { cn } from "@/lib/utils";
2 |
3 | interface BorderBeamProps {
4 | className?: string;
5 | size?: number;
6 | duration?: number;
7 | borderWidth?: number;
8 | anchor?: number;
9 | colorFrom?: string;
10 | colorTo?: string;
11 | delay?: number;
12 | }
13 |
14 | export const BorderBeam = ({
15 | className,
16 | size = 200,
17 | duration = 15,
18 | anchor = 90,
19 | borderWidth = 1.5,
20 | colorFrom = "#ffaa40",
21 | colorTo = "#9c40ff",
22 | delay = 0,
23 | }: BorderBeamProps) => {
24 | return (
25 |
48 | );
49 | };
50 |
--------------------------------------------------------------------------------
/components/ui/number-ticker.tsx:
--------------------------------------------------------------------------------
1 | "use client";
2 |
3 | import { useEffect, useRef } from "react";
4 | import { useInView, useMotionValue, useSpring } from "framer-motion";
5 |
6 | import { cn } from "@/lib/utils";
7 |
8 | export default function NumberTicker({
9 | value,
10 | direction = "up",
11 | delay = 0,
12 | className,
13 | decimalPlaces = 0,
14 | }: {
15 | value: number;
16 | direction?: "up" | "down";
17 | className?: string;
18 | delay?: number; // delay in s
19 | decimalPlaces?: number;
20 | }) {
21 | const ref = useRef(null);
22 | const motionValue = useMotionValue(direction === "down" ? value : 0);
23 | const springValue = useSpring(motionValue, {
24 | damping: 60,
25 | stiffness: 100,
26 | });
27 | const isInView = useInView(ref, { once: true, margin: "0px" });
28 |
29 | useEffect(() => {
30 | isInView &&
31 | setTimeout(() => {
32 | motionValue.set(direction === "down" ? 0 : value);
33 | }, delay * 1000);
34 | }, [motionValue, isInView, delay, value, direction]);
35 |
36 | useEffect(
37 | () =>
38 | springValue.on("change", (latest) => {
39 | if (ref.current) {
40 | ref.current.textContent = Intl.NumberFormat("en-US", {
41 | minimumFractionDigits: decimalPlaces,
42 | maximumFractionDigits: decimalPlaces,
43 | }).format(Number(latest.toFixed(decimalPlaces)));
44 | }
45 | }),
46 | [springValue, decimalPlaces],
47 | );
48 |
49 | return (
50 |
57 | );
58 | }
59 |
--------------------------------------------------------------------------------
/app/components/landingPage/AuthModal.tsx:
--------------------------------------------------------------------------------
1 | import { Button } from "@/components/ui/button";
2 | import {
3 | Dialog,
4 | DialogContent,
5 | DialogHeader,
6 | DialogTrigger,
7 | } from "@/components/ui/dialog";
8 |
9 | import Logo from "@/public/ailogo.png";
10 | import Image from "next/image";
11 |
12 | import { signIn } from "@/app/lib/auth";
13 | import { GitHubAuthButton, GoogleAuthButton } from "../SubmitButton";
14 |
15 | export function AuthModal() {
16 | return (
17 |
18 |
19 | Get started
20 |
21 |
22 |
23 |
24 |
25 | Dayflow.io
26 |
27 |
28 |
29 |
38 |
39 |
48 |
49 |
50 |
51 | );
52 | }
--------------------------------------------------------------------------------
/app/components/landingPage/Newsletter.tsx:
--------------------------------------------------------------------------------
1 | import { Button } from '@/components/ui/button'
2 | import { Input } from '@/components/ui/input'
3 |
4 | const Newsletter = () => {
5 | return (
6 |
7 |
8 |
9 |
10 |
11 | Get exclusive{" "}
12 |
13 | discount{" "}
14 |
15 | on your first purchase
16 |
17 |
18 | Subscribe to newsletter to receive exclusive updates and offers.
19 |
20 |
21 |
22 |
27 |
28 | Subscribe
29 |
30 |
31 |
32 |
33 |
34 | )
35 | };
36 | export default Newsletter
--------------------------------------------------------------------------------
/app/components/landingPage/Cards/features-list.tsx:
--------------------------------------------------------------------------------
1 | export interface Feature {
2 | id: string;
3 | title: string;
4 | description: string;
5 | }
6 |
7 | export const featuresList: Feature[] = [
8 | {
9 | id: '1',
10 | title: 'AI-Powered Personalized Learning',
11 | description:
12 | 'Leverage AI to create personalized learning paths, adapting content and assessments based on individual learning styles and performance analytics.',
13 | },
14 | {
15 | id: '2',
16 | title: 'Global Scalability & Multilingual Support',
17 | description:
18 | 'Serve millions of users globally with seamless performance, offering multilingual content and support across various regions and devices.',
19 | },
20 | {
21 | id: '3',
22 | title: 'Advanced Analytics & Predictive Insights',
23 | description:
24 | 'Utilize deep learning models to analyze learning behavior, offering predictive insights to optimize student outcomes and course effectiveness.',
25 | },
26 | {
27 | id: '4',
28 | title: 'Enterprise-Level Integrations & API Ecosystem',
29 | description:
30 | 'Connect effortlessly with enterprise systems (ERP, CRM, HRMS) and extend functionality through a robust API ecosystem for custom integrations.',
31 | },
32 | {
33 | id: '5',
34 | title: 'Automated Compliance & Certification Management',
35 | description:
36 | 'Automate compliance tracking, certification processes, and accreditation, ensuring all legal and industry standards are met.',
37 | },
38 | {
39 | id: '6',
40 | title: 'Blockchain-Powered Credentialing',
41 | description:
42 | 'Issue secure, verifiable, and immutable digital certificates and credentials using blockchain technology, reducing fraud and enhancing trust.',
43 | },
44 |
45 | ];
--------------------------------------------------------------------------------
/app/assets/social-instagram.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/components/demo/RenderCalendar.tsx:
--------------------------------------------------------------------------------
1 | "use client";
2 |
3 | import { useRouter, useSearchParams } from "next/navigation";
4 | import { Calendar } from "./Calendar";
5 | import { useState, useEffect } from "react";
6 | import {
7 | CalendarDate,
8 | DateValue,
9 | getLocalTimeZone,
10 | today,
11 | parseDate,
12 | } from "@internationalized/date";
13 |
14 | interface iAppProps {
15 | daysofWeek: { day: string; isActive: boolean }[];
16 | }
17 |
18 | export function RenderCalendar({ daysofWeek }: iAppProps) {
19 | const router = useRouter();
20 | const searchParams = useSearchParams();
21 |
22 | const [date, setDate] = useState(() => {
23 | const dateParam = searchParams.get("date");
24 | return dateParam ? parseDate(dateParam) : today(getLocalTimeZone());
25 | });
26 |
27 | useEffect(() => {
28 | const dateParam = searchParams.get("date");
29 | if (dateParam) {
30 | setDate(parseDate(dateParam));
31 | }
32 | }, [searchParams]);
33 |
34 | const handleChangeDate = (date: DateValue) => {
35 | console.log(date);
36 | setDate(date as CalendarDate);
37 | const url = new URL(window.location.href);
38 |
39 | url.searchParams.set("date", date.toString());
40 |
41 | router.push(url.toString());
42 | };
43 |
44 | const isDateUnavailable = (date: DateValue) => {
45 | const dayOfWeek = date.toDate(getLocalTimeZone()).getDay();
46 | // Adjust the index to match the daysofWeek array
47 | const adjustedIndex = dayOfWeek === 0 ? 6 : dayOfWeek - 1;
48 | return !daysofWeek[adjustedIndex].isActive;
49 | };
50 |
51 | return (
52 |
59 | );
60 | }
61 |
--------------------------------------------------------------------------------
/components/ui/word-pull-up.tsx:
--------------------------------------------------------------------------------
1 | "use client";
2 |
3 | import { motion, Variants } from "framer-motion";
4 |
5 | import { cn } from "@/lib/utils";
6 |
7 | interface WordPullUpProps {
8 | words: string;
9 | delayMultiple?: number;
10 | wrapperFramerProps?: Variants;
11 | framerProps?: Variants;
12 | className?: string;
13 | }
14 |
15 | export default function WordPullUp({
16 | words,
17 | wrapperFramerProps = {
18 | hidden: { opacity: 0 },
19 | show: {
20 | opacity: 1,
21 | transition: {
22 | staggerChildren: 0.2,
23 | },
24 | },
25 | },
26 | framerProps = {
27 | hidden: { y: 20, opacity: 0 },
28 | show: {
29 | y: [0, -10, 0], // Creates a "up-up" bouncing effect
30 | opacity: 1,
31 | transition: {
32 | y: {
33 | repeat: Infinity, // Infinite loop
34 | repeatType: "loop",
35 | ease: "easeInOut",
36 | duration: 2, // Adjust to control the speed of the bounce effect
37 | },
38 | },
39 | },
40 | },
41 | className,
42 | }: WordPullUpProps) {
43 | return (
44 |
53 | {words.split(" ").map((word, i) => (
54 |
59 | {word === "" ? : word}
60 |
61 | ))}
62 |
63 | );
64 | }
65 |
--------------------------------------------------------------------------------
/components/ui/letter-pullup.tsx:
--------------------------------------------------------------------------------
1 | "use client";
2 |
3 | import React from 'react';
4 | import { motion } from "framer-motion";
5 | import { cn } from "@/lib/utils";
6 |
7 | interface LetterPullupProps {
8 | className?: string;
9 | words: string;
10 | duration?: number;
11 | }
12 |
13 | export default function InfiniteLetterPullup({
14 | className,
15 | words,
16 | duration = 2,
17 | }: LetterPullupProps) {
18 | const letters = words.split("");
19 |
20 | const containerVariants = {
21 | animate: {
22 | transition: {
23 | staggerChildren: 0.1,
24 | repeat: Infinity,
25 | repeatType: "loop" as const,
26 | },
27 | },
28 | };
29 |
30 | const letterVariants = {
31 | initial: { y: 100, opacity: 0 },
32 | animate: {
33 | y: [100, 0, 0, -100],
34 | opacity: [0, 1, 1, 0],
35 | transition: {
36 | duration: duration,
37 | times: [0, 0.1, 0.9, 1],
38 | ease: "easeInOut",
39 | repeat: Infinity,
40 | repeatType: "loop" as const,
41 | },
42 | },
43 | };
44 |
45 | return (
46 |
51 | {letters.map((letter, i) => (
52 |
63 | {letter === " " ? : letter}
64 |
65 | ))}
66 |
67 | );
68 | }
--------------------------------------------------------------------------------
/app/onboarding/grant-id/page.tsx:
--------------------------------------------------------------------------------
1 | import {
2 | Card,
3 | CardContent,
4 | CardDescription,
5 | CardHeader,
6 | CardTitle,
7 | } from "@/components/ui/card";
8 | import React from "react";
9 | import AlmostFinished from "@/public/work-is-almost-over-happy.gif";
10 | import Image from "next/image";
11 | import { Button } from "@/components/ui/button";
12 | import { CalendarCheck2 } from "lucide-react";
13 | import Link from "next/link";
14 |
15 | const GrantIdRoute = () => {
16 | return (
17 |
18 |
19 |
20 | You Are Almost Done!!✅
21 |
22 | We have to now connect your calendar to your account
23 | To get you started instantly
24 |
25 |
30 |
31 |
32 |
33 |
34 |
35 | Connect Calender to Account
36 |
37 |
38 |
39 | something went wrong?
40 | Contact us immediately
41 |
42 |
43 |
44 |
45 | Contact Us Now⚡️
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 | );
55 | };
56 |
57 | export default GrantIdRoute;
58 |
--------------------------------------------------------------------------------
/app/components/demo/CalendarHeader.tsx:
--------------------------------------------------------------------------------
1 | /* eslint-disable @typescript-eslint/no-unused-vars */
2 | import type { AriaButtonProps } from "@react-aria/button";
3 | import { useDateFormatter } from "@react-aria/i18n";
4 | import { VisuallyHidden } from "@react-aria/visually-hidden";
5 | import type { CalendarState } from "@react-stately/calendar";
6 | import type { DOMAttributes, FocusableElement } from "@react-types/shared";
7 | import { ChevronLeftIcon, ChevronRightIcon } from "lucide-react";
8 | import { CalendarButton } from "./CalendarButton";
9 |
10 | export function CalendarHeader({
11 | state,
12 | calendarProps,
13 | prevButtonProps,
14 | nextButtonProps,
15 | }: {
16 | state: CalendarState;
17 | calendarProps: DOMAttributes;
18 | prevButtonProps: AriaButtonProps<"button">;
19 | nextButtonProps: AriaButtonProps<"button">;
20 | }) {
21 | const monthDateFormatter = useDateFormatter({
22 | month: "short",
23 | year: "numeric",
24 | timeZone: state.timeZone,
25 | });
26 |
27 | const [monthName, _, year] = monthDateFormatter
28 | .formatToParts(state.visibleRange.start.toDate(state.timeZone))
29 | .map((part) => part.value);
30 |
31 | return (
32 |
33 |
34 | {calendarProps["aria-label"]}
35 |
36 |
37 |
38 | {monthName}{" "}
39 |
40 | {year}
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 | );
53 | }
54 |
--------------------------------------------------------------------------------
/app/components/landingPage/Cards.tsx:
--------------------------------------------------------------------------------
1 | import { HoverEffect } from "@/components/ui/card-hover-effect";
2 | import { FaStripe, FaGoogle, FaAmazon, FaFacebook, FaMicrosoft } from "react-icons/fa";
3 |
4 | export function CardHoverEffect() {
5 | return (
6 |
7 |
8 |
9 | );
10 | }
11 | export const projects = [
12 | {
13 | title: "Ultra-Scheduler",
14 | description:
15 | "A $10 trillion enterprise software for global-scale scheduling, optimizing time across industries.",
16 | icon: ,
17 | link: "/dashboard",
18 | },
19 | {
20 | title: "HyperPlan",
21 | description:
22 | "An intelligent scheduling tool built for the largest enterprises, streamlining operations with AI.",
23 | icon: ,
24 | link: "/dashboard",
25 | },
26 | {
27 | title: "SchedulePro",
28 | description:
29 | "A revolutionary platform for automating scheduling for trillion-dollar companies with maximum efficiency.",
30 | icon: ,
31 | link: "/dashboard",
32 | },
33 | {
34 | title: "TimeSync",
35 | description:
36 | "A global scheduling solution for enterprises, offering predictive analytics and AI-driven insights.",
37 | // eslint-disable-next-line react/jsx-no-undef
38 | icon: ,
39 | link: "/dashboard",
40 | },
41 | {
42 | title: "CloudPlanner",
43 | description:
44 | "A cutting-edge platform that synchronizes enterprise-level schedules across global teams.",
45 | icon: ,
46 | link: "/dashboard",
47 | },
48 | {
49 | title: "SmartSchedule",
50 | description:
51 | "Empowering global operations with scalable, AI-enhanced scheduling solutions.",
52 | icon: ,
53 | link: "/dashboard",
54 | },
55 | ];
56 | export default CardHoverEffect;
--------------------------------------------------------------------------------
/public/github.svg:
--------------------------------------------------------------------------------
1 |
9 |
11 |
--------------------------------------------------------------------------------
/app/components/demo/CalendarGrid.tsx:
--------------------------------------------------------------------------------
1 | import {
2 | DateDuration,
3 | endOfMonth,
4 | getWeeksInMonth,
5 | } from "@internationalized/date";
6 | import { DateValue, useCalendarGrid, useLocale } from "react-aria";
7 | import { CalendarState } from "react-stately";
8 | import { CalendarCell } from "./CalendarCell";
9 |
10 | export function CalendarGrid({
11 | state,
12 | offset = {},
13 | isDateUnavailable,
14 | }: {
15 | state: CalendarState;
16 | offset?: DateDuration;
17 | isDateUnavailable?: (date: DateValue) => boolean;
18 | }) {
19 | const startDate = state.visibleRange.start.add(offset);
20 | const endDate = endOfMonth(startDate);
21 | const { locale } = useLocale();
22 | const { gridProps, headerProps, weekDays } = useCalendarGrid(
23 | {
24 | startDate,
25 | endDate,
26 | weekdayStyle: "short",
27 | },
28 | state
29 | );
30 |
31 | // Get the number of weeks in the month so we can render the proper number of rows.
32 | const weeksInMonth = getWeeksInMonth(startDate, locale);
33 | return (
34 |
35 |
36 |
37 | {weekDays.map((day, index) => (
38 | {day}
39 | ))}
40 |
41 |
42 |
43 | {Array.from({ length: weeksInMonth }, (_, weekIndex) => (
44 |
45 | {state
46 | .getDatesInWeek(weekIndex, startDate)
47 | .map((date, i) =>
48 | date ? (
49 |
56 | ) : (
57 |
58 | )
59 | )}
60 |
61 | ))}
62 |
63 |
64 | );
65 | }
66 |
--------------------------------------------------------------------------------
/components/ui/button.tsx:
--------------------------------------------------------------------------------
1 | import * as React from "react"
2 | import { Slot } from "@radix-ui/react-slot"
3 | import { cva, type VariantProps } from "class-variance-authority"
4 |
5 | import { cn } from "@/lib/utils"
6 |
7 | const buttonVariants = cva(
8 | "inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50",
9 | {
10 | variants: {
11 | variant: {
12 | default:
13 | "bg-gradient-to-r from-blue-600 via-purple-600 to-pink-600 text-white shadow hover:bg-primary",
14 | destructive:
15 | "bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90",
16 | outline:
17 | "border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground",
18 | secondary:
19 | "bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80",
20 | ghost: "hover:bg-accent hover:text-accent-foreground",
21 | link: "text-primary underline-offset-4 hover:underline",
22 | },
23 | size: {
24 | default: "h-9 px-4 py-2",
25 | sm: "h-8 rounded-md px-3 text-xs",
26 | lg: "h-10 rounded-md px-8",
27 | icon: "h-9 w-9",
28 | },
29 | },
30 | defaultVariants: {
31 | variant: "default",
32 | size: "default",
33 | },
34 | }
35 | )
36 |
37 | export interface ButtonProps
38 | extends React.ButtonHTMLAttributes,
39 | VariantProps {
40 | asChild?: boolean
41 | }
42 |
43 | const Button = React.forwardRef(
44 | ({ className, variant, size, asChild = false, ...props }, ref) => {
45 | const Comp = asChild ? Slot : "button"
46 | return (
47 |
52 | )
53 | }
54 | )
55 | Button.displayName = "Button"
56 |
57 | export { Button, buttonVariants }
58 |
--------------------------------------------------------------------------------
/components/ui/spotlight.tsx:
--------------------------------------------------------------------------------
1 | /* eslint-disable @typescript-eslint/no-unused-vars */
2 | import React from "react";
3 | import { cn } from "@/lib/utils";
4 |
5 | type SpotlightProps = {
6 | className?: string;
7 | fill?: string;
8 | };
9 |
10 | export const Spotlight = ({ className, fill }: SpotlightProps) => {
11 | return (
12 |
21 |
22 |
31 |
32 |
33 | {/* Define the gradient */}
34 |
35 | {/* Sky blue */}
36 | {/* Light blue */}
37 |
38 |
47 |
48 |
54 |
58 |
59 |
60 |
61 | );
62 | };
--------------------------------------------------------------------------------
/components/ui/card.tsx:
--------------------------------------------------------------------------------
1 | import * as React from "react"
2 |
3 | import { cn } from "@/lib/utils"
4 |
5 | const Card = React.forwardRef<
6 | HTMLDivElement,
7 | React.HTMLAttributes
8 | >(({ className, ...props }, ref) => (
9 |
17 | ))
18 | Card.displayName = "Card"
19 |
20 | const CardHeader = React.forwardRef<
21 | HTMLDivElement,
22 | React.HTMLAttributes
23 | >(({ className, ...props }, ref) => (
24 |
29 | ))
30 | CardHeader.displayName = "CardHeader"
31 |
32 | const CardTitle = React.forwardRef<
33 | HTMLParagraphElement,
34 | React.HTMLAttributes
35 | >(({ className, ...props }, ref) => (
36 |
41 | ))
42 | CardTitle.displayName = "CardTitle"
43 |
44 | const CardDescription = React.forwardRef<
45 | HTMLParagraphElement,
46 | React.HTMLAttributes
47 | >(({ className, ...props }, ref) => (
48 |
53 | ))
54 | CardDescription.displayName = "CardDescription"
55 |
56 | const CardContent = React.forwardRef<
57 | HTMLDivElement,
58 | React.HTMLAttributes
59 | >(({ className, ...props }, ref) => (
60 |
61 | ))
62 | CardContent.displayName = "CardContent"
63 |
64 | const CardFooter = React.forwardRef<
65 | HTMLDivElement,
66 | React.HTMLAttributes
67 | >(({ className, ...props }, ref) => (
68 |
73 | ))
74 | CardFooter.displayName = "CardFooter"
75 |
76 | export { Card, CardHeader, CardFooter, CardTitle, CardDescription, CardContent }
77 |
--------------------------------------------------------------------------------
/app/page.tsx:
--------------------------------------------------------------------------------
1 | import { Suspense } from "react";
2 | import {Navbar} from "./components/landingPage/Navbar";
3 | import {Hero} from "./components/landingPage/Hero";
4 | import {LogoTicker} from "./components/landingPage/Logos";
5 | import CardHoverEffect from "./components/landingPage/Cards";
6 | import {Features} from "./components/landingPage/Features";
7 | import FeaturesGrid from "./components/landingPage/Cards/cardsfeatures";
8 | import GridTabs from "./components/landingPage/girdtabs";
9 | import {Testimonial} from "./components/landingPage/Testimonial";
10 | import Services from "./components/landingPage/Services";
11 | import Offerings from "./components/landingPage/offerings";
12 | import Pricing from "./components/landingPage/pricings";
13 | import FAQS from "./components/landingPage/Faqs";
14 | import {Testimonials} from "./components/landingPage/Reviews";
15 | import Tools from "./components/landingPage/Tools";
16 | import Banner from "./components/landingPage/Banner";
17 | import Footer from "./components/landingPage/Footer";
18 | import { auth } from "./lib/auth";
19 | import { redirect } from "next/navigation";
20 | import Testimonialsss from "./components/landingPage/Testimonys";
21 | import Stats from "./components/landingPage/Stats"
22 | import AnimatedBeams from "./components/landingPage/Animated";
23 | import { AuthButton} from "./components/landingPage/AuthButton";
24 |
25 | export default async function Home() {
26 | const session = await auth();
27 |
28 | if (session?.user) {
29 | return redirect("/dashboard");
30 | }
31 |
32 | return (
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
Loading... }>
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 | );
58 | }
59 |
--------------------------------------------------------------------------------
/app/success/page.tsx:
--------------------------------------------------------------------------------
1 | /* eslint-disable @typescript-eslint/no-unused-vars */
2 | "use client";
3 |
4 | import { Button } from "@/components/ui/button";
5 | import { Card, CardContent, CardFooter } from "@/components/ui/card";
6 | import { Separator } from "@/components/ui/separator";
7 | import { Check } from "lucide-react";
8 | import Link from "next/link";
9 |
10 | export default function SuccessPage() {
11 | return (
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 | This event is scheduled🥰
20 |
21 |
22 | We emailed you and the other attendees a calendar invitation with
23 | all the details.
24 |
25 |
26 |
27 |
28 |
29 |
30 |
What
31 |
32 |
33 |
Design Workshop
34 |
35 |
36 |
37 |
When
38 |
39 |
42 |
43 |
Where
44 |
45 |
48 |
49 |
50 |
51 |
52 | Close this Page
53 |
54 |
55 |
56 |
57 | );
58 | }
59 |
--------------------------------------------------------------------------------
/app/components/demo/CalendarCell.tsx:
--------------------------------------------------------------------------------
1 | import { cn } from "@/lib/utils";
2 | import {
3 | CalendarDate,
4 | getLocalTimeZone,
5 | isSameMonth,
6 | isToday,
7 | } from "@internationalized/date";
8 | import { useRef } from "react";
9 | import { mergeProps, useCalendarCell, useFocusRing } from "react-aria";
10 | import { CalendarState } from "react-stately";
11 |
12 | export function CalendarCell({
13 | state,
14 | date,
15 | currentMonth,
16 | isUnavailable,
17 | }: {
18 | state: CalendarState;
19 | date: CalendarDate;
20 | currentMonth: CalendarDate;
21 | isUnavailable?: boolean;
22 | }) {
23 | const ref = useRef(null);
24 | const { cellProps, buttonProps, isSelected, isDisabled, formattedDate } =
25 | useCalendarCell({ date }, state, ref);
26 |
27 | // Override isDisabled if the date is unavailable
28 | const finalIsDisabled = isDisabled || isUnavailable;
29 |
30 | const { focusProps, isFocusVisible } = useFocusRing();
31 |
32 | const isOutsideMonth = !isSameMonth(currentMonth, date);
33 |
34 | const isDateToday = isToday(date, getLocalTimeZone());
35 |
36 | return (
37 |
41 |
47 |
58 | {formattedDate}
59 | {isDateToday && (
60 |
66 | )}
67 |
68 |
69 |
70 | );
71 | }
72 |
--------------------------------------------------------------------------------
/app/components/landingPage/Logos.tsx:
--------------------------------------------------------------------------------
1 | "use client";
2 |
3 | import WordPullUp from "@/components/ui/word-pull-up";
4 | import acmelogo from "@/app/assets/logo-acme.png";
5 | import apexLogo from "@/app/assets/logo-apex.png";
6 | import celestialLogo from "@/app/assets/logo-celestial.png";
7 | import echoLogo from "@/app/assets/logo-echo.png";
8 | import { motion } from "framer-motion";
9 | import pulseLogo from "@/app/assets/logo-pulse.png";
10 | import quantumLogo from "@/app/assets/logo-quantum.png";
11 |
12 | export const LogoTicker = () => {
13 | return (
14 |
15 | {/* Text is centered and pushed down slightly */}
16 |
29 |
30 |
31 | {/* Animation Div */}
32 |
33 |
34 |
46 | {[
47 | acmelogo,
48 | apexLogo,
49 | celestialLogo,
50 | quantumLogo,
51 | pulseLogo,
52 | echoLogo,
53 | acmelogo,
54 | apexLogo,
55 | celestialLogo,
56 | quantumLogo,
57 | pulseLogo,
58 | echoLogo,
59 | ].map((logo) => (
60 | // eslint-disable-next-line @next/next/no-img-element
61 |
67 | ))}
68 |
69 |
70 |
71 |
72 | );
73 | };
--------------------------------------------------------------------------------
/app/components/SubmitButton.tsx:
--------------------------------------------------------------------------------
1 | "use client";
2 |
3 | import { Button } from "@/components/ui/button";
4 | import { cn } from "@/lib/utils";
5 | import { Loader2 } from "lucide-react";
6 | import Image from "next/image";
7 | import { useFormStatus } from "react-dom";
8 | import GithubLogo from "@/public/github.svg";
9 | import GoogleLogo from "@/public/google.svg";
10 | import React from "react";
11 | interface iAppProps {
12 | text: string;
13 | variant?:
14 | | "default"
15 | | "destructive"
16 | | "outline"
17 | | "secondary"
18 | | "ghost"
19 | | "link"
20 | | null
21 | | undefined;
22 |
23 | className?:string;
24 | }
25 |
26 | export function SubmitButton({ text, variant, className }: iAppProps) {
27 | const { pending } = useFormStatus();
28 |
29 | return (
30 | <>
31 | {pending ? (
32 |
33 | Please wait
34 |
35 | ) : (
36 |
41 | {text}
42 |
43 | )}
44 | >
45 | );
46 | }
47 |
48 | export function GitHubAuthButton() {
49 | const { pending } = useFormStatus();
50 | return (
51 | <>
52 | {pending ? (
53 |
54 | Please wait🥲
55 |
56 | ) : (
57 |
58 |
63 | Sign in with GitHub
64 |
65 | )}
66 | >
67 | );
68 | }
69 |
70 | export function GoogleAuthButton() {
71 | const { pending } = useFormStatus();
72 | return (
73 | <>
74 | {pending ? (
75 |
76 | Please wait
77 |
78 | ) : (
79 |
80 |
81 | Sign in with Google
82 |
83 | )}
84 | >
85 | );
86 | }
87 |
--------------------------------------------------------------------------------
/app/components/landingPage/Cards/icons.tsx:
--------------------------------------------------------------------------------
1 | import type { IconProps as PhosphorProps } from '@phosphor-icons/react'
2 | import * as Phosphor from '@phosphor-icons/react'
3 |
4 | export type Icon = (props: PhosphorProps) => JSX.Element
5 |
6 | export const ArrowRight = Phosphor.ArrowRight
7 | export const Ecosystem = Phosphor.Leaf
8 | export const Plus = Phosphor.Plus
9 | export const Minus = Phosphor.Minus
10 | export const YoutubeLogo = Phosphor.YoutubeLogo
11 | export const XLogo = Phosphor.XLogo
12 | export const InstagramLogo = Phosphor.InstagramLogo
13 | export const TiktokLogo = Phosphor.TiktokLogo
14 | export const LinkedinLogo = Phosphor.LinkedinLogo
15 | export const PinterestLogo = Phosphor.PinterestLogo
16 |
17 | export const Menu: Icon = (props) => (
18 |
26 |
27 |
31 |
32 |
33 |
34 |
40 |
41 |
42 |
43 | )
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "calcom-nylas",
3 | "version": "0.1.0",
4 | "private": true,
5 | "scripts": {
6 | "dev": "next dev",
7 | "build": "prisma generate && next build",
8 | "start": "next start",
9 | "lint": "next lint"
10 | },
11 | "dependencies": {
12 | "@auth/prisma-adapter": "^2.5.0",
13 | "@chakra-ui/react": "^2.8.2",
14 | "@conform-to/react": "^1.1.5",
15 | "@conform-to/zod": "^1.1.5",
16 | "@internationalized/date": "^3.5.5",
17 | "@netlify/plugin-nextjs": "^5.7.3",
18 | "@nylas/react": "^1.1.3",
19 | "@phosphor-icons/react": "^2.1.7",
20 | "@prisma/client": "^5.20.0",
21 | "@radix-ui/react-avatar": "^1.1.1",
22 | "@radix-ui/react-dialog": "^1.1.1",
23 | "@radix-ui/react-dropdown-menu": "^2.1.1",
24 | "@radix-ui/react-icons": "^1.3.0",
25 | "@radix-ui/react-label": "^2.1.0",
26 | "@radix-ui/react-select": "^2.1.1",
27 | "@radix-ui/react-separator": "^1.1.0",
28 | "@radix-ui/react-slot": "^1.1.0",
29 | "@radix-ui/react-switch": "^1.1.0",
30 | "@radix-ui/react-tooltip": "^1.1.2",
31 | "@tsparticles/engine": "^3.5.0",
32 | "@tsparticles/react": "^3.0.0",
33 | "@tsparticles/slim": "^3.5.0",
34 | "@uploadthing/react": "^7.0.1",
35 | "class-variance-authority": "^0.7.0",
36 | "clsx": "^2.1.1",
37 | "cobe": "^0.6.3",
38 | "date-fns": "^3.6.0",
39 | "framer-motion": "^11.9.0",
40 | "gsap": "^3.12.5",
41 | "install": "^0.13.0",
42 | "iron-session": "^8.0.3",
43 | "lucide-react": "^0.440.0",
44 | "next": "^14.2.14",
45 | "next-auth": "^5.0.0-beta.21",
46 | "next-themes": "^0.3.0",
47 | "npm": "^10.8.3",
48 | "nylas": "^7.5.2",
49 | "react": "18.2.0",
50 | "react-aria": "^3.34.3",
51 | "react-aria-components": "^1.3.3",
52 | "react-countup": "^6.5.3",
53 | "react-day-picker": "^8.10.1",
54 | "react-dom": "18.2.0",
55 | "react-icons": "^5.3.0",
56 | "react-spring": "^9.7.4",
57 | "react-stately": "^3.32.2",
58 | "recharts": "^2.12.7",
59 | "sharp": "^0.33.5",
60 | "sonner": "^1.5.0",
61 | "tailwind-merge": "^2.5.2",
62 | "tailwindcss-animate": "^1.0.7",
63 | "uploadthing": "^7.0.1",
64 | "zod": "^3.23.8"
65 | },
66 | "devDependencies": {
67 | "@types/node": "^20",
68 | "@types/react": "^18",
69 | "@types/react-dom": "^18",
70 | "eslint": "^8",
71 | "eslint-config-next": "14.2.10",
72 | "postcss": "^8",
73 | "prisma": "^5.20.0",
74 | "tailwindcss": "^3.4.1",
75 | "typescript": "^5"
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/app/components/landingPage/Reviews.tsx:
--------------------------------------------------------------------------------
1 | "use client";
2 |
3 | import { motion } from "framer-motion";
4 | import { testimonials } from "./constants";
5 |
6 | export const Testimonials = () => {
7 | return (
8 |
9 |
10 |
11 | Beyond Expectations.
12 |
13 |
14 | Our revolutionary Sheduling Enterprice Software have transformed our clients'
15 | strategies✨.
16 |
17 |
18 |
32 | {[...testimonials, ...testimonials].map((testimonial, index) => (
33 |
37 |
38 | {testimonial.review}
39 |
40 |
41 |
42 |
43 |
44 |
45 | {testimonial.name}
46 |
47 | {testimonial.username}
48 |
49 |
50 |
51 |
52 | ))}
53 |
54 |
55 |
56 | );
57 | };
--------------------------------------------------------------------------------
/app/globals.css:
--------------------------------------------------------------------------------
1 | @tailwind base;
2 | @tailwind components;
3 | @tailwind utilities;
4 |
5 | @layer base {
6 | :root {
7 | --background: 0 0% 100%;
8 | --foreground: 222.2 84% 4.9%;
9 | --card: 0 0% 100%;
10 | --card-foreground: 222.2 84% 4.9%;
11 | --popover: 0 0% 100%;
12 | --popover-foreground: 222.2 84% 4.9%;
13 | --primary: 221.2 83.2% 53.3%;
14 | --primary-foreground: 210 40% 98%;
15 | --secondary: 210 40% 96.1%;
16 | --secondary-foreground: 222.2 47.4% 11.2%;
17 | --muted: 210 40% 96.1%;
18 | --muted-foreground: 215.4 16.3% 46.9%;
19 | --accent: 210 40% 96.1%;
20 | --accent-foreground: 222.2 47.4% 11.2%;
21 | --destructive: 0 84.2% 60.2%;
22 | --destructive-foreground: 210 40% 98%;
23 | --border: 214.3 31.8% 91.4%;
24 | --input: 214.3 31.8% 91.4%;
25 | --ring: 221.2 83.2% 53.3%;
26 | --radius: 0.5rem;
27 | --chart-1: 12 76% 61%;
28 | --chart-2: 173 58% 39%;
29 | --chart-3: 197 37% 24%;
30 | --chart-4: 43 74% 66%;
31 | --chart-5: 27 87% 67%;
32 | }
33 |
34 | .dark {
35 | --background: 222.2 84% 4.9%;
36 | --foreground: 210 40% 98%;
37 | --card: 222.2 84% 4.9%;
38 | --card-foreground: 210 40% 98%;
39 | --popover: 222.2 84% 4.9%;
40 | --popover-foreground: 210 40% 98%;
41 | --primary: 217.2 91.2% 59.8%;
42 | --primary-foreground: 222.2 47.4% 11.2%;
43 | --secondary: 217.2 32.6% 17.5%;
44 | --secondary-foreground: 210 40% 98%;
45 | --muted: 217.2 32.6% 17.5%;
46 | --muted-foreground: 215 20.2% 65.1%;
47 | --accent: 217.2 32.6% 17.5%;
48 | --accent-foreground: 210 40% 98%;
49 | --destructive: 0 62.8% 30.6%;
50 | --destructive-foreground: 210 40% 98%;
51 | --border: 217.2 32.6% 17.5%;
52 | --input: 217.2 32.6% 17.5%;
53 | --ring: 224.3 76.3% 48%;
54 | --chart-1: 220 70% 50%;
55 | --chart-2: 160 60% 45%;
56 | --chart-3: 30 80% 55%;
57 | --chart-4: 280 65% 60%;
58 | --chart-5: 340 75% 55%;
59 | }
60 | }
61 |
62 | @layer base {
63 | * {
64 | @apply border-border;
65 | }
66 |
67 | body:not(.dark) {
68 | @apply text-foreground;
69 | background: linear-gradient(
70 | 90deg,
71 | hsl(0, 0%, 100%) 0%, /* Deep violet */
72 | hsl(248, 82%, 85%) 30%, /* Rich blue-purple */
73 | hsl(275, 100%, 86%) 60%, /* Darker violet-blue */
74 | hsl(0, 0%, 100%)
75 | );
76 | }
77 |
78 | .dark body {
79 | background: linear-gradient(
80 | 90deg,
81 | hsl(223, 90%, 28%) 0%, /* Deep violet */
82 | hsl(241, 89%, 21%) 30%, /* Rich blue-purple */
83 | hsl(269, 85%, 26%) 60%, /* Darker violet-blue */
84 | hsl(281, 87%, 15%) 100%
85 | );
86 | }
87 | }
88 |
--------------------------------------------------------------------------------
/.github/workflows/generator-generic-ossf-slsa3-publish.yml:
--------------------------------------------------------------------------------
1 | # This workflow uses actions that are not certified by GitHub.
2 | # They are provided by a third-party and are governed by
3 | # separate terms of service, privacy policy, and support
4 | # documentation.
5 |
6 | # This workflow lets you generate SLSA provenance file for your project.
7 | # The generation satisfies level 3 for the provenance requirements - see https://slsa.dev/spec/v0.1/requirements
8 | # The project is an initiative of the OpenSSF (openssf.org) and is developed at
9 | # https://github.com/slsa-framework/slsa-github-generator.
10 | # The provenance file can be verified using https://github.com/slsa-framework/slsa-verifier.
11 | # For more information about SLSA and how it improves the supply-chain, visit slsa.dev.
12 |
13 | name: SLSA generic generator
14 | on:
15 | workflow_dispatch:
16 | release:
17 | types: [created]
18 |
19 | jobs:
20 | build:
21 | runs-on: ubuntu-latest
22 | outputs:
23 | digests: ${{ steps.hash.outputs.digests }}
24 |
25 | steps:
26 | - uses: actions/checkout@v4
27 |
28 | # ========================================================
29 | #
30 | # Step 1: Build your artifacts.
31 | #
32 | # ========================================================
33 | - name: Build artifacts
34 | run: |
35 | # These are some amazing artifacts.
36 | echo "artifact1" > artifact1
37 | echo "artifact2" > artifact2
38 |
39 | # ========================================================
40 | #
41 | # Step 2: Add a step to generate the provenance subjects
42 | # as shown below. Update the sha256 sum arguments
43 | # to include all binaries that you generate
44 | # provenance for.
45 | #
46 | # ========================================================
47 | - name: Generate subject for provenance
48 | id: hash
49 | run: |
50 | set -euo pipefail
51 |
52 | # List the artifacts the provenance will refer to.
53 | files=$(ls artifact*)
54 | # Generate the subjects (base64 encoded).
55 | echo "hashes=$(sha256sum $files | base64 -w0)" >> "${GITHUB_OUTPUT}"
56 |
57 | provenance:
58 | needs: [build]
59 | permissions:
60 | actions: read # To read the workflow path.
61 | id-token: write # To sign the provenance.
62 | contents: write # To add assets to a release.
63 | uses: slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml@v1.4.0
64 | with:
65 | base64-subjects: "${{ needs.build.outputs.digests }}"
66 | upload-assets: true # Optional: Upload to a new release
67 |
--------------------------------------------------------------------------------
/app/components/landingPage/Cards/feature-card.tsx:
--------------------------------------------------------------------------------
1 | "use client";
2 |
3 | import * as Icons from './icons'; // Ensure Icons.Ecosystem is defined in this file
4 | import { motion, useMotionTemplate, useMotionValue } from 'framer-motion';
5 | import { useEffect, useRef } from 'react';
6 | import Link from 'next/link';
7 |
8 | import { BorderBeam } from '@/components/ui/border-beam';
9 | import { Feature } from './features-list';
10 |
11 | interface FeatureCardProps {
12 | feature: Feature;
13 | href: string;
14 | }
15 |
16 | export function FeatureCard({ feature: { description, id, title }, href }: FeatureCardProps) {
17 | const offsetX = useMotionValue(-100);
18 | const offsetY = useMotionValue(-100);
19 |
20 | const maskImage = useMotionTemplate`radial-gradient(100px 100px at ${offsetX}px ${offsetY}px, black, transparent)`;
21 |
22 | const borderRef = useRef(null);
23 |
24 | useEffect(() => {
25 | const updateMousePosition = (e: MouseEvent) => {
26 | if (!borderRef.current) return;
27 |
28 | const borderRect = borderRef.current.getBoundingClientRect();
29 | offsetX.set(e.clientX - borderRect.left);
30 | offsetY.set(e.clientY - borderRect.top);
31 | };
32 |
33 | window.addEventListener('mousemove', updateMousePosition);
34 |
35 | return () => {
36 | window.removeEventListener('mousemove', updateMousePosition);
37 | };
38 | }, [offsetX, offsetY]);
39 |
40 | return (
41 |
45 |
53 |
54 |
55 | {/* Ensure this icon is correctly defined */}
56 |
57 |
{title}
58 |
{description}
59 |
60 | {/* Ensure that the Link works properly */}
61 |
62 |
63 | Learn More
64 |
65 |
66 |
67 | );
68 | }
69 |
70 | export default FeatureCard;
--------------------------------------------------------------------------------
/public/producthunt.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/app/lib/times.ts:
--------------------------------------------------------------------------------
1 | export const times = [
2 | {
3 | id: 0,
4 | time: "00:00",
5 | },
6 | {
7 | id: 1,
8 | time: "00:30",
9 | },
10 | {
11 | id: 2,
12 | time: "01:00",
13 | },
14 | {
15 | id: 3,
16 | time: "01:30",
17 | },
18 | {
19 | id: 4,
20 | time: "02:00",
21 | },
22 | {
23 | id: 5,
24 | time: "02:30",
25 | },
26 | {
27 | id: 6,
28 | time: "03:00",
29 | },
30 | {
31 | id: 7,
32 | time: "03:30",
33 | },
34 | {
35 | id: 8,
36 | time: "04:00",
37 | },
38 | {
39 | id: 9,
40 | time: "04:30",
41 | },
42 | {
43 | id: 10,
44 | time: "05:00",
45 | },
46 | {
47 | id: 11,
48 | time: "05:30",
49 | },
50 | {
51 | id: 12,
52 | time: "06:00",
53 | },
54 | {
55 | id: 13,
56 | time: "06:30",
57 | },
58 | {
59 | id: 14,
60 | time: "07:00",
61 | },
62 | {
63 | id: 15,
64 | time: "07:30",
65 | },
66 | {
67 | id: 16,
68 | time: "08:00",
69 | },
70 | {
71 | id: 17,
72 | time: "08:30",
73 | },
74 | {
75 | id: 18,
76 | time: "09:00",
77 | },
78 | {
79 | id: 19,
80 | time: "09:30",
81 | },
82 | {
83 | id: 20,
84 | time: "10:00",
85 | },
86 | {
87 | id: 21,
88 | time: "10:30",
89 | },
90 | {
91 | id: 22,
92 | time: "11:00",
93 | },
94 | {
95 | id: 23,
96 | time: "11:30",
97 | },
98 | {
99 | id: 24,
100 | time: "12:00",
101 | },
102 | {
103 | id: 25,
104 | time: "12:30",
105 | },
106 | {
107 | id: 26,
108 | time: "13:00",
109 | },
110 | {
111 | id: 27,
112 | time: "13:30",
113 | },
114 | {
115 | id: 28,
116 | time: "14:00",
117 | },
118 | {
119 | id: 29,
120 | time: "14:30",
121 | },
122 | {
123 | id: 30,
124 | time: "15:00",
125 | },
126 | {
127 | id: 31,
128 | time: "15:30",
129 | },
130 | {
131 | id: 32,
132 | time: "16:00",
133 | },
134 | {
135 | id: 33,
136 | time: "16:30",
137 | },
138 | {
139 | id: 34,
140 | time: "17:00",
141 | },
142 | {
143 | id: 35,
144 | time: "17:30",
145 | },
146 | {
147 | id: 36,
148 | time: "18:00",
149 | },
150 | {
151 | id: 37,
152 | time: "18:30",
153 | },
154 | {
155 | id: 38,
156 | time: "19:00",
157 | },
158 | {
159 | id: 39,
160 | time: "19:30",
161 | },
162 | {
163 | id: 40,
164 | time: "20:00",
165 | },
166 | {
167 | id: 41,
168 | time: "20:30",
169 | },
170 | {
171 | id: 42,
172 | time: "21:00",
173 | },
174 | {
175 | id: 43,
176 | time: "21:30",
177 | },
178 | {
179 | id: 44,
180 | time: "22:00",
181 | },
182 | {
183 | id: 45,
184 | time: "22:30",
185 | },
186 | {
187 | id: 46,
188 | time: "23:00",
189 | },
190 | {
191 | id: 47,
192 | time: "23:30",
193 | },
194 | ];
195 |
--------------------------------------------------------------------------------
/tailwind.config.ts:
--------------------------------------------------------------------------------
1 | import type { Config } from "tailwindcss";
2 | import { withUt } from "uploadthing/tw";
3 |
4 | const config: Config = {
5 |
6 | darkMode: ["class"],
7 | content: [
8 | "./pages/**/*.{js,ts,jsx,tsx,mdx}",
9 | "./components/**/*.{js,ts,jsx,tsx,mdx}",
10 | "./app/**/*.{js,ts,jsx,tsx,mdx}",
11 | ],
12 | theme: {
13 | extend: {
14 | colors: {
15 | background: 'hsl(var(--background))',
16 | foreground: 'hsl(var(--foreground))',
17 | card: {
18 | DEFAULT: 'hsl(var(--card))',
19 | foreground: 'hsl(var(--card-foreground))'
20 | },
21 | popover: {
22 | DEFAULT: 'hsl(var(--popover))',
23 | foreground: 'hsl(var(--popover-foreground))'
24 | },
25 | primary: {
26 | DEFAULT: 'hsl(var(--primary))',
27 | foreground: 'hsl(var(--primary-foreground))'
28 | },
29 | secondary: {
30 | DEFAULT: 'hsl(var(--secondary))',
31 | foreground: 'hsl(var(--secondary-foreground))'
32 | },
33 | muted: {
34 | DEFAULT: 'hsl(var(--muted))',
35 | foreground: 'hsl(var(--muted-foreground))'
36 | },
37 | accent: {
38 | DEFAULT: 'hsl(var(--accent))',
39 | foreground: 'hsl(var(--accent-foreground))'
40 | },
41 | destructive: {
42 | DEFAULT: 'hsl(var(--destructive))',
43 | foreground: 'hsl(var(--destructive-foreground))'
44 | },
45 | border: 'hsl(var(--border))',
46 | input: 'hsl(var(--input))',
47 | ring: 'hsl(var(--ring))',
48 | chart: {
49 | '1': 'hsl(var(--chart-1))',
50 | '2': 'hsl(var(--chart-2))',
51 | '3': 'hsl(var(--chart-3))',
52 | '4': 'hsl(var(--chart-4))',
53 | '5': 'hsl(var(--chart-5))'
54 | }
55 | },
56 | borderRadius: {
57 | lg: 'var(--radius)',
58 | md: 'calc(var(--radius) - 2px)',
59 | sm: 'calc(var(--radius) - 4px)'
60 | },
61 | animation: {
62 | spotlight: 'spotlight 2s ease .75s 1 forwards',
63 | 'border-beam': 'border-beam calc(var(--duration)*1s) infinite linear',
64 | gradient: 'gradient 8s linear infinite',
65 | 'shiny-text': 'shiny-text 8s infinite'
66 | },
67 | keyframes: {
68 | spotlight: {
69 | '0%': {
70 | opacity: '0',
71 | transform: 'translate(-72%, -62%) scale(0.5)'
72 | },
73 | '100%': {
74 | opacity: '1',
75 | transform: 'translate(-50%, -40%) scale(1)'
76 | }
77 | },
78 | 'border-beam': {
79 | '100%': {
80 | 'offset-distance': '100%'
81 | }
82 | },
83 | gradient: {
84 | to: {
85 | backgroundPosition: 'var(--bg-size) 0'
86 | }
87 | },
88 | 'shiny-text': {
89 | '0%, 90%, 100%': {
90 | 'background-position': 'calc(-100% - var(--shiny-width)) 0'
91 | },
92 | '30%, 60%': {
93 | 'background-position': 'calc(100% + var(--shiny-width)) 0'
94 | }
95 | }
96 | }
97 | }
98 | },
99 | plugins: [require("tailwindcss-animate")],
100 | };
101 |
102 | export default withUt(config);
--------------------------------------------------------------------------------
/components/ui/flip-words.tsx:
--------------------------------------------------------------------------------
1 | "use client";
2 | import React, { useCallback, useEffect, useState } from "react";
3 | import { AnimatePresence, motion } from "framer-motion";
4 | import { cn } from "@/lib/utils";
5 |
6 | export const FlipWords = ({
7 | words,
8 | duration = 3000,
9 | className,
10 | }: {
11 | words: string[];
12 | duration?: number;
13 | className?: string;
14 | }) => {
15 | const [currentWord, setCurrentWord] = useState(words[0]);
16 | const [isAnimating, setIsAnimating] = useState(false);
17 |
18 | // thanks for the fix Julian - https://github.com/Julian-AT
19 | const startAnimation = useCallback(() => {
20 | const word = words[words.indexOf(currentWord) + 1] || words[0];
21 | setCurrentWord(word);
22 | setIsAnimating(true);
23 | }, [currentWord, words]);
24 |
25 | useEffect(() => {
26 | if (!isAnimating)
27 | setTimeout(() => {
28 | startAnimation();
29 | }, duration);
30 | }, [isAnimating, duration, startAnimation]);
31 |
32 | return (
33 | {
35 | setIsAnimating(false);
36 | }}
37 | >
38 |
66 | {/* edit suggested by Sajal: https://x.com/DewanganSajal */}
67 | {currentWord.split(" ").map((word, wordIndex) => (
68 |
78 | {word.split("").map((letter, letterIndex) => (
79 |
89 | {letter}
90 |
91 | ))}
92 |
93 |
94 | ))}
95 |
96 |
97 | );
98 | };
99 |
--------------------------------------------------------------------------------
/components/ui/calendar.tsx:
--------------------------------------------------------------------------------
1 | "use client"
2 |
3 | import * as React from "react"
4 | import { ChevronLeftIcon, ChevronRightIcon } from "@radix-ui/react-icons"
5 | import { DayPicker } from "react-day-picker"
6 |
7 | import { cn } from "@/lib/utils"
8 | import { buttonVariants } from "@/components/ui/button"
9 |
10 | export type CalendarProps = React.ComponentProps
11 |
12 | function Calendar({
13 | className,
14 | classNames,
15 | showOutsideDays = true,
16 | ...props
17 | }: CalendarProps) {
18 | return (
19 | .day-range-end)]:rounded-r-md [&:has(>.day-range-start)]:rounded-l-md first:[&:has([aria-selected])]:rounded-l-md last:[&:has([aria-selected])]:rounded-r-md"
43 | : "[&:has([aria-selected])]:rounded-md"
44 | ),
45 | day: cn(
46 | buttonVariants({ variant: "ghost" }),
47 | "h-8 w-8 p-0 font-normal aria-selected:opacity-100"
48 | ),
49 | day_range_start: "day-range-start",
50 | day_range_end: "day-range-end",
51 | day_selected:
52 | "bg-primary text-primary-foreground hover:bg-primary hover:text-primary-foreground focus:bg-primary focus:text-primary-foreground",
53 | day_today: "bg-accent text-accent-foreground",
54 | day_outside:
55 | "day-outside text-muted-foreground opacity-50 aria-selected:bg-accent/50 aria-selected:text-muted-foreground aria-selected:opacity-30",
56 | day_disabled: "text-muted-foreground opacity-50",
57 | day_range_middle:
58 | "aria-selected:bg-accent aria-selected:text-accent-foreground",
59 | day_hidden: "invisible",
60 | ...classNames,
61 | }}
62 | components={{
63 | IconLeft: ({ ...props }) => ,
64 | IconRight: ({ ...props }) => ,
65 | }}
66 | {...props}
67 | />
68 | )
69 | }
70 | Calendar.displayName = "Calendar"
71 |
72 | export { Calendar }
73 |
--------------------------------------------------------------------------------
/app/components/landingPage/Tools.tsx:
--------------------------------------------------------------------------------
1 |
2 | import { tools } from './constants';
3 |
4 | import { LucideProps } from 'lucide-react';
5 | import AnimationContainer from "./animation-container";
6 | import AnimatedShinyText from '@/components/ui/animated-shiny-text';
7 |
8 | interface Props {
9 | tool: {
10 | id: number;
11 | name: string;
12 | info: string;
13 | icon: (props: LucideProps) => JSX.Element;
14 | }
15 | }
16 |
17 | const Tools = () => {
18 | return (
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 | JOIN OUR SHEDULING SOFTWARE!!
27 |
28 |
29 |
30 | Connect your tools
31 |
32 |
33 | Through integrations with tools like instagram, facebook and twitter, you can connect your social media accounts and post directly from your dashboard.
34 |
35 |
36 |
37 |
38 |
39 | {tools.map((tool, idx) => (
40 |
41 |
42 |
43 | ))}
44 |
45 |
46 |
47 | )
48 | };
49 |
50 | const Item = ({ tool }: Props) => {
51 | return (
52 |
53 |
54 |
55 |
56 |
57 |
58 | {tool.name}
59 |
60 |
61 | {tool.info}
62 |
63 |
64 | )
65 | };
66 |
67 | export default Tools
--------------------------------------------------------------------------------
/app/onboarding/page.tsx:
--------------------------------------------------------------------------------
1 | "use client";
2 |
3 | import {
4 | Card,
5 | CardContent,
6 | CardDescription,
7 | CardFooter,
8 | CardHeader,
9 | CardTitle,
10 | } from "@/components/ui/card";
11 | import { Input } from "@/components/ui/input";
12 | import { Label } from "@/components/ui/label";
13 | import React from "react";
14 | import { SubmitButton } from "../components/SubmitButton";
15 | import { useFormState } from "react-dom";
16 | import { parseWithZod } from "@conform-to/zod";
17 | import { onboardingSchemaLocale } from "../lib/zodSchemas";
18 | import { useForm } from "@conform-to/react";
19 | import { onboardingAction } from "../actions";
20 |
21 | const OnboardingPage = () => {
22 | const [lastResult, action] = useFormState(onboardingAction, undefined);
23 | const [form, fields] = useForm({
24 | // Sync the result of last submission
25 | lastResult,
26 |
27 | // Reuse the validation logic on the client
28 | onValidate({ formData }) {
29 | return parseWithZod(formData, { schema: onboardingSchemaLocale });
30 | },
31 |
32 | // Validate the form on blur event triggered
33 | shouldValidate: "onBlur",
34 | shouldRevalidate: "onInput",
35 | });
36 |
37 | return (
38 |
39 |
40 |
41 | Welcome to DayFlow.io
42 |
43 | We need the following information to set up your profile Quickly⚡️
44 |
45 |
46 |
47 |
82 |
83 |
84 | );
85 | };
86 |
87 | export default OnboardingPage;
88 |
--------------------------------------------------------------------------------
/prisma/schema.prisma:
--------------------------------------------------------------------------------
1 | // This is your Prisma schema file,// This is your Prisma schema file,// This is your Prisma schema file,// This is your Prisma schema file,
2 | // learn more about it in the docs: https://pris.ly/d/prisma-schema
3 |
4 | // Looking for ways to speed up your queries, or scale easily with your serverless or edge functions?
5 | // Try Prisma Accelerate: https://pris.ly/cli/accelerate-init
6 |
7 | generator client {
8 | provider = "prisma-client-js"
9 | }
10 |
11 | datasource db {
12 | provider = "postgresql"
13 | url = env("DATABASE_URL")
14 | directUrl = env("DIRECT_URL")
15 | }
16 |
17 | model User {
18 | id String @id @default(uuid())
19 | name String?
20 | email String @unique
21 | emailVerified DateTime?
22 | image String? @default("https://avatars.githubusercontent.com/u/10367109?v=4")
23 | accounts Account[]
24 | sessions Session[]
25 | grantId String?
26 | grantEmail String?
27 | username String? @unique
28 | createdAt DateTime @default(now())
29 | updatedAt DateTime @updatedAt
30 | Availability Availability[]
31 | EventType EventType[]
32 | }
33 |
34 | model Account {
35 | userId String
36 | type String
37 | provider String
38 | providerAccountId String
39 | refresh_token String?
40 | access_token String?
41 | expires_at Int?
42 | token_type String?
43 | scope String?
44 | id_token String?
45 | session_state String?
46 |
47 | createdAt DateTime @default(now())
48 | updatedAt DateTime @updatedAt
49 |
50 | user User @relation(fields: [userId], references: [id], onDelete: Cascade)
51 |
52 | @@id([provider, providerAccountId])
53 | }
54 |
55 | model Session {
56 | sessionToken String @unique
57 | userId String
58 | expires DateTime
59 | user User @relation(fields: [userId], references: [id], onDelete: Cascade)
60 |
61 | createdAt DateTime @default(now())
62 | updatedAt DateTime @updatedAt
63 | }
64 |
65 | model VerificationToken {
66 | identifier String
67 | token String
68 | expires DateTime
69 |
70 | @@id([identifier, token])
71 | }
72 |
73 | model Availability {
74 | id String @id @default(uuid())
75 |
76 | day Day
77 | fromTime String // e.g., '08:00'
78 | tillTime String // e.g., '18:00'
79 | isActive Boolean @default(true) // Toggle availability for the day
80 |
81 | User User @relation(fields: [userId], references: [id], onDelete: Cascade)
82 | userId String
83 |
84 | createdAt DateTime @default(now())
85 | updatedAt DateTime @updatedAt
86 | }
87 |
88 | enum Day {
89 | Monday
90 | Tuesday
91 | Wednesday
92 | Thursday
93 | Friday
94 | Saturday
95 | Sunday
96 | }
97 |
98 | model EventType {
99 | id String @id @default(uuid())
100 | title String
101 | duration Int
102 | url String
103 | description String
104 | active Boolean @default(true)
105 | videoCallSoftware String @default("Google Meet")
106 |
107 | user User @relation(fields: [userId], references: [id], onDelete: Cascade)
108 | userId String
109 |
110 | createdAt DateTime @default(now())
111 | }
112 |
--------------------------------------------------------------------------------
/components/ui/card-hover-effect.tsx:
--------------------------------------------------------------------------------
1 | "use client"
2 |
3 | import { AnimatePresence, motion } from "framer-motion";
4 |
5 | import Link from "next/link";
6 | import { cn } from "@/lib/utils";
7 | import { useState } from "react";
8 |
9 | export const HoverEffect = ({
10 | items,
11 | className,
12 | }: {
13 | items: {
14 | title: string;
15 | description: string;
16 | link: string;
17 | }[];
18 | className?: string;
19 | }) => {
20 | const [hoveredIndex, setHoveredIndex] = useState(null);
21 |
22 | return (
23 |
29 | {items.map((item, idx) => (
30 |
setHoveredIndex(idx)}
35 | onMouseLeave={() => setHoveredIndex(null)}
36 | >
37 |
38 | {hoveredIndex === idx && (
39 |
52 | )}
53 |
54 |
55 | {item.title}
56 | {item.description}
57 |
58 |
59 | ))}
60 |
61 | );
62 | };
63 |
64 | export const Card = ({
65 | className,
66 | children,
67 | }: {
68 | className?: string;
69 | children: React.ReactNode;
70 | }) => {
71 | return (
72 |
82 | );
83 | };
84 | export const CardTitle = ({
85 | className,
86 | children,
87 | }: {
88 | className?: string;
89 | children: React.ReactNode;
90 | }) => {
91 | return (
92 |
93 | {children}
94 |
95 | );
96 | };
97 | export const CardDescription = ({
98 | className,
99 | children,
100 | }: {
101 | className?: string;
102 | children: React.ReactNode;
103 | }) => {
104 | return (
105 |
111 | {children}
112 |
113 | );
114 | };
--------------------------------------------------------------------------------
/public/nextjs-logo.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/app/dashboard/availability/page.tsx:
--------------------------------------------------------------------------------
1 | import { SubmitButton } from "@/app/components/SubmitButton";
2 | import prisma from "@/app/lib/db";
3 | import { times } from "@/app/lib/times";
4 | import {
5 | Card,
6 | CardContent,
7 | CardDescription,
8 | CardFooter,
9 | CardHeader,
10 | CardTitle,
11 | } from "@/components/ui/card";
12 | import {
13 | Select,
14 | SelectContent,
15 | SelectGroup,
16 | SelectItem,
17 | SelectTrigger,
18 | SelectValue,
19 | } from "@/components/ui/select";
20 | import { Switch } from "@/components/ui/switch";
21 | import { notFound } from "next/navigation";
22 | import React from "react";
23 | import { requireUser } from "@/app/lib/hooks";
24 | import { updateAvailabilityAction } from "@/app/actions";
25 |
26 | async function getData(userId: string) {
27 | const data = await prisma.availability.findMany({
28 | where: {
29 | userId: userId,
30 | },
31 | });
32 |
33 | if (!data) {
34 | return notFound();
35 | }
36 |
37 | return data;
38 | }
39 |
40 | const AvailabilityPage = async () => {
41 | const session = await requireUser();
42 | const data = await getData(session.user?.id as string);
43 |
44 | return (
45 |
46 |
47 | Availability
48 |
49 | In this section you can manage your availability.
50 |
51 |
52 |
102 |
103 | );
104 | };
105 |
106 | export default AvailabilityPage;
107 |
--------------------------------------------------------------------------------
/app/components/landingPage/offerings.tsx:
--------------------------------------------------------------------------------
1 | "use client";
2 |
3 | import { offerings } from './constants';
4 | import { LifeBuoy, LucideIcon } from 'lucide-react';
5 | import { Badge } from '@/components/ui/badge';
6 | import AnimationContainer from "./animation-container";
7 |
8 | import { motion } from 'framer-motion';
9 |
10 | interface Props {
11 | title: string;
12 | description: string;
13 | icon: LucideIcon;
14 | }
15 |
16 | const Offerings = () => {
17 | return (
18 |
19 | {/* Background Shapes */}
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 | Everything on track
29 |
30 |
31 |
32 | Thousand ways to
33 | manage your business
34 |
35 |
36 | Keep your business on track with our innovative offerings to help you get the most out of your experience.
37 |
38 |
42 |
43 |
44 |
45 |
46 | {offerings.map((offering, index) => (
47 |
48 |
49 |
50 | ))}
51 |
52 |
53 | );
54 | };
55 | const Offering = ({ title, description, icon: Icon }: Props) => {
56 | return (
57 |
62 |
63 |
64 |
65 |
66 | {title}
67 |
68 |
69 | {description}
70 |
71 |
72 | );
73 | };
74 |
75 | export default Offerings;
76 |
--------------------------------------------------------------------------------
/app/lib/zodSchemas.ts:
--------------------------------------------------------------------------------
1 | import { z } from "zod";
2 | import { conformZodMessage } from "@conform-to/zod";
3 |
4 | export function onboardingSchema(options?: {
5 | isUsernameUnique: () => Promise;
6 | }) {
7 | return z.object({
8 | username: z
9 | .string()
10 | .min(3)
11 | .max(150)
12 | .regex(/^[a-zA-Z0-9-]+$/, {
13 | message: "Username must contain only letters, numbers, and hyphens",
14 | })
15 | // Pipe the schema so it runs only if the email is valid
16 | .pipe(
17 | // Note: The callback cannot be async here
18 | // As we run zod validation synchronously on the client
19 | z.string().superRefine((_, ctx) => {
20 | // This makes Conform to fallback to server validation
21 | // by indicating that the validation is not defined
22 | if (typeof options?.isUsernameUnique !== "function") {
23 | ctx.addIssue({
24 | code: "custom",
25 | message: conformZodMessage.VALIDATION_UNDEFINED,
26 | fatal: true,
27 | });
28 | return;
29 | }
30 |
31 | // If it reaches here, then it must be validating on the server
32 | // Return the result as a promise so Zod knows it's async instead
33 | return options.isUsernameUnique().then((isUnique) => {
34 | if (!isUnique) {
35 | ctx.addIssue({
36 | code: "custom",
37 | message: "Username is already used",
38 | });
39 | }
40 | });
41 | })
42 | ),
43 | fullName: z.string().min(3).max(150),
44 | });
45 | }
46 |
47 | export const onboardingSchemaLocale = z.object({
48 | username: z
49 | .string()
50 | .min(3)
51 | .max(150)
52 | .regex(/^[a-zA-Z0-9-]+$/, {
53 | message: "Username must contain only letters, numbers, and hyphens",
54 | }),
55 | fullName: z.string().min(3).max(150),
56 | });
57 |
58 | export const aboutSettingsSchema = z.object({
59 | fullName: z.string().min(3).max(150),
60 |
61 | profileImage: z.string(),
62 | });
63 |
64 | export const eventTypeSchema = z.object({
65 | title: z.string().min(3).max(150),
66 | duration: z.number().min(1).max(100),
67 | url: z.string().min(3).max(150),
68 | description: z.string().min(3).max(300),
69 | videoCallSoftware: z.string(),
70 | });
71 |
72 | export function EventTypeServerSchema(options?: {
73 | isUrlUnique: () => Promise;
74 | }) {
75 | return z.object({
76 | url: z
77 | .string()
78 | .min(3)
79 | .max(150)
80 | .pipe(
81 | // Note: The callback cannot be async here
82 | // As we run zod validation synchronously on the client
83 | z.string().superRefine((_, ctx) => {
84 | // This makes Conform to fallback to server validation
85 | // by indicating that the validation is not defined
86 | if (typeof options?.isUrlUnique !== "function") {
87 | ctx.addIssue({
88 | code: "custom",
89 | message: conformZodMessage.VALIDATION_UNDEFINED,
90 | fatal: true,
91 | });
92 | return;
93 | }
94 |
95 | // If it reaches here, then it must be validating on the server
96 | // Return the result as a promise so Zod knows it's async instead
97 | return options.isUrlUnique().then((isUnique) => {
98 | if (!isUnique) {
99 | ctx.addIssue({
100 | code: "custom",
101 | message: "Url is already used",
102 | });
103 | }
104 | });
105 | })
106 | ),
107 | title: z.string().min(3).max(150),
108 | duration: z.number().min(1).max(100),
109 | description: z.string().min(3).max(300),
110 | videoCallSoftware: z.string(),
111 | });
112 | }
113 |
--------------------------------------------------------------------------------
/app/components/landingPage/Stats.tsx:
--------------------------------------------------------------------------------
1 | "use client";
2 |
3 | import { motion } from "framer-motion";
4 | import NumberTicker from '@/components/ui/number-ticker';
5 | import React from 'react';
6 |
7 | // Animation for NumberTicker to provide ultra-smooth transitions
8 | const numberAnimation = {
9 | initial: { opacity: 0, y: 50 },
10 | animate: {
11 | opacity: 1,
12 | y: 0,
13 | transition: {
14 | type: "spring",
15 | stiffness: 150,
16 | damping: 15,
17 | mass: 0.75,
18 | duration: 2, // Smooth duration to slow down number appearance
19 | delay: 1, // Delay to ensure number generation finishes before the rest
20 | },
21 | },
22 | };
23 |
24 | // Animation for container with fade-in and fade-out applied after number generation
25 | const containerAnimation = {
26 | hidden: { opacity: 0 },
27 | visible: {
28 | opacity: 1,
29 | transition: {
30 | delayChildren: 2.5, // Applies after numbers generate
31 | staggerChildren: 0.5, // Smooth stagger between elements
32 | ease: "easeInOut",
33 | },
34 | },
35 | };
36 |
37 | // Fade-out animation to trigger after a delay
38 | const fadeOutAnimation = {
39 | initial: { opacity: 1 },
40 | animate: {
41 | opacity: 0,
42 | transition: {
43 | delay: 4, // Wait before applying fade-out
44 | duration: 1.5, // Smooth fade-out duration
45 | ease: "easeInOut",
46 | },
47 | },
48 | };
49 |
50 | const Stats: React.FC = () => {
51 | return (
52 | < div className="min-h-52 bg-transparent mt-40">
53 |
59 | {/* Active Users */}
60 |
61 |
65 | Over 10k active users
66 |
67 |
68 |
72 |
73 |
74 |
75 | {/* Paying Customers */}
76 |
77 |
81 | 2k+ Happy Paying Customers
82 |
83 |
84 |
88 |
89 |
90 |
91 | {/* Agencies Joined */}
92 |
93 |
97 | Over 500 agencies joined us 🎉
98 |
99 |
100 |
104 |
105 |
106 |
107 |
108 | );
109 | };
110 |
111 | export default Stats;
112 |
--------------------------------------------------------------------------------
/components/ui/dialog.tsx:
--------------------------------------------------------------------------------
1 | "use client"
2 |
3 | import * as React from "react"
4 | import * as DialogPrimitive from "@radix-ui/react-dialog"
5 | import { Cross2Icon } from "@radix-ui/react-icons"
6 |
7 | import { cn } from "@/lib/utils"
8 |
9 | const Dialog = DialogPrimitive.Root
10 |
11 | const DialogTrigger = DialogPrimitive.Trigger
12 |
13 | const DialogPortal = DialogPrimitive.Portal
14 |
15 | const DialogClose = DialogPrimitive.Close
16 |
17 | const DialogOverlay = React.forwardRef<
18 | React.ElementRef,
19 | React.ComponentPropsWithoutRef
20 | >(({ className, ...props }, ref) => (
21 |
29 | ))
30 | DialogOverlay.displayName = DialogPrimitive.Overlay.displayName
31 |
32 | const DialogContent = React.forwardRef<
33 | React.ElementRef,
34 | React.ComponentPropsWithoutRef
35 | >(({ className, children, ...props }, ref) => (
36 |
37 |
38 |
46 | {children}
47 |
48 |
49 | Close
50 |
51 |
52 |
53 | ))
54 | DialogContent.displayName = DialogPrimitive.Content.displayName
55 |
56 | const DialogHeader = ({
57 | className,
58 | ...props
59 | }: React.HTMLAttributes) => (
60 |
67 | )
68 | DialogHeader.displayName = "DialogHeader"
69 |
70 | const DialogFooter = ({
71 | className,
72 | ...props
73 | }: React.HTMLAttributes) => (
74 |
81 | )
82 | DialogFooter.displayName = "DialogFooter"
83 |
84 | const DialogTitle = React.forwardRef<
85 | React.ElementRef,
86 | React.ComponentPropsWithoutRef
87 | >(({ className, ...props }, ref) => (
88 |
96 | ))
97 | DialogTitle.displayName = DialogPrimitive.Title.displayName
98 |
99 | const DialogDescription = React.forwardRef<
100 | React.ElementRef,
101 | React.ComponentPropsWithoutRef
102 | >(({ className, ...props }, ref) => (
103 |
108 | ))
109 | DialogDescription.displayName = DialogPrimitive.Description.displayName
110 |
111 | export {
112 | Dialog,
113 | DialogPortal,
114 | DialogOverlay,
115 | DialogTrigger,
116 | DialogClose,
117 | DialogContent,
118 | DialogHeader,
119 | DialogFooter,
120 | DialogTitle,
121 | DialogDescription,
122 | }
123 |
--------------------------------------------------------------------------------
/app/dashboard/meetings/page.tsx:
--------------------------------------------------------------------------------
1 | import { cancelMeetingAction } from "@/app/actions";
2 | import { EmptyState } from "@/app/components/dashboard/EmptyState";
3 | import { SubmitButton } from "@/app/components/SubmitButton";
4 | import { auth } from "@/app/lib/auth";
5 | import { nylas } from "@/app/lib/nylas";
6 |
7 | import {
8 | Card,
9 | CardContent,
10 | CardDescription,
11 | CardHeader,
12 | CardTitle,
13 | } from "@/components/ui/card";
14 | import { Separator } from "@/components/ui/separator";
15 | import prisma from "@/lib/prisma";
16 | import { format } from "date-fns";
17 | import { Video } from "lucide-react";
18 |
19 | import React from "react";
20 |
21 | // Define types for the event data
22 | interface EventData {
23 | id: string;
24 | when: {
25 | start_time: number;
26 | end_time: number;
27 | };
28 | title: string;
29 | participants: Array<{ name: string }>;
30 | conferencing: {
31 | url: string;
32 | };
33 | }
34 |
35 | async function getData(userId: string): Promise<{ data: EventData[] }> {
36 | const userData = await prisma.user.findUnique({
37 | where: {
38 | id: userId,
39 | },
40 | select: {
41 | grantId: true,
42 | grantEmail: true,
43 | },
44 | });
45 |
46 | if (!userData) {
47 | throw new Error("User not found");
48 | }
49 | const data = await nylas.events.list({
50 | identifier: userData?.grantId as string,
51 | queryParams: {
52 | calendarId: userData?.grantEmail as string,
53 | },
54 | });
55 |
56 | return data as unknown as { data: EventData[] };
57 | }
58 |
59 | const MeetingsPage = async () => {
60 | const session = await auth();
61 | const data = await getData(session?.user?.id as string);
62 |
63 | return (
64 | <>
65 | {data.data.length < 1 ? (
66 |
72 | ) : (
73 |
74 |
75 | Bookings
76 |
77 | See upcoming and past events booked through your event type links.
78 |
79 |
80 |
81 | {data.data.map((item) => (
82 |
118 | ))}
119 |
120 |
121 | )}
122 | >
123 | );
124 | };
125 |
126 | export default MeetingsPage;
--------------------------------------------------------------------------------
/components/ui/lamp.tsx:
--------------------------------------------------------------------------------
1 | "use client";
2 |
3 | import React from "react";
4 | import { cn } from "@/lib/utils";
5 | import { motion } from "framer-motion";
6 |
7 | export function LampDemo() {
8 | return (
9 |
10 |
20 | Build lamps the right way
21 |
22 |
23 | );
24 | }
25 |
26 | export const LampContainer = ({
27 | children,
28 | className,
29 | }: {
30 | children: React.ReactNode;
31 | className?: string;
32 | }) => {
33 | return (
34 |
40 |
41 |
54 |
55 |
56 |
57 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
86 |
96 |
97 |
98 |
99 |
100 |
101 | {children}
102 |
103 |
104 | );
105 | };
--------------------------------------------------------------------------------
/app/components/dashboard/settingsForm.tsx:
--------------------------------------------------------------------------------
1 | "use client";
2 |
3 | import { useState } from "react";
4 | import { SettingsAction } from "@/app/actions";
5 | import { aboutSettingsSchema } from "@/app/lib/zodSchemas";
6 | import {
7 | Card,
8 | CardContent,
9 | CardDescription,
10 | CardFooter,
11 | CardHeader,
12 | CardTitle,
13 | } from "@/components/ui/card";
14 | import { Input } from "@/components/ui/input";
15 | import { Label } from "@/components/ui/label";
16 | import { useForm } from "@conform-to/react";
17 | import { parseWithZod } from "@conform-to/zod";
18 | import { useFormState } from "react-dom";
19 | import { SubmitButton } from "../SubmitButton";
20 | import { UploadDropzone } from "@/app/lib/uploadthing";
21 | import Image from "next/image";
22 | import { X } from "lucide-react";
23 | import { Button } from "@/components/ui/button";
24 | import { toast } from "sonner";
25 |
26 | interface iAppProps {
27 | fullName: string;
28 | email: string;
29 |
30 | profileImage: string;
31 | }
32 |
33 | export function SettingsForm({ fullName, email, profileImage }: iAppProps) {
34 | const [lastResult, action] = useFormState(SettingsAction, undefined);
35 | const [currentProfileImage, setCurrentProfileImage] = useState(profileImage);
36 |
37 | const [form, fields] = useForm({
38 | // Sync the result of last submission
39 | lastResult,
40 |
41 | // Reuse the validation logic on the client
42 | onValidate({ formData }) {
43 | return parseWithZod(formData, { schema: aboutSettingsSchema });
44 | },
45 |
46 | // Validate the form on blur event triggered
47 | shouldValidate: "onBlur",
48 | shouldRevalidate: "onInput",
49 | });
50 |
51 | const handleDeleteImage = () => {
52 | setCurrentProfileImage("");
53 | };
54 |
55 | return (
56 |
57 |
58 | Settings
59 | Manage your account settings.
60 |
61 |
127 |
128 | );
129 | }
130 |
--------------------------------------------------------------------------------
/components/ui/sheet.tsx:
--------------------------------------------------------------------------------
1 | "use client"
2 |
3 | import * as React from "react"
4 | import * as SheetPrimitive from "@radix-ui/react-dialog"
5 | import { Cross2Icon } from "@radix-ui/react-icons"
6 | import { cva, type VariantProps } from "class-variance-authority"
7 |
8 | import { cn } from "@/lib/utils"
9 |
10 | const Sheet = SheetPrimitive.Root
11 |
12 | const SheetTrigger = SheetPrimitive.Trigger
13 |
14 | const SheetClose = SheetPrimitive.Close
15 |
16 | const SheetPortal = SheetPrimitive.Portal
17 |
18 | const SheetOverlay = React.forwardRef<
19 | React.ElementRef,
20 | React.ComponentPropsWithoutRef
21 | >(({ className, ...props }, ref) => (
22 |
30 | ))
31 | SheetOverlay.displayName = SheetPrimitive.Overlay.displayName
32 |
33 | const sheetVariants = cva(
34 | "fixed z-50 gap-4 bg-background p-6 shadow-lg transition ease-in-out data-[state=closed]:duration-300 data-[state=open]:duration-500 data-[state=open]:animate-in data-[state=closed]:animate-out",
35 | {
36 | variants: {
37 | side: {
38 | top: "inset-x-0 top-0 border-b data-[state=closed]:slide-out-to-top data-[state=open]:slide-in-from-top",
39 | bottom:
40 | "inset-x-0 bottom-0 border-t data-[state=closed]:slide-out-to-bottom data-[state=open]:slide-in-from-bottom",
41 | left: "inset-y-0 left-0 h-full w-3/4 border-r data-[state=closed]:slide-out-to-left data-[state=open]:slide-in-from-left sm:max-w-sm",
42 | right:
43 | "inset-y-0 right-0 h-full w-3/4 border-l data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right sm:max-w-sm",
44 | },
45 | },
46 | defaultVariants: {
47 | side: "right",
48 | },
49 | }
50 | )
51 |
52 | interface SheetContentProps
53 | extends React.ComponentPropsWithoutRef,
54 | VariantProps {}
55 |
56 | const SheetContent = React.forwardRef<
57 | React.ElementRef,
58 | SheetContentProps
59 | >(({ side = "right", className, children, ...props }, ref) => (
60 |
61 |
62 |
67 |
68 |
69 | Close
70 |
71 | {children}
72 |
73 |
74 | ))
75 | SheetContent.displayName = SheetPrimitive.Content.displayName
76 |
77 | const SheetHeader = ({
78 | className,
79 | ...props
80 | }: React.HTMLAttributes) => (
81 |
88 | )
89 | SheetHeader.displayName = "SheetHeader"
90 |
91 | const SheetFooter = ({
92 | className,
93 | ...props
94 | }: React.HTMLAttributes) => (
95 |
102 | )
103 | SheetFooter.displayName = "SheetFooter"
104 |
105 | const SheetTitle = React.forwardRef<
106 | React.ElementRef,
107 | React.ComponentPropsWithoutRef
108 | >(({ className, ...props }, ref) => (
109 |
114 | ))
115 | SheetTitle.displayName = SheetPrimitive.Title.displayName
116 |
117 | const SheetDescription = React.forwardRef<
118 | React.ElementRef,
119 | React.ComponentPropsWithoutRef
120 | >(({ className, ...props }, ref) => (
121 |
126 | ))
127 | SheetDescription.displayName = SheetPrimitive.Description.displayName
128 |
129 | export {
130 | Sheet,
131 | SheetPortal,
132 | SheetOverlay,
133 | SheetTrigger,
134 | SheetClose,
135 | SheetContent,
136 | SheetHeader,
137 | SheetFooter,
138 | SheetTitle,
139 | SheetDescription,
140 | }
141 |
--------------------------------------------------------------------------------
/app/dashboard/layout.tsx:
--------------------------------------------------------------------------------
1 | /* eslint-disable @typescript-eslint/no-unused-vars */
2 | import Link from "next/link";
3 | import { Menu } from "lucide-react";
4 |
5 | import { Button } from "@/components/ui/button";
6 |
7 | import {
8 | DropdownMenu,
9 | DropdownMenuContent,
10 | DropdownMenuItem,
11 | DropdownMenuLabel,
12 | DropdownMenuSeparator,
13 | DropdownMenuTrigger,
14 | } from "@/components/ui/dropdown-menu";
15 | import { Sheet, SheetContent, SheetTrigger } from "@/components/ui/sheet";
16 | import { ReactNode } from "react";
17 | import { requireUser } from "../lib/hooks";
18 | import prisma from "../lib/db";
19 | import { redirect } from "next/navigation";
20 | import Logo from "@/public/logo.png";
21 | import Image from "next/image";
22 | import { DasboardLinks } from "../components/dashboard/DasboardLinks";
23 | import { ThemeToggle } from "../components/dashboard/ThemeToggle";
24 | import { Toaster } from "@/components/ui/sonner";
25 | import { auth, signOut } from "../lib/auth";
26 | import React from "react";
27 |
28 | async function getData(id: string) {
29 | const data = await prisma.user.findUnique({
30 | where: {
31 | id: id,
32 | },
33 | select: {
34 | username: true,
35 | grantId: true,
36 | },
37 | });
38 |
39 | if (!data?.username) {
40 | return redirect("/onboarding");
41 | }
42 |
43 | if (!data.grantId) {
44 | return redirect("/onboarding/grant-id");
45 | }
46 |
47 | return data;
48 | }
49 |
50 | export default async function Dashboard({ children }: { children: ReactNode }) {
51 | const session = await auth();
52 |
53 | if (!session?.user) {
54 | return redirect("/");
55 | }
56 |
57 | const data = await getData(session.user.id as string);
58 |
59 | return (
60 | <>
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 | Dayflow.io
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
139 |
140 | {children}
141 |
142 |
143 |
144 |
145 | >
146 | );
147 | }
148 |
--------------------------------------------------------------------------------
/public/supabase.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------