@@ -11,6 +11,9 @@ SEAFILE_PUBLIC_SHARE_TOKEN=your_seafile_public_share_token
|
|||||||
WIBU_UPLOAD_DIR=uploads
|
WIBU_UPLOAD_DIR=uploads
|
||||||
WIBU_DOWNLOAD_DIR=./download
|
WIBU_DOWNLOAD_DIR=./download
|
||||||
|
|
||||||
|
# WhatsApp Server Configuration
|
||||||
|
WA_SERVER_TOKEN=your_whatsapp_server_token
|
||||||
|
|
||||||
# Application Configuration
|
# Application Configuration
|
||||||
# IMPORTANT: For staging/production, set this to your actual domain
|
# IMPORTANT: For staging/production, set this to your actual domain
|
||||||
# Local development: NEXT_PUBLIC_BASE_URL=http://localhost:3000
|
# Local development: NEXT_PUBLIC_BASE_URL=http://localhost:3000
|
||||||
|
|||||||
32
src/app/api/auth/_lib/sendCodeOtp.ts
Normal file
32
src/app/api/auth/_lib/sendCodeOtp.ts
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
// app/api/auth/_lib/sendCodeOtp.ts
|
||||||
|
|
||||||
|
const sendCodeOtp = async ({
|
||||||
|
nomor,
|
||||||
|
codeOtp,
|
||||||
|
newMessage,
|
||||||
|
}: {
|
||||||
|
nomor: string;
|
||||||
|
codeOtp?: string | number;
|
||||||
|
newMessage?: string;
|
||||||
|
}) => {
|
||||||
|
const msg =
|
||||||
|
newMessage ||
|
||||||
|
`Website Desa Darmasaba - Kode ini bersifat RAHASIA dan JANGAN DI BAGIKAN KEPADA SIAPAPUN, termasuk anggota ataupun Admin lainnya.\n\n>> Kode OTP anda: ${codeOtp}.`;
|
||||||
|
const enCode = msg;
|
||||||
|
|
||||||
|
const res = await fetch(`https://otp.wibudev.com/api/wa/send-text`, {
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
Authorization: `Bearer ${process.env.WA_SERVER_TOKEN}`,
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
number: nomor,
|
||||||
|
text: enCode,
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
return res;
|
||||||
|
};
|
||||||
|
|
||||||
|
export { sendCodeOtp };
|
||||||
@@ -2,16 +2,10 @@
|
|||||||
import prisma from "@/lib/prisma";
|
import prisma from "@/lib/prisma";
|
||||||
import { NextResponse } from "next/server";
|
import { NextResponse } from "next/server";
|
||||||
import { randomOTP } from "../_lib/randomOTP";
|
import { randomOTP } from "../_lib/randomOTP";
|
||||||
|
import { sendCodeOtp } from "../_lib/sendCodeOtp";
|
||||||
import { cookies } from "next/headers";
|
import { cookies } from "next/headers";
|
||||||
|
|
||||||
export async function POST(req: Request) {
|
export async function POST(req: Request) {
|
||||||
if (req.method !== "POST") {
|
|
||||||
return NextResponse.json(
|
|
||||||
{ success: false, message: "Method Not Allowed" },
|
|
||||||
{ status: 405 }
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const { nomor } = await req.json();
|
const { nomor } = await req.json();
|
||||||
|
|
||||||
@@ -35,26 +29,33 @@ export async function POST(req: Request) {
|
|||||||
|
|
||||||
console.log(`🔑 DEBUG OTP [${nomor}]: ${codeOtp}`);
|
console.log(`🔑 DEBUG OTP [${nomor}]: ${codeOtp}`);
|
||||||
|
|
||||||
const waMessage = `Website Desa Darmasaba - Kode ini bersifat RAHASIA dan JANGAN DI BAGIKAN KEPADA SIAPAPUN, termasuk anggota ataupun Admin lainnya.\n\n>> Kode OTP anda: ${codeOtp}.`;
|
|
||||||
const waUrl = `https://wa.wibudev.com/code?nom=${encodeURIComponent(nomor)}&text=${encodeURIComponent(waMessage)}`;
|
|
||||||
|
|
||||||
console.log("🔍 Debug WA URL:", waUrl);
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const res = await fetch(waUrl);
|
const waResponse = await sendCodeOtp({
|
||||||
if (!res.ok) {
|
nomor,
|
||||||
console.error(`⚠️ WA Service HTTP Error: ${res.status} ${res.statusText}. Continuing since OTP is logged.`);
|
codeOtp,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!waResponse.ok) {
|
||||||
|
console.error(
|
||||||
|
`⚠️ WA Service HTTP Error: ${waResponse.status} ${waResponse.statusText}. Continuing since OTP is logged.`
|
||||||
|
);
|
||||||
console.log(`💡 Use this OTP to login: ${codeOtp}`);
|
console.log(`💡 Use this OTP to login: ${codeOtp}`);
|
||||||
} else {
|
} else {
|
||||||
const sendWa = await res.json();
|
const sendWa = await waResponse.json();
|
||||||
console.log("📱 WA Response:", sendWa);
|
console.log("📱 WA Response:", sendWa);
|
||||||
|
|
||||||
if (sendWa.status !== "success") {
|
if (sendWa.status !== "success") {
|
||||||
console.error("⚠️ WA Service Logic Error:", sendWa);
|
console.error("⚠️ WA Service Logic Error:", sendWa);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (waError: unknown) {
|
} catch (waError: unknown) {
|
||||||
const errorMessage = waError instanceof Error ? waError.message : String(waError);
|
const errorMessage =
|
||||||
console.error("⚠️ WA Connection Exception. Continuing since OTP is logged.", errorMessage);
|
waError instanceof Error ? waError.message : String(waError);
|
||||||
|
|
||||||
|
console.error(
|
||||||
|
"⚠️ WA Connection Exception. Continuing since OTP is logged.",
|
||||||
|
errorMessage
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const createOtpId = await prisma.kodeOtp.create({
|
const createOtpId = await prisma.kodeOtp.create({
|
||||||
@@ -62,12 +63,12 @@ export async function POST(req: Request) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const cookieStore = await cookies();
|
const cookieStore = await cookies();
|
||||||
cookieStore.set('auth_flow', 'login', {
|
cookieStore.set("auth_flow", "login", {
|
||||||
httpOnly: true,
|
httpOnly: true,
|
||||||
secure: process.env.NODE_ENV === 'production',
|
secure: process.env.NODE_ENV === "production",
|
||||||
sameSite: 'lax',
|
sameSite: "lax",
|
||||||
maxAge: 60 * 5, // 5 menit
|
maxAge: 60 * 5,
|
||||||
path: '/'
|
path: "/",
|
||||||
});
|
});
|
||||||
|
|
||||||
return NextResponse.json({
|
return NextResponse.json({
|
||||||
@@ -85,6 +86,7 @@ export async function POST(req: Request) {
|
|||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("❌ Error Login:", error);
|
console.error("❌ Error Login:", error);
|
||||||
|
|
||||||
return NextResponse.json(
|
return NextResponse.json(
|
||||||
{ success: false, message: "Terjadi kesalahan saat login" },
|
{ success: false, message: "Terjadi kesalahan saat login" },
|
||||||
{ status: 500 }
|
{ status: 500 }
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { Paper, Title, Progress, Stack, Text, Group, Box } from '@mantine/core'
|
import { Paper, Title, Progress, Stack, Text, Group, Box, type MantineColor } from '@mantine/core'
|
||||||
import { IconArrowUpRight, IconArrowDownRight } from '@tabler/icons-react'
|
import { IconArrowUpRight, IconArrowDownRight } from '@tabler/icons-react'
|
||||||
import { APBDes, APBDesItem } from '../types/apbdes'
|
import { APBDes, APBDesItem } from '../types/apbdes'
|
||||||
|
|
||||||
@@ -106,7 +106,7 @@ function Summary({ title, data, icon }: SummaryProps) {
|
|||||||
|
|
||||||
<Text
|
<Text
|
||||||
fz="xs"
|
fz="xs"
|
||||||
c={statusMessage.color}
|
c={statusMessage.color as MantineColor}
|
||||||
fw={600}
|
fw={600}
|
||||||
style={{
|
style={{
|
||||||
backgroundColor: `var(--mantine-color-${statusMessage.color}-0)`,
|
backgroundColor: `var(--mantine-color-${statusMessage.color}-0)`,
|
||||||
|
|||||||
Reference in New Issue
Block a user