Compare commits
No commits in common. "b7d144bb66d86bb1cbbabe1660fbb82407a202a3" and "f047a9ec1c100b12476930ef7a16475abc03fc54" have entirely different histories.
b7d144bb66
...
f047a9ec1c
@ -1,3 +0,0 @@
|
||||
NEXT_PUBLIC_CHINT_TOKEN=lIywwAMdrOdsRxuWvRoekdxrPtmIPkxA
|
||||
DATABASE_URL="postgresql://postgres:root@localhost:5432/rooftop?schema=public"
|
||||
JWT_SECRET="secret_key"
|
2
.gitignore
vendored
2
.gitignore
vendored
@ -34,5 +34,3 @@ yarn-error.log*
|
||||
# typescript
|
||||
*.tsbuildinfo
|
||||
next-env.d.ts
|
||||
|
||||
.env
|
||||
|
@ -64,6 +64,34 @@ const InverterViewPage = (props: Props) => {
|
||||
</button>
|
||||
)}
|
||||
</Tab>
|
||||
<Tab as={Fragment}>
|
||||
{({ selected }) => (
|
||||
<button className={`${selected ? 'border-b !border-primary text-primary !outline-none' : ''} -mb-[1px] flex items-center border-transparent p-5 py-3 before:inline-block hover:border-b hover:!border-primary hover:text-primary`} >
|
||||
Event
|
||||
</button>
|
||||
)}
|
||||
</Tab>
|
||||
<Tab as={Fragment}>
|
||||
{({ selected }) => (
|
||||
<button className={`${selected ? 'border-b !border-primary text-primary !outline-none' : ''} -mb-[1px] flex items-center border-transparent p-5 py-3 before:inline-block hover:border-b hover:!border-primary hover:text-primary`} >
|
||||
Settings
|
||||
</button>
|
||||
)}
|
||||
</Tab>
|
||||
<Tab as={Fragment}>
|
||||
{({ selected }) => (
|
||||
<button className={`${selected ? 'border-b !border-primary text-primary !outline-none' : ''} -mb-[1px] flex items-center border-transparent p-5 py-3 before:inline-block hover:border-b hover:!border-primary hover:text-primary`} >
|
||||
Firmware
|
||||
</button>
|
||||
)}
|
||||
</Tab>
|
||||
<Tab as={Fragment}>
|
||||
{({ selected }) => (
|
||||
<button className={`${selected ? 'border-b !border-primary text-primary !outline-none' : ''} -mb-[1px] flex items-center border-transparent p-5 py-3 before:inline-block hover:border-b hover:!border-primary hover:text-primary`} >
|
||||
Data
|
||||
</button>
|
||||
)}
|
||||
</Tab>
|
||||
</Tab.List>
|
||||
<Tab.Panels>
|
||||
<Tab.Panel>
|
||||
@ -90,8 +118,9 @@ const InverterViewPage = (props: Props) => {
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
</Tab.Panel>
|
||||
<Tab.Panel>Chart</Tab.Panel>
|
||||
</Tab.Panels>
|
||||
</Tab.Group>
|
||||
)}
|
||||
|
@ -100,30 +100,12 @@ const Sidebar = () => {
|
||||
</li>
|
||||
|
||||
<li className="menu nav-item">
|
||||
<button type="button" className={`${currentMenu === 'sungrow' ? 'active' : ''} nav-link group w-full`} onClick={() => toggleMenu('sungrow')}>
|
||||
<Link href="#" className="nav-link group">
|
||||
<div className="flex items-center">
|
||||
<IconMenuComponents className="shrink-0 group-hover:!text-primary" />
|
||||
<span className="text-black ltr:pl-3 rtl:pr-3 dark:text-[#506690] dark:group-hover:text-white-dark">Sungrow</span>
|
||||
</div>
|
||||
|
||||
<div className={currentMenu !== 'component' ? '-rotate-90 rtl:rotate-90' : ''}>
|
||||
<IconCaretDown />
|
||||
</div>
|
||||
</button>
|
||||
|
||||
<AnimateHeight duration={300} height={currentMenu === 'sungrow' ? 'auto' : 0}>
|
||||
<ul className="sub-menu text-gray-500">
|
||||
<li>
|
||||
<Link href="/sungrow/plant">Plant</Link>
|
||||
</li>
|
||||
<li>
|
||||
<Link href="/sungrow/device">Device</Link>
|
||||
</li>
|
||||
<li>
|
||||
<Link href="/sungrow/maintenance">Maintenance</Link>
|
||||
</li>
|
||||
</ul>
|
||||
</AnimateHeight>
|
||||
</Link>
|
||||
</li>
|
||||
|
||||
<li className="menu nav-item">
|
||||
|
@ -1,20 +0,0 @@
|
||||
GET http://localhost:3005/api/auth/me
|
||||
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOiI2YmM2MGIzMC1hNzcyLTRiM2MtOTYwOC1jMjgyNmNhMjA2NjEiLCJlbWFpbCI6ImFzZEBhc2QuY29tIiwiaWF0IjoxNzQwNTUyMjE4LCJleHAiOjE3NDA1NTU4MTh9.n3rFlFbqKY-kg8YF6cuRkT_Kc6hsCqQQ87TJbkS8DAg
|
||||
|
||||
###
|
||||
POST http://localhost:3005/api/register
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"email": "asd@asd.com",
|
||||
"password":"123456"
|
||||
}
|
||||
|
||||
###
|
||||
POST http://localhost:3005/api/login
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"email": "asd@asd.com",
|
||||
"password":"123456"
|
||||
}
|
@ -1,19 +0,0 @@
|
||||
import { NextRequest, NextResponse } from "next/server";
|
||||
import jwt from "jsonwebtoken";
|
||||
|
||||
const SECRET_KEY = process.env.JWT_SECRET as string;
|
||||
|
||||
export function middleware(req: NextRequest) {
|
||||
const token = req.cookies.get("token")?.value;
|
||||
|
||||
if (!token) return NextResponse.redirect(new URL("/login", req.url));
|
||||
|
||||
try {
|
||||
jwt.verify(token, SECRET_KEY);
|
||||
return NextResponse.next();
|
||||
} catch (error) {
|
||||
return NextResponse.redirect(new URL("/login", req.url));
|
||||
}
|
||||
}
|
||||
|
||||
export const config = { matcher: ["/dashboard", "/profile"] };
|
893
package-lock.json
generated
893
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -11,7 +11,6 @@
|
||||
"dependencies": {
|
||||
"@emotion/react": "^11.10.6",
|
||||
"@headlessui/react": "^1.7.8",
|
||||
"@prisma/client": "^6.4.1",
|
||||
"@reduxjs/toolkit": "^1.9.1",
|
||||
"@tippyjs/react": "^4.2.6",
|
||||
"@types/node": "18.11.18",
|
||||
@ -19,12 +18,9 @@
|
||||
"@types/react-dom": "18.0.10",
|
||||
"apexcharts": "^4.5.0",
|
||||
"axios": "^1.7.9",
|
||||
"bcrypt": "^5.1.1",
|
||||
"cookie": "^1.0.2",
|
||||
"eslint": "8.32.0",
|
||||
"eslint-config-next": "13.1.2",
|
||||
"i18next": "^22.4.10",
|
||||
"jsonwebtoken": "^9.0.2",
|
||||
"next": "14.0.3",
|
||||
"ni18n": "^1.0.5",
|
||||
"react": "18.2.0",
|
||||
@ -35,6 +31,7 @@
|
||||
"react-perfect-scrollbar": "^1.5.8",
|
||||
"react-popper": "^2.3.0",
|
||||
"react-redux": "^8.1.3",
|
||||
"typescript": "4.9.4",
|
||||
"universal-cookie": "^6.1.1",
|
||||
"yup": "^0.32.11"
|
||||
},
|
||||
@ -47,7 +44,6 @@
|
||||
"postcss": "^8.4.35",
|
||||
"prettier": "^2.8.0",
|
||||
"prettier-plugin-tailwindcss": "^0.2.0",
|
||||
"tailwindcss": "^3.4.1",
|
||||
"typescript": "^5.7.3"
|
||||
"tailwindcss": "^3.4.1"
|
||||
}
|
||||
}
|
||||
|
@ -1,27 +0,0 @@
|
||||
import { NextApiRequest, NextApiResponse } from "next";
|
||||
import jwt from "jsonwebtoken";
|
||||
import { PrismaClient } from "@prisma/client";
|
||||
|
||||
const prisma = new PrismaClient();
|
||||
const SECRET_KEY = process.env.JWT_SECRET as string;
|
||||
|
||||
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||
const authHeader = req.headers.authorization;
|
||||
|
||||
if (!authHeader || !authHeader.startsWith("Bearer ")) {
|
||||
return res.status(401).json({ message: "Unauthorized" });
|
||||
}
|
||||
|
||||
const token = authHeader.split(" ")[1]; // Extract token
|
||||
|
||||
try {
|
||||
const decoded: any = jwt.verify(token, SECRET_KEY);
|
||||
const user = await prisma.user.findUnique({ where: { id: decoded.userId } });
|
||||
|
||||
if (!user) return res.status(401).json({ message: "User not found" });
|
||||
|
||||
res.json({ user });
|
||||
} catch (error) {
|
||||
res.status(401).json({ message: "Invalid token" });
|
||||
}
|
||||
}
|
@ -1,24 +0,0 @@
|
||||
import { NextApiRequest, NextApiResponse } from "next";
|
||||
import { PrismaClient } from "@prisma/client";
|
||||
import bcrypt from "bcrypt";
|
||||
import jwt from "jsonwebtoken";
|
||||
|
||||
const prisma = new PrismaClient();
|
||||
const SECRET_KEY = process.env.JWT_SECRET as string;
|
||||
|
||||
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||
if (req.method !== "POST") return res.status(405).json({ message: "Method not allowed" });
|
||||
|
||||
const { email, password } = req.body;
|
||||
|
||||
const user = await prisma.user.findUnique({ where: { email } });
|
||||
if (!user) return res.status(401).json({ message: "Invalid credentials" });
|
||||
|
||||
const isMatch = await bcrypt.compare(password, user.password);
|
||||
if (!isMatch) return res.status(401).json({ message: "Invalid credentials" });
|
||||
|
||||
const token = jwt.sign({ userId: user.id, email: user.email }, SECRET_KEY, { expiresIn: "1h" });
|
||||
|
||||
res.setHeader("Set-Cookie", `token=${token}; HttpOnly; Path=/; Secure`);
|
||||
res.json({ token });
|
||||
}
|
@ -1,21 +0,0 @@
|
||||
import { NextApiRequest, NextApiResponse } from "next";
|
||||
import { PrismaClient } from "@prisma/client";
|
||||
import bcrypt from "bcrypt";
|
||||
|
||||
const prisma = new PrismaClient();
|
||||
|
||||
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||
if (req.method !== "POST") return res.status(405).json({ message: "Method not allowed" });
|
||||
|
||||
const { email, password } = req.body;
|
||||
|
||||
const existingUser = await prisma.user.findUnique({ where: { email } });
|
||||
if (existingUser) return res.status(400).json({ message: "User already exists" });
|
||||
|
||||
const hashedPassword = await bcrypt.hash(password, 10);
|
||||
const user = await prisma.user.create({
|
||||
data: { email, password: hashedPassword },
|
||||
});
|
||||
|
||||
res.status(201).json({ message: "User registered", user });
|
||||
}
|
@ -1,12 +0,0 @@
|
||||
-- CreateTable
|
||||
CREATE TABLE "User" (
|
||||
"id" TEXT NOT NULL,
|
||||
"email" TEXT NOT NULL,
|
||||
"password" TEXT NOT NULL,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
|
||||
CONSTRAINT "User_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "User_email_key" ON "User"("email");
|
@ -1,3 +0,0 @@
|
||||
# Please do not edit this file manually
|
||||
# It should be added in your version-control system (e.g., Git)
|
||||
provider = "postgresql"
|
@ -1,22 +0,0 @@
|
||||
// This is your Prisma schema file,
|
||||
// learn more about it in the docs: https://pris.ly/d/prisma-schema
|
||||
|
||||
// Looking for ways to speed up your queries, or scale easily with your serverless or edge functions?
|
||||
// Try Prisma Accelerate: https://pris.ly/cli/accelerate-init
|
||||
|
||||
generator client {
|
||||
provider = "prisma-client-js"
|
||||
}
|
||||
|
||||
datasource db {
|
||||
provider = "postgresql"
|
||||
url = env("DATABASE_URL")
|
||||
}
|
||||
|
||||
|
||||
model User {
|
||||
id String @id @default(uuid())
|
||||
email String @unique
|
||||
password String
|
||||
createdAt DateTime @default(now())
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user