Skip to content

Commit

Permalink
fixed admin
Browse files Browse the repository at this point in the history
  • Loading branch information
tanmay4l authored and tanmay4l committed Jul 14, 2024
1 parent 984cb3f commit 2c0e3d4
Show file tree
Hide file tree
Showing 10 changed files with 178 additions and 21 deletions.
24 changes: 23 additions & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
"lunr": "^2.3.9",
"next": "^14.2.3",
"next-auth": "^4.24.7",
"next-connect": "^1.0.0",
"next-sitemap": "^4.0.9",
"nextjs-google-analytics": "^2.3.3",
"prisma": "^5.14.0",
Expand Down
18 changes: 18 additions & 0 deletions pages/admin/ middleware/auth.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// middleware/auth.ts

import { NextApiRequest, NextApiResponse } from "next";
import { NextHandler } from "next-connect";

export function isAuthenticated(
req: NextApiRequest,
res: NextApiResponse,
next: NextHandler
) {
const session = req.cookies.session;

if (session === "admin") {
next();
} else {
res.status(401).json({ message: "Unauthorized" });
}
}
23 changes: 17 additions & 6 deletions pages/admin/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,23 @@ const LoginPage: React.FC = () => {
const [password, setPassword] = useState("");
const [error, setError] = useState("");

const handleLogin = () => {
if (username === "admin" && password === "password") {
// Replace with secure authentication
router.push("/admin/therapist-list");
} else {
setError("Invalid username or password");
const handleLogin = async () => {
try {
const response = await fetch("/api/auth/login", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({ username, password }),
});

if (response.ok) {
router.push("/admin/therapist-list");
} else {
setError("Invalid username or password");
}
} catch (error) {
setError("An error occurred. Please try again.");
}
};

Expand Down
49 changes: 39 additions & 10 deletions pages/admin/therapist-list.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
/* eslint-disable react-hooks/exhaustive-deps */
// pages/admin/therapist-list.tsx

import { useEffect, useState } from "react";
import { useRouter } from "next/router";
import { useAuth } from "./utils/auth";

interface Therapist {
id: string;
Expand All @@ -24,12 +27,18 @@ interface Therapist {
}

const AdminTherapistListPage: React.FC = () => {
useAuth();
const router = useRouter();
const [therapistsList, setTherapistsList] = useState<Therapist[]>([]);
const [error, setError] = useState<string | null>(null);

const fetchTherapists = async () => {
try {
const response = await fetch("/api/therapists");
if (response.status === 401) {
router.push("/admin"); // Redirect to login if unauthorized
return;
}
if (!response.ok) {
throw new Error("Failed to fetch therapists");
}
Expand All @@ -46,20 +55,24 @@ const AdminTherapistListPage: React.FC = () => {
fetchTherapists();
}, []);

const toggleVerificationStatus = async (therapistId: string) => {
const updateVerificationStatus = async (
therapistId: string,
isVerified: boolean
) => {
try {
const response = await fetch(`/api/therapists/${therapistId}`, {
method: "PATCH",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({ isVerified }),
});
if (!response.ok) {
throw new Error("Failed to toggle verification status");
throw new Error("Failed to update verification status");
}
await fetchTherapists(); // Refresh therapists list after toggle
await fetchTherapists(); // Refresh therapists list after update
} catch (error) {
console.error("Error toggling verification status:", error);
console.error("Error updating verification status:", error);
setError("Failed to update therapist status. Please try again.");
}
};
Expand Down Expand Up @@ -91,12 +104,28 @@ const AdminTherapistListPage: React.FC = () => {
{therapist.isVerified ? "Yes" : "No"}
</span>
</p>
<button
className="bg-blue-500 hover:bg-blue-600 text-white font-bold py-2 px-4 rounded mt-2"
onClick={() => toggleVerificationStatus(therapist.id)}
>
Toggle Verification
</button>
<div className="mt-2">
<button
className={`mr-2 px-4 py-2 rounded ${
therapist.isVerified
? "bg-green-500 text-white"
: "bg-gray-300 text-gray-700"
}`}
onClick={() => updateVerificationStatus(therapist.id, true)}
>
Verify
</button>
<button
className={`px-4 py-2 rounded ${
!therapist.isVerified
? "bg-red-500 text-white"
: "bg-gray-300 text-gray-700"
}`}
onClick={() => updateVerificationStatus(therapist.id, false)}
>
Unverify
</button>
</div>
</li>
))}
</ul>
Expand Down
18 changes: 18 additions & 0 deletions pages/admin/utils/auth.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// utils/auth.ts

import { useEffect } from "react";
import { useRouter } from "next/router";

export function useAuth() {
const router = useRouter();

useEffect(() => {
async function checkAuth() {
const response = await fetch("/api/auth/check");
if (!response.ok) {
router.push("/admin");
}
}
checkAuth();
}, [router]);
}
15 changes: 15 additions & 0 deletions pages/api/auth/check.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// pages/api/auth/check.ts

import { NextApiRequest, NextApiResponse } from "next";
import { isAuthenticated } from "../../admin/ middleware/auth";

export default function handler(req: NextApiRequest, res: NextApiResponse) {
if (req.method === "GET") {
isAuthenticated(req, res, () => {
res.status(200).json({ message: "Authenticated" });
});
} else {
res.setHeader("Allow", ["GET"]);
res.status(405).end(`Method ${req.method} Not Allowed`);
}
}
24 changes: 24 additions & 0 deletions pages/api/auth/login.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// pages/api/auth/login.ts

import { NextApiRequest, NextApiResponse } from "next";

export default function handler(req: NextApiRequest, res: NextApiResponse) {
if (req.method === "POST") {
const { username, password } = req.body;

// In a real application, you would check these credentials against a database
if (username === "admin" && password === "securepassword") {
// Set a secure, HTTP-only cookie
res.setHeader(
"Set-Cookie",
"session=admin; Path=/; HttpOnly; Secure; SameSite=Strict; Max-Age=3600"
);
res.status(200).json({ message: "Logged in successfully" });
} else {
res.status(401).json({ message: "Invalid credentials" });
}
} else {
res.setHeader("Allow", ["POST"]);
res.status(405).end(`Method ${req.method} Not Allowed`);
}
}
12 changes: 9 additions & 3 deletions pages/api/therapists/[therapistId].ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,20 +10,26 @@ export default async function handler(
const { therapistId } = req.query;

if (req.method === "PATCH") {
const { isVerified } = req.body;

if (typeof isVerified !== "boolean") {
return res.status(400).json({ error: "Invalid isVerified value" });
}

try {
const updatedTherapist = await prisma.therapist.update({
where: { id: String(therapistId) },
data: {
isVerified: true,
isVerified: isVerified,
},
include: {
specializations: true,
},
});
res.status(200).json(updatedTherapist);
} catch (error) {
console.error("Error toggling verification status:", error);
res.status(500).json({ error: "Failed to toggle verification status" });
console.error("Error updating verification status:", error);
res.status(500).json({ error: "Failed to update verification status" });
}
} else {
res.setHeader("Allow", ["PATCH"]);
Expand Down
15 changes: 14 additions & 1 deletion yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2158,7 +2158,7 @@
resolved "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz"
integrity sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==

"@tsconfig/node16@^1.0.2":
"@tsconfig/node16@^1.0.2", "@tsconfig/node16@^1.0.3":
version "1.0.3"
resolved "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.3.tgz"
integrity sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==
Expand Down Expand Up @@ -7311,6 +7311,14 @@ next-auth@^4.24.7:
preact-render-to-string "^5.1.19"
uuid "^8.3.2"

next-connect@^1.0.0:
version "1.0.0"
resolved "https://registry.npmjs.org/next-connect/-/next-connect-1.0.0.tgz"
integrity sha512-FeLURm9MdvzY1SDUGE74tk66mukSqL6MAzxajW7Gqh6DZKBZLrXmXnGWtHJZXkfvoi+V/DUe9Hhtfkl4+nTlYA==
dependencies:
"@tsconfig/node16" "^1.0.3"
regexparam "^2.0.1"

next-mdx-remote@^4.4.1:
version "4.4.1"
resolved "https://registry.npmjs.org/next-mdx-remote/-/next-mdx-remote-4.4.1.tgz"
Expand Down Expand Up @@ -8371,6 +8379,11 @@ regexp.prototype.flags@^1.4.3:
define-properties "^1.1.3"
functions-have-names "^1.2.2"

regexparam@^2.0.1:
version "2.0.2"
resolved "https://registry.npmjs.org/regexparam/-/regexparam-2.0.2.tgz"
integrity sha512-A1PeDEYMrkLrfyOwv2jwihXbo9qxdGD3atBYQA9JJgreAx8/7rC6IUkWOw2NQlOxLp2wL0ifQbh1HuidDfYA6w==

registry-auth-token@^4.0.0:
version "4.2.2"
resolved "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-4.2.2.tgz"
Expand Down

0 comments on commit 2c0e3d4

Please sign in to comment.