create-fe-boilerplate 0.4.1 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. package/package.json +1 -1
  2. package/templates/next/js/scss/axios/README.md +36 -0
  3. package/templates/next/js/scss/axios/eslint.config.mjs +18 -0
  4. package/templates/next/js/scss/axios/jsconfig.json +8 -0
  5. package/templates/next/js/scss/axios/next.config.js +5 -0
  6. package/templates/next/js/scss/axios/package-lock.json +6950 -0
  7. package/templates/next/js/scss/axios/package.json +23 -0
  8. package/templates/next/js/scss/axios/postcss.config.mjs +7 -0
  9. package/templates/next/js/scss/axios/public/file.svg +1 -0
  10. package/templates/next/js/scss/axios/public/globe.svg +1 -0
  11. package/templates/next/js/scss/axios/public/next.svg +1 -0
  12. package/templates/next/js/scss/axios/public/vercel.svg +1 -0
  13. package/templates/next/js/scss/axios/public/window.svg +1 -0
  14. package/templates/next/js/scss/axios/src/api/auth.js +7 -0
  15. package/templates/next/js/scss/axios/src/api/axios.js +16 -0
  16. package/templates/next/js/scss/axios/src/app/dashboard/Dashboard.scss +35 -0
  17. package/templates/next/js/scss/axios/src/app/dashboard/page.jsx +30 -0
  18. package/templates/next/js/scss/axios/src/app/favicon.ico +0 -0
  19. package/templates/next/js/scss/axios/src/app/layout.jsx +9 -0
  20. package/templates/next/js/scss/axios/src/app/login/Login.scss +58 -0
  21. package/templates/next/js/scss/axios/src/app/login/page.jsx +61 -0
  22. package/templates/next/js/scss/axios/src/app/page.jsx +5 -0
  23. package/templates/next/js/scss/axios/src/app/signup/Signup.scss +58 -0
  24. package/templates/next/js/scss/axios/src/app/signup/page.jsx +45 -0
  25. package/templates/next/js/scss/axios/src/components/AuthGuard.jsx +32 -0
  26. package/templates/next/js/scss/axios/src/components/VerifyOtpModal.jsx +51 -0
  27. package/templates/next/js/scss/axios/src/components/VerifyOtpModal.scss +66 -0
  28. package/templates/next/js/scss/axios/src/styles/globals.scss +10 -0
  29. package/templates/next/ts/scss/axios/README.md +36 -0
  30. package/templates/next/ts/scss/axios/eslint.config.mjs +18 -0
  31. package/templates/next/ts/scss/axios/next.config.ts +7 -0
  32. package/templates/next/ts/scss/axios/package-lock.json +6997 -0
  33. package/templates/next/ts/scss/axios/package.json +28 -0
  34. package/templates/next/ts/scss/axios/postcss.config.mjs +7 -0
  35. package/templates/next/ts/scss/axios/public/file.svg +1 -0
  36. package/templates/next/ts/scss/axios/public/globe.svg +1 -0
  37. package/templates/next/ts/scss/axios/public/next.svg +1 -0
  38. package/templates/next/ts/scss/axios/public/vercel.svg +1 -0
  39. package/templates/next/ts/scss/axios/public/window.svg +1 -0
  40. package/templates/next/ts/scss/axios/src/api/auth.ts +10 -0
  41. package/templates/next/ts/scss/axios/src/api/axios.ts +31 -0
  42. package/templates/next/ts/scss/axios/src/app/dashboard/Dashboard.scss +35 -0
  43. package/templates/next/ts/scss/axios/src/app/dashboard/page.tsx +30 -0
  44. package/templates/next/ts/scss/axios/src/app/favicon.ico +0 -0
  45. package/templates/next/ts/scss/axios/src/app/layout.tsx +13 -0
  46. package/templates/next/ts/scss/axios/src/app/login/Login.scss +58 -0
  47. package/templates/next/ts/scss/axios/src/app/login/page.tsx +60 -0
  48. package/templates/next/ts/scss/axios/src/app/page.tsx +5 -0
  49. package/templates/next/ts/scss/axios/src/app/signup/Signup.scss +58 -0
  50. package/templates/next/ts/scss/axios/src/app/signup/page.tsx +45 -0
  51. package/templates/next/ts/scss/axios/src/components/AuthGuard.tsx +35 -0
  52. package/templates/next/ts/scss/axios/src/components/VerifyOtpModal.scss +66 -0
  53. package/templates/next/ts/scss/axios/src/components/VerifyOtpModal.tsx +57 -0
  54. package/templates/next/ts/scss/axios/src/styles/globals.scss +10 -0
  55. package/templates/next/ts/scss/axios/tsconfig.json +36 -0
