diff --git a/app/(application)/(user)/home.tsx b/app/(application)/(user)/home.tsx index 800890c..95cf893 100644 --- a/app/(application)/(user)/home.tsx +++ b/app/(application)/(user)/home.tsx @@ -1,6 +1,6 @@ /* eslint-disable @typescript-eslint/no-unused-vars */ /* eslint-disable react-hooks/exhaustive-deps */ -import { ButtonCustom, StackCustom, ViewWrapper } from "@/components"; +import { StackCustom, ViewWrapper } from "@/components"; import { MainColor } from "@/constants/color-palet"; import { useAuth } from "@/hooks/use-auth"; import { useNotificationStore } from "@/hooks/use-notification-store"; @@ -23,14 +23,12 @@ export default function Application() { const [refreshing, setRefreshing] = useState(false); const { syncUnreadCount } = useNotificationStore(); - - useFocusEffect( useCallback(() => { onLoadData(); checkVersion(); userData(token as string); - syncUnreadCount() + syncUnreadCount(); }, [user?.id, token]) ); @@ -56,10 +54,10 @@ export default function Application() { setRefreshing(false); }, []); - if (user && user?.termsOfServiceAccepted === false) { - console.log("User is not accept term service"); - return ; - } + // if (user && user?.termsOfServiceAccepted === false) { + // console.log("User is not accept term service"); + // return ; + // } if (data && data?.active === false) { console.log("User is not active"); diff --git a/app/eula.tsx b/app/eula.tsx new file mode 100644 index 0000000..953b70e --- /dev/null +++ b/app/eula.tsx @@ -0,0 +1,9 @@ +import EULAView from "@/screens/Authentication/EULAView"; + +export default function EULA() { + return ( + <> + + + ); +} diff --git a/context/AuthContext.tsx b/context/AuthContext.tsx index 5d87fdd..416c5c7 100644 --- a/context/AuthContext.tsx +++ b/context/AuthContext.tsx @@ -2,6 +2,7 @@ import { apiConfig, apiLogin, apiRegister, + apiUpdatedTermCondition, apiValidationCode, } from "@/service/api-config"; import { apiDeviceTokenDeleted } from "@/service/api-device-token"; @@ -29,6 +30,7 @@ type AuthContextType = { termsOfServiceAccepted: boolean; }) => Promise; userData: (token: string) => Promise; + acceptedTerms: (nomor: string) => Promise; }; // --- Create Context --- @@ -74,28 +76,32 @@ export const AuthProvider = ({ children }: { children: React.ReactNode }) => { const loginWithNomor = async (nomor: string) => { setIsLoading(true); try { - console.log("[Masuk provider]", nomor); const response = await apiLogin({ nomor: nomor }); - console.log("[RESPONSE AUTH]", JSON.stringify(response)); + console.log("[RESPONSE AUTH]", JSON.stringify(response, null, 2)); if (response.success) { - console.log("[Keluar provider]", nomor); - Toast.show({ - type: "success", - text1: "Sukses", - text2: "Kode OTP berhasil dikirim", - }); + if (response.isAcceptTerms) { + Toast.show({ + type: "success", + text1: "Sukses", + text2: "Kode OTP berhasil dikirim", + }); - await AsyncStorage.setItem("kode_otp", response.kodeId); - router.push(`/verification?nomor=${nomor}`); - return; + await AsyncStorage.setItem("kode_otp", response.kodeId); + router.push(`/verification?nomor=${nomor}`); + return; + } else { + router.push(`/eula?nomor=${nomor}`); + return; + } } else { - router.push(`/register?nomor=${nomor}`); - Toast.show({ - type: "info", - text1: "Info", - text2: "Silahkan mendaftar", - }); + router.push(`/eula?nomor=${nomor}`); + + // Toast.show({ + // type: "info", + // text1: "Info", + // text2: "Silahkan mendaftar", + // }); return; } } catch (error: any) { @@ -226,7 +232,6 @@ export const AuthProvider = ({ children }: { children: React.ReactNode }) => { setIsLoading(false); } }; - // --- 5. Logout --- @@ -256,6 +261,31 @@ export const AuthProvider = ({ children }: { children: React.ReactNode }) => { } }; + const acceptedTerms = async (nomor: string) => { + try { + setIsLoading(true); + const response = await apiUpdatedTermCondition({ nomor: nomor }); + + if (response.success) { + router.replace(`/verification?nomor=${nomor}`); + } else { + if (response.status === 404) { + router.replace(`/register?nomor=${nomor}`); + } else { + Toast.show({ + type: "error", + text1: "Error", + text2: response.message, + }); + } + } + } catch (error) { + console.log("Error accept terms", error); + } finally { + setIsLoading(false); + } + }; + return ( <> { logout, registerUser, userData, + acceptedTerms, }} > {children} diff --git a/screens/Authentication/EULAView.tsx b/screens/Authentication/EULAView.tsx new file mode 100644 index 0000000..58b7ebd --- /dev/null +++ b/screens/Authentication/EULAView.tsx @@ -0,0 +1,278 @@ +// app/syarat-dan-ketentuan.tsx +import { + View, + Text, + ScrollView, + TouchableOpacity, + StyleSheet, +} from "react-native"; +import { useState, useRef } from "react"; +import { useLocalSearchParams, useRouter } from "expo-router"; +import { SafeAreaView } from "react-native-safe-area-context"; +import { AccentColor, MainColor } from "@/constants/color-palet"; +import { useAuth } from "@/hooks/use-auth"; + +// Ganti dengan API call ke backend Anda +// const acceptEula = async (): Promise => { +// try { +// const response = await fetch("/api/user/update-eula", { +// method: "PATCH", +// headers: { "Content-Type": "application/json" }, +// credentials: "include", +// body: JSON.stringify({ +// eulaAcceptedAt: new Date().toISOString(), +// eulaVersion: "2026-01-v1", // sesuaikan versi Anda +// }), +// }); +// return response.ok; +// } catch (error) { +// console.error("Gagal menyimpan persetujuan EULA:", error); +// return false; +// } +// }; + +export default function EULAView() { + const { acceptedTerms } = useAuth(); + const { nomor } = useLocalSearchParams(); + const [isLoading, setIsLoading] = useState(false); + const [isAtBottom, setIsAtBottom] = useState(false); + const scrollViewRef = useRef(null); + + const handleScroll = (event: any) => { + const { layoutMeasurement, contentOffset, contentSize } = event.nativeEvent; + const paddingToBottom = 20; + const isCloseToBottom = + layoutMeasurement.height + contentOffset.y >= + contentSize.height - paddingToBottom; + setIsAtBottom(isCloseToBottom); + }; + + const handleAccept = async () => { + try { + if (!isAtBottom) return; + + setIsLoading(true); + await acceptedTerms(nomor as string); + } catch (error) { + console.log("Error accept terms", error); + } finally { + setIsLoading(false); + } + }; + + return ( + + + Syarat & Ketentuan Penggunaan HIPMI Badung Connect + + + + + Dengan menggunakan aplikasi{" "} + HIPMI Badung Connect (“Aplikasi”), + Anda setuju untuk mematuhi dan terikat oleh syarat dan ketentuan + berikut. Jika Anda tidak setuju dengan ketentuan ini, harap jangan + gunakan Aplikasi. + + + 1. Definisi + + HIPMI Badung Connect adalah platform + digital resmi untuk anggota Himpunan Pengusaha Muda Indonesia (HIPMI) + Kabupaten Badung, yang bertujuan memfasilitasi jaringan, kolaborasi, + dan pertumbuhan bisnis para pengusaha muda. + + + 2. Larangan Konten Tidak Pantas + + Anda dilarang keras memposting, + mengirim, membagikan, atau mengunggah konten apa pun yang mengandung: + + + + • Ujaran kebencian, diskriminasi, atau konten SARA (Suku, Agama, + Ras, Antar-golongan) + + + • Pornografi, konten seksual eksplisit, atau gambar tidak senonoh + + + • Ancaman, pelecehan, bullying, atau perilaku melecehkan + + + • Informasi palsu, hoaks, spam, atau konten menyesatkan + + + • Konten ilegal, melanggar hukum, atau melanggar hak kekayaan + intelektual pihak lain + + + • Promosi narkoba, perjudian, atau aktivitas ilegal lainnya + + + + 3. Tanggung Jawab Pengguna + + Anda bertanggung jawab penuh atas setiap konten yang Anda unggah atau + bagikan melalui fitur-fitur berikut: + + + • Profil (bio, foto, portofolio) + • Forum diskusi + • Chat pribadi atau grup + + • Lowongan kerja, investasi, dan donasi + + + + Konten yang melanggar ketentuan ini dapat dihapus kapan saja tanpa + pemberitahuan. + + + 4. Tindakan terhadap Pelanggaran + + Jika kami menerima laporan atau menemukan konten yang melanggar + ketentuan ini, kami akan: + + + + • Segera menghapus konten tersebut + + + • Memberikan peringatan atau memblokir akun pengguna + + + • Dalam kasus berat, melaporkan ke pihak berwajib sesuai hukum yang + berlaku + + + + Tim kami berkomitmen untuk menanggapi laporan konten tidak pantas{" "} + dalam waktu 24 jam. + + + 5. Mekanisme Pelaporan + + Anda dapat melaporkan konten atau pengguna yang mencurigakan melalui: + + + + • Tombol “Laporkan” di setiap + posting forum atau pesan chat + + + • Tombol “Blokir Pengguna” di + profil pengguna + + + + Setiap laporan akan ditangani secara rahasia dan segera. + + + 6. Perubahan Ketentuan + + Kami berhak memperbarui Syarat & Ketentuan ini sewaktu-waktu. Versi + terbaru akan dipublikasikan di halaman ini dengan tanggal revisi yang + diperbarui. + + + 7. Kontak + + Jika Anda memiliki pertanyaan tentang ketentuan ini, silakan hubungi + kami di:{"\n"} + + bip.baliinteraktifperkasa@gmail.com + + + + + © 2026 Bali Interaktif Perkasa. All rights reserved. + + + + + + {isLoading ? "Menyimpan..." : "Saya Setuju"} + + + + ); +} + +const styles = StyleSheet.create({ + container: { + flex: 1, + backgroundColor: MainColor.darkblue, + padding: 16, + }, + title: { + fontSize: 20, + fontWeight: "bold", + textAlign: "center", + marginBottom: 16, + color: MainColor.white, + }, + scrollView: { + flex: 1, + marginBottom: 20, + }, + scrollContent: { + paddingBottom: 30, + }, + heading: { + fontSize: 16, + fontWeight: "600", + marginTop: 16, + marginBottom: 8, + color: MainColor.white, + }, + paragraph: { + fontSize: 14, + lineHeight: 22, + color: MainColor.white, + marginBottom: 12, + }, + bold: { + fontWeight: "600", + }, + list: { + marginLeft: 8, + marginBottom: 12, + }, + listItem: { + fontSize: 14, + lineHeight: 22, + color: MainColor.white, + marginBottom: 6, + }, + footer: { + fontSize: 12, + color: MainColor.white, + textAlign: "center", + marginTop: 20, + paddingTop: 10, + borderTopWidth: 2, + borderTopColor: AccentColor.blue, + }, + button: { + backgroundColor: MainColor.yellow, + paddingVertical: 14, + borderRadius: 8, + alignItems: "center", + }, + buttonText: { + color: "#fff", + fontSize: 16, + fontWeight: "600", + }, +}); diff --git a/screens/Authentication/RegisterView.tsx b/screens/Authentication/RegisterView.tsx index 214a63b..bc9fbe7 100644 --- a/screens/Authentication/RegisterView.tsx +++ b/screens/Authentication/RegisterView.tsx @@ -1,4 +1,3 @@ -import { CheckboxCustom } from "@/components"; import Spacing from "@/components/_ShareComponent/Spacing"; import ViewWrapper from "@/components/_ShareComponent/ViewWrapper"; import ButtonCustom from "@/components/Button/ButtonCustom"; @@ -7,7 +6,6 @@ import { MainColor } from "@/constants/color-palet"; import { useAuth } from "@/hooks/use-auth"; import { BASE_URL } from "@/service/api-config"; import { GStyles } from "@/styles/global-styles"; -import { openBrowser } from "@/utils/openBrower"; import { MaterialCommunityIcons } from "@expo/vector-icons"; import { useLocalSearchParams } from "expo-router"; import { useState } from "react"; @@ -17,7 +15,7 @@ import Toast from "react-native-toast-message"; export default function RegisterView() { const { nomor } = useLocalSearchParams(); const [username, setUsername] = useState(""); - const [term, setTerm] = useState(false); + // const [term, setTerm] = useState(false); const url = BASE_URL; const { registerUser, isLoading } = useAuth(); @@ -65,7 +63,7 @@ export default function RegisterView() { await registerUser({ nomor: nomor as string, username: usernameLower, - termsOfServiceAccepted: term, + termsOfServiceAccepted: true, }); } @@ -106,12 +104,12 @@ export default function RegisterView() { flexDirection: "row", alignItems: "center", marginTop: 16, - marginBottom: 16, + // marginBottom: 16, }} > - setTerm(!term)} /> + {/* setTerm(!term)} /> */} - + {/* Saya setuju dengan{" "} {" "} yang melarang konten tidak pantas dan perilaku merugikan. - + */} diff --git a/screens/RootLayout/AppRoot.tsx b/screens/RootLayout/AppRoot.tsx index e513fbf..203d43c 100644 --- a/screens/RootLayout/AppRoot.tsx +++ b/screens/RootLayout/AppRoot.tsx @@ -15,6 +15,7 @@ export default function AppRoot() { name="index" options={{ title: "", headerBackVisible: false }} /> +