├── bun.lockb ├── src ├── app │ ├── favicon.ico │ ├── fonts │ │ ├── GeistVF.woff │ │ └── GeistMonoVF.woff │ ├── api │ │ └── auth │ │ │ └── [...nextauth] │ │ │ └── route.ts │ ├── actions │ │ ├── user.ts │ │ └── task.ts │ ├── globals.css │ ├── layout.tsx │ ├── page.tsx │ ├── dashboard │ │ └── page.tsx │ └── (auth) │ │ └── getstarted │ │ └── page.tsx ├── utils │ └── tokenUtils.ts ├── types │ ├── api.types.ts │ └── index.ts ├── components │ ├── Section-wrapper.tsx │ ├── ui │ │ ├── skeleton.tsx │ │ ├── label.tsx │ │ ├── input.tsx │ │ ├── toaster.tsx │ │ ├── switch.tsx │ │ ├── badge.tsx │ │ ├── tooltip.tsx │ │ ├── Spotlight.tsx │ │ ├── scroll-area.tsx │ │ ├── grid-pattern.tsx │ │ ├── animated-list.tsx │ │ ├── button.tsx │ │ ├── magic-card.tsx │ │ ├── card.tsx │ │ ├── RotatingIcons.tsx │ │ ├── HoverBorderGradient.tsx │ │ ├── dialog.tsx │ │ ├── sheet.tsx │ │ ├── form.tsx │ │ ├── toast.tsx │ │ ├── flickering-grid.tsx │ │ ├── dropdown-menu.tsx │ │ └── chart.tsx │ ├── theme-provider.tsx │ ├── SessionProvider.tsx │ ├── Footer.tsx │ ├── wrappers │ │ └── sheetWrapper.tsx │ ├── Cta.tsx │ ├── Navlogin.tsx │ ├── TaskContainer.tsx │ ├── Features.tsx │ ├── AnimateNoti.tsx │ ├── Hero.tsx │ ├── forms │ │ └── addTask.tsx │ ├── Navbar.tsx │ └── cards │ │ └── Task.tsx ├── constants │ └── constants.tsx ├── lib │ ├── async-wrapper.ts │ ├── success.ts │ ├── error.ts │ ├── auth.ts │ └── utils.ts ├── middleware.ts ├── config │ └── error.config.ts └── hooks │ └── use-toast.ts ├── public ├── images │ └── landing-hero.jpeg └── assets │ ├── discord.svg │ └── gmail.svg ├── postcss.config.mjs ├── .eslintrc.json ├── next.config.mjs ├── components.json ├── .gitignore ├── tsconfig.json ├── package.json ├── README.md └── tailwind.config.ts /bun.lockb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VineeTagarwaL-code/upbot/HEAD/bun.lockb -------------------------------------------------------------------------------- /src/app/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VineeTagarwaL-code/upbot/HEAD/src/app/favicon.ico -------------------------------------------------------------------------------- /src/app/fonts/GeistVF.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VineeTagarwaL-code/upbot/HEAD/src/app/fonts/GeistVF.woff -------------------------------------------------------------------------------- /public/images/landing-hero.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VineeTagarwaL-code/upbot/HEAD/public/images/landing-hero.jpeg -------------------------------------------------------------------------------- /src/app/fonts/GeistMonoVF.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VineeTagarwaL-code/upbot/HEAD/src/app/fonts/GeistMonoVF.woff -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /src/utils/tokenUtils.ts: -------------------------------------------------------------------------------- 1 | import crypto from "crypto"; 2 | 3 | export function hashToken(token: string) { 4 | return crypto.createHash("sha256").update(token).digest("hex"); 5 | } 6 | -------------------------------------------------------------------------------- /src/app/api/auth/[...nextauth]/route.ts: -------------------------------------------------------------------------------- 1 | import NextAuth from "next-auth"; 2 | import { authOptions } from "@/lib/auth"; 3 | const handler = NextAuth(authOptions); 4 | 5 | export { handler as GET, handler as POST }; 6 | -------------------------------------------------------------------------------- /src/types/api.types.ts: -------------------------------------------------------------------------------- 1 | import { ErrorResponseType } from "@/lib/error"; 2 | import { SuccessResponseType } from "@/lib/success"; 3 | 4 | export type ServerActionReturnType = 5 | | SuccessResponseType 6 | | ErrorResponseType; 7 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["next/core-web-vitals", "next/typescript"], 3 | "rules":{ 4 | "@typescript-eslint/no-explicit-any": "off", 5 | "@typescript-eslint/no-empty-object-type":"off", 6 | "@typescript-eslint/no-unused-vars":"off", 7 | "@typescript-eslint/ts-ignore":"0" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/app/actions/user.ts: -------------------------------------------------------------------------------- 1 | "use server"; 2 | import { authOptions } from "@/lib/auth"; 3 | import { getServerSession } from "next-auth"; 4 | async function getUser() { 5 | const session = await getServerSession(authOptions); 6 | if (session) { 7 | return session; 8 | } 9 | return null; 10 | } 11 | export { getUser }; 12 | -------------------------------------------------------------------------------- /next.config.mjs: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = { 3 | images: { 4 | remotePatterns: [ 5 | { 6 | protocol: "https", 7 | hostname: "lh3.googleusercontent.com", // Change this to your CDN domain 8 | }, 9 | ], 10 | }, 11 | }; 12 | 13 | export default nextConfig; 14 | -------------------------------------------------------------------------------- /src/components/Section-wrapper.tsx: -------------------------------------------------------------------------------- 1 | import { cn } from "@/lib/utils"; 2 | export const SectionWrapper = ({ 3 | children, 4 | className, 5 | }: { 6 | children: React.ReactNode; 7 | className?: string; 8 | }) => { 9 | return ( 10 |
{children}
11 | ); 12 | }; 13 | -------------------------------------------------------------------------------- /src/components/ui/skeleton.tsx: -------------------------------------------------------------------------------- 1 | import { cn } from "@/lib/utils" 2 | 3 | function Skeleton({ 4 | className, 5 | ...props 6 | }: React.HTMLAttributes) { 7 | return ( 8 |
12 | ) 13 | } 14 | 15 | export { Skeleton } 16 | -------------------------------------------------------------------------------- /src/components/theme-provider.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import * as React from "react"; 4 | import { ThemeProvider as NextThemesProvider } from "next-themes"; 5 | import { type ThemeProviderProps } from "next-themes/dist/types"; 6 | 7 | export function ThemeProvider({ children, ...props }: ThemeProviderProps) { 8 | return {children}; 9 | } 10 | -------------------------------------------------------------------------------- /src/constants/constants.tsx: -------------------------------------------------------------------------------- 1 | type NavbarType = { 2 | link: string; 3 | title: string; 4 | }[]; 5 | export const NAVBAR: NavbarType = [ 6 | { 7 | link: "https://upbot.vineet.pro/", 8 | title: "Home", 9 | }, 10 | { 11 | link: "https://upbot.vineet.pro/#features", 12 | title: "Features", 13 | }, 14 | { 15 | link: "https://github.com/vineetagarwal-code/upbot", 16 | title: "Github", 17 | }, 18 | ]; 19 | -------------------------------------------------------------------------------- /src/types/index.ts: -------------------------------------------------------------------------------- 1 | type PingLog = { 2 | time: string; 3 | logResponse: string; 4 | isSuccess: boolean; 5 | timeTake: number; 6 | respCode: number; 7 | }; 8 | 9 | type PingTask = { 10 | ID: number; 11 | url: string; 12 | isActive: boolean; 13 | logs: PingLog[]; 14 | }; 15 | 16 | type TAxiosResponse = { 17 | message: string; 18 | additional: T; 19 | }; 20 | 21 | export type { PingLog, PingTask, TAxiosResponse }; 22 | -------------------------------------------------------------------------------- /components.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://ui.shadcn.com/schema.json", 3 | "style": "new-york", 4 | "rsc": true, 5 | "tsx": true, 6 | "tailwind": { 7 | "config": "tailwind.config.ts", 8 | "css": "src/app/globals.css", 9 | "baseColor": "neutral", 10 | "cssVariables": true, 11 | "prefix": "" 12 | }, 13 | "aliases": { 14 | "components": "@/components", 15 | "utils": "@/lib/utils", 16 | "ui": "@/components/ui", 17 | "lib": "@/lib", 18 | "hooks": "@/hooks" 19 | } 20 | } -------------------------------------------------------------------------------- /src/components/SessionProvider.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import { QueryClientProvider, QueryClient } from "@tanstack/react-query"; 4 | import { SessionProvider } from "next-auth/react"; 5 | import React from "react"; 6 | export default function Providers({ children }: { children: React.ReactNode }) { 7 | const [queryClient] = React.useState(() => new QueryClient()); 8 | return ( 9 | 10 | {children} 11 | 12 | ); 13 | } 14 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | .yarn/install-state.gz 8 | 9 | # testing 10 | /coverage 11 | 12 | # next.js 13 | /.next/ 14 | /out/ 15 | 16 | # production 17 | /build 18 | 19 | # misc 20 | .DS_Store 21 | *.pem 22 | 23 | # debug 24 | npm-debug.log* 25 | yarn-debug.log* 26 | yarn-error.log* 27 | 28 | # local env files 29 | .env*.local 30 | 31 | # vercel 32 | .vercel 33 | 34 | # typescript 35 | *.tsbuildinfo 36 | next-env.d.ts 37 | .env -------------------------------------------------------------------------------- /src/lib/async-wrapper.ts: -------------------------------------------------------------------------------- 1 | import { standardizeApiError } from "./error"; 2 | export type withServerActionAsyncCatcherType = (args?: T) => Promise; 3 | 4 | function withServerActionAsyncCatcher( 5 | serverAction: withServerActionAsyncCatcherType 6 | ): withServerActionAsyncCatcherType { 7 | return async (args?: T): Promise => { 8 | try { 9 | return await serverAction(args); 10 | } catch (error) { 11 | return standardizeApiError(error) as R; 12 | } 13 | }; 14 | } 15 | 16 | export { withServerActionAsyncCatcher }; 17 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "lib": ["dom", "dom.iterable", "esnext"], 4 | "allowJs": true, 5 | "skipLibCheck": true, 6 | "strict": true, 7 | "noEmit": true, 8 | "esModuleInterop": true, 9 | "module": "esnext", 10 | "moduleResolution": "bundler", 11 | "resolveJsonModule": true, 12 | "isolatedModules": true, 13 | "jsx": "preserve", 14 | "incremental": true, 15 | 16 | "plugins": [ 17 | { 18 | "name": "next" 19 | } 20 | ], 21 | "paths": { 22 | "@/*": ["./src/*"] 23 | } 24 | }, 25 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], 26 | "exclude": ["node_modules"] 27 | } 28 | -------------------------------------------------------------------------------- /public/assets/discord.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/lib/success.ts: -------------------------------------------------------------------------------- 1 | class SuccessResponse { 2 | status: true; 3 | code: number; 4 | additional?: T; 5 | message: string; 6 | constructor(message: string, code: number, additional?: T) { 7 | this.message = message; 8 | this.status = true; 9 | this.code = code; 10 | this.additional = additional; 11 | } 12 | serialize() { 13 | return { 14 | status: this.status, 15 | code: this.code, 16 | message: this.message, 17 | additional: this.additional as T, 18 | }; 19 | } 20 | } 21 | export type SuccessResponseType = { 22 | status: true; 23 | code: number; 24 | message: string; 25 | additional?: T; 26 | }; 27 | export { SuccessResponse }; 28 | -------------------------------------------------------------------------------- /src/middleware.ts: -------------------------------------------------------------------------------- 1 | import { NextResponse } from "next/server"; 2 | import type { NextRequest } from "next/server"; 3 | import { getToken } from "next-auth/jwt"; 4 | 5 | export async function middleware(req: NextRequest) { 6 | const session = await getToken({ req, secret: process.env.NEXTAUTH_SECRET }); 7 | 8 | const protectedRoute = "/dashboard"; 9 | const getstarted = "/getstarted"; 10 | if (req.nextUrl.pathname === getstarted && session) { 11 | return NextResponse.redirect(new URL(protectedRoute, req.url)); 12 | } 13 | if (req.nextUrl.pathname === protectedRoute && !session) { 14 | return NextResponse.redirect(new URL(getstarted, req.url)); 15 | } 16 | 17 | return NextResponse.next(); 18 | } 19 | 20 | export const config = { 21 | matcher: ["/dashboard", "/getstarted", "/"], 22 | }; 23 | -------------------------------------------------------------------------------- /src/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 | -------------------------------------------------------------------------------- /src/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 | -------------------------------------------------------------------------------- /src/components/ui/toaster.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import { useToast } from "@/hooks/use-toast"; 4 | import { 5 | Toast, 6 | ToastClose, 7 | ToastDescription, 8 | ToastProvider, 9 | ToastTitle, 10 | ToastViewport, 11 | } from "@/components/ui/toast"; 12 | 13 | export function Toaster() { 14 | const { toasts } = useToast(); 15 | 16 | return ( 17 | 18 | {toasts.map(function ({ id, title, description, action, ...props }) { 19 | return ( 20 | 21 |
22 | {title && {title}} 23 | {description && ( 24 | {description} 25 | )} 26 |
27 | {action} 28 | 29 |
30 | ); 31 | })} 32 | 33 |
34 | ); 35 | } 36 | -------------------------------------------------------------------------------- /src/components/Footer.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | import Link from "next/link"; 3 | 4 | export const Footer = () => { 5 | return ( 6 |
7 |
© 2024 upbot.vineet.tech
8 |
9 | 13 | Contact 14 | 15 | 20 | Twitter 21 | 22 | 27 | GitHub 28 | 29 |
30 |
31 | ); 32 | }; 33 | -------------------------------------------------------------------------------- /src/components/wrappers/sheetWrapper.tsx: -------------------------------------------------------------------------------- 1 | import { 2 | Sheet, 3 | SheetContent, 4 | SheetDescription, 5 | SheetHeader, 6 | SheetTitle, 7 | } from "@/components/ui/sheet"; 8 | import React from "react"; 9 | 10 | interface SheetWrapperProps { 11 | title: string; 12 | description: string; 13 | isOpen: boolean; 14 | handleClose: () => void; 15 | children: React.ReactNode; 16 | } 17 | 18 | const SheetWrapper: React.FC = ({ 19 | isOpen, 20 | handleClose, 21 | children, 22 | title, 23 | description, 24 | }) => { 25 | return ( 26 | 27 | 28 | 29 | {title} 30 | {description} 31 | 32 | 33 | {children} 34 | 35 | 36 | ); 37 | }; 38 | 39 | export default SheetWrapper; 40 | -------------------------------------------------------------------------------- /public/assets/gmail.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/lib/error.ts: -------------------------------------------------------------------------------- 1 | import { ERROR_CODE, ERROR_NAME } from "@/config/error.config"; 2 | export type ErrorResponseType = { 3 | name: string; 4 | message: string; 5 | code: number; 6 | status: false; 7 | }; 8 | class ErrorHandler extends Error { 9 | status: false; 10 | error?: any; 11 | code: number; 12 | constructor(message: string, code: keyof typeof ERROR_CODE, error?: any) { 13 | super(message); 14 | this.status = false; 15 | this.error = error; 16 | this.code = ERROR_CODE[code]; 17 | this.name = ERROR_NAME[code]; 18 | } 19 | } 20 | 21 | function standardizeApiError(error: unknown): ErrorResponseType { 22 | if (error instanceof ErrorHandler) { 23 | return { 24 | name: error.name, 25 | message: error.message, 26 | code: error.code, 27 | status: false, 28 | }; 29 | } 30 | 31 | return { 32 | name: ERROR_NAME.INTERNAL_SERVER_ERROR, 33 | message: 34 | "We're sorry for the inconvenience. Please report this issue to our support team ", 35 | code: ERROR_CODE.INTERNAL_SERVER_ERROR, 36 | status: false, 37 | }; 38 | } 39 | export { ErrorHandler, standardizeApiError }; 40 | -------------------------------------------------------------------------------- /src/app/globals.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | 5 | 6 | @layer base { 7 | :root { 8 | --background: 0 4% 5%; 9 | --foreground: 0 0% 98%; 10 | --card: 0 0% 10%; 11 | --card-foreground: 0 0% 95%; 12 | --popover: 0 0% 12%; 13 | --popover-foreground: 0 0% 95%; 14 | 15 | --primary: 0 0% 15%; 16 | --primary-foreground: 0 0% 98%; 17 | 18 | --secondary: 0 0% 85%; 19 | --secondary-foreground: 0 0% 12%; 20 | 21 | --muted: 0 0% 90%; 22 | --muted-foreground: 0 0% 35%; 23 | 24 | --accent: 0 0% 85%; 25 | --accent-foreground: 0 0% 15%; 26 | 27 | --destructive: 0 84% 60%; 28 | --destructive-foreground: 0 0% 98%; 29 | 30 | --border: 0 0% 20%; 31 | --input: 0 0% 15%; 32 | 33 | --ring: 0 0% 30%; 34 | 35 | --chart-1: 12 76% 61%; 36 | --chart-2: 173 58% 39%; 37 | --chart-3: 197 37% 24%; 38 | --chart-4: 43 74% 66%; 39 | --chart-5: 27 87% 67%; 40 | 41 | } 42 | 43 | } 44 | 45 | @layer base { 46 | * { 47 | @apply border-border; 48 | } 49 | body { 50 | @apply bg-background text-foreground; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/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 | -------------------------------------------------------------------------------- /src/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 | -------------------------------------------------------------------------------- /src/components/Cta.tsx: -------------------------------------------------------------------------------- 1 | import FlickeringGrid from "./ui/flickering-grid"; 2 | import { Button } from "./ui/button"; 3 | import { Zap } from "lucide-react"; 4 | import { motion } from "framer-motion"; 5 | export function FlickeringGridList() { 6 | return ( 7 |
8 | 18 | 34 |
35 | ); 36 | } 37 | -------------------------------------------------------------------------------- /src/lib/auth.ts: -------------------------------------------------------------------------------- 1 | import axios from "axios"; 2 | import { SessionStrategy } from "next-auth"; 3 | import GoogleProvider from "next-auth/providers/google"; 4 | 5 | export const authOptions = { 6 | providers: [ 7 | GoogleProvider({ 8 | clientId: process.env.GOOGLE_CLIENT_ID || "", 9 | clientSecret: process.env.GOOGLE_CLIENT_SECRET || "", 10 | }), 11 | ], 12 | secret: process.env.NEXTAUTH_SECRET || "secret", 13 | session: { strategy: "jwt" as SessionStrategy }, 14 | 15 | callbacks: { 16 | async jwt({ token, account }: any) { 17 | if (account?.access_token) { 18 | token.accessToken = account.access_token; 19 | 20 | try { 21 | const response = await axios.get( 22 | `${process.env.BACKEND_URL}/auth/google`, 23 | { 24 | headers: { 25 | Authorization: `Bearer ${token.accessToken}`, 26 | }, 27 | } 28 | ); 29 | 30 | token.signedToken = response.data.token; 31 | } catch (error) { 32 | console.error("Error fetching custom JWT:", error); 33 | } 34 | } 35 | 36 | return token; 37 | }, 38 | 39 | async session({ session, token }: any) { 40 | session.token = token.signedToken; 41 | return session; 42 | }, 43 | }, 44 | }; 45 | -------------------------------------------------------------------------------- /src/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 | 19 | 28 | 29 | )) 30 | TooltipContent.displayName = TooltipPrimitive.Content.displayName 31 | 32 | export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider } 33 | -------------------------------------------------------------------------------- /src/components/Navlogin.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import { useState } from "react"; 4 | import { Button } from "@/components/ui/button"; 5 | import { 6 | DropdownMenu, 7 | DropdownMenuContent, 8 | DropdownMenuItem, 9 | DropdownMenuTrigger, 10 | } from "@/components/ui/dropdown-menu"; 11 | import Image from "next/image"; 12 | import { useSession, signOut } from "next-auth/react"; 13 | import Link from "next/link"; 14 | import { signIn } from "next-auth/react"; 15 | 16 | export const Navlogin = () => { 17 | const { data: session, status } = useSession(); 18 | const [open, setOpen] = useState(false); 19 | 20 | if (status === "loading") { 21 | return ( 22 |
23 | ); 24 | } 25 | 26 | if (status === "unauthenticated") { 27 | return ( 28 | 37 | ); 38 | } 39 | 40 | if (!session || !session.user) return null; 41 | 42 | return ( 43 | User profile picture 50 | ); 51 | }; 52 | -------------------------------------------------------------------------------- /src/config/error.config.ts: -------------------------------------------------------------------------------- 1 | export const ERROR_NAME = { 2 | UNAUTHORIZED: "Unauthorized access", 3 | INTERNAL_SERVER_ERROR: "Internal server error", 4 | BAD_REQUEST: "Bad request", 5 | NOT_FOUND: "Resource not found", 6 | FORBIDDEN: "Access forbidden", 7 | CONFLICT: "Resource conflict", 8 | UNPROCESSABLE_ENTITY: "Unprocessable entity", 9 | TOO_MANY_REQUESTS: "Too many requests", 10 | SERVICE_UNAVAILABLE: "Service unavailable", 11 | GATEWAY_TIMEOUT: "Gateway timeout", 12 | VALIDATION_ERROR: "Validation error", 13 | AUTHENTICATION_FAILED: "Authentication failed", 14 | INSUFFICIENT_PERMISSIONS: "Insufficient permissions", 15 | REQUEST_TIMEOUT: "Request timeout", 16 | UNSUPPORTED_MEDIA_TYPE: "Unsupported media type", 17 | METHOD_NOT_ALLOWED: "Method not allowed", 18 | DATABASE_ERROR: "Database error", 19 | NETWORK_ERROR: "Network error", 20 | RESOURCE_GONE: "Resource gone", 21 | PRECONDITION_FAILED: "Precondition failed", 22 | }; 23 | export const ERROR_CODE = { 24 | UNAUTHORIZED: 401, 25 | INTERNAL_SERVER_ERROR: 500, 26 | BAD_REQUEST: 400, 27 | NOT_FOUND: 404, 28 | FORBIDDEN: 403, 29 | CONFLICT: 409, 30 | UNPROCESSABLE_ENTITY: 422, 31 | TOO_MANY_REQUESTS: 429, 32 | SERVICE_UNAVAILABLE: 503, 33 | GATEWAY_TIMEOUT: 504, 34 | VALIDATION_ERROR: 422, 35 | AUTHENTICATION_FAILED: 401, 36 | INSUFFICIENT_PERMISSIONS: 403, 37 | REQUEST_TIMEOUT: 408, 38 | UNSUPPORTED_MEDIA_TYPE: 415, 39 | METHOD_NOT_ALLOWED: 405, 40 | DATABASE_ERROR: 500, 41 | NETWORK_ERROR: 502, 42 | RESOURCE_GONE: 410, 43 | PRECONDITION_FAILED: 412, 44 | }; 45 | -------------------------------------------------------------------------------- /src/app/layout.tsx: -------------------------------------------------------------------------------- 1 | import "./globals.css"; 2 | 3 | import { Footer } from "@/components/Footer"; 4 | import type { Metadata } from "next"; 5 | import { Navbar } from "@/components/Navbar"; 6 | import Providers from "@/components/SessionProvider"; 7 | import Script from "next/script"; 8 | import { ThemeProvider } from "@/components/theme-provider"; 9 | import { Toaster } from "@/components/ui/toaster"; 10 | import localFont from "next/font/local"; 11 | 12 | const geistSans = localFont({ 13 | src: "./fonts/GeistVF.woff", 14 | variable: "--font-geist-sans", 15 | weight: "100 900", 16 | }); 17 | const geistMono = localFont({ 18 | src: "./fonts/GeistMonoVF.woff", 19 | variable: "--font-geist-mono", 20 | weight: "100 900", 21 | }); 22 | 23 | export const metadata: Metadata = { 24 | title: "Upbot", 25 | description: "Never let your server sleep while you do.", 26 | }; 27 | 28 | export default function RootLayout({ 29 | children, 30 | }: Readonly<{ 31 | children: React.ReactNode; 32 | }>) { 33 | return ( 34 | 35 | 38 | 39 | 40 | 41 | {children} 42 |