├── .eslintrc.json ├── 6.png ├── sample.env ├── src ├── app │ ├── favicon.ico │ ├── (pages) │ │ ├── (protected) │ │ │ ├── layout.tsx │ │ │ └── profile │ │ │ │ └── page.tsx │ │ ├── login │ │ │ └── page.tsx │ │ ├── signup │ │ │ └── page.tsx │ │ ├── logout │ │ │ └── page.tsx │ │ ├── page.tsx │ │ └── layout.tsx │ ├── layout.tsx │ └── globals.css ├── conf │ └── config.ts ├── context │ ├── useAuth.ts │ └── authContext.ts ├── components │ ├── Avatar.tsx │ ├── Blog.tsx │ ├── Header.tsx │ ├── ProfileCard.tsx │ ├── Logo.tsx │ ├── Login.tsx │ └── Signup.tsx └── appwrite │ └── config.ts ├── next.config.js ├── postcss.config.js ├── .gitignore ├── public ├── vercel.svg └── next.svg ├── tailwind.config.js ├── package.json ├── tsconfig.json └── README.md /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "next/core-web-vitals" 3 | } 4 | -------------------------------------------------------------------------------- /6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hiteshchoudhary/nextjs-appwrite-auth/HEAD/6.png -------------------------------------------------------------------------------- /sample.env: -------------------------------------------------------------------------------- 1 | NEXT_PUBLIC_APPWRITE_URL=https://cloud.appwrite.io/v1 2 | NEXT_PUBLIC_APPWRITE_PROJECT_ID=5c5c5c5c -------------------------------------------------------------------------------- /src/app/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hiteshchoudhary/nextjs-appwrite-auth/HEAD/src/app/favicon.ico -------------------------------------------------------------------------------- /next.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = {} 3 | 4 | module.exports = nextConfig 5 | -------------------------------------------------------------------------------- /postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | } 7 | -------------------------------------------------------------------------------- /src/conf/config.ts: -------------------------------------------------------------------------------- 1 | const conf = { 2 | appwriteUrl: String(process.env.NEXT_PUBLIC_APPWRITE_URL), 3 | appwriteProjectId: String(process.env.NEXT_PUBLIC_APPWRITE_PROJECT_ID), 4 | } 5 | 6 | export default conf -------------------------------------------------------------------------------- /src/context/useAuth.ts: -------------------------------------------------------------------------------- 1 | import { useContext } from "react"; 2 | import AuthContext from "./authContext"; 3 | 4 | const useAuth = () => { 5 | const data = useContext(AuthContext); 6 | return data; 7 | } 8 | 9 | export default useAuth; -------------------------------------------------------------------------------- /src/context/authContext.ts: -------------------------------------------------------------------------------- 1 | import { createContext } from "react"; 2 | 3 | export const AuthContext = createContext<{ 4 | authStatus: boolean; 5 | setAuthStatus: (status: boolean) => void; 6 | }>({ 7 | authStatus: false, 8 | setAuthStatus: () => {}, 9 | }); 10 | 11 | export const AuthProvider = AuthContext.Provider; 12 | 13 | export default AuthContext; -------------------------------------------------------------------------------- /src/components/Avatar.tsx: -------------------------------------------------------------------------------- 1 | 2 | import React from "react"; 3 | 4 | type Props = { 5 | img: string; 6 | alt?: string; 7 | } 8 | 9 | const Avatar: React.FC = ({ img, alt }) => { 10 | return ( 11 |
12 |
13 | {alt 14 |
15 |
16 | ); 17 | 18 | } 19 | 20 | export default Avatar; -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | .env 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # next.js 12 | /.next/ 13 | /out/ 14 | 15 | # production 16 | /build 17 | 18 | # misc 19 | .DS_Store 20 | *.pem 21 | 22 | # debug 23 | npm-debug.log* 24 | yarn-debug.log* 25 | yarn-error.log* 26 | 27 | # local env files 28 | .env*.local 29 | 30 | # vercel 31 | .vercel 32 | 33 | # typescript 34 | *.tsbuildinfo 35 | next-env.d.ts 36 | -------------------------------------------------------------------------------- /src/app/(pages)/(protected)/layout.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | import useAuth from "@/context/useAuth" 3 | import { useRouter } from "next/navigation" 4 | 5 | import React from "react" 6 | 7 | const ProtectedLayout = ({ 8 | children, 9 | }: { 10 | children: React.ReactNode 11 | }) => { 12 | 13 | const router = useRouter(); 14 | const { authStatus } = useAuth(); 15 | 16 | if (!authStatus) { 17 | router.replace("/login"); 18 | return <>; 19 | } 20 | return children 21 | 22 | } 23 | 24 | export default ProtectedLayout; -------------------------------------------------------------------------------- /src/app/layout.tsx: -------------------------------------------------------------------------------- 1 | import './globals.css' 2 | import { Inter } from 'next/font/google' 3 | 4 | const inter = Inter({ subsets: ['latin'] }) 5 | 6 | export const metadata = { 7 | title: 'Create next and appwrite app', 8 | description: 'learning it on youtube', 9 | } 10 | 11 | export default function RootLayout({ 12 | children, 13 | }: { 14 | children: React.ReactNode 15 | }) { 16 | return ( 17 | 18 | 19 | 20 | {children} 21 | 22 | 23 | ) 24 | } 25 | -------------------------------------------------------------------------------- /public/vercel.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/app/(pages)/login/page.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | import useAuth from "@/context/useAuth"; 3 | import { useRouter } from "next/navigation"; 4 | import React from "react"; 5 | import Login from "@/components/Login"; 6 | 7 | const LoginPage = () => { 8 | const router = useRouter(); 9 | const { authStatus } = useAuth(); 10 | 11 | if (authStatus) { 12 | router.replace("/profile"); 13 | return <>; 14 | } 15 | 16 | return( 17 |
18 | 19 |
20 | ) 21 | } 22 | 23 | 24 | export default LoginPage; -------------------------------------------------------------------------------- /src/app/(pages)/signup/page.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | import useAuth from "@/context/useAuth"; 3 | import { useRouter } from "next/navigation"; 4 | import React from "react"; 5 | import Signup from "@/components/Signup"; 6 | 7 | const SignupPage = () => { 8 | const router = useRouter(); 9 | const { authStatus } = useAuth(); 10 | 11 | if (authStatus) { 12 | router.replace("/profile"); 13 | return <>; 14 | } 15 | 16 | return( 17 |
18 | 19 |
20 | ) 21 | } 22 | 23 | export default SignupPage; -------------------------------------------------------------------------------- /src/app/(pages)/logout/page.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | import appwriteService from "@/appwrite/config"; 3 | import useAuth from "@/context/useAuth"; 4 | import { useRouter } from "next/navigation"; 5 | import React, {useEffect} from "react"; 6 | 7 | const LogoutPage = () => { 8 | const router = useRouter(); 9 | const {setAuthStatus} = useAuth(); 10 | 11 | useEffect(() => { 12 | appwriteService.logout() 13 | .then(() => { 14 | setAuthStatus(false); 15 | router.replace("/"); 16 | }) 17 | }, []); 18 | 19 | return( 20 | <> 21 | ) 22 | } 23 | 24 | 25 | export default LogoutPage; 26 | -------------------------------------------------------------------------------- /src/app/globals.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | 5 | :root { 6 | --foreground-rgb: 0, 0, 0; 7 | --background-start-rgb: 214, 219, 220; 8 | --background-end-rgb: 255, 255, 255; 9 | } 10 | 11 | @media (prefers-color-scheme: dark) { 12 | :root { 13 | --foreground-rgb: 255, 255, 255; 14 | --background-start-rgb: 0, 0, 0; 15 | --background-end-rgb: 0, 0, 0; 16 | } 17 | } 18 | 19 | body { 20 | color: rgb(var(--foreground-rgb)); 21 | background: linear-gradient( 22 | to bottom, 23 | transparent, 24 | rgb(var(--background-end-rgb)) 25 | ) 26 | rgb(var(--background-start-rgb)); 27 | } 28 | -------------------------------------------------------------------------------- /tailwind.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('tailwindcss').Config} */ 2 | module.exports = { 3 | content: [ 4 | './src/pages/**/*.{js,ts,jsx,tsx,mdx}', 5 | './src/components/**/*.{js,ts,jsx,tsx,mdx}', 6 | './src/app/**/*.{js,ts,jsx,tsx,mdx}', 7 | ], 8 | theme: { 9 | extend: { 10 | colors: { 11 | primary: "#f02e65", 12 | secondary: "#fe9684", 13 | }, 14 | backgroundImage: { 15 | 'gradient-radial': 'radial-gradient(var(--tw-gradient-stops))', 16 | 'gradient-conic': 17 | 'conic-gradient(from 180deg at 50% 50%, var(--tw-gradient-stops))', 18 | }, 19 | }, 20 | }, 21 | plugins: [], 22 | } 23 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "nextjs-appwrite-youtube", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "dev": "next dev", 7 | "build": "next build", 8 | "start": "next start", 9 | "lint": "next lint" 10 | }, 11 | "dependencies": { 12 | "@types/node": "20.3.3", 13 | "@types/react": "18.2.14", 14 | "@types/react-dom": "18.2.6", 15 | "appwrite": "^11.0.0", 16 | "autoprefixer": "10.4.14", 17 | "eslint": "8.44.0", 18 | "eslint-config-next": "13.4.7", 19 | "next": "13.4.7", 20 | "postcss": "8.4.24", 21 | "react": "18.2.0", 22 | "react-dom": "18.2.0", 23 | "tailwindcss": "3.3.2", 24 | "typescript": "5.1.6" 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "lib": ["dom", "dom.iterable", "esnext"], 5 | "allowJs": true, 6 | "skipLibCheck": true, 7 | "strict": true, 8 | "forceConsistentCasingInFileNames": true, 9 | "noEmit": true, 10 | "esModuleInterop": true, 11 | "module": "esnext", 12 | "moduleResolution": "node", 13 | "resolveJsonModule": true, 14 | "isolatedModules": true, 15 | "jsx": "preserve", 16 | "incremental": true, 17 | "plugins": [ 18 | { 19 | "name": "next" 20 | } 21 | ], 22 | "paths": { 23 | "@/*": ["./src/*"] 24 | } 25 | }, 26 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], 27 | "exclude": ["node_modules"] 28 | } 29 | -------------------------------------------------------------------------------- /src/components/Blog.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | type Props = { 4 | blur?: boolean; 5 | }; 6 | 7 | const Blog: React.FC = ({ blur = false }) => { 8 | return ( 9 | 10 | 11 | 16 | 17 | 18 | ); 19 | }; 20 | 21 | export default Blog; 22 | -------------------------------------------------------------------------------- /src/app/(pages)/(protected)/profile/page.tsx: -------------------------------------------------------------------------------- 1 | import ProfileCard from "@/components/ProfileCard"; 2 | import Link from "next/link"; 3 | import React from "react"; 4 | 5 | const ProfilePage = () => { 6 | return ( 7 |
8 |

9 | 10 | 11 | < 12 | 13 | 14 | My Account 15 |

16 | 17 |
18 | ); 19 | } 20 | 21 | export default ProfilePage; -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # A detailed course to undestand nextjs 2 | 3 | This long video was designed to give you an indepth understanding about latest nextjs and how it works. If you have improved the project add your repo link in the assignment section. Please do not change main code files as students need to learn from the same code. 4 | 5 | ## Tech Stack 6 | - Nextjs 7 | - typescript 8 | - mongodb 9 | - mailtrap 10 | 11 | ![Course Image](./6.png) 12 | 13 | --- 14 | Available on my youtube channel 15 | [Youtube channel link](https://www.youtube.com/@HiteshChoudharydotcom) 16 | 17 | ## Getting Started 18 | 19 | First, run the development server: 20 | 21 | ```bash 22 | npm run dev 23 | # or 24 | yarn dev 25 | # or 26 | pnpm dev 27 | ``` 28 | ## Assignment 29 | 1. Improve the UI of the application 30 | 2. Add a new feature to the application 31 | --- 32 | ## your completed assignments 33 | 34 | - Add your repo link here 35 | - 36 | 37 | 38 | --- 39 | -------------------------------------------------------------------------------- /public/next.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/app/(pages)/page.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import useAuth from "@/context/useAuth"; 4 | import React from "react"; 5 | import ProfileCard from "@/components/ProfileCard"; 6 | import Login from "@/components/Login"; 7 | 8 | const Home = () => { 9 | const {authStatus} = useAuth(); 10 | return ( 11 |
12 |
13 |
14 |
15 |
16 | Logo 17 |
18 |
19 |

