A sign-in link has been sent to your email address.
32 |
39 | >
40 | )}
41 |
42 |
43 | );
44 | }
45 |
46 | function SignInWithGitHub() {
47 | const { signIn } = useAuthActions();
48 | return (
49 |
57 | );
58 | }
59 |
60 | function SignInWithMagicLink({
61 | handleLinkSent,
62 | }: {
63 | handleLinkSent: () => void;
64 | }) {
65 | const { signIn } = useAuthActions();
66 | return (
67 |
86 | );
87 | }
88 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Welcome to your Convex + Next.js + Convex Auth app
2 |
3 | This is a [Convex](https://convex.dev/) project created with [`npm create convex`](https://www.npmjs.com/package/create-convex).
4 |
5 | After the initial setup (<2 minutes) you'll have a working full-stack app using:
6 |
7 | - Convex as your backend (database, server logic)
8 | - [Convex Auth](https://labs.convex.dev/auth) for your authentication implementation
9 | - [React](https://react.dev/) as your frontend (web page interactivity)
10 | - [Next.js](https://nextjs.org/) for optimized web hosting and page routing
11 | - [Tailwind](https://tailwindcss.com/) and [shadcn/ui](https://ui.shadcn.com/) for building great looking accessible UI fast
12 |
13 | ## Get started
14 |
15 | If you just cloned this codebase and didn't use `npm create convex`, run:
16 |
17 | ```
18 | npm install
19 | npm run dev
20 | ```
21 |
22 | If you're reading this README on GitHub and want to use this template, run:
23 |
24 | ```
25 | npm create convex@latest -- -t nextjs-convexauth-shadcn
26 | ```
27 |
28 | ## The app
29 |
30 | The app is a basic multi-user chat. Walkthrough of the source code:
31 |
32 | - [convex/auth.ts](./convex/auth.ts) configures the available authentication methods
33 | - [convex/messages.ts](./convex/messages.ts) is the chat backend implementation
34 | - [middleware.ts](./middleware.ts) determines which pages require sign-in
35 | - [app/layout.tsx](./app/layout.tsx) is the main app layout
36 | - [app/(splash)/page.tsx](<./app/(splash)/page.tsx>) is the splash page (doesn't require sign-in)
37 | - [app/product/layout.tsx](./app/product/layout.tsx) is the "product" layout for the [product page](./app/product/page.tsx) (requires sign-in)
38 | - [app/signin/page.tsx](./app/signin/page.tsx) is the sign-in page
39 | - [app/product/Chat/Chat.tsx](./app/product/Chat/Chat.tsx) is the chat frontend
40 |
41 | ## Configuring other authentication methods
42 |
43 | To configure different authentication methods, see [Configuration](https://labs.convex.dev/auth/config) in the Convex Auth docs.
44 |
45 | ## Learn more
46 |
47 | To learn more about developing your project with Convex, check out:
48 |
49 | - The [Tour of Convex](https://docs.convex.dev/get-started) for a thorough introduction to Convex principles.
50 | - The rest of [Convex docs](https://docs.convex.dev/) to learn about all Convex features.
51 | - [Stack](https://stack.convex.dev/) for in-depth articles on advanced topics.
52 |
53 | ## Join the community
54 |
55 | Join thousands of developers building full-stack apps with Convex:
56 |
57 | ## Deploy on Vercel
58 |
59 | 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.
60 |
61 | Check out our [Next.js deployment documentation](https://nextjs.org/docs/app/building-your-application/deploying) for more details.
62 |
63 | ## Deploy on Vercel
64 |
65 | 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.
66 |
67 | # Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details.
68 |
69 | - Join the [Convex Discord community](https://convex.dev/community) to get help in real-time.
70 | - Follow [Convex on GitHub](https://github.com/get-convex/), star and contribute to the open-source implementation of Convex.
71 |
--------------------------------------------------------------------------------
/convex/_generated/server.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 | /**
3 | * Generated utilities for implementing server-side Convex query and mutation functions.
4 | *
5 | * THIS CODE IS AUTOMATICALLY GENERATED.
6 | *
7 | * To regenerate, run `npx convex dev`.
8 | * @module
9 | */
10 |
11 | import {
12 | actionGeneric,
13 | httpActionGeneric,
14 | queryGeneric,
15 | mutationGeneric,
16 | internalActionGeneric,
17 | internalMutationGeneric,
18 | internalQueryGeneric,
19 | } from "convex/server";
20 |
21 | /**
22 | * Define a query in this Convex app's public API.
23 | *
24 | * This function will be allowed to read your Convex database and will be accessible from the client.
25 | *
26 | * @param func - The query function. It receives a {@link QueryCtx} as its first argument.
27 | * @returns The wrapped query. Include this as an `export` to name it and make it accessible.
28 | */
29 | export const query = queryGeneric;
30 |
31 | /**
32 | * Define a query that is only accessible from other Convex functions (but not from the client).
33 | *
34 | * This function will be allowed to read from your Convex database. It will not be accessible from the client.
35 | *
36 | * @param func - The query function. It receives a {@link QueryCtx} as its first argument.
37 | * @returns The wrapped query. Include this as an `export` to name it and make it accessible.
38 | */
39 | export const internalQuery = internalQueryGeneric;
40 |
41 | /**
42 | * Define a mutation in this Convex app's public API.
43 | *
44 | * This function will be allowed to modify your Convex database and will be accessible from the client.
45 | *
46 | * @param func - The mutation function. It receives a {@link MutationCtx} as its first argument.
47 | * @returns The wrapped mutation. Include this as an `export` to name it and make it accessible.
48 | */
49 | export const mutation = mutationGeneric;
50 |
51 | /**
52 | * Define a mutation that is only accessible from other Convex functions (but not from the client).
53 | *
54 | * This function will be allowed to modify your Convex database. It will not be accessible from the client.
55 | *
56 | * @param func - The mutation function. It receives a {@link MutationCtx} as its first argument.
57 | * @returns The wrapped mutation. Include this as an `export` to name it and make it accessible.
58 | */
59 | export const internalMutation = internalMutationGeneric;
60 |
61 | /**
62 | * Define an action in this Convex app's public API.
63 | *
64 | * An action is a function which can execute any JavaScript code, including non-deterministic
65 | * code and code with side-effects, like calling third-party services.
66 | * They can be run in Convex's JavaScript environment or in Node.js using the "use node" directive.
67 | * They can interact with the database indirectly by calling queries and mutations using the {@link ActionCtx}.
68 | *
69 | * @param func - The action. It receives an {@link ActionCtx} as its first argument.
70 | * @returns The wrapped action. Include this as an `export` to name it and make it accessible.
71 | */
72 | export const action = actionGeneric;
73 |
74 | /**
75 | * Define an action that is only accessible from other Convex functions (but not from the client).
76 | *
77 | * @param func - The function. It receives an {@link ActionCtx} as its first argument.
78 | * @returns The wrapped function. Include this as an `export` to name it and make it accessible.
79 | */
80 | export const internalAction = internalActionGeneric;
81 |
82 | /**
83 | * Define a Convex HTTP action.
84 | *
85 | * @param func - The function. It receives an {@link ActionCtx} as its first argument, and a `Request` object
86 | * as its second.
87 | * @returns The wrapped endpoint function. Route a URL path to this function in `convex/http.js`.
88 | */
89 | export const httpAction = httpActionGeneric;
90 |
--------------------------------------------------------------------------------
/app/(splash)/GetStarted/GetStarted.tsx:
--------------------------------------------------------------------------------
1 | import { ConvexLogo } from "@/app/(splash)/GetStarted/ConvexLogo";
2 | import { Code } from "@/components/Code";
3 | import { Button } from "@/components/ui/button";
4 | import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
5 | import {
6 | CodeIcon,
7 | MagicWandIcon,
8 | PlayIcon,
9 | StackIcon,
10 | } from "@radix-ui/react-icons";
11 | import Link from "next/link";
12 | import { ReactNode } from "react";
13 |
14 | export const GetStarted = () => {
15 | return (
16 |
17 |
18 |
19 | Your app powered by
20 |
21 |
22 |
23 | Build a realtime full-stack app in no time.
24 |
25 |
26 |
29 |
32 |
33 |
34 |
35 | Next steps
36 |
37 |
38 | This template is a starting point for building your web application.
39 |
40 |
41 |
42 |
43 |
44 | Play with the app
45 |
46 |
47 |
48 | Click on{" "}
49 |
53 | Get Started
54 | {" "}
55 | to see the app in action.
56 |
57 |
58 |
59 |
60 |
61 | Inspect your database
62 |
63 |
64 |
65 | The{" "}
66 |
71 | Convex dashboard
72 | {" "}
73 | is already open in another window.
74 |
75 |
76 |
77 |
78 |
79 |
80 | Change the backend
81 |
82 |
83 |
84 | Edit convex/messages.ts to change the backend
85 | functionality.
86 |
87 |
88 |
89 |
90 |
91 |
92 | Change the frontend
93 |
94 |
95 |
96 | Edit app/page.tsx to change your frontend.
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 | Helpful resources
106 |
107 |
108 |
109 | Read comprehensive documentation for all Convex features.
110 |
111 |
112 | Learn about best practices, use cases, and more from a growing
113 | collection of articles, videos, and walkthroughs.
114 |
115 |
116 | Join our developer community to ask questions, trade tips &
117 | tricks, and show off your projects.
118 |
119 |
120 | Get unblocked quickly by searching across the docs, Stack, and
121 | Discord chats.
122 |
123 |
124 |
125 |
126 |
127 | );
128 | };
129 |
130 | function Resource({
131 | title,
132 | children,
133 | href,
134 | }: {
135 | title: string;
136 | children: ReactNode;
137 | href: string;
138 | }) {
139 | return (
140 |
150 | );
151 | }
152 |
--------------------------------------------------------------------------------
/convex/_generated/server.d.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 | /**
3 | * Generated utilities for implementing server-side Convex query and mutation functions.
4 | *
5 | * THIS CODE IS AUTOMATICALLY GENERATED.
6 | *
7 | * To regenerate, run `npx convex dev`.
8 | * @module
9 | */
10 |
11 | import {
12 | ActionBuilder,
13 | HttpActionBuilder,
14 | MutationBuilder,
15 | QueryBuilder,
16 | GenericActionCtx,
17 | GenericMutationCtx,
18 | GenericQueryCtx,
19 | GenericDatabaseReader,
20 | GenericDatabaseWriter,
21 | } from "convex/server";
22 | import type { DataModel } from "./dataModel.js";
23 |
24 | /**
25 | * Define a query in this Convex app's public API.
26 | *
27 | * This function will be allowed to read your Convex database and will be accessible from the client.
28 | *
29 | * @param func - The query function. It receives a {@link QueryCtx} as its first argument.
30 | * @returns The wrapped query. Include this as an `export` to name it and make it accessible.
31 | */
32 | export declare const query: QueryBuilder;
33 |
34 | /**
35 | * Define a query that is only accessible from other Convex functions (but not from the client).
36 | *
37 | * This function will be allowed to read from your Convex database. It will not be accessible from the client.
38 | *
39 | * @param func - The query function. It receives a {@link QueryCtx} as its first argument.
40 | * @returns The wrapped query. Include this as an `export` to name it and make it accessible.
41 | */
42 | export declare const internalQuery: QueryBuilder;
43 |
44 | /**
45 | * Define a mutation in this Convex app's public API.
46 | *
47 | * This function will be allowed to modify your Convex database and will be accessible from the client.
48 | *
49 | * @param func - The mutation function. It receives a {@link MutationCtx} as its first argument.
50 | * @returns The wrapped mutation. Include this as an `export` to name it and make it accessible.
51 | */
52 | export declare const mutation: MutationBuilder;
53 |
54 | /**
55 | * Define a mutation that is only accessible from other Convex functions (but not from the client).
56 | *
57 | * This function will be allowed to modify your Convex database. It will not be accessible from the client.
58 | *
59 | * @param func - The mutation function. It receives a {@link MutationCtx} as its first argument.
60 | * @returns The wrapped mutation. Include this as an `export` to name it and make it accessible.
61 | */
62 | export declare const internalMutation: MutationBuilder;
63 |
64 | /**
65 | * Define an action in this Convex app's public API.
66 | *
67 | * An action is a function which can execute any JavaScript code, including non-deterministic
68 | * code and code with side-effects, like calling third-party services.
69 | * They can be run in Convex's JavaScript environment or in Node.js using the "use node" directive.
70 | * They can interact with the database indirectly by calling queries and mutations using the {@link ActionCtx}.
71 | *
72 | * @param func - The action. It receives an {@link ActionCtx} as its first argument.
73 | * @returns The wrapped action. Include this as an `export` to name it and make it accessible.
74 | */
75 | export declare const action: ActionBuilder;
76 |
77 | /**
78 | * Define an action that is only accessible from other Convex functions (but not from the client).
79 | *
80 | * @param func - The function. It receives an {@link ActionCtx} as its first argument.
81 | * @returns The wrapped function. Include this as an `export` to name it and make it accessible.
82 | */
83 | export declare const internalAction: ActionBuilder;
84 |
85 | /**
86 | * Define an HTTP action.
87 | *
88 | * This function will be used to respond to HTTP requests received by a Convex
89 | * deployment if the requests matches the path and method where this action
90 | * is routed. Be sure to route your action in `convex/http.js`.
91 | *
92 | * @param func - The function. It receives an {@link ActionCtx} as its first argument.
93 | * @returns The wrapped function. Import this function from `convex/http.js` and route it to hook it up.
94 | */
95 | export declare const httpAction: HttpActionBuilder;
96 |
97 | /**
98 | * A set of services for use within Convex query functions.
99 | *
100 | * The query context is passed as the first argument to any Convex query
101 | * function run on the server.
102 | *
103 | * This differs from the {@link MutationCtx} because all of the services are
104 | * read-only.
105 | */
106 | export type QueryCtx = GenericQueryCtx;
107 |
108 | /**
109 | * A set of services for use within Convex mutation functions.
110 | *
111 | * The mutation context is passed as the first argument to any Convex mutation
112 | * function run on the server.
113 | */
114 | export type MutationCtx = GenericMutationCtx;
115 |
116 | /**
117 | * A set of services for use within Convex action functions.
118 | *
119 | * The action context is passed as the first argument to any Convex action
120 | * function run on the server.
121 | */
122 | export type ActionCtx = GenericActionCtx;
123 |
124 | /**
125 | * An interface to read from the database within Convex query functions.
126 | *
127 | * The two entry points are {@link DatabaseReader.get}, which fetches a single
128 | * document by its {@link Id}, or {@link DatabaseReader.query}, which starts
129 | * building a query.
130 | */
131 | export type DatabaseReader = GenericDatabaseReader;
132 |
133 | /**
134 | * An interface to read from and write to the database within Convex mutation
135 | * functions.
136 | *
137 | * Convex guarantees that all writes within a single mutation are
138 | * executed atomically, so you never have to worry about partial writes leaving
139 | * your data in an inconsistent state. See [the Convex Guide](https://docs.convex.dev/understanding/convex-fundamentals/functions#atomicity-and-optimistic-concurrency-control)
140 | * for the guarantees Convex provides your functions.
141 | */
142 | export type DatabaseWriter = GenericDatabaseWriter;
143 |
--------------------------------------------------------------------------------
/components/ui/dropdown-menu.tsx:
--------------------------------------------------------------------------------
1 | "use client";
2 |
3 | import * as React from "react";
4 | import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu";
5 | import { Check, ChevronRight, Circle } from "lucide-react";
6 |
7 | import { cn } from "@/lib/utils";
8 |
9 | const DropdownMenu = DropdownMenuPrimitive.Root;
10 |
11 | const DropdownMenuTrigger = DropdownMenuPrimitive.Trigger;
12 |
13 | const DropdownMenuGroup = DropdownMenuPrimitive.Group;
14 |
15 | const DropdownMenuPortal = DropdownMenuPrimitive.Portal;
16 |
17 | const DropdownMenuSub = DropdownMenuPrimitive.Sub;
18 |
19 | const DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup;
20 |
21 | const DropdownMenuSubTrigger = React.forwardRef<
22 | React.ElementRef,
23 | React.ComponentPropsWithoutRef & {
24 | inset?: boolean;
25 | }
26 | >(({ className, inset, children, ...props }, ref) => (
27 |
36 | {children}
37 |
38 |
39 | ));
40 | DropdownMenuSubTrigger.displayName =
41 | DropdownMenuPrimitive.SubTrigger.displayName;
42 |
43 | const DropdownMenuSubContent = React.forwardRef<
44 | React.ElementRef,
45 | React.ComponentPropsWithoutRef
46 | >(({ className, ...props }, ref) => (
47 |
55 | ));
56 | DropdownMenuSubContent.displayName =
57 | DropdownMenuPrimitive.SubContent.displayName;
58 |
59 | const DropdownMenuContent = React.forwardRef<
60 | React.ElementRef,
61 | React.ComponentPropsWithoutRef
62 | >(({ className, sideOffset = 4, ...props }, ref) => (
63 |
64 |
74 |
75 | ));
76 | DropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName;
77 |
78 | const DropdownMenuItem = React.forwardRef<
79 | React.ElementRef,
80 | React.ComponentPropsWithoutRef & {
81 | inset?: boolean;
82 | }
83 | >(({ className, inset, ...props }, ref) => (
84 | svg]:size-4 [&>svg]:shrink-0",
88 | inset && "pl-8",
89 | className,
90 | )}
91 | {...props}
92 | />
93 | ));
94 | DropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName;
95 |
96 | const DropdownMenuCheckboxItem = React.forwardRef<
97 | React.ElementRef,
98 | React.ComponentPropsWithoutRef
99 | >(({ className, children, checked, ...props }, ref) => (
100 |
109 |
110 |
111 |
112 |
113 |
114 | {children}
115 |
116 | ));
117 | DropdownMenuCheckboxItem.displayName =
118 | DropdownMenuPrimitive.CheckboxItem.displayName;
119 |
120 | const DropdownMenuRadioItem = React.forwardRef<
121 | React.ElementRef,
122 | React.ComponentPropsWithoutRef
123 | >(({ className, children, ...props }, ref) => (
124 |
132 |
133 |
134 |
135 |
136 |
137 | {children}
138 |
139 | ));
140 | DropdownMenuRadioItem.displayName = DropdownMenuPrimitive.RadioItem.displayName;
141 |
142 | const DropdownMenuLabel = React.forwardRef<
143 | React.ElementRef,
144 | React.ComponentPropsWithoutRef & {
145 | inset?: boolean;
146 | }
147 | >(({ className, inset, ...props }, ref) => (
148 |
157 | ));
158 | DropdownMenuLabel.displayName = DropdownMenuPrimitive.Label.displayName;
159 |
160 | const DropdownMenuSeparator = React.forwardRef<
161 | React.ElementRef,
162 | React.ComponentPropsWithoutRef
163 | >(({ className, ...props }, ref) => (
164 |
169 | ));
170 | DropdownMenuSeparator.displayName = DropdownMenuPrimitive.Separator.displayName;
171 |
172 | const DropdownMenuShortcut = ({
173 | className,
174 | ...props
175 | }: React.HTMLAttributes) => {
176 | return (
177 |
181 | );
182 | };
183 | DropdownMenuShortcut.displayName = "DropdownMenuShortcut";
184 |
185 | export {
186 | DropdownMenu,
187 | DropdownMenuTrigger,
188 | DropdownMenuContent,
189 | DropdownMenuItem,
190 | DropdownMenuCheckboxItem,
191 | DropdownMenuRadioItem,
192 | DropdownMenuLabel,
193 | DropdownMenuSeparator,
194 | DropdownMenuShortcut,
195 | DropdownMenuGroup,
196 | DropdownMenuPortal,
197 | DropdownMenuSub,
198 | DropdownMenuSubContent,
199 | DropdownMenuSubTrigger,
200 | DropdownMenuRadioGroup,
201 | };
202 |
--------------------------------------------------------------------------------