Deskripsi:
- Create validasi
- Create register
- create global prisma, color tune,dan global state
This commit is contained in:
2023-10-02 22:13:08 +08:00
parent 193dc27e9c
commit cf6aaf500e
32 changed files with 1094 additions and 97 deletions

View File

@@ -0,0 +1,20 @@
import { MyConsole } from "@/app/fun/my_console";
import prisma from "@/app/lib/prisma";
import { NextResponse } from "next/server";
export async function POST(req: Request) {
if (req.method === "POST") {
const body = await req.json();
MyConsole(body);
try {
await fetch(
`https://wa.wibudev.com/code?nom=${body.nomor}&text=${body.otp}`
);
return NextResponse.json({ body, status: 200, message: "Login Success" });
} catch (error) {
return NextResponse.json({ status: 500, message: "Server Error !!!" });
}
}
return NextResponse.json({ success: false });
}

View File

@@ -0,0 +1,12 @@
import { cookies } from "next/headers";
import { NextResponse } from "next/server";
export async function GET() {
cookies().set({
name: "ssn",
value: "",
maxAge: 0,
});
return NextResponse.json({ status: 200, message: "Logout" });
}

View File

@@ -0,0 +1,55 @@
import { sealData } from "iron-session";
import { MyConsole } from "@/app/fun/my_console";
import prisma from "@/app/lib/prisma";
import { data } from "autoprefixer";
import { NextResponse } from "next/server";
import { cookies } from "next/headers";
export async function POST(req: Request) {
if (req.method === "POST") {
const body = await req.json();
// MyConsole(body);
const cekUsername = await prisma.user.findUnique({
where: {
username: body.username,
},
});
MyConsole(cekUsername);
if (cekUsername)
return NextResponse.json({ status: 400, message: "Username sudah ada" });
const data = await prisma.user.create({
data: {
username: body.username,
nomor: body.nomor,
},
});
if (data) {
const seal = await sealData(
JSON.stringify({
id: data.id,
username: data.username,
}),
{
password: process.env.PWD as string,
}
);
cookies().set({
name: "ssn",
value: seal,
maxAge: 60 * 60 * 24 * 7,
});
return NextResponse.json({ status: 201});
}
return NextResponse.json({ success: true });
}
return NextResponse.json({ success: false });
}

View File

@@ -0,0 +1,52 @@
import { MyConsole } from "@/app/fun/my_console";
import prisma from "@/app/lib/prisma";
import { NextResponse } from "next/server";
import { cookies } from "next/headers";
import { sealData, unsealData } from "iron-session";
export async function POST(req: Request) {
if (req.method === "POST") {
const body = await req.json();
MyConsole(body);
const data = await prisma.user.findUnique({
where: {
nomor: body.nomor,
},
select: {
id: true,
nomor: true,
username: true,
active: true,
},
});
if (!data) return NextResponse.json({ status: 404 });
if (data) {
const res = await sealData(
JSON.stringify({
id: data.id,
username: data.username,
}),
{
password: process.env.PWD as string,
}
);
const un = await unsealData(res, { password: process.env.PWD as string });
// console.log(JSON.stringify(un), "route validasi")
cookies().set({
name: "ssn",
value: res,
maxAge: 60 * 60 * 24 * 7,
});
return NextResponse.json({ status: 200, data });
}
return NextResponse.json({ success: true });
}
return NextResponse.json({ success: false });
}

View File

@@ -0,0 +1,27 @@
import prisma from "@/app/lib/prisma";
import userRole from "../../../bin/seeder/user_role.json";
import { NextResponse } from "next/server";
export async function GET(req: Request) {
const dev = new URL(req.url).searchParams.get("dev");
if (dev === "DEV-HIPMI") {
for (let i of userRole) {
const data = await prisma.masterUserRole.upsert({
where: {
id: i.id.toString(),
},
update: {
id: i.id.toString(),
name: i.name,
},
create: {
id: i.id.toString(),
name: i.name,
},
});
}
return NextResponse.json({ success: true });
}
return NextResponse.json({ success: false });
}

View File

@@ -0,0 +1,12 @@
import { unsealData } from 'iron-session';
import { cookies } from "next/headers";
import { NextResponse } from "next/server";
export async function GET() {
const c = cookies().get("ssn");
const data = JSON.parse(
await unsealData(c?.value as string, {password: process.env.PWD as string})
)
return NextResponse.json(data);
}

