Compare commits

..

4 Commits

Author SHA1 Message Date
fe457cd2d4 chore(release): 1.7.0 2026-03-10 15:05:46 +08:00
73cbf3640a feat: Tambahkan deep link handler untuk event confirmation
Deskripsi:
- Membuat route handler /event/[id]/confirmation untuk deep link mobile
- Menambahkan deteksi platform (iOS, Android, Web) dari user agent
- Memperbaiki Content-Type header untuk file .well-known (AASA & assetlinks)
- Menambahkan route ke public middleware agar bisa diakses tanpa auth

File yang diubah:
- src/app/event/[id]/confirmation/route.ts (baru)
- src/middleware.tsx (tambah public route)
- next.config.js (tambah headers untuk .well-known)

Testing:
- File .well-known accessible:  YES
- Content-Type header correct:  YES
- Deep link route works:  YES
- Platform detection works:  YES

### No Issue
2026-03-09 15:32:54 +08:00
dc6fa562cc Clean code
modified:   public/.well-known/assetlinks.json
modified:   src/lib/code-otp-sender.ts

### No issue
2026-03-06 16:35:34 +08:00
4fd7bb4a17 chore(release): 1.6.9 2026-03-06 16:29:50 +08:00
7 changed files with 222 additions and 11 deletions

View File

