Resolve rejected Apple:

Add:
public/aset/logo/hiconnect.png
        src/app/(support)/
        src/app/api/helper/

Fix:

- bun.lock
- package.json
- src/app/api/auth/login/route.ts
- src/app/api/auth/resend/route.ts
- src/middleware.tsx

### No issue
This commit is contained in:
2025-11-17 17:41:08 +08:00
parent 14fbd1a6dd
commit b6e5755942
10 changed files with 476 additions and 13 deletions

View File

@@ -0,0 +1,133 @@
"use client";
import {
Box,
Button,
Grid,
Paper,
Stack,
Text,
TextInput,
Title,
} from "@mantine/core";
import { notifications } from "@mantine/notifications";
import Image from "next/image";
import { useParams } from "next/navigation";
import { useEffect, useState } from "react";
export default function DeleteAccount() {
const [phoneNumber, setPhoneNumber] = useState<string>("");
const [data, setData] = useState({
description: "",
});
useEffect(() => {
// Hanya di client, setelah mount
const urlParams = new URLSearchParams(window.location.search);
const phone = urlParams.get("phone");
if (phone) {
setPhoneNumber(phone);
}
}, []);
const handlerSubmit = async () => {
if (!phoneNumber || !data.description) {
return notifications.show({
title: "Error",
message: "Please fill in description & phone number",
color: "red",
});
}
try {
const response = await fetch("/api/helper/delete-account", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
number: phoneNumber,
description: data.description,
}),
});
const result = await response.json();
if (result.success) {
notifications.show({
title: "Success",
message: "Account will process to delete",
color: "green",
});
setData({
description: "",
});
}
if (!result.success) {
notifications.show({
title: "Error",
message: result.error,
color: "red",
});
}
} catch (error) {
console.log(error);
}
};
return (
<Box
style={{
display: "flex",
justifyContent: "center",
alignItems: "center",
height: "100vh",
backgroundColor: "#f5f5f5",
padding: "20px",
}}
>
<Paper withBorder shadow="md" p={"lg"}>
<Stack align="center">
<Image
src="/aset/logo/hiconnect.png"
alt="logo"
width={100}
height={100}
/>
<Title>Delete Account</Title>
<Stack spacing={0} align="center">
<Text align="center" fw={"lighter"}>
To delete your account with phone number{" "}
{phoneNumber ? `+${phoneNumber}` : ""}.
</Text>
<Text align="center" fw={"lighter"}>
Type your message with subject Delete Account
</Text>
</Stack>
<Grid w={"100%"}>
<Grid.Col span={8}>
<TextInput
value={data.description}
w={"100%"}
placeholder="Type your subject here"
onChange={(e) => {
setData({
...data,
description: e.target.value,
});
}}
/>
</Grid.Col>
<Grid.Col span={4}>
<Button onClick={handlerSubmit} w={"100%"}>
Submit
</Button>
</Grid.Col>
</Grid>
</Stack>
</Paper>
</Box>
);
}

View File

@@ -0,0 +1,189 @@
"use client";
import {
Box,
Button,
Group,
Paper,
SimpleGrid,
Stack,
Text,
Textarea,
TextInput,
Title
} from "@mantine/core";
import { notifications } from "@mantine/notifications";
import { IconBrandGmail, IconLocation } from "@tabler/icons-react";
import Image from "next/image";
import { useState } from "react";
export default function SupportCenter() {
const [data, setData] = useState({
email: "",
title: "",
description: "",
});
const handleSubmit = async () => {
if (!data.email || !data.title || !data.description) {
return notifications.show({
title: "Error",
color: "red",
message: "Please fill in all fields.",
});
}
const response = await fetch("/api/helper/support-center", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(data),
});
const result = await response.json();
if (result.success) {
notifications.show({
title: "Success",
color: "green",
message: "Message sent successfully.",
});
setData({
email: "",
title: "",
description: "",
});
}
if (!result.success) {
notifications.show({
title: "Error",
color: "red",
message: result.error,
});
}
};
return (
<Box
style={{
display: "flex",
justifyContent: "center",
alignItems: "center",
height: "100vh",
backgroundColor: "#f5f5f5",
padding: "20px",
}}
>
<Stack spacing={"lg"}>
<Stack align="center">
<Stack spacing={"xs"} align="center">
<Group>
<Image
src="/aset/logo/hiconnect.png"
alt="logo"
width={50}
height={50}
/>
<Title>Support Center</Title>
</Group>
<Text align="center">
Send us a message and we'll get back to you as soon as possible.
</Text>
</Stack>
</Stack>
<Paper style={{ padding: "20px" }} withBorder shadow="md">
<SimpleGrid
cols={2}
// verticalSpacing={50}
spacing={50}
breakpoints={[
{ maxWidth: "md", cols: 2, spacing: "md" },
{ maxWidth: "sm", cols: 2, spacing: "sm" },
{ maxWidth: "xs", cols: 1, spacing: "sm" },
]}
>
<Stack>
<Stack spacing={0}>
<Title order={2}>Contact Information</Title>
<Text>For general inquiries, please contact us !</Text>
</Stack>
<Group>
<IconBrandGmail
size={40}
style={{
backgroundColor: "gray",
borderRadius: "10%",
padding: "5px",
}}
/>
<Stack spacing={0}>
<Text fw={"bold"}>Email</Text>
<Text>bip.baliinteraktifperkasa@gmail.com</Text>
</Stack>
</Group>
<Group>
<IconLocation
size={40}
style={{
backgroundColor: "gray",
borderRadius: "10%",
padding: "5px",
}}
/>
<Stack spacing={0}>
<Text fw={"bold"}>Location</Text>
<Text>Bali, Indonesia</Text>
</Stack>
</Group>
</Stack>
<Stack>
<Title order={2}>Send a Message</Title>
<TextInput
label="Email"
placeholder="Email"
onChange={(e) => {
setData({
...data,
email: e.target.value,
});
}}
/>
<TextInput
label="Title"
placeholder="Title"
onChange={(e) => {
setData({
...data,
title: e.target.value,
});
}}
/>
<Textarea
label="Description"
placeholder="Description"
onChange={(e) => {
setData({
...data,
description: e.target.value,
});
}}
/>
<Button color="yellow" onClick={() => handleSubmit()}>
Submit
</Button>
</Stack>
</SimpleGrid>
</Paper>
</Stack>
</Box>
);
}

