diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 01b4438..4a37f8a 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -37,7 +37,7 @@ - + diff --git a/app.config.js b/app.config.js index f3ca81a..e93d76c 100644 --- a/app.config.js +++ b/app.config.js @@ -1,6 +1,17 @@ // app.config.js require("dotenv").config(); +// const isDev = process.env.NODE_ENV === "development"; +// const isStaging = process.env.NEXT_PUBLIC_ENV === "staging"; +// const isProd = process.env.NEXT_PUBLIC_ENV === "production"; + +// Domain berdasarkan environment +// const domain = isDev +// ? "localhost:3000" +// : isStaging +// ? "cld-dkr-hipmi-stg.wibudev.com" +// : "hipmi.muku.id"; // Production domain + export default { name: "HIPMI Badung Connect", slug: "hipmi-mobile", @@ -20,8 +31,10 @@ export default { NSLocationWhenInUseUsageDescription: "Aplikasi membutuhkan akses lokasi untuk menampilkan peta.", }, - associatedDomains: ["applinks:cld-dkr-staging-hipmi.wibudev.com"], - buildNumber: "3", + associatedDomains: [ + "applinks:cld-dkr-hipmi-stg.wibudev.com", + ], + buildNumber: "4", }, android: { @@ -41,7 +54,7 @@ export default { data: [ { scheme: "https", - host: "cld-dkr-staging-hipmi.wibudev.com", + host: "cld-dkr-hipmi-stg.wibudev.com", pathPrefix: "/", }, ], diff --git a/app/(application)/(user)/event/[id]/confirmation.tsx b/app/(application)/(user)/event/[id]/confirmation.tsx index 7151fbf..3f70f92 100644 --- a/app/(application)/(user)/event/[id]/confirmation.tsx +++ b/app/(application)/(user)/event/[id]/confirmation.tsx @@ -9,7 +9,7 @@ import { TextCustom, ViewWrapper, } from "@/components"; -import { AccentColor, MainColor } from "@/constants/color-palet"; +import { MainColor } from "@/constants/color-palet"; import { useAuth } from "@/hooks/use-auth"; import { apiEventConfirmationAction, @@ -60,7 +60,7 @@ export default function UserEventConfirmation() { useFocusEffect( useCallback(() => { checkTokenAndDataParticipants() || console.log("Token is null"); - }, [token, id, user?.id]) + }, [token, id, user?.id]), ); const checkTokenAndDataParticipants = async () => { @@ -113,7 +113,7 @@ export default function UserEventConfirmation() { confirmationStart, confirmationEnd, null, - "[]" + "[]", ); // --- [4] Status waktu event (untuk pesan UI) --- @@ -218,9 +218,14 @@ export default function UserEventConfirmation() { if (isWithinConfirmationWindow) { if (konfirmasi === false) { return ( - - - + // + // + // + ); } return ( @@ -261,17 +266,15 @@ export default function UserEventConfirmation() { ( - // - // router.navigate("/(application)/(user)/event/create") - // } - // /> - // ), - }} + headerLeft: () => ( + router.navigate("/")} + /> + ), + }} /> {handlerReturn()} @@ -497,7 +500,6 @@ const UserNotParticipan_And_DuringEvent = ({ ); }; - // 🟡 ZONA ACARA BERLANGSUN // User sudah terdaftar & Event sedang berlangsung & user harus konfirmasi const UserParticipan_And_DuringEvent = ({ diff --git a/app/(application)/admin/_layout.tsx b/app/(application)/admin/_layout.tsx index 3e4da82..6749e9b 100644 --- a/app/(application)/admin/_layout.tsx +++ b/app/(application)/admin/_layout.tsx @@ -17,6 +17,7 @@ import { ICON_SIZE_XLARGE, } from "@/constants/constans-value"; import { useAuth } from "@/hooks/use-auth"; +import { useNotificationStore } from "@/hooks/use-notification-store"; import AdminNotificationBell from "@/screens/Admin/AdminNotificationBell"; import { adminListMenu, diff --git a/context/AuthContext.tsx b/context/AuthContext.tsx index 8dd2818..a03f240 100644 --- a/context/AuthContext.tsx +++ b/context/AuthContext.tsx @@ -22,7 +22,7 @@ type AuthContextType = { isAdmin: boolean; isUserActive: boolean; loginWithNomor: (nomor: string) => Promise; - validateOtp: (nomor: string) => Promise; + validateOtp: (nomor: string, code: string) => Promise; logout: () => Promise; registerUser: (userData: { username: string; @@ -97,10 +97,10 @@ export const AuthProvider = ({ children }: { children: React.ReactNode }) => { }; // --- 2. Validasi OTP & cek user --- - const validateOtp = async (nomor: string) => { + const validateOtp = async (nomor: string, code: string) => { try { setIsLoading(true); - const response = await apiValidationCode({ nomor: nomor }); + const response = await apiValidationCode({ nomor: nomor, code: code }); const { token } = response; console.log("[RESPONSE VALIDASI OTP]", JSON.stringify(response, null, 2)); diff --git a/docs/QR_CODE_TESTING.md b/docs/QR_CODE_TESTING.md new file mode 100644 index 0000000..57b86ad --- /dev/null +++ b/docs/QR_CODE_TESTING.md @@ -0,0 +1,253 @@ +# QR Code Testing Guide - HIPMI Mobile + +## 📋 Overview + +Dokumentasi ini menjelaskan cara testing QR Code untuk Universal Links (iOS) dan App Links (Android) pada fitur Event Confirmation. + +## 🔧 Update Terbaru + +File `screens/Admin/Event/EventDetailQRCode.tsx` telah diupdate dengan fitur: +- **Toggle Button**: Switch antara HTTPS link dan Custom Scheme link +- **HTTPS Link**: Untuk testing Universal Links/App Links dengan domain staging +- **Custom Scheme**: Untuk testing langsung tanpa domain verification + +## 🎯 Cara Testing QR Code + +### Opsi 1: HTTPS Link (Recommended untuk Production) + +**Gunakan tombol "HTTPS"** di component QR Code. + +**Link yang di-generate:** +``` +https://cld-dkr-staging-hipmi.wibudev.com/event/{id}/confirmation?userId={userId} +``` + +**Cara kerja:** +1. User scan QR code dengan kamera +2. Safari/Chrome terbuka dengan URL HTTPS +3. iOS/Android mendeteksi domain terverifikasi +4. App terbuka otomatis dan menuju halaman confirmation + +**Prerequisites:** +- ✅ File `apple-app-site-association` harus accessible di Next.js server +- ✅ File `assetlinks.json` harus accessible di Next.js server +- ✅ Domain harus terverifikasi di app.config.js +- ✅ App harus di-build ulang setelah perubahan domain + +**Testing Steps:** +```bash +# 1. Pastikan .well-known files accessible +curl https://cld-dkr-staging-hipmi.wibudev.com/.well-known/apple-app-site-association +curl https://cld-dkr-staging-hipmi.wibudev.com/.well-known/assetlinks.json + +# 2. Rebuild app +bunx expo prebuild --clean + +# 3. Run di physical device (bukan simulator) +bun run android # untuk Android +bun run ios # untuk iOS +``` + +### Opsi 2: Custom Scheme Link (Untuk Development/Testing Cepat) + +**Gunakan tombol "Custom Scheme"** di component QR Code. + +**Link yang di-generate:** +``` +hipmimobile://event/{id}/confirmation?userId={userId} +``` + +**Cara kerja:** +1. User scan QR code dengan kamera +2. iOS: Pilih "Open in HIPMI Badung Connect" +3. Android: Langsung buka app +4. App terbuka dan menuju halaman confirmation + +**Keuntungan:** +- ✅ Tidak butuh domain verification +- ✅ Bisa testing langsung tanpa rebuild +- ✅ Cocok untuk development + +**Kekurangan:** +- ❌ Tidak bisa dibuka dari web browser +- ❌ Tidak support universal linking dari website lain + +## 📱 Testing Checklist + +### iOS (Universal Links) + +- [ ] File `apple-app-site-association` valid dan accessible +- [ ] Domain terdaftar di `app.config.js` → `ios.associatedDomains` +- [ ] Bundle ID match dengan konfigurasi +- [ ] Team ID benar di apple-app-site-association +- [ ] Test dengan **physical device** (simulator tidak support) +- [ ] Test dengan **Safari** (bukan Chrome) +- [ ] Long press link → ada opsi "Open" + +**Debug iOS:** +```bash +# Cek apple-app-site-association +curl -I https://cld-dkr-staging-hipmi.wibudev.com/.well-known/apple-app-site-association + +# Harus return: +# Content-Type: application/json +# HTTP/2 200 +``` + +### Android (App Links) + +- [ ] File `assetlinks.json` valid dan accessible +- [ ] SHA256 fingerprint benar +- [ ] Package name match +- [ ] Intent filters terdaftar di app.config.js +- [ ] Test dengan **physical device** +- [ ] Test dengan **Chrome** + +**Debug Android:** +```bash +# Dapatkan SHA256 fingerprint +cd android +./gradlew signingReport + +# Cek assetlinks.json +curl https://cld-dkr-staging-hipmi.wibudev.com/.well-known/assetlinks.json +``` + +## 🐛 Troubleshooting + +### Problem: QR Scan Terbuka di Safari, Tidak Balik ke App + +**Penyebab:** +- Domain belum terverifikasi untuk Universal Links/App Links +- File `.well-known` tidak accessible atau invalid +- App belum di-rebuild setelah perubahan domain + +**Solusi:** +1. Pastikan file `.well-known` accessible: + ```bash + curl https://cld-dkr-staging-hipmi.wibudev.com/.well-known/apple-app-site-association + ``` + +2. Rebuild app: + ```bash + bunx expo prebuild --clean + bun run android # atau bun run ios + ``` + +3. Gunakan **Custom Scheme** untuk testing cepat + +### Problem: Link Tidak Membuka App Sama Sekali + +**Cek:** +1. App sudah terinstall di device +2. Link format benar (hipmimobile:// atau https://) +3. Route handler sudah ada di app folder + +**Test manual:** +```bash +# iOS Simulator +xcrun simctl openurl booted "hipmimobile://event/123/confirmation?userId=456" + +# Android Emulator +adb shell am start -W -a android.intent.action.VIEW \ + -d "hipmimobile://event/123/confirmation?userId=456" \ + com.bip.hipmimobileapp +``` + +### Problem: "Cannot GET /event/..." di Next.js + +**Penyebab:** +Route `/event/[id]/confirmation` tidak ada di Next.js server + +**Solusi:** +Pastikan Next.js project punya file: +``` +public/.well-known/apple-app-site-association +public/.well-known/assetlinks.json +``` + +Dan API route untuk handle: +``` +pages/api/event/[id]/confirmation.ts +``` + +## 📄 File Configuration + +### app.config.js - iOS +```javascript +ios: { + associatedDomains: ["applinks:cld-dkr-staging-hipmi.wibudev.com"], +} +``` + +### app.config.js - Android +```javascript +android: { + intentFilters: [ + { + action: "VIEW", + autoVerify: true, + data: [ + { + scheme: "https", + host: "cld-dkr-staging-hipmi.wibudev.com", + pathPrefix: "/", + }, + ], + category: ["BROWSABLE", "DEFAULT"], + }, + ], +} +``` + +### apple-app-site-association (Next.js) +```json +{ + "applinks": { + "apps": [], + "details": [ + { + "appID": "TEAM_ID.com.anonymous.hipmi-mobile", + "paths": ["/event/*/confirmation"] + } + ] + } +} +``` + +### assetlinks.json (Next.js) +```json +[ + { + "relation": ["delegate_permission/common.handle_all_urls"], + "target": { + "namespace": "android_app", + "package_name": "com.bip.hipmimobileapp", + "sha256_cert_fingerprints": ["YOUR_SHA256_FINGERPRINT"] + } + } +] +``` + +## 🎓 Best Practices + +1. **Development**: Gunakan Custom Scheme untuk testing cepat +2. **Staging**: Gunakan HTTPS link dengan domain staging +3. **Production**: Gunakan HTTPS link dengan domain production +4. **Testing**: Selalu test di physical device, bukan simulator +5. **Debugging**: Enable logging di confirmation page untuk track deep link + +## 🔗 Related Files + +- `screens/Admin/Event/EventDetailQRCode.tsx` - QR Code generator +- `app/(application)/(user)/event/[id]/confirmation.tsx` - Confirmation page +- `app.config.js` - App configuration +- `service/api-config.ts` - API configuration (DEEP_LINK_URL) + +## 📞 Support + +Jika masih ada masalah: +1. Cek logs di console +2. Test manual dengan adb/xcrun +3. Verify .well-known files dengan curl +4. Pastikan app rebuild setelah perubahan config diff --git a/ios/HIPMIBadungConnect.xcodeproj/project.pbxproj b/ios/HIPMIBadungConnect.xcodeproj/project.pbxproj index d7d08be..86618eb 100644 --- a/ios/HIPMIBadungConnect.xcodeproj/project.pbxproj +++ b/ios/HIPMIBadungConnect.xcodeproj/project.pbxproj @@ -183,6 +183,12 @@ FB0CB57BF4D74C1D87C2036C /* Remove signature files (Xcode workaround) */, 14B3DE54EE4049AEB1EADA6B /* Remove signature files (Xcode workaround) */, B4CF5E09DBB44A4FB9CB91B9 /* Remove signature files (Xcode workaround) */, + C894BD25C8224984AAD73398 /* Remove signature files (Xcode workaround) */, + F0C608193824414E93E23BC7 /* Remove signature files (Xcode workaround) */, + A3E2EDBCFB514A6487E28BEC /* Remove signature files (Xcode workaround) */, + 0D62979D96BF4B99AB9FBE7C /* Remove signature files (Xcode workaround) */, + 49B80EF12BE8476C86534CEA /* Remove signature files (Xcode workaround) */, + 6218417B3C954EFF9B5F4853 /* Remove signature files (Xcode workaround) */, ); buildRules = ( ); @@ -995,6 +1001,108 @@ rm -rf \"$CONFIGURATION_BUILD_DIR/MapLibre.xcframework-ios.signature\"; "; }; + C894BD25C8224984AAD73398 /* Remove signature files (Xcode workaround) */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + name = "Remove signature files (Xcode workaround)"; + inputPaths = ( + ); + outputPaths = ( + ); + shellPath = /bin/sh; + shellScript = " + echo \"Remove signature files (Xcode workaround)\"; + rm -rf \"$CONFIGURATION_BUILD_DIR/MapLibre.xcframework-ios.signature\"; + "; + }; + F0C608193824414E93E23BC7 /* Remove signature files (Xcode workaround) */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + name = "Remove signature files (Xcode workaround)"; + inputPaths = ( + ); + outputPaths = ( + ); + shellPath = /bin/sh; + shellScript = " + echo \"Remove signature files (Xcode workaround)\"; + rm -rf \"$CONFIGURATION_BUILD_DIR/MapLibre.xcframework-ios.signature\"; + "; + }; + A3E2EDBCFB514A6487E28BEC /* Remove signature files (Xcode workaround) */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + name = "Remove signature files (Xcode workaround)"; + inputPaths = ( + ); + outputPaths = ( + ); + shellPath = /bin/sh; + shellScript = " + echo \"Remove signature files (Xcode workaround)\"; + rm -rf \"$CONFIGURATION_BUILD_DIR/MapLibre.xcframework-ios.signature\"; + "; + }; + 0D62979D96BF4B99AB9FBE7C /* Remove signature files (Xcode workaround) */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + name = "Remove signature files (Xcode workaround)"; + inputPaths = ( + ); + outputPaths = ( + ); + shellPath = /bin/sh; + shellScript = " + echo \"Remove signature files (Xcode workaround)\"; + rm -rf \"$CONFIGURATION_BUILD_DIR/MapLibre.xcframework-ios.signature\"; + "; + }; + 49B80EF12BE8476C86534CEA /* Remove signature files (Xcode workaround) */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + name = "Remove signature files (Xcode workaround)"; + inputPaths = ( + ); + outputPaths = ( + ); + shellPath = /bin/sh; + shellScript = " + echo \"Remove signature files (Xcode workaround)\"; + rm -rf \"$CONFIGURATION_BUILD_DIR/MapLibre.xcframework-ios.signature\"; + "; + }; + 6218417B3C954EFF9B5F4853 /* Remove signature files (Xcode workaround) */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + name = "Remove signature files (Xcode workaround)"; + inputPaths = ( + ); + outputPaths = ( + ); + shellPath = /bin/sh; + shellScript = " + echo \"Remove signature files (Xcode workaround)\"; + rm -rf \"$CONFIGURATION_BUILD_DIR/MapLibre.xcframework-ios.signature\"; + "; + }; /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ diff --git a/ios/HIPMIBadungConnect/HIPMIBadungConnect.entitlements b/ios/HIPMIBadungConnect/HIPMIBadungConnect.entitlements index 7a318c4..f44aa40 100644 --- a/ios/HIPMIBadungConnect/HIPMIBadungConnect.entitlements +++ b/ios/HIPMIBadungConnect/HIPMIBadungConnect.entitlements @@ -6,7 +6,7 @@ development com.apple.developer.associated-domains - applinks:cld-dkr-staging-hipmi.wibudev.com + applinks:cld-dkr-hipmi-stg.wibudev.com \ No newline at end of file diff --git a/ios/HIPMIBadungConnect/Info.plist b/ios/HIPMIBadungConnect/Info.plist index f55aadf..4077bf2 100644 --- a/ios/HIPMIBadungConnect/Info.plist +++ b/ios/HIPMIBadungConnect/Info.plist @@ -39,7 +39,7 @@ CFBundleVersion - 3 + 4 ITSAppUsesNonExemptEncryption LSMinimumSystemVersion diff --git a/screens/Admin/AdminNotificationBell.tsx b/screens/Admin/AdminNotificationBell.tsx index 1666d72..eff5c97 100644 --- a/screens/Admin/AdminNotificationBell.tsx +++ b/screens/Admin/AdminNotificationBell.tsx @@ -4,10 +4,16 @@ import { ICON_SIZE_SMALL } from "@/constants/constans-value"; import { useNotificationStore } from "@/hooks/use-notification-store"; import { Ionicons } from "@expo/vector-icons"; import { router } from "expo-router"; +import { useEffect } from "react"; import { Text, View } from "react-native"; export default function AdminNotificationBell() { - const { unreadCount } = useNotificationStore(); + const { unreadCount, syncUnreadCount } = useNotificationStore(); + + useEffect(() => { + console.log("Syncing unread count"); + syncUnreadCount(); + }, [syncUnreadCount]); return ( diff --git a/screens/Admin/Event/EventDetailQRCode.tsx b/screens/Admin/Event/EventDetailQRCode.tsx index 7604aa6..b7b5cef 100644 --- a/screens/Admin/Event/EventDetailQRCode.tsx +++ b/screens/Admin/Event/EventDetailQRCode.tsx @@ -1,26 +1,93 @@ -import { BaseBox, LoaderCustom, Spacing, StackCustom, TextCustom } from "@/components"; +import { + BaseBox, + ButtonCustom, + LoaderCustom, + Spacing, + StackCustom, + TextCustom, +} from "@/components"; +import { MainColor } from "@/constants/color-palet"; +import { BASE_URL } from "@/service/api-config"; +import { useLocalSearchParams } from "expo-router"; +import { useState } from "react"; +import { StyleSheet } from "react-native"; import QRCode from "react-native-qrcode-svg"; interface EventDetailQRCodeProps { - qrValue: string; + userId: string; isLoading: boolean; } -export function EventDetailQRCode({ qrValue, isLoading }: EventDetailQRCodeProps) { +export function EventDetailQRCode({ + userId, + isLoading, +}: EventDetailQRCodeProps) { + const { id } = useLocalSearchParams(); + const [useHttpsLink, setUseHttpsLink] = useState(true); + + // HTTPS link untuk Universal Links (iOS) dan App Links (Android) + // Ini akan membuka file .well-known di Next.js server Anda + const httpsLink = `https://cld-dkr-hipmi-stg.wibudev.com/event/${id}/confirmation?userId=${userId}`; + + // Custom scheme link untuk fallback atau testing tanpa universal links + const deepLinkURL = `${BASE_URL}/event/${id}/confirmation?userId=${userId}`; + + // Toggle antara HTTPS link dan custom scheme + const qrValue = useHttpsLink ? httpsLink : deepLinkURL; + return ( QR Code Event - {isLoading ? ( - - ) : ( - - )} + {isLoading ? : } + + {qrValue} + + + + setUseHttpsLink(true)} + backgroundColor={useHttpsLink ? MainColor.yellow : "transparent"} + textColor={useHttpsLink ? MainColor.black : MainColor.yellow} + style={[ + stylesButton.smallButton, + useHttpsLink && stylesButton.border, + ]} + > + HTTPS + + setUseHttpsLink(false)} + backgroundColor={!useHttpsLink ? MainColor.yellow : "transparent"} + textColor={!useHttpsLink ? MainColor.black : MainColor.yellow} + style={[ + stylesButton.smallButton, + !useHttpsLink && stylesButton.border, + ]} + > + Custom Scheme + + + + + {useHttpsLink + ? "✅ Testing Universal Links/App Links (butuh .well-known config)" + : "🔧 Testing langsung (tanpa domain verification)"} + ); } + +const stylesButton = StyleSheet.create({ + smallButton: { + paddingHorizontal: 12, + paddingVertical: 6, + minWidth: 140, + }, + border: { + borderWidth: 1, + borderColor: MainColor.yellow, + }, +}); diff --git a/screens/Admin/Event/ScreenEventDetail.tsx b/screens/Admin/Event/ScreenEventDetail.tsx index 195676d..c7cbce6 100644 --- a/screens/Admin/Event/ScreenEventDetail.tsx +++ b/screens/Admin/Event/ScreenEventDetail.tsx @@ -1,22 +1,22 @@ /* eslint-disable react-hooks/exhaustive-deps */ -import { ActionIcon, AlertDefaultSystem } from "@/components"; +import { ActionIcon, AlertDefaultSystem, Spacing } from "@/components"; import { IconDot } from "@/components/_Icon/IconComponent"; import AdminBackButtonAntTitle from "@/components/_ShareComponent/Admin/BackButtonAntTitle"; import AdminButtonReject from "@/components/_ShareComponent/Admin/ButtonReject"; import AdminButtonReview from "@/components/_ShareComponent/Admin/ButtonReview"; -import ReportBox from "@/components/Box/ReportBox"; import NewWrapper from "@/components/_ShareComponent/NewWrapper"; +import ReportBox from "@/components/Box/ReportBox"; import { ICON_SIZE_BUTTON } from "@/constants/constans-value"; import { useAuth } from "@/hooks/use-auth"; import { funUpdateStatusEvent } from "@/screens/Admin/Event/funUpdateStatus"; import { apiAdminEventById } from "@/service/api-admin/api-admin-event"; -import { DEEP_LINK_URL } from "@/service/api-config"; import { router, useFocusEffect, useLocalSearchParams } from "expo-router"; import { useCallback, useMemo, useState } from "react"; import Toast from "react-native-toast-message"; import { BoxEventDetail } from "./BoxEventDetail"; import { EventDetailDrawer } from "./EventDetailDrawer"; import { EventDetailQRCode } from "./EventDetailQRCode"; +import { View } from "react-native"; export function Admin_ScreenEventDetail() { const { user } = useAuth(); @@ -25,11 +25,6 @@ export function Admin_ScreenEventDetail() { const [data, setData] = useState(null); const [loadData, setLoadData] = useState(false); - const deepLinkURL = `${DEEP_LINK_URL}/event/${id}/confirmation?userId=${user?.id}`; - const deepLinkURLDEV = `${DEEP_LINK_URL}/--/event/${id}/confirmation?userId=${user?.id}`; - const isDevLink = - process.env.NODE_ENV === "development" ? deepLinkURLDEV : deepLinkURL; - useFocusEffect( useCallback(() => { onLoadData(); @@ -140,7 +135,11 @@ export function Admin_ScreenEventDetail() { <> + // {footerComponent} + // + // } > @@ -149,8 +148,11 @@ export function Admin_ScreenEventDetail() { )} {(status === "publish" || status === "history") && ( - + )} + + {footerComponent} + (false); const [recodeOtp, setRecodeOtp] = useState(false); - // 🔑 DETEKSI MODE REVIEW (HANYA UNTUK NOMOR DEMO & PRODUCTION) + // 🔑 DETEKSI MODE REVIEW (HANYA UNTUK NOMOR DEMO & DEVELOPMENT BUILD) + // Menggunakan Constants.expoConfig untuk mendeteksi development build const isReviewMode = - typeof window !== "undefined" && // pastikan di browser/production - process.env.NODE_ENV === "production" && + process.env.NODE_ENV === "development" && nomor === "6282340374412"; // --- Context --- @@ -37,10 +37,6 @@ export default function VerificationView() { // Hanya jalankan logika OTP normal jika BUKAN review mode onLoadCheckCodeOtp(); } - - console.log("[NODE_ENV]:", process.env.NODE_ENV); - console.log("[isReviewMode]:", isReviewMode); - console.log("[nomor]:", nomor); }, [recodeOtp, isReviewMode]); async function onLoadCheckCodeOtp() { @@ -85,29 +81,30 @@ export default function VerificationView() { const handleVerification = async () => { if (isReviewMode) { - // ✅ VERIFIKASI OTOMATIS UNTUK APPLE REVIEW - if (inputOtp === "1234") { - try { - await validateOtp(nomor as string); - - return; - } catch (error) { - console.log("Error verification", error); - Toast.show({ type: "error", text1: "Gagal verifikasi" }); - } - } else { + // ✅ VERIFIKASI OTOMATIS UNTUK APPLE REVIEW (Development Only) + if (inputOtp !== "1234") { Toast.show({ type: "error", text1: "Kode OTP tidak sesuai" }); + return; + } + try { + await validateOtp(nomor as string, inputOtp); + return; + } catch (error) { + console.log("Error verification", error); + Toast.show({ type: "error", text1: "Gagal verifikasi" }); } - return; } // 🔁 VERIFIKASI NORMAL (untuk pengguna sungguhan) try { - await validateOtp(nomor as string); - return - } catch (error) { + await validateOtp(nomor as string, inputOtp); + return; + } catch (error: any) { console.log("Error verification", error); - Toast.show({ type: "error", text1: "Gagal verifikasi" }); + Toast.show({ + type: "error", + text1: error.response?.data?.message || "Gagal verifikasi", + }); } }; diff --git a/service/api-config.ts b/service/api-config.ts index 71485be..f4dc7ef 100644 --- a/service/api-config.ts +++ b/service/api-config.ts @@ -45,9 +45,16 @@ export async function apiCheckCodeOtp({ kodeId }: { kodeId: string }) { return response.data; } -export async function apiValidationCode({ nomor }: { nomor: string }) { +export async function apiValidationCode({ + nomor, + code, +}: { + nomor: string; + code: string; +}) { const response = await apiConfig.post(`/auth/mobile-validasi`, { nomor: nomor, + code: code, }); return response.data; }