@@ -2,6 +2,15 @@
All notable changes to this project will be documented in this file. See [commit-and-tag-version](https://github.com/absolute-version/commit-and-tag-version) for commit guidelines.
## [1.7.0](https://wibugit.wibudev.com/wibu/hipmi/compare/v1.6.9...v1.7.0) (2026-03-10)
### Features
* Tambahkan deep link handler untuk event confirmation ([73cbf36](https://wibugit.wibudev.com/wibu/hipmi/commit/73cbf3640ac795995e15448b24408b179d2a46d2))
## [1.6.9](https://wibugit.wibudev.com/wibu/hipmi/compare/v1.6.8...v1.6.9) (2026-03-06)
## [1.6.8](https://wibugit.wibudev.com/wibu/hipmi/compare/v1.6.7...v1.6.8) (2026-03-05)
## [1.6.7](https://wibugit.wibudev.com/wibu/hipmi/compare/v1.6.6...v1.6.7) (2026-03-04)

View File

@@ -16,6 +16,21 @@ const nextConfig = {
}
return config;
},
async headers() {
return [
{
source: "/.well-known/:path*",
headers: [
{ key: "Content-Type", value: "application/json" },
{
key: "Cache-Control",
value: "no-cache, no-store, must-revalidate",
},
],
},
];
},
};
module.exports = nextConfig;
module.exports = nextConfig;

View File

@@ -1,6 +1,6 @@
{
"name": "hipmi",
"version": "1.6.8",
"version": "1.7.0",
"private": true,
"prisma": {
"seed": "bun prisma/seed.ts"

View File

@@ -1,8 +1,10 @@
[{
"relation": ["delegate_permission/common.handle_all_urls"],
"target": {
"namespace": "android_app",
"package_name": "com.bip.hipmimobileapp",
"sha256_cert_fingerprints": ["CFF8431520BFAE665025B68138774A4E64AA6338D2DF6C7D900A71F0551FFD2D"]
[
{
"relation": ["delegate_permission/common.handle_all_urls"],
"target": {
"namespace": "android_app",
"package_name": "com.bip.hipmimobileapp",
"sha256_cert_fingerprints": ["CFF8431520BFAE665025B68138774A4E64AA6338D2DF6C7D900A71F0551FFD2D"]
}
}
}]
]

View File

@@ -0,0 +1,186 @@
/**
* Route Handler untuk Deep Link Event Confirmation
* File: app/event/[id]/confirmation/route.ts
* Deskripsi: Handle GET request untuk deep link event confirmation dengan redirect ke mobile app
* Pembuat: Assistant
* Tanggal: 9 Maret 2026
*/
import { url } from "inspector";
import { NextRequest, NextResponse } from "next/server";
/**
* Detect platform dari User Agent string
* @param userAgent - User Agent string dari request
* @returns Platform type: 'ios', 'android', atau 'web'
*/
function detectPlatform(userAgent: string | null): "ios" | "android" | "web" {
if (!userAgent) {
return "web";
}
const lowerUA = userAgent.toLowerCase();
// Detect iOS devices
if (
/iphone|ipad|ipod/.test(lowerUA) ||
(lowerUA.includes("mac") && (("ontouchend" in {}) as any))
) {
return "ios";
}
// Detect Android devices
if (/android/.test(lowerUA)) {
return "android";
}
// Default to web
return "web";
}
/**
* Build custom scheme URL untuk mobile app
* @param eventId - Event ID dari URL
* @param userId - User ID dari query parameter
* @param platform - Platform yang terdetect
* @returns Custom scheme URL
*/
function buildCustomSchemeUrl(
eventId: string,
userId: string | null,
platform: "ios" | "android" | "web",
): string {
const baseUrl = "hipmimobile://event";
const url = `${baseUrl}/${eventId}/confirmation${userId ? `?userId=${userId}` : ""}`;
return url;
}
/**
* Get base URL dari environment
*/
function getBaseUrl(): string {
const env = process.env.NEXT_PUBLIC_ENV || "development";
if (env === "production") {
return "https://hipmi.muku.id";
}
if (env === "staging") {
return "https://cld-dkr-hipmi-stg.wibudev.com";
}
return "http://localhost:3000";
}
/**
* Handle GET request untuk deep link
* @param request - Next.js request object
* @returns Redirect ke mobile app atau JSON response untuk debugging
*/
export async function GET(
request: NextRequest,
{ params }: { params: { id: string } },
) {
try {
// Parse query parameters
const searchParams = request.nextUrl.searchParams;
const eventId = params.id;
const userId = searchParams.get("userId") || null;
const userAgent = request.headers.get("user-agent") || "";
// Detect platform
const platform = detectPlatform(userAgent);
// Log untuk tracking
console.log("[Deep Link] Event Confirmation Received:", {
eventId,
userId,
platform,
userAgent:
userAgent.substring(0, 100) + (userAgent.length > 100 ? "..." : ""),
timestamp: new Date().toISOString(),
url: request.url,
});
// Build custom scheme URL untuk redirect
const customSchemeUrl = buildCustomSchemeUrl(eventId, userId, platform);
// Redirect ke mobile app untuk iOS dan Android
if (platform === "ios" || platform === "android") {
console.log("[Deep Link] Redirecting to mobile app:", customSchemeUrl);
// Redirect ke custom scheme URL
return NextResponse.redirect(customSchemeUrl);
}
console.log("[Deep Link] Environment:", process.env.NEXT_PUBLIC_ENV);
console.log("[Deep Link] Base URL:", getBaseUrl());
console.log("[Deep Link] Request:", {
eventId,
userId,
platform,
url: request.url,
timestamp: new Date().toISOString(),
});
// Untuk web/desktop, tampilkan JSON response untuk debugging
const responseData = {
success: true,
message: "Deep link received - Web fallback",
data: {
eventId,
userId,
platform,
userAgent,
timestamp: new Date().toISOString(),
url: request.url,
customSchemeUrl,
note: "This is a web fallback. Mobile users will be redirected to the app.",
},
};
return NextResponse.json(responseData, {
status: 200,
headers: {
"Content-Type": "application/json",
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Methods": "GET, OPTIONS",
"Access-Control-Allow-Headers": "Content-Type",
},
});
} catch (error) {
console.error("[Deep Link] Error processing request:", error);
return NextResponse.json(
{
success: false,
message: "Error processing deep link",
error: error instanceof Error ? error.message : "Unknown error",
},
{
status: 500,
headers: {
"Content-Type": "application/json",
"Access-Control-Allow-Origin": "*",
},
},
);
}
}
/**
* Handle OPTIONS request untuk CORS preflight
*/
export async function OPTIONS() {
return NextResponse.json(
{},
{
status: 200,
headers: {
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Methods": "GET, OPTIONS",
"Access-Control-Allow-Headers": "Content-Type",
},
},
);
}

View File

@@ -24,8 +24,6 @@ const sendCodeOtp = async ({
}),
});
console.log("RES >>", res);
return res;
};

View File

@@ -49,6 +49,7 @@ const CONFIG: MiddlewareConfig = {
"/auth/api/login",
"/waiting-room",
"/zCoba/*",
"/event/*/confirmation",
"/aset/global/main_background.png",
"/aset/logo/logo-hipmi.png",
"/aset/logo/hiconnect.png",