View File

@@ -29,11 +29,11 @@ export async function POST(req: Request) {
{ status: 400 }
);
const msg = `HIPMI - Kode ini bersifat RAHASIA dan JANGAN DI BAGIKAN KEPADA SIAPAPUN, termasuk anggota ataupun pengurus HIPMI lainnya.\n\n>> Kode OTP anda: ${codeOtp}.`;
const encodedMsg = encodeURIComponent(msg);
const msg = `HIPMI%20-%20Kode%20ini%20bersifat%20RAHASIA%20dan%20JANGAN%20DI%20BAGIKAN%20KEPADA%20SIAPAPUN%2C%20termasuk%20anggota%20ataupun%20pengurus%20HIPMI%20lainnya.%5Cn%5Cn%3E%3E%20Kode%20OTP%20anda%3A%20${codeOtp}.`;
// const encodedMsg = encodeURIComponent(msg);
const res = await fetch(
`https://wa.wibudev.com/code?nom=${nomor}&text=${encodedMsg}`,
`https://wa.wibudev.com/code?nom=${nomor}&text=${msg}`,
{ cache: "no-cache" }
);

View File

@@ -16,11 +16,10 @@ export async function POST(req: Request) {
const body = await req.json();
const { nomor } = body;
const msg = `HIPMI - Kode ini bersifat RAHASIA dan JANGAN DI BAGIKAN KEPADA SIAPAPUN, termasuk anggota ataupun pengurus HIPMI lainnya.\n\n>> Kode OTP anda: ${codeOtp}.`;
const encodedMsg = encodeURIComponent(msg);
const msg = `HIPMI%20-%20Kode%20ini%20bersifat%20RAHASIA%20dan%20JANGAN%20DI%20BAGIKAN%20KEPADA%20SIAPAPUN%2C%20termasuk%20anggota%20ataupun%20pengurus%20HIPMI%20lainnya.%5Cn%5Cn%3E%3E%20Kode%20OTP%20anda%3A%20${codeOtp}.`;
const res = await fetch(
`https://wa.wibudev.com/code?nom=${nomor}&text=${encodedMsg}`,
`https://wa.wibudev.com/code?nom=${nomor}&text=${msg}`,
{ cache: "no-cache" }
);

View File

@@ -0,0 +1,41 @@
import { NextResponse } from "next/server";
import { Resend } from "resend";
const resend = new Resend(process.env.RESEND_APIKEY);
export async function POST(req: Request) {
const body = await req.json();
try {
const { number } = body;
if (!number) {
return NextResponse.json({
success: false,
error: "Missing required fields.",
});
}
const data = await resend.emails.send({
from: `+${number} <onboarding@resend.dev>`,
to: ["bagasbanuna02@gmail.com"], // ganti sesuai email kamu
// cc: ["bip.baliinteraktifperkasa@gmail.com"],
subject: "Delete Account",
html: `
<div style="font-family: Arial, sans-serif; font-size: 16px; color: #333;">
<h3>New Message to Delete Account</h3>
<p><strong>User with phone number +${number}</strong></p>
<p><strong>Description: Want to delete account !!</strong></p>
</div>
`,
});
return NextResponse.json({ success: true, data });
} catch (error) {
console.error(error);
return NextResponse.json({
success: false,
error: (error as Error).message,
});
}
}

View File

@@ -0,0 +1,41 @@
import { NextResponse } from "next/server";
import { Resend } from "resend";
const resend = new Resend(process.env.RESEND_APIKEY);
export async function POST(req: Request) {
const body = await req.json();
try {
const { email, title, description } = body;
if (!email || !title || !description) {
return NextResponse.json({
success: false,
error: "Missing required fields.",
});
}
const data = await resend.emails.send({
from: `${email} <onboarding@resend.dev>`,
to: ["bip.baliinteraktifperkasa@gmail.com"], // ganti sesuai email kamu
subject: title,
html: `
<div style="font-family: Arial, sans-serif; font-size: 16px; color: #333;">
<h3>New Message Received</h3>
<p><strong>Email:</strong> ${email}</p>
<p><strong>Title:</strong> ${title}</p>
<p><strong>Description:</strong><br/>${description.replace(/\n/g, "<br/>")}</p>
</div>
`,
});
return NextResponse.json({ success: true, data });
} catch (error) {
console.error(error);
return NextResponse.json({
success: false,
error: (error as Error).message,
});
}
}