20 | NextJS 13 Authentication with Appwrite 21 |

22 |

23 | Integrate secure user authentication into your Next.js web applications using 24 | Appwrite, an open-source backend server. Follow along as we demonstrate the 25 | step-by-step process of setting up and implementing authentication 26 | functionality, ensuring the highest level of security for your users. 27 |

28 |
29 |
30 |
31 |
32 | {authStatus ? ( 33 |
34 | 35 |
36 | ) : ( 37 | 38 | )} 39 |
40 |
41 |
42 | ); 43 | } 44 | 45 | export default Home; -------------------------------------------------------------------------------- /src/appwrite/config.ts: -------------------------------------------------------------------------------- 1 | import conf from "@/conf/config"; 2 | import {Client, Account, ID} from 'appwrite' 3 | 4 | type CreateUserAccount = { 5 | email: string, 6 | password: string, 7 | name: string, 8 | } 9 | 10 | type LoginUserAccount = { 11 | email: string, 12 | password: string, 13 | } 14 | 15 | const appwriteClient = new Client() 16 | 17 | appwriteClient.setEndpoint(conf.appwriteUrl).setProject(conf.appwriteProjectId); 18 | 19 | export const account = new Account(appwriteClient) 20 | 21 | export class AppwriteService { 22 | //create a new record of user inside appwrite 23 | async createUserAccount({email, password, name}: CreateUserAccount) { 24 | try { 25 | const userAccount = await account.create(ID.unique(), email, password, name) 26 | if (userAccount) { 27 | return this.login({email, password}) 28 | } else { 29 | return userAccount 30 | } 31 | } catch (error:any) { 32 | throw error 33 | } 34 | 35 | 36 | } 37 | 38 | async login( { email, password }: LoginUserAccount) { 39 | try { 40 | return await account.createEmailSession(email, password) 41 | } catch (error:any) { 42 | throw error 43 | } 44 | } 45 | 46 | async isLoggedIn(): Promise { 47 | try { 48 | const data = await this.getCurrentUser(); 49 | return Boolean(data) 50 | } catch (error) {} 51 | 52 | return false 53 | } 54 | 55 | async getCurrentUser() { 56 | try { 57 | return account.get() 58 | } catch (error) { 59 | console.log("getcurrentUser error: " + error) 60 | 61 | } 62 | 63 | return null 64 | } 65 | 66 | async logout() { 67 | try { 68 | return await account.deleteSession("current") 69 | } catch (error) { 70 | console.log("logout error: " + error) 71 | } 72 | } 73 | 74 | 75 | } 76 | 77 | const appwriteService = new AppwriteService() 78 | 79 | export default appwriteService -------------------------------------------------------------------------------- /src/app/(pages)/layout.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | import appwriteService from "@/appwrite/config"; 3 | import Blog from "@/components/Blog"; 4 | import Header from "@/components/Header"; 5 | import { AuthProvider } from "@/context/authContext"; 6 | import React, { useEffect, useState } from "react"; 7 | 8 | const ProtectedLayout = ({ 9 | children, 10 | }: { 11 | children: React.ReactNode 12 | }) => { 13 | 14 | const [authStatus, setAuthStatus] = useState(false); 15 | const [loader, setLoader] = useState(true); 16 | 17 | useEffect(() => { 18 | appwriteService.isLoggedIn() 19 | .then(setAuthStatus) 20 | .finally(() => setLoader(false)); 21 | }, []); 22 | 23 | return 24 | {!loader && ( 25 | <> 26 |
27 |
28 | 29 |
30 |
31 | 32 |
33 |
34 | 35 |
36 |
37 | 38 |
39 |
40 | 41 |
42 |
43 | 44 |
45 |
46 |
47 |
{children}
48 | 49 | )} 50 | 51 | 52 | } 53 | 54 | export default ProtectedLayout; -------------------------------------------------------------------------------- /src/components/Header.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | import useAuth from "@/context/useAuth"; 3 | import Link from "next/link"; 4 | import React from "react"; 5 | import Logo from "./Logo"; 6 | 7 | const menuItems = [ 8 | { 9 | name: "Home", 10 | href: "/", 11 | }, 12 | { 13 | name: "About", 14 | href: "#", 15 | }, 16 | { 17 | name: "Contact", 18 | href: "#", 19 | }, 20 | ]; 21 | 22 | export default function Header() { 23 | const { authStatus } = useAuth(); 24 | return ( 25 |
26 |
27 |
28 | 29 | 30 | 31 |
32 |
33 |
    34 | {menuItems.map((item) => ( 35 |
  • 36 | 40 | {item.name} 41 | 42 |
  • 43 | ))} 44 |
45 |
46 |
47 | 51 | {authStatus ? "Profile" : "Sign up"} 52 | 53 | 57 | {authStatus ? "Logout" : "Log In"} 58 | 59 |
60 |
61 |
62 | ); 63 | } 64 | -------------------------------------------------------------------------------- /src/components/ProfileCard.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | import appwriteService from "@/appwrite/config"; 3 | import { Models } from "appwrite"; 4 | import Link from "next/link"; 5 | import React, { useEffect, useState } from "react"; 6 | import Avatar from "./Avatar"; 7 | 8 | 9 | const ProfileCard= () => { 10 | const [user, setUser] = useState | null>(null); 11 | 12 | useEffect(() => { 13 | (async () => { 14 | const userData = await appwriteService.getCurrentUser() 15 | if (userData) { 16 | setUser(userData) 17 | } 18 | })() 19 | }, []) 20 | 21 | return ( 22 | user && ( 23 | <> 24 |
25 |
26 |
27 | 28 |
29 |
30 |

{user.name}

31 |
32 | 33 |
34 |
35 |
36 |
37 |
38 |

Display Name

39 |

{user.name}

40 |
41 |
42 |

Email Id

43 |

{user.email}

44 |
45 |
46 |

Phone Number

47 |

999-888-7777

48 |
49 |
50 |

Password

51 |

********

52 |
53 |
54 |
55 | 59 | Logout 60 | 61 |
62 |
63 | 64 | ) 65 | ); 66 | } 67 | 68 | export default ProfileCard; -------------------------------------------------------------------------------- /src/components/Logo.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | const Logo = () => { 4 | return ( 5 | 6 | 10 | 16 | 21 | 25 | 26 | ); 27 | }; 28 | 29 | export default Logo; 30 | -------------------------------------------------------------------------------- /src/components/Login.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | import appwriteService from "@/appwrite/config"; 3 | import useAuth from "@/context/useAuth"; 4 | import Link from "next/link"; 5 | import { useRouter } from "next/navigation"; 6 | import React, {FormEvent, useState} from "react"; 7 | 8 | const Login = () => { 9 | const router = useRouter() 10 | const {setAuthStatus} = useAuth() 11 | const [formData, setFormData] = useState({ 12 | email: "", 13 | password: "", 14 | }) 15 | const [error, setError] = useState("") 16 | 17 | const login = async (e: FormEvent) => { 18 | e.preventDefault() 19 | try { 20 | const session = await appwriteService.login(formData); 21 | if (session) { 22 | setAuthStatus(true) 23 | router.push("/profile") 24 | } 25 | 26 | 27 | } catch (error: any) { 28 | setError(error.message) 29 | } 30 | } 31 | 32 | return ( 33 |
34 |
35 |
36 | 37 | Logo 38 | 39 |
40 |

41 | Sign in to your account 42 |

43 |

44 | Don't have any account?  45 | 49 | Sign Up 50 | 51 |

52 | {error &&

{error}

} 53 |
54 |
55 |
56 | 59 |
60 | 65 | setFormData((prev) => ({ ...prev, email: e.target.value })) 66 | } 67 | placeholder="Email" 68 | id="email" 69 | required 70 | /> 71 |
72 |
73 |
74 |
75 | 78 |
79 |
80 | 86 | setFormData((prev) => ({ 87 | ...prev, 88 | password: e.target.value, 89 | })) 90 | } 91 | id="password" 92 | required 93 | /> 94 |
95 |
96 |
97 | 103 |
104 |
105 |
106 |
107 |
108 | ); 109 | } 110 | 111 | 112 | export default Login; -------------------------------------------------------------------------------- /src/components/Signup.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | import appwriteService from "@/appwrite/config"; 3 | import useAuth from "@/context/useAuth"; 4 | import Link from "next/link"; 5 | import { useRouter } from "next/navigation"; 6 | import React, {FormEvent, useState} from "react"; 7 | 8 | 9 | const Signup = () => { 10 | 11 | const router = useRouter() 12 | const [formData, setFormData] = useState({ 13 | email: "", 14 | password: "", 15 | name: "", 16 | }) 17 | const [error, setError] = useState("") 18 | 19 | const {setAuthStatus} = useAuth() 20 | 21 | const create = async (e: FormEvent) => { 22 | e.preventDefault() 23 | try { 24 | const userData = await appwriteService.createUserAccount(formData); 25 | if (userData) { 26 | setAuthStatus(true) 27 | router.push("/profile") 28 | } 29 | } catch (error: any) { 30 | setError(error.message) 31 | } 32 | } 33 | 34 | return( 35 |
36 |
37 |
38 | 39 | Logo 40 | 41 |
42 |

43 | Sign up to create account 44 |

45 |

46 | Already have an account?  47 | 51 | Sign In 52 | 53 |

54 | {error &&

{error}

} 55 |
56 |
57 |
58 | 61 |
62 | 69 | setFormData((prev) => ({ ...prev, name: e.target.value })) 70 | } 71 | required 72 | /> 73 |
74 |
75 |
76 | 79 |
80 | 85 | setFormData((prev) => ({ ...prev, email: e.target.value })) 86 | } 87 | placeholder="Email" 88 | id="email" 89 | required 90 | /> 91 |
92 |
93 |
94 |
95 | 98 |
99 |
100 | 106 | setFormData((prev) => ({ 107 | ...prev, 108 | password: e.target.value, 109 | })) 110 | } 111 | id="password" 112 | required 113 | /> 114 |
115 |
116 |
117 | 123 |
124 |
125 |
126 |
127 |
128 | ) 129 | } 130 | 131 | export default Signup; --------------------------------------------------------------------------------