@@ -0,0 +1,28 @@
1
+ {
2
+ "name": "axios",
3
+ "version": "0.1.0",
4
+ "private": true,
5
+ "scripts": {
6
+ "dev": "next dev",
7
+ "build": "next build",
8
+ "start": "next start",
9
+ "lint": "eslint"
10
+ },
11
+ "dependencies": {
12
+ "axios": "^1.13.2",
13
+ "next": "16.1.1",
14
+ "react": "19.2.3",
15
+ "react-dom": "19.2.3",
16
+ "sass": "^1.97.2"
17
+ },
18
+ "devDependencies": {
19
+ "@tailwindcss/postcss": "^4",
20
+ "@types/node": "^20",
21
+ "@types/react": "^19",
22
+ "@types/react-dom": "^19",
23
+ "eslint": "^9",
24
+ "eslint-config-next": "16.1.1",
25
+ "tailwindcss": "^4",
26
+ "typescript": "^5"
27
+ }
28
+ }
@@ -0,0 +1,7 @@
1
+ const config = {
2
+ plugins: {
3
+ "@tailwindcss/postcss": {},
4
+ },
5
+ };
6
+
7
+ export default config;
@@ -0,0 +1 @@
1
+ <svg fill="none" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><path d="M14.5 13.5V5.41a1 1 0 0 0-.3-.7L9.8.29A1 1 0 0 0 9.08 0H1.5v13.5A2.5 2.5 0 0 0 4 16h8a2.5 2.5 0 0 0 2.5-2.5m-1.5 0v-7H8v-5H3v12a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1M9.5 5V2.12L12.38 5zM5.13 5h-.62v1.25h2.12V5zm-.62 3h7.12v1.25H4.5zm.62 3h-.62v1.25h7.12V11z" clip-rule="evenodd" fill="#666" fill-rule="evenodd"/></svg>
@@ -0,0 +1 @@
1
+ <svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><g clip-path="url(#a)"><path fill-rule="evenodd" clip-rule="evenodd" d="M10.27 14.1a6.5 6.5 0 0 0 3.67-3.45q-1.24.21-2.7.34-.31 1.83-.97 3.1M8 16A8 8 0 1 0 8 0a8 8 0 0 0 0 16m.48-1.52a7 7 0 0 1-.96 0H7.5a4 4 0 0 1-.84-1.32q-.38-.89-.63-2.08a40 40 0 0 0 3.92 0q-.25 1.2-.63 2.08a4 4 0 0 1-.84 1.31zm2.94-4.76q1.66-.15 2.95-.43a7 7 0 0 0 0-2.58q-1.3-.27-2.95-.43a18 18 0 0 1 0 3.44m-1.27-3.54a17 17 0 0 1 0 3.64 39 39 0 0 1-4.3 0 17 17 0 0 1 0-3.64 39 39 0 0 1 4.3 0m1.1-1.17q1.45.13 2.69.34a6.5 6.5 0 0 0-3.67-3.44q.65 1.26.98 3.1M8.48 1.5l.01.02q.41.37.84 1.31.38.89.63 2.08a40 40 0 0 0-3.92 0q.25-1.2.63-2.08a4 4 0 0 1 .85-1.32 7 7 0 0 1 .96 0m-2.75.4a6.5 6.5 0 0 0-3.67 3.44 29 29 0 0 1 2.7-.34q.31-1.83.97-3.1M4.58 6.28q-1.66.16-2.95.43a7 7 0 0 0 0 2.58q1.3.27 2.95.43a18 18 0 0 1 0-3.44m.17 4.71q-1.45-.12-2.69-.34a6.5 6.5 0 0 0 3.67 3.44q-.65-1.27-.98-3.1" fill="#666"/></g><defs><clipPath id="a"><path fill="#fff" d="M0 0h16v16H0z"/></clipPath></defs></svg>
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 394 80"><path fill="#000" d="M262 0h68.5v12.7h-27.2v66.6h-13.6V12.7H262V0ZM149 0v12.7H94v20.4h44.3v12.6H94v21h55v12.6H80.5V0h68.7zm34.3 0h-17.8l63.8 79.4h17.9l-32-39.7 32-39.6h-17.9l-23 28.6-23-28.6zm18.3 56.7-9-11-27.1 33.7h17.8l18.3-22.7z"/><path fill="#000" d="M81 79.3 17 0H0v79.3h13.6V17l50.2 62.3H81Zm252.6-.4c-1 0-1.8-.4-2.5-1s-1.1-1.6-1.1-2.6.3-1.8 1-2.5 1.6-1 2.6-1 1.8.3 2.5 1a3.4 3.4 0 0 1 .6 4.3 3.7 3.7 0 0 1-3 1.8zm23.2-33.5h6v23.3c0 2.1-.4 4-1.3 5.5a9.1 9.1 0 0 1-3.8 3.5c-1.6.8-3.5 1.3-5.7 1.3-2 0-3.7-.4-5.3-1s-2.8-1.8-3.7-3.2c-.9-1.3-1.4-3-1.4-5h6c.1.8.3 1.6.7 2.2s1 1.2 1.6 1.5c.7.4 1.5.5 2.4.5 1 0 1.8-.2 2.4-.6a4 4 0 0 0 1.6-1.8c.3-.8.5-1.8.5-3V45.5zm30.9 9.1a4.4 4.4 0 0 0-2-3.3 7.5 7.5 0 0 0-4.3-1.1c-1.3 0-2.4.2-3.3.5-.9.4-1.6 1-2 1.6a3.5 3.5 0 0 0-.3 4c.3.5.7.9 1.3 1.2l1.8 1 2 .5 3.2.8c1.3.3 2.5.7 3.7 1.2a13 13 0 0 1 3.2 1.8 8.1 8.1 0 0 1 3 6.5c0 2-.5 3.7-1.5 5.1a10 10 0 0 1-4.4 3.5c-1.8.8-4.1 1.2-6.8 1.2-2.6 0-4.9-.4-6.8-1.2-2-.8-3.4-2-4.5-3.5a10 10 0 0 1-1.7-5.6h6a5 5 0 0 0 3.5 4.6c1 .4 2.2.6 3.4.6 1.3 0 2.5-.2 3.5-.6 1-.4 1.8-1 2.4-1.7a4 4 0 0 0 .8-2.4c0-.9-.2-1.6-.7-2.2a11 11 0 0 0-2.1-1.4l-3.2-1-3.8-1c-2.8-.7-5-1.7-6.6-3.2a7.2 7.2 0 0 1-2.4-5.7 8 8 0 0 1 1.7-5 10 10 0 0 1 4.3-3.5c2-.8 4-1.2 6.4-1.2 2.3 0 4.4.4 6.2 1.2 1.8.8 3.2 2 4.3 3.4 1 1.4 1.5 3 1.5 5h-5.8z"/></svg>
@@ -0,0 +1 @@
1
+ <svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1155 1000"><path d="m577.3 0 577.4 1000H0z" fill="#fff"/></svg>
@@ -0,0 +1 @@
1
+ <svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path fill-rule="evenodd" clip-rule="evenodd" d="M1.5 2.5h13v10a1 1 0 0 1-1 1h-11a1 1 0 0 1-1-1zM0 1h16v11.5a2.5 2.5 0 0 1-2.5 2.5h-11A2.5 2.5 0 0 1 0 12.5zm3.75 4.5a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5M7 4.75a.75.75 0 1 1-1.5 0 .75.75 0 0 1 1.5 0m1.75.75a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5" fill="#666"/></svg>
@@ -0,0 +1,10 @@
1
+ import { axiosApi } from "./axios";
2
+
3
+ export const loginApi = (data: { email: string; password: string }) =>
4
+ axiosApi.post("/auth/login", data);
5
+
6
+ export const signupApi = (data: { email: string; password: string }) =>
7
+ axiosApi.post("/auth/signup", data);
8
+
9
+ export const verifyOtpApi = (data: { refId: string; otp: string }) =>
10
+ axiosApi.post("/auth/verify-otp", data);
@@ -0,0 +1,31 @@
1
+ import axios from "axios";
2
+
3
+ export const axiosApi = axios.create({
4
+ baseURL: process.env.NEXT_PUBLIC_API_HOST,
5
+ headers: {
6
+ "Content-Type": "application/json",
7
+ },
8
+ });
9
+
10
+ axiosApi.interceptors.request.use((config) => {
11
+ if (typeof window !== "undefined") {
12
+ const token = localStorage.getItem("token");
13
+ if (token) {
14
+ config.headers.Authorization = `Bearer ${token}`;
15
+ }
16
+ }
17
+ return config;
18
+ });
19
+
20
+ axiosApi.interceptors.response.use(
21
+ (response) => response,
22
+ (error) => {
23
+ if (error?.response?.status === 401) {
24
+ if (typeof window !== "undefined") {
25
+ localStorage.removeItem("token");
26
+ window.location.href = "/login";
27
+ }
28
+ }
29
+ return Promise.reject(error);
30
+ }
31
+ );
@@ -0,0 +1,35 @@
1
+ .dashboard-wrapper {
2
+ padding: 24px;
3
+
4
+ .dashboard-header {
5
+ display: flex;
6
+ justify-content: space-between;
7
+ align-items: center;
8
+ margin-bottom: 24px;
9
+
10
+ h1 {
11
+ font-size: 1.5rem;
12
+ font-weight: 700;
13
+ color: #000;
14
+ }
15
+
16
+ .btn-logout {
17
+ padding: 8px 16px;
18
+ background: #dc2626;
19
+ color: #fff;
20
+ border: none;
21
+ border-radius: 4px;
22
+ cursor: pointer;
23
+ font-weight: 500;
24
+
25
+ &:hover {
26
+ background: #b91c1c;
27
+ }
28
+ }
29
+ }
30
+
31
+ .dashboard-content {
32
+ color: #4b5563;
33
+ font-size: 1rem;
34
+ }
35
+ }
@@ -0,0 +1,30 @@
1
+ "use client";
2
+
3
+ import AuthGuard from "@/components/AuthGuard";
4
+ import { useRouter } from "next/navigation";
5
+ import "./Dashboard.scss";
6
+
7
+ export default function DashboardPage() {
8
+ const router = useRouter();
9
+
10
+ const handleLogout = () => {
11
+ localStorage.removeItem("token");
12
+ router.replace("/login");
13
+ };
14
+
15
+ return (
16
+ <AuthGuard>
17
+ <div className="dashboard-wrapper">
18
+ <div className="dashboard-header">
19
+ <h1>Dashboard</h1>
20
+
21
+ <button onClick={handleLogout} className="btn-logout">
22
+ Logout
23
+ </button>
24
+ </div>
25
+
26
+ <p className="dashboard-content">Protected dashboard content</p>
27
+ </div>
28
+ </AuthGuard>
29
+ );
30
+ }
@@ -0,0 +1,13 @@
1
+ import "../styles/globals.scss";
2
+
3
+ export default function RootLayout({
4
+ children,
5
+ }: {
6
+ children: React.ReactNode;
7
+ }) {
8
+ return (
9
+ <html lang="en">
10
+ <body>{children}</body>
11
+ </html>
12
+ );
13
+ }
@@ -0,0 +1,58 @@
1
+ .auth-wrapper {
2
+ min-height: 100vh;
3
+ display: flex;
4
+ align-items: center;
5
+ justify-content: center;
6
+ background: #eef1f5;
7
+ }
8
+
9
+ .auth-card {
10
+ width: 360px;
11
+ padding: 24px;
12
+ background: #fff;
13
+ border-radius: 6px;
14
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
15
+
16
+ h2 {
17
+ margin-bottom: 16px;
18
+ font-size: 1.25rem;
19
+ font-weight: 700;
20
+ color: #000;
21
+ }
22
+
23
+ input {
24
+ width: 100%;
25
+ padding: 10px;
26
+ margin-bottom: 12px;
27
+ border: 1px solid #d1d5db;
28
+ border-radius: 4px;
29
+ }
30
+
31
+ button {
32
+ width: 100%;
33
+ padding: 10px;
34
+ background: #2563eb;
35
+ color: #fff;
36
+ border: none;
37
+ border-radius: 4px;
38
+ cursor: pointer;
39
+ font-weight: 600;
40
+
41
+ &:hover {
42
+ background: #1d4ed8;
43
+ }
44
+ }
45
+
46
+ .auth-link {
47
+ display: block;
48
+ margin-top: 16px;
49
+ font-size: 0.875rem;
50
+ color: #2563eb;
51
+ cursor: pointer;
52
+ text-align: center;
53
+
54
+ &:hover {
55
+ text-decoration: underline;
56
+ }
57
+ }
58
+ }
@@ -0,0 +1,60 @@
1
+ "use client";
2
+
3
+ import { useRouter } from "next/navigation";
4
+ import { useState } from "react";
5
+ import VerifyOtpModal from "@/components/VerifyOtpModal";
6
+ import { loginApi } from "@/api/auth";
7
+ import "./Login.scss";
8
+
9
+ export default function LoginPage() {
10
+ const router = useRouter();
11
+ const [showOtp, setShowOtp] = useState(false);
12
+ const [refId, setRefId] = useState("");
13
+
14
+ const handleLogin = async () => {
15
+ // 🔴 simulate API response
16
+ // await loginApi({
17
+ // email: "",
18
+ // password: "",
19
+ // });
20
+
21
+ const requiresOtp = true;
22
+
23
+ if (requiresOtp) {
24
+ setRefId("ref-123");
25
+ setShowOtp(true);
26
+ return;
27
+ }
28
+
29
+ router.push("/dashboard");
30
+ };
31
+
32
+ return (
33
+ <>
34
+ <div className="auth-wrapper">
35
+ <div className="auth-card">
36
+ <h2>Login</h2>
37
+
38
+ <input placeholder="Email" />
39
+ <input placeholder="Password" type="password" />
40
+
41
+ <button onClick={handleLogin}>Login</button>
42
+
43
+ <p className="auth-link" onClick={() => router.push("/signup")}>
44
+ Don’t have an account? Signup
45
+ </p>
46
+ </div>
47
+ </div>
48
+
49
+ <VerifyOtpModal
50
+ isOpen={showOtp}
51
+ refId={refId}
52
+ onClose={() => setShowOtp(false)}
53
+ onSuccess={(token) => {
54
+ localStorage.setItem("token", token);
55
+ router.push("/dashboard");
56
+ }}
57
+ />
58
+ </>
59
+ );
60
+ }
@@ -0,0 +1,5 @@
1
+ import { redirect } from "next/navigation";
2
+
3
+ export default function Home() {
4
+ redirect("/login");
5
+ }
@@ -0,0 +1,58 @@
1
+ .auth-wrapper {
2
+ min-height: 100vh;
3
+ display: flex;
4
+ align-items: center;
5
+ justify-content: center;
6
+ background: #eef1f5;
7
+ }
8
+
9
+ .auth-card {
10
+ width: 360px;
11
+ padding: 24px;
12
+ background: #fff;
13
+ border-radius: 6px;
14
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
15
+
16
+ h2 {
17
+ margin-bottom: 16px;
18
+ font-size: 1.25rem;
19
+ font-weight: 700;
20
+ color: #000;
21
+ }
22
+
23
+ input {
24
+ width: 100%;
25
+ padding: 10px;
26
+ margin-bottom: 12px;
27
+ border: 1px solid #d1d5db;
28
+ border-radius: 4px;
29
+ }
30
+
31
+ button {
32
+ width: 100%;
33
+ padding: 10px;
34
+ background: #2563eb;
35
+ color: #fff;
36
+ border: none;
37
+ border-radius: 4px;
38
+ cursor: pointer;
39
+ font-weight: 600;
40
+
41
+ &:hover {
42
+ background: #1d4ed8;
43
+ }
44
+ }
45
+
46
+ .auth-link {
47
+ display: block;
48
+ margin-top: 16px;
49
+ font-size: 0.875rem;
50
+ color: #2563eb;
51
+ cursor: pointer;
52
+ text-align: center;
53
+
54
+ &:hover {
55
+ text-decoration: underline;
56
+ }
57
+ }
58
+ }
@@ -0,0 +1,45 @@
1
+ "use client";
2
+
3
+ import { useRouter } from "next/navigation";
4
+ import { useState } from "react";
5
+ import VerifyOtpModal from "@/components/VerifyOtpModal";
6
+ import "./Signup.scss";
7
+
8
+ export default function SignupPage() {
9
+ const router = useRouter();
10
+ const [showOtp, setShowOtp] = useState(false);
11
+ const [refId, setRefId] = useState("");
12
+
13
+ const handleSignup = async () => {
14
+ setRefId("ref-456");
15
+ setShowOtp(true);
16
+ };
17
+
18
+ return (
19
+ <>
20
+ <div className="auth-wrapper">
21
+ <div className="auth-card">
22
+ <h2>Signup</h2>
23
+
24
+ <input placeholder="Email" />
25
+ <input placeholder="Password" type="password" />
26
+
27
+ <button onClick={handleSignup}>Signup</button>
28
+ <p className="auth-link" onClick={() => router.push("/login")}>
29
+ Already have an Account? Login
30
+ </p>
31
+ </div>
32
+ </div>
33
+
34
+ <VerifyOtpModal
35
+ isOpen={showOtp}
36
+ refId={refId}
37
+ onClose={() => setShowOtp(false)}
38
+ onSuccess={(token) => {
39
+ localStorage.setItem("token", token);
40
+ router.push("/dashboard");
41
+ }}
42
+ />
43
+ </>
44
+ );
45
+ }
@@ -0,0 +1,35 @@
1
+ "use client";
2
+
3
+ import { useEffect, useState } from "react";
4
+ import { useRouter } from "next/navigation";
5
+
6
+ interface AuthGuardProps {
7
+ children: React.ReactNode;
8
+ }
9
+
10
+ export default function AuthGuard({ children }: AuthGuardProps) {
11
+ const router = useRouter();
12
+ const [checking, setChecking] = useState(true);
13
+
14
+ useEffect(() => {
15
+ const token = localStorage.getItem("token");
16
+
17
+ if (!token) {
18
+ router.replace("/login");
19
+ return;
20
+ }
21
+
22
+ setChecking(false);
23
+ }, [router]);
24
+
25
+ // Prevent flicker
26
+ if (checking) {
27
+ return (
28
+ <div className="min-h-screen flex items-center justify-center">
29
+ <p className="text-gray-600">Checking authentication...</p>
30
+ </div>
31
+ );
32
+ }
33
+
34
+ return <>{children}</>;
35
+ }
@@ -0,0 +1,66 @@
1
+ .modal-overlay {
2
+ position: fixed;
3
+ inset: 0;
4
+ z-index: 50;
5
+ display: flex;
6
+ align-items: center;
7
+ justify-content: center;
8
+ background: rgba(0, 0, 0, 0.5);
9
+ }
10
+
11
+ .modal-content {
12
+ background: #fff;
13
+ width: 360px;
14
+ padding: 24px;
15
+ border-radius: 6px;
16
+ box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1);
17
+
18
+ h2 {
19
+ font-size: 1.25rem;
20
+ font-weight: 700;
21
+ margin-bottom: 16px;
22
+ color: #000;
23
+ }
24
+
25
+ .modal-input {
26
+ width: 100%;
27
+ padding: 10px;
28
+ margin-bottom: 16px;
29
+ border: 1px solid #d1d5db;
30
+ border-radius: 4px;
31
+ color: #000;
32
+ }
33
+
34
+ .modal-actions {
35
+ display: flex;
36
+ justify-content: flex-end;
37
+ gap: 8px;
38
+
39
+ button {
40
+ padding: 8px 16px;
41
+ border-radius: 4px;
42
+ font-weight: 500;
43
+ cursor: pointer;
44
+ }
45
+
46
+ .btn-cancel {
47
+ background: #fff;
48
+ border: 1px solid #d1d5db;
49
+ color: #000;
50
+
51
+ &:hover {
52
+ background: #f9fafb;
53
+ }
54
+ }
55
+
56
+ .btn-verify {
57
+ background: #059669;
58
+ border: none;
59
+ color: #fff;
60
+
61
+ &:hover {
62
+ background: #047857;
63
+ }
64
+ }
65
+ }
66
+ }
@@ -0,0 +1,57 @@
1
+ "use client";
2
+
3
+ import { axiosApi } from "@/api/axios";
4
+ import { useState } from "react";
5
+ import "./VerifyOtpModal.scss";
6
+
7
+ interface VerifyOtpModalProps {
8
+ isOpen: boolean;
9
+ refId: string;
10
+ onClose: () => void;
11
+ onSuccess: (token: string) => void;
12
+ }
13
+
14
+ export default function VerifyOtpModal({
15
+ isOpen,
16
+ refId,
17
+ onClose,
18
+ onSuccess,
19
+ }: VerifyOtpModalProps) {
20
+ const [otp, setOtp] = useState("");
21
+
22
+ if (!isOpen) return null;
23
+
24
+ const handleVerify = async () => {
25
+ // const res = await axiosApi.post("/auth/verify-otp", {
26
+ // refId,
27
+ // otp,
28
+ // });
29
+
30
+ onSuccess("dummy Token");
31
+ };
32
+
33
+ return (
34
+ <div className="modal-overlay">
35
+ <div className="modal-content">
36
+ <h2>Verify OTP</h2>
37
+
38
+ <input
39
+ className="modal-input"
40
+ placeholder="Enter OTP"
41
+ value={otp}
42
+ onChange={(e) => setOtp(e.target.value)}
43
+ />
44
+
45
+ <div className="modal-actions">
46
+ <button onClick={onClose} className="btn-cancel">
47
+ Cancel
48
+ </button>
49
+
50
+ <button onClick={handleVerify} className="btn-verify">
51
+ Verify
52
+ </button>
53
+ </div>
54
+ </div>
55
+ </div>
56
+ );
57
+ }
@@ -0,0 +1,10 @@
1
+ * {
2
+ box-sizing: border-box;
3
+ }
4
+
5
+ body {
6
+ margin: 0;
7
+ font-family: system-ui, -apple-system, BlinkMacSystemFont, sans-serif;
8
+ background: #f4f6f8;
9
+ color: #222;
10
+ }
@@ -0,0 +1,36 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2017",
4
+ "lib": ["dom", "dom.iterable", "esnext"],
5
+ "allowJs": true,
6
+ "skipLibCheck": true,
7
+ "strict": true,
8
+ "noEmit": true,
9
+ "esModuleInterop": true,
10
+ "module": "esnext",
11
+ "moduleResolution": "bundler",
12
+ "resolveJsonModule": true,
13
+ "isolatedModules": true,
14
+ "jsx": "react-jsx",
15
+ "incremental": true,
16
+ "plugins": [
17
+ {
18
+ "name": "next"
19
+ }
20
+ ],
21
+ "paths": {
22
+ "@/*": ["./src/*"]
23
+ },
24
+ "types": ["next", "react", "react-dom", "node"],
25
+ "typeRoots": ["./node_modules/@types"]
26
+ },
27
+ "include": [
28
+ "next-env.d.ts",
29
+ "**/*.ts",
30
+ "**/*.tsx",
31
+ ".next/types/**/*.ts",
32
+ ".next/dev/types/**/*.ts",
33
+ "**/*.mts"
34
+ ],
35
+ "exclude": ["node_modules"]
36
+ }