View File

@@ -1,9 +1,14 @@
import { Login } from "@/app_modules/auth";
import { cookies } from "next/headers";
export default function Page() {
const c = cookies().getAll();
const tkn = c;
return (
<>
<Login />
{JSON.stringify(tkn)}
<Login />;
</>
);
}

View File

@@ -0,0 +1,5 @@
import { Register } from "@/app_modules/auth";
export default function Page() {
return <Register />;
}

View File

@@ -1,12 +1,25 @@
import { SplashScreen } from "@/app_modules/auth";
import { useShallowEffect } from "@mantine/hooks";
import { cookies } from "next/headers";
import { useRouter } from "next/navigation";
import { useState } from "react";
import {unsealData} from "iron-session"
export default async function PageSplash() {
const c = cookies().get("ssn");
const tkn = !c
? null
: JSON.parse(
await unsealData(c.value as string, {
password: process.env.PWD as string,
})
);
export default function PageSplash() {
return (
<>
<SplashScreen />
<SplashScreen data={tkn} />
</>
);
}

View File

@@ -0,0 +1,5 @@
import { Validasi } from "@/app_modules/auth";
export default function Page() {
return <Validasi />;
}

View File

@@ -1,8 +1,24 @@
import { HomeView } from "@/app_modules/home";
import { cookies } from "next/headers";
import { unsealData } from "iron-session";
import _ from "lodash";
import { redirect } from "next/navigation";
export default async function Page() {
const c = cookies().get("ssn");
const tkn = !c
? null
: JSON.parse(
await unsealData(c.value as string, {
password: process.env.PWD as string,
})
);
if (!c?.value) return redirect("/dev/auth/login");
export default function Page() {
return (
<>
{/* {JSON.stringify(tkn)} */}
<HomeView />
</>
);

View File

@@ -0,0 +1,8 @@
import { useState } from "react";
export function MyConsole(value: any) {
const onData = true;
if (onData) {
console.log(value);
}
}

View File

@@ -0,0 +1,4 @@
export function randomOTP(){
const random = Math.floor(Math.random() * (9000 - 1000 )) + 1000
return random;
}

9
src/app/lib/api.ts Normal file
View File

@@ -0,0 +1,9 @@
export const ApiHipmi = {
// Get one token
get_token: "/api/user/get-token",
// Auth
login: "/api/auth/login",
validasi: "/api/auth/validasi",
register: "/api/auth/register",
logout: "/api/auth/logout",
};

17
src/app/lib/prisma.ts Normal file
View File

@@ -0,0 +1,17 @@
import { PrismaClient } from '@prisma/client'
const prismaClientSingleton = () => {
return new PrismaClient()
}
type PrismaClientSingleton = ReturnType<typeof prismaClientSingleton>
const globalForPrisma = globalThis as unknown as {
prisma: PrismaClientSingleton | undefined
}
const prisma = globalForPrisma.prisma ?? prismaClientSingleton()
export default prisma
if (process.env.NODE_ENV !== 'production') globalForPrisma.prisma = prisma

10
src/app/lib/warna.ts Normal file
View File

@@ -0,0 +1,10 @@
export const Warna = {
hijau_tua: "#297646",
hijau_muda: "#3da18d",
hijau_cerah: "#42c748",
kuning: "#fed630",
biru: "#3175b1",
merah: "#DE2E2D",
hitam: "#121517",
};

View File

@@ -3,5 +3,5 @@ import { redirect } from "next/navigation";
import PageSplash from "./dev/auth/splash/page";
export default async function Page() {
return <PageSplash />;
return <PageSplash/>
}

View File

@@ -1,4 +1,7 @@
import SplashScreen from "./splash/view";
import Login from "./login/view";
import Validasi from "./validasi/view";
import Register from "./register/view";
import Logout from "./logout/view";
export {SplashScreen, Login}
export { SplashScreen, Login, Validasi, Register, Logout };

View File

@@ -1,11 +1,98 @@
"use client"
import { Center, Title } from "@mantine/core";
"use client";
export default function Login(){
return <>
<Center h={"100vh"}>
<Title>Login</Title>
</Center>
import { MyConsole } from "@/app/fun/my_console";
import { randomOTP } from "@/app/fun/rondom_otp";
import { ApiHipmi } from "@/app/lib/api";
import { Warna } from "@/app/lib/warna";
import { Button, Center, Flex, Stack, TextInput, Title } from "@mantine/core";
import { getHotkeyHandler, useHotkeys } from "@mantine/hooks";
import { useRouter } from "next/navigation";
import { useState } from "react";
import toast from "react-simple-toasts";
import { useAtom } from "jotai";
import { gs_otp, gs_nomor } from "../state/state";
import { IconCircleLetterH } from "@tabler/icons-react";
export default function Login() {
const router = useRouter();
const [nomor, setNomor] = useState("");
const [inputNumber, setInputNumber] = useAtom(gs_nomor);
const [code, setCode] = useAtom(gs_otp);
const onLogin = async () => {
const body = {
nomor: nomor,
otp: randomOTP(),
};
if (body.nomor.length < 10) return toast("Nomor minimal 10 digit");
if (body.nomor.length > 13) return toast("Nomor maximal 13 digit");
await fetch(ApiHipmi.login, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(body),
})
.then((res) => res.json())
.then((val) => {
MyConsole(val);
if (val.status == 200) {
toast(val.message);
setCode(val.body.otp);
setInputNumber(val.body.nomor);
router.push("/dev/auth/validasi");
} else {
toast(val.message);
}
});
};
return (
<>
<pre>
{JSON.stringify(inputNumber, null, 2)}
<br />
{JSON.stringify(code)}
</pre>
<Flex
h={"100vh"}
direction={"column"}
justify={"center"}
align={"center"}
gap={"lg"}
>
<>
<IconCircleLetterH size={150} />
<Title>Login</Title>
<TextInput
label="Phone Number"
w={250}
type="number"
placeholder="62 xx xxx xxx xxx"
// value={nomor}
onChange={(val) => {
setNomor(val.target.value);
}}
/>
<Button
h={30}
radius={50}
compact
bg={Warna.hijau_muda}
color={"green"}
onClick={() => {
onLogin();
}}
>
Login
</Button>
</>
</Flex>
</>
}
);
}

View File

@@ -0,0 +1,36 @@
"use client";
import { MyConsole } from "@/app/fun/my_console";
import { ApiHipmi } from "@/app/lib/api";
import { Button } from "@mantine/core";
import { useRouter } from "next/navigation";
import { useAtom } from "jotai";
import { gs_nomor, gs_otp } from "../state/state";
export default function Logout() {
const router = useRouter();
const [nomor, setnomor] = useAtom(gs_nomor);
const [code, setCode] = useAtom(gs_otp);
const onLogout = async () => {
// MyConsole("keluar");
await fetch(ApiHipmi.logout)
.then((res) => res.json())
.then((val) => {
if (val.status == 200) {
setnomor(null);
setCode(null);
return router.push("/dev/auth/login");
}
});
};
return (
<>
<Button compact onClick={() => onLogout()}>
Logout
</Button>
</>
);
}

View File

@@ -0,0 +1,87 @@
"use client";
import { Warna } from "@/app/lib/warna";
import { Flex, Title, TextInput, Button, Text } from "@mantine/core";
import { IconCircleLetterH } from "@tabler/icons-react";
import { gs_nomor } from "../state/state";
import { useAtom } from "jotai";
import { useState } from "react";
import { MyConsole } from "@/app/fun/my_console";
import toast from "react-simple-toasts";
import { ApiHipmi } from "@/app/lib/api";
import { useRouter } from "next/navigation";
export default function Register() {
const route = useRouter();
const [nomor, setNomor] = useAtom(gs_nomor);
const [value, setValue] = useState("");
const onRegister = async () => {
MyConsole(value);
const body = {
username: value,
nomor: nomor,
};
if (!body) return toast("Lengkapi username");
if (body.username.length < 5) return toast("Username minimal 5 karakter");
await fetch(ApiHipmi.register, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(body),
})
.then((res) => res.json())
.then((val) => {
MyConsole(val);
if (val.status == 201) {
toast("Pendaftaran Berhasil");
return route.push("/dev/home");
} else {
return toast(val.message);
}
});
};
return (
<>
<Flex
align={"center"}
justify={"center"}
direction={"column"}
gap={50}
h={"100vh"}
>
<Title order={4}>Registrasi</Title>
<IconCircleLetterH size={150} />
<Flex direction={"column"} gap={"xl"} align={"center"}>
<Flex direction={"column"}>
<TextInput
label="Username"
placeholder="Username"
onChange={(val) => {
setValue(val.target.value);
}}
/>
<Text>Nomor : {nomor}</Text>
</Flex>
<Button
radius={50}
bg={Warna.biru}
color="cyan"
compact
onClick={() => {
onRegister();
}}
>
Register
</Button>
</Flex>
</Flex>
</>
);
}

View File

@@ -5,12 +5,12 @@ import { useShallowEffect } from "@mantine/hooks";
import { useRouter } from "next/navigation";
import { useState } from "react";
export default function SplashScreen() {
export default function SplashScreen({ data }: { data: any }) {
const router = useRouter();
const [val, setVal] = useState(false);
useShallowEffect(() => {
if (!val) {
if (!data) {
setTimeout(() => {
return router.push("/dev/auth/login");
}, 2000);

View File

@@ -0,0 +1,4 @@
import { atomWithStorage } from 'jotai/utils'
export const gs_nomor = atomWithStorage<any | null>("nomorHp", null)
export const gs_otp = atomWithStorage<any | null>("code_otp", null)

View File

@@ -0,0 +1,103 @@
"use client";
import { useAtom } from "jotai";
import {
Button,
Center,
Flex,
PinInput,
Stack,
Text,
Title,
} from "@mantine/core";
import { gs_nomor, gs_otp } from "../state/state";
import { Warna } from "@/app/lib/warna";
import { useState } from "react";
import { MyConsole } from "@/app/fun/my_console";
import { IconCircleLetterH } from "@tabler/icons-react";
import toast from "react-simple-toasts";
import { ApiHipmi } from "@/app/lib/api";
import { useRouter } from "next/navigation";
export default function Validasi() {
const router = useRouter();
const [nomor, setnomor] = useAtom(gs_nomor);
const [code, setCode] = useAtom(gs_otp);
const [inputCode, setInputOtp] = useState("");
const onValid = async () => {
// MyConsole(inputCode)
const body = {
nomor: nomor,
otp: code,
};
if (!inputCode) return toast("Lengkapi Kode");
if (body.otp != inputCode) return toast("Kode Salah");
await fetch(ApiHipmi.validasi, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(body),
})
.then((res) => res.json())
.then((val) => {
MyConsole(val);
if (val.status == 200) {
toast("Berhasil Login");
return router.push("/dev/home");
} else {
toast("Silahkan Registrasi");
return router.push("/dev/auth/register");
}
});
};
return (
<>
{JSON.stringify(nomor)}
{JSON.stringify(code)}
<Flex
align={"center"}
justify={"center"}
direction={"column"}
gap={50}
h={"100vh"}
>
<Title order={4}>Validasi Kode OTP</Title>
<IconCircleLetterH size={150} />
<Flex direction={"column"} gap={"xl"} align={"center"}>
<Flex
justify={"center"}
gap={1}
direction={"column"}
align={"center"}
>
<Text>Enter the 6-digit OTP , weve just sent</Text>
<Text>to {nomor}</Text>
</Flex>
<PinInput
onChange={(val) => {
setInputOtp(val);
}}
/>
<Button
compact
radius={50}
bg={Warna.hijau_tua}
color="green"
onClick={() => {
onValid();
}}
>
Submit
</Button>
</Flex>
</Flex>
</>
);
}

View File

@@ -1,11 +1,30 @@
"use client";
import { Title } from "@mantine/core";
import { Text, Title } from "@mantine/core";
import { Logout } from "../auth";
import { useState } from "react";
import { ApiHipmi } from "@/app/lib/api";
import { useShallowEffect } from "@mantine/hooks";
export default function HomeView() {
const [token, setToken] = useState<any | null>(null);
useShallowEffect(() => {
userToken();
}, []);
async function userToken() {
await fetch(ApiHipmi.get_token)
.then((res) => res.json())
.then((val) => setToken(val));
}
return (
<>
{/* <pre>{JSON.stringify(token, null, 2)}</pre> */}
<Title>Home</Title>
<Text>Welcome, {token?.username}</Text>
<Logout />
</>
);
}

View File

@@ -0,0 +1,18 @@
[
{
"id": 1,
"name": "User",
"user": 1
},
{
"id": 2,
"name": "Admin",
"user": 2
},
{
"id": 3,
"name": "Super Admin",
"user": 3
}
]