Compare commits

...

24 Commits

Author SHA1 Message Date
6f9481c7c9 Fix QC ( Ayu )
Fix:
- modified:   app/(application)/(user)/event/[id]/publish.tsx
- modified:   app/(application)/(user)/event/create.tsx
- modified:   app/(application)/(user)/portofolio/[id]/create.tsx
- modified:   app/(application)/(user)/portofolio/[id]/edit.tsx
- modified:   app/(application)/admin/collaboration/[id]/group.tsx
- modified:   app/(application)/admin/collaboration/group.tsx
- modified:   app/(application)/admin/collaboration/publish.tsx
- modified:   app/(application)/admin/forum/[id]/list-report-comment.tsx
- modified:   app/(application)/admin/forum/[id]/list-report-posting.tsx
- modified:   app/(application)/admin/forum/posting.tsx
- modified:   app/(application)/admin/forum/report-comment.tsx
- modified:   app/(application)/admin/forum/report-posting.tsx
- modified:   app/(application)/admin/voting/[status]/status.tsx
- modified:   app/(application)/admin/voting/history.tsx
- modified:   components/Select/SelectCustom.tsx
- modified:   components/_ShareComponent/GridSpan_4_8.tsx
- modified:   screens/Authentication/LoginView.tsx
- modified:   screens/Collaboration/BoxPublishSection.tsx
- modified:   screens/Event/BoxDetailPublishSection.tsx
- modified:   screens/Home/topFeatureSection.tsx
- modified:   screens/Portofolio/ButtonCreatePortofolio.tsx

Add:
- app/(application)/admin/app-information/business-field/[id]/bidang-update.tsx
- app/(application)/admin/app-information/business-field/[id]/sub-bidang-update.tsx

### No Issue
2025-12-10 17:35:15 +08:00
cccb44a835 Fix QC Ayu
Fix:
- modified:   app/(application)/(user)/event/[id]/publish.tsx
- modified:   app/(application)/(user)/event/create.tsx
- modified:   app/(application)/(user)/portofolio/[id]/create.tsx
- modified:   app/(application)/(user)/portofolio/[id]/edit.tsx
- modified:   app/(application)/admin/collaboration/[id]/group.tsx
- modified:   app/(application)/admin/collaboration/group.tsx
- modified:   app/(application)/admin/collaboration/publish.tsx
- modified:   app/(application)/admin/forum/[id]/list-report-comment.tsx
- modified:   app/(application)/admin/forum/[id]/list-report-posting.tsx
- modified:   app/(application)/admin/forum/posting.tsx
- modified:   app/(application)/admin/forum/report-comment.tsx
- modified:   app/(application)/admin/forum/report-posting.tsx
- modified:   app/(application)/admin/voting/[status]/status.tsx
- modified:   app/(application)/admin/voting/history.tsx
- modified:   components/Select/SelectCustom.tsx
- modified:   components/_ShareComponent/GridSpan_4_8.tsx
- modified:   screens/Authentication/LoginView.tsx
- modified:   screens/Collaboration/BoxPublishSection.tsx
- modified:   screens/Event/BoxDetailPublishSection.tsx
- modified:   screens/Home/topFeatureSection.tsx
- modified:   screens/Portofolio/ButtonCreatePortofolio.tsx

Add:
- components/_ShareComponent/GridSpan_NewComponent.tsx

### No Issue
2025-12-09 17:36:36 +08:00
0f5862ce70 Fix Apple Reject:
Add:
- app/(application)/(user)/forum/terms.tsx

Fix:
- app/(application)/(user)/_layout.tsx
- app/(application)/(user)/home.tsx
- screens/Home/tabsList.ts
- service/api-client/api-user.ts

### No Issue
2025-12-08 16:34:33 +08:00
624bd49f69 QC Admin ( Inno )
Fix:
   modified:   android/app/build.gradle
        modified:   app.config.js
        modified:   app/(application)/admin/donation/[id]/[status]/index.tsx
        modified:   app/(application)/admin/donation/[id]/[status]/transaction-detail.tsx
        modified:   app/(application)/admin/donation/[id]/detail-disbursement-of-funds.tsx
        modified:   app/(application)/admin/donation/category.tsx
        modified:   app/(application)/admin/event/[id]/[status]/index.tsx
        modified:   app/(application)/admin/event/[id]/list-of-participants.tsx
        modified:   app/(application)/admin/event/[status]/status.tsx
        modified:   app/(application)/admin/forum/[id]/index.tsx
        modified:   app/(application)/admin/forum/[id]/list-report-comment.tsx
        modified:   app/(application)/admin/forum/[id]/list-report-posting.tsx
        modified:   app/(application)/admin/investment/[id]/[status]/index.tsx
        modified:   app/(application)/admin/investment/[id]/[status]/transaction-detail.tsx
        modified:   app/(application)/admin/voting/[id]/[status]/index.tsx
        modified:   components/DateInput/DateTimeIOS.tsx
        modified:   components/_ShareComponent/Admin/ButtonReject.tsx
        deleted:    components/_ShareComponent/GridDetail_4_8.tsx

Add:/
components/_ShareComponent/GridSpan_4_8.tsx

### No Issue
2025-12-05 17:20:39 +08:00
2446e9d51a Fix apple reject EULA
Add:
components/Alert/AlertWarning.ts
        utils/badWordsIndonesia.ts

Fix:
- app.config.js
- app/(application)/(user)/forum/[id]/edit.tsx
- app/(application)/(user)/forum/[id]/index.tsx
- app/(application)/(user)/forum/create.tsx
- ios/HIPMIBadungConnect/Info.plist

### No Issue
2025-12-05 11:46:36 +08:00
ab5733f336 Fix redirect admin 2025-12-04 17:41:19 +08:00
f5e30087ed Fix QC Inno
Fix:
- app/(application)/admin/donation/category-create.tsx
- app/(application)/admin/donation/category-update.tsx
- app/(application)/admin/donation/category.tsx
- components/_ShareComponent/Admin/TableValue.tsx
- screens/Authentication/LoginView.tsx
- service/api-admin/api-master-admin.ts

### No Issue
2025-12-04 16:59:39 +08:00
a93f97ed6a Fix rejected Apple
Add:
-  utils/viersionBadge.ts

Fix:
- app.config.js
- context/AuthContext.tsx
- ios/HIPMIBadungConnect/Info.plist
- screens/Authentication/LoginView.tsx
- screens/Authentication/VerificationView.tsx
- service/api-config.ts

### No Issue
2025-12-03 17:23:12 +08:00
858b441a8c Clearing apple rejected
QC: Inno

Fix:
- app.config.js
- app/(application)/(user)/investment/[id]/index.tsx
- app/(application)/(user)/voting/(tabs)/index.tsx
- app/(application)/(user)/waiting-room.tsx
- app/(application)/terms-agreement.tsx
- context/AuthContext.tsx
- ios/HIPMIBadungConnect.xcodeproj/project.pbxproj
- ios/HIPMIBadungConnect/Info.plist
- screens/Authentication/LoginView.tsx
- screens/Authentication/VerificationView.tsx
- screens/Home/topFeatureSection.tsx
- screens/Invesment/BoxBerandaSection.tsx
- screens/Invesment/ButtonInvestasiSection.tsx
- screens/Invesment/DetailDataPublishSection.tsx
- service/api-client/api-voting.ts
- service/api-config.ts

### No Issue
2025-12-02 17:48:24 +08:00
98aaa126a1 QC: Inno dan Pak Jun
Fix:
- app/(application)/(user)/collaboration/create.tsx
- app/(application)/(user)/event/[id]/edit.tsx
- app/(application)/(user)/event/create.tsx
- app/(application)/(user)/profile/[id]/blocked-list.tsx
- app/(application)/(user)/profile/[id]/index.tsx
- app/(application)/(user)/voting/[id]/[status]/detail.tsx
- components/Button/FloatingButton.tsx
- components/TextArea/TextAreaCustom.tsx
- components/TextInput/TextInputCustom.tsx
- constants/color-palet.ts
- screens/Authentication/LoginView.tsx
- screens/Home/topFeatureSection.tsx
- screens/Portofolio/SocialMediaSection.tsx
- screens/Voting/BoxDetailHasilVotingSection.tsx
- styles/global-styles.ts

### No Issue
2025-12-01 17:43:20 +08:00
69452ff4e7 Fix loader fetch data di Forum dan Forumku
### No Issue
2025-11-28 17:27:59 +08:00
33ec892ec8 Prebuild : untuk Maps box
### No issue
2025-11-28 16:35:18 +08:00
8a900e9469 Halaman unblock user
Add:
- app/(application)/(user)/profile/[id]/blocked-list.tsx
app/(application)/(user)/profile/[id]/detail-blocked.tsx
components/_ShareComponent/ListEmptyComponent.tsx
components/_ShareComponent/ListLoaderFooterComponent.tsx
components/_ShareComponent/ListSkeletonComponent.tsx
hooks/use-paginated-api.ts
service/api-client/api-blocked.ts

Fix:
modified:   app/(application)/(user)/profile/_layout.tsx
modified:   components/_ShareComponent/NewWrapper.tsx
modified:   components/index.ts
modified:   screens/Profile/ListPage.tsx
modified:   styles/global-styles.ts

### No Issue
2025-11-28 13:55:48 +08:00
d471682ae7 Refresh control dan Blockir user di forum
### No Issue
2025-11-26 16:13:05 +08:00
00eea71248 Penambahan fitur block user: 50%
Fix:
- app/(application)/(user)/forum/[id]/index.tsx
- app/(application)/(user)/home.tsx
- screens/Forum/ListPage.tsx
- screens/Forum/MenuDrawerSection.tsx/MenuBeranda.tsx
- service/api-client/api-master.ts
- service/api-client/api-user.ts

### No Issue
2025-11-25 11:04:12 +08:00
41e648d8f3 Fix rejected Apple :
Submission ID: 1efcd8eb-7d68-4348-9925-43a8e1bd7d1e

Add:
-  app/(application)/terms-agreement.tsx

Fix:
- app/(application)/(user)/home.tsx
- app/(application)/_layout.tsx
- context/AuthContext.tsx
- ios/HIPMIBadungConnect/Info.plist
- screens/Authentication/LoginView.tsx
- screens/Authentication/RegisterView.tsx
- service/api-config.ts
- types/User.ts

### NO Issue
2025-11-24 17:09:52 +08:00
0c4deac6e2 Fix map android :
Add:
- screens/Maps/

Fix:
- android/app/src/main/AndroidManifest.xml
- app.config.js
- app/(application)/(user)/maps/index.tsx
- bun.lock
- ios/HIPMIBadungConnect.xcodeproj/project.pbxproj
- ios/HIPMIBadungConnect/Info.plist
- ios/Podfile.lock
- package.json

### No Issue
2025-11-21 17:43:58 +08:00
676b8a38be Fix apple rejected:
-  app/(application)/(user)/delete-account.tsx
-  screens/Profile/menuDrawerSection.tsx

### No Issue
2025-11-20 15:42:37 +08:00
0a2aa71013 Add:
-  app/(application)/(user)/delete-account.tsx
-  assets/images/constants/logo-hipmi_back.png

Fix:
- app/(application)/(user)/_layout.tsx
- assets/images/constants/logo-hipmi.png
- components/Grid/GridCustom.tsx
- screens/Profile/ListPage.tsx
- screens/Profile/menuDrawerSection.tsx
- service/api-client/api-user.ts

### No Issue
2025-11-19 17:40:35 +08:00
868e96a54a Try to notification
### Issue: package import * as Notifications from expo-notifications;
2025-11-18 17:46:33 +08:00
059b4d053a Fix rejected apple delete account & start for notification
### No issue
2025-11-18 14:29:02 +08:00
76debfd6a6 Add:
-  google-services.json
- utils/notifications.ts

Fix:
- app.config.js : tambah access googleServicesFile
- app/_layout.tsx : tambah untuk push notifikasi
- package.json: install install expo-notifications expo-device expo-constants

### No Issue
2025-11-14 17:44:22 +08:00
8c3aec8e57 Admin Event: QR Code sudah bisa di scan
### No issue
2025-11-14 14:44:36 +08:00
1ade69ff2f Fix QR Code Access
### No Issue
2025-11-13 17:41:54 +08:00
132 changed files with 4837 additions and 1316 deletions

View File

@@ -82,6 +82,14 @@ def enableMinifyInReleaseBuilds = (findProperty('android.enableMinifyInReleaseBu
def jscFlavor = 'io.github.react-native-community:jsc-android:2026004.+' def jscFlavor = 'io.github.react-native-community:jsc-android:2026004.+'
android { android {
// @generated begin @rnmapbox/maps-libcpp - expo prebuild (DO NOT MODIFY) sync-e24830a5a3e854b398227dfe9630aabfaa1cadd1
packagingOptions {
pickFirst 'lib/x86/libc++_shared.so'
pickFirst 'lib/x86_64/libc++_shared.so'
pickFirst 'lib/arm64-v8a/libc++_shared.so'
pickFirst 'lib/armeabi-v7a/libc++_shared.so'
}
// @generated end @rnmapbox/maps-libcpp
ndkVersion rootProject.ext.ndkVersion ndkVersion rootProject.ext.ndkVersion
buildToolsVersion rootProject.ext.buildToolsVersion buildToolsVersion rootProject.ext.buildToolsVersion
@@ -92,8 +100,8 @@ android {
applicationId 'com.bip.hipmimobileapp' applicationId 'com.bip.hipmimobileapp'
minSdkVersion rootProject.ext.minSdkVersion minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion
versionCode 1 versionCode 3
versionName "1.0.0" versionName "1.0.1"
buildConfigField "String", "REACT_NATIVE_RELEASE_LEVEL", "\"${findProperty('reactNativeReleaseLevel') ?: 'stable'}\"" buildConfigField "String", "REACT_NATIVE_RELEASE_LEVEL", "\"${findProperty('reactNativeReleaseLevel') ?: 'stable'}\""
} }
@@ -180,3 +188,5 @@ dependencies {
implementation jscFlavor implementation jscFlavor
} }
} }
apply plugin: 'com.google.gms.google-services'

View File

@@ -0,0 +1,29 @@
{
"project_info": {
"project_number": "608461535079",
"project_id": "hipmi-badung-connect",
"storage_bucket": "hipmi-badung-connect.firebasestorage.app"
},
"client": [
{
"client_info": {
"mobilesdk_app_id": "1:608461535079:android:4ff12ddc283fb3746761c2",
"android_client_info": {
"package_name": "com.bip.hipmimobileapp"
}
},
"oauth_client": [],
"api_key": [
{
"current_key": "AIzaSyBiDtIk3Q9zffFwIdJ5cjqY7e4390JGSkM"
}
],
"services": {
"appinvite_service": {
"other_platform_oauth_client": []
}
}
}
],
"configuration_version": "1"
}

View File

@@ -1,4 +1,6 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools"> <manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.CAMERA"/> <uses-permission android:name="android.permission.CAMERA"/>
<uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
@@ -29,6 +31,12 @@
<data android:scheme="hipmimobile"/> <data android:scheme="hipmimobile"/>
<data android:scheme="exp+hipmi-mobile"/> <data android:scheme="exp+hipmi-mobile"/>
</intent-filter> </intent-filter>
<intent-filter android:autoVerify="true" data-generated="true">
<action android:name="android.intent.action.VIEW"/>
<data android:scheme="https" android:host="cld-dkr-staging-hipmi.wibudev.com" android:pathPrefix="/"/>
<category android:name="android.intent.category.BROWSABLE"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</activity> </activity>
</application> </application>
</manifest> </manifest>

View File

@@ -6,6 +6,7 @@ buildscript {
mavenCentral() mavenCentral()
} }
dependencies { dependencies {
classpath 'com.google.gms:google-services:4.4.1'
classpath('com.android.tools.build:gradle') classpath('com.android.tools.build:gradle')
classpath('com.facebook.react:react-native-gradle-plugin') classpath('com.facebook.react:react-native-gradle-plugin')
classpath('org.jetbrains.kotlin:kotlin-gradle-plugin') classpath('org.jetbrains.kotlin:kotlin-gradle-plugin')
@@ -22,3 +23,25 @@ allprojects {
apply plugin: "expo-root-project" apply plugin: "expo-root-project"
apply plugin: "com.facebook.react.rootproject" apply plugin: "com.facebook.react.rootproject"
// @generated begin @rnmapbox/maps-v2-maven - expo prebuild (DO NOT MODIFY) sync-d4ccbfdff48fdba3138b02a8ba41b9722af001d8
allprojects {
repositories {
maven {
url 'https://api.mapbox.com/downloads/v2/releases/maven'
// Authentication is no longer required as per Mapbox's removal of download token requirement
// See: https://github.com/mapbox/mapbox-maps-flutter/issues/775
// Keeping this as optional for backward compatibility
def token = project.properties['MAPBOX_DOWNLOADS_TOKEN'] ?: System.getenv('RNMAPBOX_MAPS_DOWNLOAD_TOKEN')
if (token) {
authentication { basic(BasicAuthentication) }
credentials {
username = 'mapbox'
password = token
}
}
}
}
}
// @generated end @rnmapbox/maps-v2-maven

View File

@@ -4,7 +4,7 @@ require("dotenv").config();
export default { export default {
name: "HIPMI Badung Connect", name: "HIPMI Badung Connect",
slug: "hipmi-mobile", slug: "hipmi-mobile",
version: "1.0.0", version: "1.0.1",
orientation: "portrait", orientation: "portrait",
icon: "./assets/images/icon.png", icon: "./assets/images/icon.png",
scheme: "hipmimobile", scheme: "hipmimobile",
@@ -16,17 +16,21 @@ export default {
bundleIdentifier: "com.anonymous.hipmi-mobile", bundleIdentifier: "com.anonymous.hipmi-mobile",
infoPlist: { infoPlist: {
ITSAppUsesNonExemptEncryption: false, ITSAppUsesNonExemptEncryption: false,
"NSLocationWhenInUseUsageDescription": "Aplikasi membutuhkan akses lokasi untuk menampilkan peta.",
}, },
associatedDomains: ["applinks:cld-dkr-staging-hipmi.wibudev.com"], associatedDomains: ["applinks:cld-dkr-staging-hipmi.wibudev.com"],
buildNumber: "14",
}, },
android: { android: {
googleServicesFile: "./google-services.json",
adaptiveIcon: { adaptiveIcon: {
foregroundImage: "./assets/images/splash-icon.png", foregroundImage: "./assets/images/splash-icon.png",
backgroundColor: "#ffffff", backgroundColor: "#ffffff",
}, },
edgeToEdgeEnabled: true, edgeToEdgeEnabled: true,
package: "com.bip.hipmimobileapp", package: "com.bip.hipmimobileapp",
versionCode: 3,
// softwareKeyboardLayoutMode: 'resize', // option: untuk mengatur keyboard pada room chst collaboration // softwareKeyboardLayoutMode: 'resize', // option: untuk mengatur keyboard pada room chst collaboration
intentFilters: [ intentFilters: [
{ {
@@ -36,7 +40,7 @@ export default {
{ {
scheme: "https", scheme: "https",
host: "cld-dkr-staging-hipmi.wibudev.com", host: "cld-dkr-staging-hipmi.wibudev.com",
pathPrefix: "/app", pathPrefix: "/",
}, },
], ],
category: ["BROWSABLE", "DEFAULT"], category: ["BROWSABLE", "DEFAULT"],
@@ -52,6 +56,7 @@ export default {
plugins: [ plugins: [
"expo-router", "expo-router",
"expo-notifications",
"expo-web-browser", "expo-web-browser",
[ [
"expo-splash-screen", "expo-splash-screen",
@@ -71,6 +76,7 @@ export default {
}, },
], ],
"expo-font", "expo-font",
"@rnmapbox/maps",
], ],
experiments: { experiments: {

View File

@@ -10,6 +10,13 @@ export default function UserLayout() {
return ( return (
<> <>
<Stack screenOptions={HeaderStyles}> <Stack screenOptions={HeaderStyles}>
<Stack.Screen
name="delete-account"
options={{
title: "Hapus Akun",
headerLeft: () => <BackButton />,
}}
/>
<Stack.Screen <Stack.Screen
name="waiting-room" name="waiting-room"
options={{ options={{
@@ -588,6 +595,13 @@ export default function UserLayout() {
headerLeft: () => <BackButton />, headerLeft: () => <BackButton />,
}} }}
/> />
<Stack.Screen
name="forum/terms"
options={{
title: "Syarat & Ketentuan Forum",
headerLeft: () => <BackButton />,
}}
/>
{/* ========== Maps Section ========= */} {/* ========== Maps Section ========= */}
<Stack.Screen <Stack.Screen

View File

@@ -155,7 +155,7 @@ export default function CollaborationCreate() {
<TextAreaCustom <TextAreaCustom
required required
label="Keuntungan Proyek" label="Keuntungan Proyek"
placeholder="Masukan keuntungan proyek" placeholder="Masukan keuntungan proyek, contoh: Meningkatkan relasi bisnis , menjamin kualitas produk, meningkatkan kinerja dan lain lain"
showCount showCount
maxLength={1000} maxLength={1000}
value={data?.benefit} value={data?.benefit}

View File

@@ -0,0 +1,111 @@
import {
AlertDefaultSystem,
BaseBox,
ButtonCustom,
CenterCustom,
StackCustom,
TextCustom,
TextInputCustom,
ViewWrapper,
} from "@/components";
import { useAuth } from "@/hooks/use-auth";
import { apiDeleteUser } from "@/service/api-client/api-user";
import { Image } from "expo-image";
import { useLocalSearchParams } from "expo-router/build/hooks";
import { useState } from "react";
import Toast from "react-native-toast-message";
export default function DeleteAccount() {
const { token, logout, user } = useAuth();
const { phone } = useLocalSearchParams();
const [text, setText] = useState("");
const [isLoading, setLoading] = useState(false);
const deleteAccount = async () => {
if (text !== "Delete Account") {
return Toast.show({
type: "error",
text1: "Ketik 'Delete Account' untuk menghapus akun",
});
}
AlertDefaultSystem({
title: "Anda yakin akan menghapus akun ini?",
message:
"Semua data yang pernah anda buat akan terhapus secara permanen !",
textLeft: "Batal",
textRight: "Ya",
onPressRight: async () => {
try {
setLoading(true);
const response = await apiDeleteUser({ id: user?.id as string });
if (response.success) {
console.log("RESPONSE >> ", response);
Toast.show({
type: "success",
text1: "Akun berhasil dihapus",
});
setTimeout(() => {
logout();
setLoading(false);
}, 2000);
} else {
Toast.show({
type: "error",
text1: "Gagal menghapus akun",
});
setLoading(false);
}
} catch (error) {
console.log("ERROR >> ", error);
setLoading(false);
}
},
});
};
return (
<>
<ViewWrapper>
<StackCustom>
<BaseBox>
<StackCustom>
<CenterCustom>
<Image
source={require("@/assets/images/constants/logo-hipmi.png")}
style={{
width: 150,
height: 150,
}}
/>
</CenterCustom>
<TextCustom align="center">
Anda akan menghapus akun dengan nomor +{phone}
</TextCustom>
<TextCustom align="center">
Ketik 'Delete Account' untuk menghapus akun
</TextCustom>
<TextInputCustom
value={text}
onChangeText={setText}
placeholder="Ketik 'Delete Account'"
/>
<ButtonCustom
backgroundColor="red"
textColor="white"
onPress={deleteAccount}
isLoading={isLoading}
disabled={isLoading}
>
Submit
</ButtonCustom>
</StackCustom>
</BaseBox>
</StackCustom>
</ViewWrapper>
</>
);
}

View File

@@ -18,7 +18,7 @@ import {
import { apiMasterEventType } from "@/service/api-client/api-master"; import { apiMasterEventType } from "@/service/api-client/api-master";
import { DateTimePickerEvent } from "@react-native-community/datetimepicker"; import { DateTimePickerEvent } from "@react-native-community/datetimepicker";
import { router, useFocusEffect, useLocalSearchParams } from "expo-router"; import { router, useFocusEffect, useLocalSearchParams } from "expo-router";
import React, { useCallback, useEffect, useState } from "react"; import { useCallback, useEffect, useState } from "react";
import Toast from "react-native-toast-message"; import Toast from "react-native-toast-message";
export default function EventEdit() { export default function EventEdit() {
@@ -55,6 +55,7 @@ export default function EventEdit() {
try { try {
setIsLoadData(true); setIsLoadData(true);
const response = await apiEventGetOne({ id: id as string }); const response = await apiEventGetOne({ id: id as string });
console.log("[DATA BY ID]", JSON.stringify(response, null, 2));
if (response.success) { if (response.success) {
setData(response.data); setData(response.data);
setSelectedDate(new Date(response.data.tanggal)); setSelectedDate(new Date(response.data.tanggal));
@@ -209,7 +210,7 @@ export default function EventEdit() {
minimumDate={new Date(Date.now())} minimumDate={new Date(Date.now())}
label="Tanggal & Waktu Mulai" label="Tanggal & Waktu Mulai"
required required
value={selectedDate as any} value={selectedDate}
onChange={(date: any) => { onChange={(date: any) => {
setSelectedDate(date as any); setSelectedDate(date as any);
}} }}
@@ -254,7 +255,6 @@ export default function EventEdit() {
placeholder="Masukkan deskripsi event" placeholder="Masukkan deskripsi event"
required required
showCount showCount
maxLength={100}
value={data?.deskripsi} value={data?.deskripsi}
onChangeText={(value) => setData({ ...data, deskripsi: value })} onChangeText={(value) => setData({ ...data, deskripsi: value })}
/> />

View File

@@ -71,8 +71,6 @@ export default function EventDetailPublish() {
} }
} }
console.log("[participans]", isParticipant);
const handlePress = (item: IMenuDrawerItem) => { const handlePress = (item: IMenuDrawerItem) => {
console.log("PATH ", item.path); console.log("PATH ", item.path);
router.navigate(item.path as any); router.navigate(item.path as any);
@@ -139,7 +137,7 @@ export default function EventDetailPublish() {
<> <>
<Stack.Screen <Stack.Screen
options={{ options={{
title: `Event publish`, title: `Event Publish`,
headerLeft: () => <LeftButtonCustom />, headerLeft: () => <LeftButtonCustom />,
headerRight: () => <DotButton onPress={() => setOpenDrawer(true)} />, headerRight: () => <DotButton onPress={() => setOpenDrawer(true)} />,
}} }}

View File

@@ -110,13 +110,14 @@ export default function EventCreate() {
const response = await apiEventCreate(newData); const response = await apiEventCreate(newData);
console.log("Response", JSON.stringify(response, null, 2)); console.log("Response", JSON.stringify(response, null, 2));
router.navigate("/event/status"); router.replace("/event/status");
} catch (error) { } catch (error) {
console.log(error); console.log(error);
} finally { } finally {
setIsLoading(false); setIsLoading(false);
} }
}; };
const buttonSubmit = ( const buttonSubmit = (
<ButtonCustom <ButtonCustom
@@ -144,7 +145,7 @@ export default function EventCreate() {
label: item.name, label: item.name,
value: item.id, value: item.id,
}))} }))}
value={data?.eventMaster_TipeAcaraId || ""} value={data?.eventMaster_TipeAcaraId || null}
onChange={(value: any) => onChange={(value: any) =>
setData({ ...data, eventMaster_TipeAcaraId: value }) setData({ ...data, eventMaster_TipeAcaraId: value })
} }
@@ -191,7 +192,7 @@ export default function EventCreate() {
placeholder="Masukkan deskripsi event" placeholder="Masukkan deskripsi event"
required required
showCount showCount
maxLength={1000} value={data?.deskripsi || ""}
onChangeText={(value: any) => onChangeText={(value: any) =>
setData({ ...data, deskripsi: value }) setData({ ...data, deskripsi: value })
} }

View File

@@ -5,9 +5,12 @@ import {
TextAreaCustom, TextAreaCustom,
ViewWrapper, ViewWrapper,
} from "@/components"; } from "@/components";
import AlertWarning from "@/components/Alert/AlertWarning";
import { apiForumGetOne, apiForumUpdate } from "@/service/api-client/api-forum"; import { apiForumGetOne, apiForumUpdate } from "@/service/api-client/api-forum";
import { isBadContent } from "@/utils/badWordsIndonesia";
import { router, useFocusEffect, useLocalSearchParams } from "expo-router"; import { router, useFocusEffect, useLocalSearchParams } from "expo-router";
import { useCallback, useState } from "react"; import { useCallback, useState } from "react";
import { Alert } from "react-native";
import Toast from "react-native-toast-message"; import Toast from "react-native-toast-message";
export default function ForumEdit() { export default function ForumEdit() {
@@ -43,6 +46,12 @@ export default function ForumEdit() {
}); });
return; return;
} }
if (isBadContent(text)) {
AlertWarning({});
return;
}
try { try {
setIsLoading(true); setIsLoading(true);
const response = await apiForumUpdate({ const response = await apiForumUpdate({

View File

@@ -1,142 +1,12 @@
/* eslint-disable react-hooks/exhaustive-deps */ /* eslint-disable react-hooks/exhaustive-deps */
import { import View_Forumku from "@/screens/Forum/ViewForumku";
AvatarComp, import View_Forumku2 from "@/screens/Forum/ViewForumku2";
ButtonCustom,
CenterCustom,
DrawerCustom,
FloatingButton,
Grid,
LoaderCustom,
StackCustom,
TextCustom,
ViewWrapper,
} from "@/components";
import { useAuth } from "@/hooks/use-auth";
import Forum_BoxDetailSection from "@/screens/Forum/DiscussionBoxSection";
import Forum_MenuDrawerBerandaSection from "@/screens/Forum/MenuDrawerSection.tsx/MenuBeranda";
import { apiForumGetAll } from "@/service/api-client/api-forum";
import { apiUser } from "@/service/api-client/api-user";
import { router, useFocusEffect, useLocalSearchParams } from "expo-router";
import _ from "lodash";
import { useCallback, useState } from "react";
export default function Forumku() { export default function Forumku() {
const { id } = useLocalSearchParams();
const { user } = useAuth();
const [openDrawer, setOpenDrawer] = useState(false);
const [status, setStatus] = useState("");
const [listData, setListData] = useState<any | null>(null);
const [dataUser, setDataUser] = useState<any | null>(null);
const [loadingGetList, setLoadingGetList] = useState(false);
useFocusEffect(
useCallback(() => {
onLoadData();
onLoadDataProfile(id as string);
}, [id])
);
const onLoadDataProfile = async (id: string) => {
try {
const response = await apiUser(id);
setDataUser(response.data);
} catch (error) {
console.log("[ERROR]", error);
} finally {
}
};
const onLoadData = async () => {
try {
setLoadingGetList(true);
const response = await apiForumGetAll({
search: "",
authorId: id as string,
});
setListData(response.data);
} catch (error) {
console.log("[ERROR]", error);
} finally {
setLoadingGetList(false);
}
};
return ( return (
<> <>
<ViewWrapper {/* <View_Forumku /> */}
floatingButton={ <View_Forumku2 />
user?.id === id && (
<FloatingButton
onPress={() =>
router.navigate("/(application)/(user)/forum/create")
}
/>
)
}
>
<StackCustom>
<CenterCustom>
<AvatarComp
fileId={dataUser?.Profile?.imageId}
href={`/(application)/(image)/preview-image/${dataUser?.Profile?.imageId}`}
size="xl"
/>
</CenterCustom>
<Grid>
<Grid.Col span={6}>
<TextCustom bold truncate>
@{dataUser?.username || "-"}
</TextCustom>
<TextCustom>{listData?.length || "0"} postingan</TextCustom>
</Grid.Col>
<Grid.Col span={6} style={{ alignItems: "flex-end" }}>
<ButtonCustom href={`/profile/${dataUser?.Profile?.id}`}>
Kunjungi Profile
</ButtonCustom>
</Grid.Col>
</Grid>
{loadingGetList ? (
<LoaderCustom />
) : _.isEmpty(listData) ? (
<TextCustom> Tidak ada diskusi</TextCustom>
) : (
<>
{listData?.map((item: any, index: number) => (
<Forum_BoxDetailSection
isRightComponent={false}
key={index}
data={item}
isTruncate={true}
href={`/forum/${item.id}`}
onSetData={(value) => {
setOpenDrawer(value.setOpenDrawer);
setStatus(value.setStatus);
}}
/>
))}
</>
)}
</StackCustom>
</ViewWrapper>
{/* Drawer Komponen Eksternal */}
<DrawerCustom
height={"auto"}
isVisible={openDrawer}
closeDrawer={() => setOpenDrawer(false)}
>
<Forum_MenuDrawerBerandaSection
id={id as string}
status={status}
setIsDrawerOpen={() => {
setOpenDrawer(false);
}}
authorId={id as string}
/>
</DrawerCustom>
</> </>
); );
} }

View File

@@ -7,6 +7,7 @@ import {
TextCustom, TextCustom,
ViewWrapper, ViewWrapper,
} from "@/components"; } from "@/components";
import AlertWarning from "@/components/Alert/AlertWarning";
import { useAuth } from "@/hooks/use-auth"; import { useAuth } from "@/hooks/use-auth";
import Forum_CommentarBoxSection from "@/screens/Forum/CommentarBoxSection"; import Forum_CommentarBoxSection from "@/screens/Forum/CommentarBoxSection";
import Forum_BoxDetailSection from "@/screens/Forum/DiscussionBoxSection"; import Forum_BoxDetailSection from "@/screens/Forum/DiscussionBoxSection";
@@ -18,9 +19,11 @@ import {
apiForumGetOne, apiForumGetOne,
apiForumUpdateStatus, apiForumUpdateStatus,
} from "@/service/api-client/api-forum"; } from "@/service/api-client/api-forum";
import { isBadContent } from "@/utils/badWordsIndonesia";
import { useFocusEffect, useLocalSearchParams } from "expo-router"; import { useFocusEffect, useLocalSearchParams } from "expo-router";
import _ from "lodash"; import _ from "lodash";
import { useCallback, useEffect, useState } from "react"; import { useCallback, useEffect, useState } from "react";
import { Alert } from "react-native";
interface CommentProps { interface CommentProps {
id: string; id: string;
@@ -110,11 +113,15 @@ export default function ForumDetail() {
// Create Commentar // Create Commentar
const handlerCreateCommentar = async () => { const handlerCreateCommentar = async () => {
if (isBadContent(text)) {
AlertWarning({});
return;
}
const newData = { const newData = {
comment: text, comment: text,
authorId: user?.id, authorId: user?.id,
}; };
try { try {
setLoadingComment(true); setLoadingComment(true);
const response = await apiForumCreateComment({ const response = await apiForumCreateComment({
@@ -223,6 +230,7 @@ export default function ForumDetail() {
> >
<Forum_MenuDrawerBerandaSection <Forum_MenuDrawerBerandaSection
id={dataId} id={dataId}
authorUsername={data?.Author?.username as string}
status={status} status={status}
setIsDrawerOpen={() => { setIsDrawerOpen={() => {
setOpenDrawer(false); setOpenDrawer(false);

View File

@@ -2,12 +2,15 @@ import {
BoxButtonOnFooter, BoxButtonOnFooter,
ButtonCustom, ButtonCustom,
TextAreaCustom, TextAreaCustom,
ViewWrapper, ViewWrapper
} from "@/components"; } from "@/components";
import AlertWarning from "@/components/Alert/AlertWarning";
import { useAuth } from "@/hooks/use-auth"; import { useAuth } from "@/hooks/use-auth";
import { apiForumCreate } from "@/service/api-client/api-forum"; import { apiForumCreate } from "@/service/api-client/api-forum";
import { isBadContent } from "@/utils/badWordsIndonesia";
import { router } from "expo-router"; import { router } from "expo-router";
import { useState } from "react"; import { useState } from "react";
import { Alert } from "react-native";
import Toast from "react-native-toast-message"; import Toast from "react-native-toast-message";
export default function ForumCreate() { export default function ForumCreate() {
@@ -16,11 +19,16 @@ export default function ForumCreate() {
const [isLoading, setIsLoading] = useState(false); const [isLoading, setIsLoading] = useState(false);
const handlerSubmit = async () => { const handlerSubmit = async () => {
if (isBadContent(text)) {
AlertWarning({})
return;
}
const newData = { const newData = {
diskusi: text, diskusi: text,
authorId: user?.id, authorId: user?.id,
}; };
try { try {
setIsLoading(true); setIsLoading(true);
const response = await apiForumCreate({ data: newData }); const response = await apiForumCreate({ data: newData });

View File

@@ -1,129 +1,12 @@
/* eslint-disable react-hooks/exhaustive-deps */ /* eslint-disable react-hooks/exhaustive-deps */
import { import Forum_ViewBeranda from "@/screens/Forum/ViewBeranda";
AvatarComp, import Forum_ViewBeranda2 from "@/screens/Forum/ViewBeranda2";
BackButton,
DrawerCustom,
LoaderCustom,
SearchInput,
TextCustom,
ViewWrapper,
} from "@/components";
import FloatingButton from "@/components/Button/FloatingButton";
import { useAuth } from "@/hooks/use-auth";
import Forum_BoxDetailSection from "@/screens/Forum/DiscussionBoxSection";
import Forum_MenuDrawerBerandaSection from "@/screens/Forum/MenuDrawerSection.tsx/MenuBeranda";
import { apiForumGetAll } from "@/service/api-client/api-forum";
import { apiUser } from "@/service/api-client/api-user";
import { router, Stack, useFocusEffect } from "expo-router";
import _ from "lodash";
import { useCallback, useState } from "react";
export default function Forum() { export default function Forum() {
const [openDrawer, setOpenDrawer] = useState(false);
const [status, setStatus] = useState("");
const { user } = useAuth();
const [dataUser, setDataUser] = useState<any>();
const [listData, setListData] = useState<any[]>();
const [loadingGetList, setLoadingGetList] = useState(false);
const [search, setSearch] = useState("");
const [dataId, setDataId] = useState("");
const [authorId, setAuthorId] = useState("");
useFocusEffect(
useCallback(() => {
onLoadData();
onLoadDataProfile(user?.id as string);
}, [user?.id, search])
);
const onLoadDataProfile = async (id: string) => {
const response = await apiUser(id);
setDataUser(response.data);
};
const onLoadData = async () => {
try {
setLoadingGetList(true);
const response = await apiForumGetAll({ search: search });
setListData(response.data);
} catch (error) {
console.log("[ERROR]", error);
} finally {
setLoadingGetList(false);
}
};
return ( return (
<> <>
<Stack.Screen {/* <Forum_ViewBeranda /> */}
options={{ <Forum_ViewBeranda2 />
title: "Forum",
headerLeft: () => <BackButton />,
headerRight: () => (
<AvatarComp
fileId={dataUser?.Profile?.imageId}
size="base"
href={`/forum/${user?.id}/forumku`}
/>
),
}}
/>
<ViewWrapper
headerComponent={
<SearchInput
placeholder="Cari topik diskusi"
onChangeText={(e) => setSearch(e)}
/>
}
floatingButton={
<FloatingButton
onPress={() =>
router.navigate("/(application)/(user)/forum/create")
}
/>
}
>
{loadingGetList ? (
<LoaderCustom />
) : _.isEmpty(listData) ? (
<TextCustom align="center" color="gray">
Tidak ada diskusi
</TextCustom>
) : (
listData?.map((e: any, i: number) => (
<Forum_BoxDetailSection
key={i}
data={e}
onSetData={() => {
setDataId(e.id);
setOpenDrawer(true);
setStatus(e.ForumMaster_StatusPosting?.status);
setAuthorId(e.Author?.id);
}}
isTruncate={true}
href={`/forum/${e.id}`}
isRightComponent={false}
/>
))
)}
</ViewWrapper>
<DrawerCustom
height={"auto"}
isVisible={openDrawer}
closeDrawer={() => setOpenDrawer(false)}
>
<Forum_MenuDrawerBerandaSection
id={dataId}
authorId={authorId}
status={status}
setIsDrawerOpen={() => {
setOpenDrawer(false);
}}
/>
</DrawerCustom>
</> </>
); );
} }

View File

@@ -0,0 +1,202 @@
import {
BaseBox,
ButtonCustom,
CheckboxCustom,
NewWrapper,
StackCustom,
TextCustom,
} from "@/components";
import { useAuth } from "@/hooks/use-auth";
import { apiAcceptForumTerms } from "@/service/api-client/api-user";
import { GStyles } from "@/styles/global-styles";
import { Ionicons } from "@expo/vector-icons";
import { router } from "expo-router";
import { useState } from "react";
import { View } from "react-native";
import { Text } from "react-native-paper";
import Toast from "react-native-toast-message";
export default function ForumSplash() {
const { user } = useAuth();
const [term, setTerm] = useState(false);
const [loading, setLoading] = useState(false);
const handleSubmit = async () => {
try {
setLoading(true);
const respone = await apiAcceptForumTerms({
category: "Forum",
userId: user?.id as any,
});
if (respone.success) {
Toast.show({
type: "success",
text1: "Berhasil",
text2: "Terima kasih telah menerima syarat & ketentuan forum ini",
});
router.replace("/(application)/forum");
return;
}
Toast.show({
type: "error",
text1: "Gagal",
text2: "Terjadi kesalahan, silahkan coba lagi",
});
} catch (error) {
console.log("[ERROR]", error);
} finally {
setLoading(false);
}
};
return (
<NewWrapper>
{/* <TextCustom bold>HIPMI Badung Connect</TextCustom> . */}
<BaseBox>
<StackCustom>
<TextCustom>
Dengan mengakses dan menggunakan Forum HIPMI Badung Connect, Anda
secara sadar menyetujui ketentuan berikut:
</TextCustom>
<TextCustom bold>
1. Dilarang keras memposting konten yang mengandung:
</TextCustom>
<View style={{ paddingInline: 10 }}>
{forumTerms1.map((term, index) => (
<View
key={index}
style={{
flexDirection: "row",
alignItems: "center",
gap: 10,
paddingBottom: 10,
}}
>
<Ionicons name="radio-button-on" color={"white"} />
<TextCustom>{term.text}</TextCustom>
</View>
))}
</View>
<TextCustom bold>
2. Setiap pengguna bertanggung jawab penuh atas konten yang
diunggah. Konten yang melanggar ketentuan ini dapat dihapus kapan
saja tanpa pemberitahuan.
</TextCustom>
<TextCustom bold>
3. Jika Anda menemukan konten tidak pantas, segera:
</TextCustom>
<View style={{ paddingInline: 10 }}>
{forumTerms2.map((term, index) => (
<View
key={index}
style={{
flexDirection: "row",
alignItems: "center",
gap: 10,
paddingBottom: 10,
}}
>
<Ionicons name="radio-button-on" color={"white"} />
<TextCustom>{term.text}</TextCustom>
</View>
))}
</View>
<TextCustom bold>
4. Gunakan fitur Blokir Pengguna di profil pengguna terkait
</TextCustom>
<View style={{ paddingInline: 10 }}>
{forumTerms3.map((term, index) => (
<View
key={index}
style={{
flexDirection: "row",
alignItems: "center",
gap: 10,
paddingBottom: 10,
}}
>
<Ionicons name="radio-button-on" color={"white"} />
<TextCustom>{term.text}</TextCustom>
</View>
))}
</View>
<TextCustom>
Pelanggaran terhadap ketentuan ini berakibat{" "}
<TextCustom bold>pencabutan akses</TextCustom> ke Forum dan/atau{" "}
<TextCustom bold>pemblokiran akun secara permanen</TextCustom> tanpa
pemberitahuan lebih lanjut.
</TextCustom>
<View
style={{
flexDirection: "row",
alignItems: "center",
marginTop: 16,
marginBottom: 16,
}}
>
<CheckboxCustom value={term} onChange={() => setTerm(!term)} />
<Text style={GStyles.textLabel}>
Saya telah membaca dan menyetujui Syarat & Ketentuan Forum ini
</Text>
</View>
<ButtonCustom
disabled={!term || loading}
onPress={() => {
handleSubmit();
}}
>
Lanjut
</ButtonCustom>
</StackCustom>
</BaseBox>
</NewWrapper>
);
}
// Data dalam format JSON (bisa juga diimpor dari file terpisah)
interface Term {
text: string;
}
const forumTerms1: Term[] = [
{
text: "Ujaran kebencian, diskriminasi, atau konten SARA (Suku, Agama, Ras, Antar-golongan)",
},
{ text: "Kata kasar, pelecehan, ancaman, atau bullying" },
{ text: "Pornografi, hoaks, spam, atau informasi menyesatkan" },
{ text: "Promosi aktivitas ilegal seperti perjudian atau narkoba" },
];
const forumTerms2: Term[] = [
{
text: "Gunakan tombol “Laporkan” di setiap postingan, atau",
},
{
text: "Gunakan fitur “Blokir Pengguna” di profil pengguna terkait.",
},
];
const forumTerms3: Term[] = [
{
text: "Meninjau setiap laporan dalam waktu 24 jam",
},
{
text: "Menghapus konten yang melanggar",
},
{
text: "Memblokir akun pelanggar sesuai tingkat pelanggaran",
},
];

View File

@@ -11,31 +11,52 @@ import Home_FeatureSection from "@/screens/Home/topFeatureSection";
import { apiUser } from "@/service/api-client/api-user"; import { apiUser } from "@/service/api-client/api-user";
import { apiVersion } from "@/service/api-config"; import { apiVersion } from "@/service/api-config";
import { Ionicons } from "@expo/vector-icons"; import { Ionicons } from "@expo/vector-icons";
import { Redirect, router, Stack } from "expo-router"; import { Redirect, router, Stack, useFocusEffect } from "expo-router";
import { useEffect, useState } from "react"; import { useCallback, useEffect, useState } from "react";
import { RefreshControl } from "react-native";
export default function Application() { export default function Application() {
const { token, user } = useAuth(); const { token, user, userData } = useAuth();
const [data, setData] = useState<any>(); const [data, setData] = useState<any>();
const [refreshing, setRefreshing] = useState(false);
console.log("[User] >>", JSON.stringify(user?.id, null, 2));
useEffect(() => { // ‼️ Untuk cek apakah: 1. user ada, 2. user punya profile, 3. accept temrs of forum nya ada atau tidak
onLoadData(); useFocusEffect(
checkVersion(); useCallback(() => {
}, []); onLoadData();
checkVersion();
userData(token as string);
}, [user?.id, token])
);
async function onLoadData() { async function onLoadData() {
const response = await apiUser(user?.id as string); const response = await apiUser(user?.id as string);
console.log("Response profile >>", JSON.stringify(response?.data?.Profile, null, 2)); console.log(
"[Profile ID]>>",
JSON.stringify(response?.data?.Profile?.id, null, 2)
);
setData(response.data); setData(response.data);
} }
const checkVersion = async () => { const checkVersion = async () => {
const response = await apiVersion(); const response = await apiVersion();
console.log("Version >>", JSON.stringify(response.data, null, 2)); console.log("[Version] >>", JSON.stringify(response.data, null, 2));
}; };
const onRefresh = useCallback(() => {
setRefreshing(true);
onLoadData();
checkVersion();
setRefreshing(false);
}, []);
if (user && user?.termsOfServiceAccepted === false) {
console.log("User is not accept term service");
return <Redirect href={`/terms-agreement`} />;
}
if (data && data?.active === false) { if (data && data?.active === false) {
console.log("User is not active"); console.log("User is not active");
return <Redirect href={`/waiting-room`} />; return <Redirect href={`/waiting-room`} />;
@@ -63,6 +84,7 @@ export default function Application() {
), ),
headerRight: () => ( headerRight: () => (
<Ionicons <Ionicons
disabled={true}
name="notifications" name="notifications"
size={20} size={20}
color={MainColor.yellow} color={MainColor.yellow}
@@ -74,8 +96,16 @@ export default function Application() {
}} }}
/> />
<ViewWrapper <ViewWrapper
refreshControl={
<RefreshControl refreshing={refreshing} onRefresh={onRefresh} />
}
footerComponent={ footerComponent={
<TabSection tabs={tabsHome(data?.Profile?.id as string)} /> <TabSection
tabs={tabsHome({
acceptedForumTermsAt: data?.acceptedForumTermsAt,
profileId: data?.Profile?.id,
})}
/>
} }
> >
<StackCustom> <StackCustom>

View File

@@ -15,6 +15,7 @@ import Investment_ButtonInvestasiSection from "@/screens/Invesment/ButtonInvesta
import Invesment_ComponentBoxOnBottomDetail from "@/screens/Invesment/ComponentBoxOnBottomDetail"; import Invesment_ComponentBoxOnBottomDetail from "@/screens/Invesment/ComponentBoxOnBottomDetail";
import Invesment_DetailDataPublishSection from "@/screens/Invesment/DetailDataPublishSection"; import Invesment_DetailDataPublishSection from "@/screens/Invesment/DetailDataPublishSection";
import { apiInvestmentGetOne } from "@/service/api-client/api-investment"; import { apiInvestmentGetOne } from "@/service/api-client/api-investment";
import { countDownAndCondition } from "@/utils/countDownAndCondition";
import { AntDesign, MaterialIcons } from "@expo/vector-icons"; import { AntDesign, MaterialIcons } from "@expo/vector-icons";
import { import {
router, router,
@@ -23,7 +24,7 @@ import {
useLocalSearchParams, useLocalSearchParams,
} from "expo-router"; } from "expo-router";
import _ from "lodash"; import _ from "lodash";
import { useCallback, useState } from "react"; import { useCallback, useEffect, useState } from "react";
export default function InvestmentDetail() { export default function InvestmentDetail() {
const { user } = useAuth(); const { user } = useAuth();
@@ -62,6 +63,31 @@ export default function InvestmentDetail() {
setOpenDrawerPublish(false); setOpenDrawerPublish(false);
}; };
const [value, setValue] = useState({
sisa: 0,
reminder: false,
});
useEffect(() => {
updateCountDown();
}, [data]);
console.log("[DATA DETAIL]", JSON.stringify(data, null, 2));
const updateCountDown = () => {
const countDown = countDownAndCondition({
duration: data?.MasterPencarianInvestor.name,
publishTime: data?.countDown,
});
setValue({
sisa: countDown.durationDay,
reminder: countDown.reminder,
});
};
const bottomSection = ( const bottomSection = (
<Invesment_ComponentBoxOnBottomDetail <Invesment_ComponentBoxOnBottomDetail
id={id as string} id={id as string}
@@ -71,7 +97,7 @@ export default function InvestmentDetail() {
); );
const buttonSection = ( const buttonSection = (
<Investment_ButtonInvestasiSection id={id as string} isMine={user?.id === data?.author?.id} /> <Investment_ButtonInvestasiSection id={id as string} isMine={user?.id === data?.author?.id} reminder={value.reminder} />
); );
return ( return (

View File

@@ -1,32 +1,6 @@
import { import MapsView from "@/screens/Maps/MapsView";
ButtonCustom, import MapsView2 from "@/screens/Maps/MapsView2";
DrawerCustom, import { Text, View } from "react-native";
DummyLandscapeImage,
Grid,
Spacing,
StackCustom,
TextCustom,
ViewWrapper,
} from "@/components";
import GridTwoView from "@/components/_ShareComponent/GridTwoView";
import API_IMAGE from "@/constants/api-storage";
import { ICON_SIZE_SMALL } from "@/constants/constans-value";
import { apiMapsGetAll } from "@/service/api-client/api-maps";
import { openInDeviceMaps } from "@/utils/openInDeviceMaps";
import { FontAwesome, Ionicons } from "@expo/vector-icons";
import { Image } from "expo-image";
import { router, useFocusEffect } from "expo-router";
import { useCallback, useState } from "react";
import { View } from "react-native";
import MapView, { Marker } from "react-native-maps";
const defaultRegion = {
latitude: -8.737109,
longitude: 115.1756897,
latitudeDelta: 0.1,
longitudeDelta: 0.1,
height: 300,
};
export interface LocationItem { export interface LocationItem {
id: string | number; id: string | number;
@@ -37,198 +11,11 @@ export interface LocationItem {
} }
export default function Maps() { export default function Maps() {
const [list, setList] = useState<any[] | null>(null);
const [loadList, setLoadList] = useState(false);
const [openDrawer, setOpenDrawer] = useState(false);
const [selected, setSelected] = useState({
id: "",
bidangBisnis: "",
nomorTelepon: "",
alamatBisnis: "",
namePin: "",
imageId: "",
portofolioId: "",
latitude: 0,
longitude: 0,
});
useFocusEffect(
useCallback(() => {
handlerLoadList();
}, [])
);
const handlerLoadList = async () => {
try {
setLoadList(true);
const response = await apiMapsGetAll();
if (response.success) {
setList(response.data);
}
} catch (error) {
console.log("[ERROR]", error);
} finally {
setLoadList(false);
}
};
return ( return (
<> <>
<ViewWrapper style={{ paddingInline: 0, paddingBlock: 0 }}> <MapsView />
{/* <MapCustom height={"100%"} /> */} {/* <MapsView2 />, */}
<View style={{ flex: 1 }}> {/* <View style={{ flex: 1, backgroundColor: "gray" }}><Text style={{ color: "white" }}>Map disabled</Text></View> */}
{loadList ? (
<MapView
initialRegion={defaultRegion}
style={{
width: "100%",
height: "100%",
}}
/>
) : (
<MapView
initialRegion={defaultRegion}
style={{
width: "100%",
height: "100%",
}}
>
{list?.map((item: any, index: number) => {
return (
<Marker
key={item?.id}
coordinate={{
latitude: item?.latitude,
longitude: item?.longitude,
}}
title={item?.namePin}
onPress={() => {
setOpenDrawer(true);
setSelected({
id: item?.id,
bidangBisnis:
item?.Portofolio?.MasterBidangBisnis?.name,
nomorTelepon: item?.Portofolio?.tlpn,
alamatBisnis: item?.Portofolio?.alamatKantor,
namePin: item?.namePin,
imageId: item?.imageId,
portofolioId: item?.Portofolio?.id,
latitude: item?.latitude,
longitude: item?.longitude,
});
}}
// Gunakan gambar kustom jika tersedia
>
<View style={{}}>
<Image
source={{
uri: API_IMAGE.GET({
fileId: item?.Portofolio?.logoId,
}),
}}
style={{
width: 30,
height: 30,
borderRadius: 100,
borderWidth: 1,
}}
/>
</View>
</Marker>
);
})}
</MapView>
)}
</View>
</ViewWrapper>
<DrawerCustom
isVisible={openDrawer}
closeDrawer={() => setOpenDrawer(false)}
height={"auto"}
>
<DummyLandscapeImage height={200} imageId={selected.imageId} />
<Spacing />
<StackCustom gap={"xs"}>
<GridTwoView
spanLeft={2}
spanRight={10}
leftIcon={
<FontAwesome
name="building-o"
size={ICON_SIZE_SMALL}
color="white"
/>
}
rightIcon={<TextCustom>{selected.namePin}</TextCustom>}
/>
<GridTwoView
spanLeft={2}
spanRight={10}
leftIcon={
<Ionicons
name="list-outline"
size={ICON_SIZE_SMALL}
color="white"
/>
}
rightIcon={<TextCustom>{selected.bidangBisnis}</TextCustom>}
/>
<GridTwoView
spanLeft={2}
spanRight={10}
leftIcon={
<Ionicons
name="call-outline"
size={ICON_SIZE_SMALL}
color="white"
/>
}
rightIcon={<TextCustom>{selected.nomorTelepon}</TextCustom>}
/>
<GridTwoView
spanLeft={2}
spanRight={10}
leftIcon={
<Ionicons
name="location-outline"
size={ICON_SIZE_SMALL}
color="white"
/>
}
rightIcon={<TextCustom>{selected.alamatBisnis}</TextCustom>}
/>
<Grid>
<Grid.Col span={6} style={{ paddingRight: 10 }}>
<ButtonCustom
onPress={() => {
setOpenDrawer(false);
router.push(`/portofolio/${selected.portofolioId}`);
}}
>
Detail
</ButtonCustom>
</Grid.Col>
<Grid.Col span={6} style={{ paddingLeft: 10 }}>
<ButtonCustom
onPress={() => {
openInDeviceMaps({
latitude: selected.latitude,
longitude: selected.longitude,
title: selected.namePin,
});
}}
>
Buka Maps
</ButtonCustom>
</Grid.Col>
</Grid>
</StackCustom>
</DrawerCustom>
</> </>
); );
} }

View File

@@ -31,9 +31,9 @@ import {
import pickImage from "@/utils/pickImage"; import pickImage from "@/utils/pickImage";
import { Ionicons } from "@expo/vector-icons"; import { Ionicons } from "@expo/vector-icons";
import { Image } from "expo-image"; import { Image } from "expo-image";
import { useLocalSearchParams } from "expo-router"; import { useFocusEffect, useLocalSearchParams } from "expo-router";
import _ from "lodash"; import _ from "lodash";
import { useEffect, useState } from "react"; import { useCallback, useEffect, useState } from "react";
import { Text, TouchableOpacity, View } from "react-native"; import { Text, TouchableOpacity, View } from "react-native";
import PhoneInput, { ICountry } from "react-native-international-phone-number"; import PhoneInput, { ICountry } from "react-native-international-phone-number";
import { Avatar } from "react-native-paper"; import { Avatar } from "react-native-paper";
@@ -76,7 +76,7 @@ export default function PortofolioCreate() {
function handleInputValue(phoneNumber: string) { function handleInputValue(phoneNumber: string) {
setInputValue(phoneNumber); setInputValue(phoneNumber);
const callingCode = selectedCountry?.callingCode.replace(/^\+/, "") || ""; const callingCode = selectedCountry?.callingCode.replace(/^\+/, "") || "";
const fixNumber = inputValue.replace(/\s+/g, ""); let fixNumber = inputValue.replace(/\s+/g, "").replace(/^0+/, "");
const realNumber = callingCode + fixNumber; const realNumber = callingCode + fixNumber;
setData({ ...data, tlpn: realNumber }); setData({ ...data, tlpn: realNumber });
} }
@@ -85,10 +85,12 @@ export default function PortofolioCreate() {
setSelectedCountry(country); setSelectedCountry(country);
} }
useEffect(() => { useFocusEffect(
onLoadMaster(); useCallback(() => {
onLoadMasterSubBidangBisnis(); onLoadMaster();
}, []); onLoadMasterSubBidangBisnis();
}, [])
);
const onLoadMaster = async () => { const onLoadMaster = async () => {
try { try {

View File

@@ -244,7 +244,7 @@ export default function PortofolioEdit() {
const handleSubmitUpdate = async () => { const handleSubmitUpdate = async () => {
const callingCode = selectedCountry?.callingCode.replace(/^\+/, "") || ""; const callingCode = selectedCountry?.callingCode.replace(/^\+/, "") || "";
const fixNumber = data.tlpn.replace(/\s+/g, ""); let fixNumber = data.tlpn.replace(/\s+/g, "").replace(/^0+/, "");
const realNumber = callingCode + fixNumber; const realNumber = callingCode + fixNumber;
const newData: IFormData = { const newData: IFormData = {

View File

@@ -0,0 +1,148 @@
import {
AvatarUsernameAndOtherComponent,
BadgeCustom,
ClickableCustom,
Divider,
SelectCustom,
TextCustom,
} from "@/components";
import ListEmptyComponent from "@/components/_ShareComponent/ListEmptyComponent";
import ListLoaderFooterComponent from "@/components/_ShareComponent/ListLoaderFooterComponent";
import ListSkeletonComponent from "@/components/_ShareComponent/ListSkeletonComponent";
import NewWrapper from "@/components/_ShareComponent/NewWrapper";
import { MainColor } from "@/constants/color-palet";
import { useAuth } from "@/hooks/use-auth";
import { usePaginatedApi } from "@/hooks/use-paginated-api";
import { apiGetBlocked } from "@/service/api-client/api-blocked";
import { apiMasterAppCategory } from "@/service/api-client/api-master";
import { router, useFocusEffect } from "expo-router";
import _ from "lodash";
import { useCallback, useEffect, useRef, useState } from "react";
import { RefreshControl, View } from "react-native";
const PAGE_SIZE = 10;
export default function ProfileBlockedList() {
const { user } = useAuth();
const [masterApp, setMasterApp] = useState<any[]>([]);
const isInitialMount = useRef(true);
const {
data: listData,
loading,
refreshing,
hasMore,
search,
setSearch,
onRefresh,
loadMore,
} = usePaginatedApi({
fetcher: async (params: { page: number; search?: string }) => {
const response = await apiGetBlocked({
id: user?.id as any,
search: search,
page: String(params.page) as any,
});
return response.data;
},
initialSearch: "",
pageSize: PAGE_SIZE,
dependencies: [user?.id],
});
useEffect(() => {
fetchMasterApp();
}, []);
// 🔁 Refresh otomatis saat kembali ke halaman ini
useFocusEffect(
useCallback(() => {
if (isInitialMount.current) {
// Skip saat pertama kali mount
isInitialMount.current = false;
return;
}
// Hanya refresh saat kembali dari screen lain
onRefresh();
}, [onRefresh])
);
const fetchMasterApp = async () => {
const response = await apiMasterAppCategory();
setMasterApp(response.data);
};
const renderHeader = () => (
<SelectCustom
placeholder="Pilih Kategori Fitur"
data={masterApp.map((item) => ({
label: item.name,
value: item.id,
}))}
value={search === "" ? undefined : search}
onChange={(value) => {
setSearch(value as any);
}}
/>
);
const renderItem = ({ item }: { item: any }) => (
<>
<ClickableCustom
onPress={() => {
router.push(`/profile/${item.id}/detail-blocked`);
}}
>
<View
style={{
paddingInline: 8,
}}
>
<AvatarUsernameAndOtherComponent
avatarHref={`/profile/${item?.blocked?.Profile?.id}`}
avatar={item?.blocked?.Profile?.imageId}
name={item?.blocked?.username}
rightComponent={
<View style={{ flexDirection: "row", gap: 4 }}>
<BadgeCustom>
<TextCustom size={"small"} bold truncate>
{item?.menuFeature?.name}
</TextCustom>
</BadgeCustom>
</View>
}
/>
<Divider color="gray" />
</View>
</ClickableCustom>
</>
);
return (
<>
<NewWrapper
// headerComponent={renderHeader()}
listData={listData}
renderItem={renderItem}
onEndReached={loadMore}
refreshControl={
<RefreshControl
progressBackgroundColor={MainColor.yellow}
refreshing={refreshing}
onRefresh={onRefresh}
/>
}
ListFooterComponent={
hasMore && !refreshing ? <ListLoaderFooterComponent /> : null
}
ListEmptyComponent={
!loading && _.isEmpty(listData) ? (
<ListSkeletonComponent />
) : (
<ListEmptyComponent />
)
}
/>
</>
);
}

View File

@@ -0,0 +1,93 @@
import {
AlertDefaultSystem,
AvatarUsernameAndOtherComponent,
BaseBox,
BoxButtonOnFooter,
BoxWithHeaderSection,
ButtonCustom,
NewWrapper,
StackCustom,
TextCustom,
} from "@/components";
import AvatarAndBackground from "@/screens/Profile/AvatarAndBackground";
import {
apiGetBlockedById,
apiUnblock,
} from "@/service/api-client/api-blocked";
import { router, useLocalSearchParams } from "expo-router";
import _ from "lodash";
import { useEffect, useState } from "react";
export default function ProfileDetailBlocked() {
const { id } = useLocalSearchParams();
const [data, setData] = useState<any>(null);
const [isLoading, setIsLoading] = useState<boolean>(false);
useEffect(() => {
fetchData();
}, [id]);
const fetchData = async () => {
const response = await apiGetBlockedById({ id: String(id) });
// console.log("[RESPONSE >>]", JSON.stringify(response, null, 2));
setData(response.data);
};
const handleSubmit = async () => {
try {
setIsLoading(true);
await apiUnblock({ id: String(id) });
router.back();
} catch (error) {
console.log("[ERROR >>]", JSON.stringify(error, null, 2));
} finally {
setIsLoading(false);
}
};
return (
<>
<NewWrapper
footerComponent={
<BoxButtonOnFooter>
<ButtonCustom
isLoading={isLoading}
onPress={() => {
AlertDefaultSystem({
title: "Buka Blokir",
message: "Apakah anda yakin ingin membuka blokir ini?",
textLeft: "Tidak",
textRight: "Ya",
onPressRight: () => {
handleSubmit();
},
});
}}
>
Buka Blokir
</ButtonCustom>
</BoxButtonOnFooter>
}
>
<BoxWithHeaderSection>
<StackCustom>
<AvatarUsernameAndOtherComponent
avatarHref={`/profile/${data?.blocked?.Profile?.id}`}
avatar={data?.blocked?.Profile?.imageId}
name={data?.blocked?.username}
/>
<TextCustom align="center">
Jika anda membuka blokir ini maka semua postingan terkait user ini
akan muncul kembali di beranda
<TextCustom bold color="red">
{" "}
{_.upperCase(data?.menuFeature?.name)}
</TextCustom>
</TextCustom>
</StackCustom>
</BoxWithHeaderSection>
</NewWrapper>
</>
);
}

View File

@@ -64,14 +64,18 @@ export default function Profile() {
}; };
const onLoadPortofolio = async (id: string) => { const onLoadPortofolio = async (id: string) => {
const response = await apiGetPortofolio({ id: id }); try {
const lastTwoByDate = response.data const response = await apiGetPortofolio({ id: id });
.sort( const lastTwoByDate = response.data
(a: any, b: any) => .sort(
new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime() (a: any, b: any) =>
) // urut desc new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime()
.slice(0, 2); ) // urut desc
setListPortofolio(lastTwoByDate); .slice(0, 2);
setListPortofolio(lastTwoByDate);
} catch (error) {
console.log("[ERROR]", error);
}
}; };
return ( return (

View File

@@ -33,6 +33,16 @@ export default function ProfileLayout() {
name="create" name="create"
options={{ title: "Buat Profile", headerBackVisible: false }} options={{ title: "Buat Profile", headerBackVisible: false }}
/> />
<Stack.Screen
name="[id]/blocked-list"
options={{ title: "Blocked List", headerLeft: () => <BackButton /> }}
/>
<Stack.Screen
name="[id]/detail-blocked"
options={{ title: "Detail Blokir", headerLeft: () => <BackButton /> }}
/>
</Stack> </Stack>
</> </>
); );

View File

@@ -6,6 +6,7 @@ import {
TextCustom, TextCustom,
ViewWrapper, ViewWrapper,
} from "@/components"; } from "@/components";
import { useAuth } from "@/hooks/use-auth";
import Voting_BoxPublishSection from "@/screens/Voting/BoxPublishSection"; import Voting_BoxPublishSection from "@/screens/Voting/BoxPublishSection";
import { apiVotingGetAll } from "@/service/api-client/api-voting"; import { apiVotingGetAll } from "@/service/api-client/api-voting";
import { router, useFocusEffect } from "expo-router"; import { router, useFocusEffect } from "expo-router";
@@ -13,6 +14,7 @@ import _ from "lodash";
import { useCallback, useState } from "react"; import { useCallback, useState } from "react";
export default function VotingBeranda() { export default function VotingBeranda() {
const { user } = useAuth();
const [listData, setListData] = useState<any>([]); const [listData, setListData] = useState<any>([]);
const [loadingGetData, setLoadingGetData] = useState(false); const [loadingGetData, setLoadingGetData] = useState(false);
const [search, setSearch] = useState(""); const [search, setSearch] = useState("");
@@ -29,6 +31,7 @@ export default function VotingBeranda() {
const response = await apiVotingGetAll({ const response = await apiVotingGetAll({
search, search,
category: "beranda", category: "beranda",
userLoginId: user?.id,
}); });
if (response.success) { if (response.success) {
setListData(response.data); setListData(response.data);

View File

@@ -134,7 +134,7 @@ export default function VotingDetailStatus() {
{data && {data &&
data?.catatan && data?.catatan &&
(status === "draft" || status === "rejected") && ( (status === "draft" || status === "reject") && (
<ReportBox text={data?.catatan} /> <ReportBox text={data?.catatan} />
)} )}

View File

@@ -4,6 +4,7 @@ import {
ButtonCenteredOnly, ButtonCenteredOnly,
ButtonCustom, ButtonCustom,
InformationBox, InformationBox,
NewWrapper,
StackCustom, StackCustom,
ViewWrapper, ViewWrapper,
} from "@/components"; } from "@/components";
@@ -12,6 +13,7 @@ import { useAuth } from "@/hooks/use-auth";
import { apiUser } from "@/service/api-client/api-user"; import { apiUser } from "@/service/api-client/api-user";
import { Ionicons } from "@expo/vector-icons"; import { Ionicons } from "@expo/vector-icons";
import { router } from "expo-router"; import { router } from "expo-router";
import { RefreshControl } from "react-native";
import Toast from "react-native-toast-message"; import Toast from "react-native-toast-message";
export default function WaitingRoom() { export default function WaitingRoom() {
@@ -33,7 +35,7 @@ export default function WaitingRoom() {
} else { } else {
Toast.show({ Toast.show({
type: "success", type: "success",
text1: "Akun anda telah aktif", // text2: "Anda berhasil login", text1: "Selamat ! Akun anda telah aktif", // text2: "Anda berhasil login",
}); });
router.replace(`/(application)/(user)/profile/create`); router.replace(`/(application)/(user)/profile/create`);
} }
@@ -82,10 +84,18 @@ export default function WaitingRoom() {
return ( return (
<> <>
<ViewWrapper footerComponent={logoutButton()}> <NewWrapper
footerComponent={logoutButton()}
refreshControl={
<RefreshControl refreshing={isLoading} onRefresh={handleCheck} />
}
>
<StackCustom> <StackCustom>
<InformationBox text="Permohonan akses Anda sedang dalam proses verifikasi oleh admin. Harap tunggu, Anda akan menerima pemberitahuan melalui Whatsapp setelah disetujui." /> <InformationBox
<ButtonCenteredOnly text="Akun Anda sedang menunggu aktivasi.
Silakan tunggu beberapa saat. Untuk memperbarui status, tarik layar ke bawah."
/>
{/* <ButtonCenteredOnly
isLoading={isLoading} isLoading={isLoading}
onPress={() => { onPress={() => {
handleCheck(); handleCheck();
@@ -93,9 +103,9 @@ export default function WaitingRoom() {
icon="refresh-ccw" icon="refresh-ccw"
> >
Check Check
</ButtonCenteredOnly> </ButtonCenteredOnly> */}
</StackCustom> </StackCustom>
</ViewWrapper> </NewWrapper>
</> </>
); );
} }

View File

@@ -9,6 +9,7 @@ export default function ApplicationLayout() {
<Stack.Screen name="(user)" options={{ headerShown: false }} /> <Stack.Screen name="(user)" options={{ headerShown: false }} />
<Stack.Screen name="admin" options={{ headerShown: false }} /> <Stack.Screen name="admin" options={{ headerShown: false }} />
{/* Take Picture */} {/* Take Picture */}
<Stack.Screen <Stack.Screen

View File

@@ -0,0 +1,129 @@
/* eslint-disable react-hooks/exhaustive-deps */
import {
BoxButtonOnFooter,
ButtonCustom,
StackCustom,
TextCustom,
TextInputCustom,
ViewWrapper,
} from "@/components";
import AdminBackButtonAntTitle from "@/components/_ShareComponent/Admin/BackButtonAntTitle";
import { MainColor } from "@/constants/color-palet";
import {
apiAdminMasterBusinessFieldById,
apiAdminMasterBusinessFieldUpdate,
} from "@/service/api-admin/api-master-admin";
import { router, useFocusEffect, useLocalSearchParams } from "expo-router";
import { useCallback, useState } from "react";
import { Switch } from "react-native-paper";
import Toast from "react-native-toast-message";
export default function AdminAppInformation_BusinessFieldDetail() {
const { id } = useLocalSearchParams();
const [data, setData] = useState<any | null>(null);
const [isLoading, setIsLoading] = useState(false);
useFocusEffect(
useCallback(() => {
onLoadDetail();
}, [id])
);
const onLoadDetail = async () => {
try {
const response = await apiAdminMasterBusinessFieldById({
id: id as string,
category: "bidang"
});
setData(response.data);
} catch (error) {
console.log("[ERROR]", error);
setData(null);
}
};
const handlerSubmit = async () => {
if (!data.name) {
Toast.show({
type: "error",
text1: "Lengkapi Data",
});
return;
}
try {
setIsLoading(true);
const response = await apiAdminMasterBusinessFieldUpdate({
id: id as string,
data: data,
category: "bidang",
});
if (!response.success) {
Toast.show({
type: "error",
text1: "Gagal update data",
});
return;
}
Toast.show({
type: "success",
text1: "Data berhasil di update",
});
router.back();
} catch (error) {
console.log(error);
} finally {
setIsLoading(false);
}
};
const buttonSubmit = (
<BoxButtonOnFooter>
<ButtonCustom
disabled={!data?.name}
isLoading={isLoading}
onPress={() => handlerSubmit()}
>
Update
</ButtonCustom>
</BoxButtonOnFooter>
);
return (
<>
<ViewWrapper footerComponent={buttonSubmit}>
<StackCustom>
<AdminBackButtonAntTitle title="Update Bidang Bisnis" />
<TextInputCustom
label="Nama Bidang Bisnis"
placeholder="Masukan Nama Bidang Bisnis"
required
value={data?.name}
onChangeText={(value) => setData({ ...data, name: value })}
/>
<StackCustom
gap={"sm"}
style={{
alignContent: "flex-start",
}}
>
<TextCustom>Status</TextCustom>
<Switch
style={{
alignSelf: "flex-start",
}}
color={MainColor.yellow}
value={data?.active}
onValueChange={(value) => setData({ ...data, active: value })}
/>
</StackCustom>
</StackCustom>
</ViewWrapper>
</>
);
}

View File

@@ -1,22 +1,22 @@
/* eslint-disable react-hooks/exhaustive-deps */ /* eslint-disable react-hooks/exhaustive-deps */
import { import {
BoxButtonOnFooter, ActionIcon,
ButtonCustom, BaseBox,
CenterCustom,
LoaderCustom,
Spacing,
StackCustom, StackCustom,
TextCustom, TextCustom,
TextInputCustom,
ViewWrapper, ViewWrapper,
} from "@/components"; } from "@/components";
import { IconEdit } from "@/components/_Icon";
import AdminBackButtonAntTitle from "@/components/_ShareComponent/Admin/BackButtonAntTitle"; import AdminBackButtonAntTitle from "@/components/_ShareComponent/Admin/BackButtonAntTitle";
import { GridSpan_NewComponent } from "@/components/_ShareComponent/GridSpan_NewComponent";
import { MainColor } from "@/constants/color-palet"; import { MainColor } from "@/constants/color-palet";
import { import { apiAdminMasterBusinessFieldById } from "@/service/api-admin/api-master-admin";
apiAdminMasterBusinessFieldById,
apiAdminMasterBusinessFieldUpdate,
} from "@/service/api-admin/api-master-admin";
import { router, useFocusEffect, useLocalSearchParams } from "expo-router"; import { router, useFocusEffect, useLocalSearchParams } from "expo-router";
import { useCallback, useState } from "react"; import { useCallback, useState } from "react";
import { Switch } from "react-native-paper"; import { Divider } from "react-native-paper";
import Toast from "react-native-toast-message";
export default function AdminAppInformation_BusinessFieldDetail() { export default function AdminAppInformation_BusinessFieldDetail() {
const { id } = useLocalSearchParams(); const { id } = useLocalSearchParams();
@@ -33,8 +33,11 @@ export default function AdminAppInformation_BusinessFieldDetail() {
try { try {
const response = await apiAdminMasterBusinessFieldById({ const response = await apiAdminMasterBusinessFieldById({
id: id as string, id: id as string,
category: "all",
}); });
console.log("Response >>", JSON.stringify(response, null, 2));
setData(response.data); setData(response.data);
} catch (error) { } catch (error) {
console.log("[ERROR]", error); console.log("[ERROR]", error);
@@ -42,73 +45,89 @@ export default function AdminAppInformation_BusinessFieldDetail() {
} }
}; };
const handlerSubmit = async () => {
if (!data.name) {
Toast.show({
type: "error",
text1: "Lengkapi Data",
});
return;
}
try {
setIsLoading(true);
const response = await apiAdminMasterBusinessFieldUpdate({
id: id as string,
data: data,
});
if (!response.success) {
Toast.show({
type: "error",
text1: "Gagal update data",
});
return;
}
Toast.show({
type: "success",
text1: "Data berhasil di update",
});
router.back();
} catch (error) {
console.log(error);
} finally {
setIsLoading(false);
}
};
const buttonSubmit = (
<BoxButtonOnFooter>
<ButtonCustom
disabled={!data?.name}
isLoading={isLoading}
onPress={() => handlerSubmit()}
>
Update
</ButtonCustom>
</BoxButtonOnFooter>
);
return ( return (
<> <>
<ViewWrapper footerComponent={buttonSubmit}> <ViewWrapper>
<StackCustom> <StackCustom>
<AdminBackButtonAntTitle title="Update Bidang Bisnis" /> <AdminBackButtonAntTitle title="Detail Bidang & Sub Bidang" />
<TextInputCustom {!data ? (
label="Nama Bidang Bisnis" <LoaderCustom />
placeholder="Masukan Nama Bidang Bisnis" ) : (
required <StackCustom gap={"xs"}>
value={data?.name} <TextCustom bold>Nama Bidang</TextCustom>
onChangeText={(value) => setData({ ...data, name: value })} <Spacing height={5} />
/> <BaseBox>
<StackCustom gap={"xs"}>
<TextCustom bold>
Status: {data?.bidang?.active ? "Aktif" : "Tidak Aktif"}
</TextCustom>
<GridSpan_NewComponent
span1={10}
span2={2}
text1={
<TextCustom bold size={"large"}>
{data?.bidang?.name}
</TextCustom>
}
text2={
<CenterCustom>
<ActionIcon
icon={<IconEdit size={16} color={MainColor.black} />}
onPress={() =>
router.push(
`/admin/app-information/business-field/${id}/bidang-update`
)
}
/>
</CenterCustom>
}
/>
</StackCustom>
</BaseBox>
{/* <Divider /> */}
<Spacing height={5} />
<TextCustom>Status Aktivasi</TextCustom> <TextCustom bold>Sub Bidang Bisnis</TextCustom>
<Switch <Spacing height={5} />
color={MainColor.yellow}
value={data?.active} {data?.subBidang?.map((item: any, index: number) => (
onValueChange={(value) => setData({ ...data, active: value })} <BaseBox key={index}>
/> <StackCustom gap={0}>
<TextCustom bold>
Status: {item?.isActive ? "Aktif" : "Tidak Aktif"}
</TextCustom>
<GridSpan_NewComponent
span1={10}
span2={2}
text1={
<TextCustom bold size={"large"}>
{item.name}
</TextCustom>
}
text2={
<CenterCustom>
<ActionIcon
icon={
<IconEdit size={16} color={MainColor.black} />
}
onPress={() =>
router.push(
`/admin/app-information/business-field/${item?.id}/sub-bidang-update`
)
}
/>
</CenterCustom>
}
/>
</StackCustom>
</BaseBox>
))}
</StackCustom>
)}
{/* <TextCustom>{JSON.stringify(data, null, 2)}</TextCustom> */}
</StackCustom> </StackCustom>
</ViewWrapper> </ViewWrapper>
</> </>

View File

@@ -0,0 +1,135 @@
/* eslint-disable react-hooks/exhaustive-deps */
import {
BoxButtonOnFooter,
ButtonCustom,
StackCustom,
TextCustom,
TextInputCustom,
ViewWrapper,
} from "@/components";
import AdminBackButtonAntTitle from "@/components/_ShareComponent/Admin/BackButtonAntTitle";
import { MainColor } from "@/constants/color-palet";
import {
apiAdminMasterBusinessFieldById,
apiAdminMasterBusinessFieldUpdate,
} from "@/service/api-admin/api-master-admin";
import { router, useFocusEffect, useLocalSearchParams } from "expo-router";
import { useCallback, useState } from "react";
import { Switch } from "react-native-paper";
import Toast from "react-native-toast-message";
export default function AdminAppInformation_BusinessFieldDetail() {
const { id } = useLocalSearchParams();
const [data, setData] = useState<any | null>(null);
const [isLoading, setIsLoading] = useState(false);
useFocusEffect(
useCallback(() => {
onLoadDetail();
}, [id])
);
const onLoadDetail = async () => {
try {
const response = await apiAdminMasterBusinessFieldById({
id: id as string,
category: "sub-bidang",
subBidangId: id as string,
});
console.log("Response >>", JSON.stringify(response, null, 2));
setData(response.data);
} catch (error) {
console.log("[ERROR]", error);
setData(null);
}
};
const handlerSubmit = async () => {
if (!data.name) {
Toast.show({
type: "error",
text1: "Lengkapi Data",
});
return;
}
try {
setIsLoading(true);
const response = await apiAdminMasterBusinessFieldUpdate({
id: id as string,
data: data,
category: "sub-bidang",
});
if (!response.success) {
Toast.show({
type: "error",
text1: "Gagal update data",
});
return;
}
Toast.show({
type: "success",
text1: "Data berhasil di update",
});
router.back();
} catch (error) {
console.log(error);
} finally {
setIsLoading(false);
}
};
const buttonSubmit = (
<BoxButtonOnFooter>
<ButtonCustom
disabled={!data?.name}
isLoading={isLoading}
onPress={() => handlerSubmit()}
>
Update
</ButtonCustom>
</BoxButtonOnFooter>
);
return (
<>
<ViewWrapper footerComponent={buttonSubmit}>
<StackCustom>
<AdminBackButtonAntTitle title="Update Bidang Bisnis" />
<TextInputCustom
label="Nama Bidang Bisnis"
placeholder="Masukan Nama Bidang Bisnis"
required
value={data?.name}
onChangeText={(value) => setData({ ...data, name: value })}
/>
<StackCustom
gap={"sm"}
style={{
alignContent: "flex-start",
}}
>
<TextCustom>Status</TextCustom>
<Switch
style={{
alignSelf: "flex-start",
}}
color={MainColor.yellow}
value={data?.isActive}
onValueChange={(value) => setData({ ...data, isActive: value })}
/>
</StackCustom>
</StackCustom>
</ViewWrapper>
</>
);
}

View File

@@ -1,40 +1,81 @@
import { import {
BoxButtonOnFooter, ActionIcon,
ButtonCustom, BoxButtonOnFooter,
StackCustom, ButtonCustom,
TextInputCustom, CenterCustom,
ViewWrapper, Grid,
Spacing,
StackCustom,
TextInputCustom,
ViewWrapper,
} from "@/components"; } from "@/components";
import AdminBackButtonAntTitle from "@/components/_ShareComponent/Admin/BackButtonAntTitle"; import AdminBackButtonAntTitle from "@/components/_ShareComponent/Admin/BackButtonAntTitle";
import { MainColor } from "@/constants/color-palet";
import { ICON_SIZE_XLARGE } from "@/constants/constans-value";
import { apiAdminMasterBusinessFieldCreate } from "@/service/api-admin/api-master-admin"; import { apiAdminMasterBusinessFieldCreate } from "@/service/api-admin/api-master-admin";
import { Ionicons } from "@expo/vector-icons";
import { router } from "expo-router"; import { router } from "expo-router";
import _ from "lodash";
import { useState } from "react"; import { useState } from "react";
import { View } from "react-native";
import { Divider } from "react-native-paper";
import Toast from "react-native-toast-message"; import Toast from "react-native-toast-message";
export default function AdminAppInformation_BusinessFieldCreate() { export default function AdminAppInformation_BusinessFieldCreate() {
const [data, setData] = useState<any>({ const [isLoading, setIsLoading] = useState(false);
const [bidang, setBidang] = useState<any>({
name: "", name: "",
}); });
const [isLoading, setIsLoading] = useState(false); const [subBidang, setSubBidang] = useState<any[]>([
{
name: "",
},
]);
const handlerSubmit = async () => { const handlerSubmit = async () => {
if (!data.name) { if (!bidang.name) {
Toast.show({ Toast.show({
type: "error", type: "error",
text1: "Lengkapi Data", text1: "Lengkapi Data",
}); });
return; return;
} }
if (subBidang[0].name === "") {
Toast.show({
type: "error",
text1: "Lengkapi Sub Bidang",
});
return;
}
try { try {
setIsLoading(true); setIsLoading(true);
const response = await apiAdminMasterBusinessFieldCreate({ data: data });
const newData = {
bidang: bidang,
subBidang: subBidang,
};
console.log("[DATA]", newData);
const response = await apiAdminMasterBusinessFieldCreate({
data: newData,
});
console.log("[RESPONSE]", response);
if (response.success) { if (response.success) {
Toast.show({ Toast.show({
type: "success", type: "success",
text1: "Data berhasil di tambah", text1: "Data berhasil di tambah",
}); });
router.back(); // router.back();
} else {
Toast.show({
type: "error",
text1: "Gagal tambah data",
});
} }
} catch (error) { } catch (error) {
console.log("[ERROR]", error); console.log("[ERROR]", error);
@@ -50,6 +91,7 @@ export default function AdminAppInformation_BusinessFieldCreate() {
const buttonSubmit = ( const buttonSubmit = (
<BoxButtonOnFooter> <BoxButtonOnFooter>
<ButtonCustom <ButtonCustom
disabled={subBidang[0].name === ""}
onPress={() => handlerSubmit()} onPress={() => handlerSubmit()}
isLoading={isLoading} isLoading={isLoading}
> >
@@ -60,16 +102,70 @@ export default function AdminAppInformation_BusinessFieldCreate() {
return ( return (
<> <>
<ViewWrapper footerComponent={buttonSubmit}> <ViewWrapper footerComponent={buttonSubmit}>
<StackCustom> <StackCustom gap={"xs"}>
<AdminBackButtonAntTitle title="Tambah Bidang Bisnis" /> <AdminBackButtonAntTitle title="Tambah Bidang Bisnis" />
<TextInputCustom <TextInputCustom
label="Nama Bidang Bisnis" label="Nama Bidang Bisnis"
placeholder="Masukan Nama Bidang Bisnis" placeholder="Masukan Nama Bidang Bisnis"
required required
value={data.name} value={bidang.name}
onChangeText={(value) => setData({ ...data, name: value })} onChangeText={(value) => setBidang({ ...bidang, name: value })}
/> />
<Divider />
<Spacing height={5} />
{subBidang.map((item, index) => (
<TextInputCustom
key={index}
label="Nama Sub Bidang"
placeholder="Masukan Nama Sub Bidang"
required
value={item.name}
onChangeText={(value) => {
const list = _.clone(subBidang);
list[index].name = value;
setSubBidang(list);
}}
/>
))}
<CenterCustom>
<View
style={{ flexDirection: "row", alignItems: "center", gap: 10 }}
>
<ActionIcon
onPress={() => {
setSubBidang([...subBidang, { name: "" }]);
}}
icon={
<Ionicons
name="add-circle-outline"
size={ICON_SIZE_XLARGE}
color={MainColor.black}
/>
}
size="xl"
/>
<ActionIcon
disabled={subBidang.length <= 1}
onPress={() => {
const list = _.clone(subBidang);
list.pop();
setSubBidang(list);
}}
icon={
<Ionicons
name="remove-circle-outline"
size={ICON_SIZE_XLARGE}
color={MainColor.black}
/>
}
size="xl"
/>
</View>
</CenterCustom>
</StackCustom> </StackCustom>
</ViewWrapper> </ViewWrapper>
</> </>

View File

@@ -75,7 +75,7 @@ const listPage = [
}, },
{ {
id: "2", id: "2",
label: "Bidang Bisnis", label: "Bidang & Sub Bidang",
value: "business", value: "business",
}, },
{ {

View File

@@ -2,11 +2,13 @@
import { import {
BaseBox, BaseBox,
Grid, Grid,
Spacing,
StackCustom, StackCustom,
TextCustom, TextCustom,
ViewWrapper, ViewWrapper,
} from "@/components"; } from "@/components";
import AdminBackButtonAntTitle from "@/components/_ShareComponent/Admin/BackButtonAntTitle"; import AdminBackButtonAntTitle from "@/components/_ShareComponent/Admin/BackButtonAntTitle";
import { GridSpan_4_8 } from "@/components/_ShareComponent/GridSpan_4_8";
import { apiAdminCollaborationGetById } from "@/service/api-admin/api-admin-collaboration"; import { apiAdminCollaborationGetById } from "@/service/api-admin/api-admin-collaboration";
import { useFocusEffect, useLocalSearchParams } from "expo-router"; import { useFocusEffect, useLocalSearchParams } from "expo-router";
import { useCallback, useState } from "react"; import { useCallback, useState } from "react";
@@ -28,6 +30,8 @@ export default function AdminCollaborationGroup() {
category: "group", category: "group",
}); });
console.log("[DATA]", JSON.stringify(response.data, null, 2));
if (response.success) { if (response.success) {
setData(response.data); setData(response.data);
} }
@@ -59,38 +63,33 @@ export default function AdminCollaborationGroup() {
))} ))}
</StackCustom> </StackCustom>
</BaseBox> </BaseBox>
<TextCustom bold>Anggota</TextCustom>
<Spacing height={5}/>
<BaseBox> <BaseBox>
<StackCustom> <StackCustom>
<TextCustom align="center">Anggota</TextCustom>
<Grid>
<Grid.Col span={6} style={{ justifyContent: "center", paddingRight: 10 }}>
<TextCustom bold>Nomor</TextCustom>
</Grid.Col>
<Grid.Col span={6} style={{ justifyContent: "center" }}>
<TextCustom bold>Username</TextCustom>
</Grid.Col>
</Grid>
{data?.ProjectCollaboration_AnggotaRoomChat?.map( {data?.ProjectCollaboration_AnggotaRoomChat?.map(
(item: any, index: number) => ( (item: any, index: number) => (
<StackCustom key={index} gap={0}> <Grid key={index}>
<Grid> <Grid.Col span={6} style={{ justifyContent: "center", paddingRight: 10 }}>
<Grid.Col <TextCustom bold truncate>+{item?.User?.nomor || "-"}</TextCustom>
span={4} </Grid.Col>
style={{ justifyContent: "center", paddingRight: 10 }} <Grid.Col span={6} style={{ justifyContent: "center" }}>
> <TextCustom bold>
<TextCustom bold>Nama</TextCustom> {item?.User?.username || "-"}
</Grid.Col> </TextCustom>
<Grid.Col span={8} style={{ justifyContent: "center" }}> </Grid.Col>
<TextCustom> </Grid>
{item?.User?.Profile?.name || "-"}
</TextCustom>
</Grid.Col>
</Grid>
<Grid>
<Grid.Col
span={4}
style={{ justifyContent: "center", paddingRight: 10 }}
>
<TextCustom bold>Username</TextCustom>
</Grid.Col>
<Grid.Col span={8} style={{ justifyContent: "center" }}>
<TextCustom>{item?.User?.username || "-"}</TextCustom>
</Grid.Col>
</Grid>
</StackCustom>
) )
)} )}
</StackCustom> </StackCustom>

View File

@@ -1,17 +1,14 @@
import { import {
ActionIcon, ClickableCustom,
LoaderCustom, LoaderCustom,
StackCustom, StackCustom,
TextCustom, TextCustom,
ViewWrapper ViewWrapper
} from "@/components"; } from "@/components";
import AdminComp_BoxTitle from "@/components/_ShareComponent/Admin/BoxTitlePage"; import AdminComp_BoxTitle from "@/components/_ShareComponent/Admin/BoxTitlePage";
import AdminTitleTable from "@/components/_ShareComponent/Admin/TableTitle";
import AdminTableValue from "@/components/_ShareComponent/Admin/TableValue";
import AdminTitlePage from "@/components/_ShareComponent/Admin/TitlePage"; import AdminTitlePage from "@/components/_ShareComponent/Admin/TitlePage";
import { ICON_SIZE_BUTTON } from "@/constants/constans-value"; import { GridSpan_NewComponent } from "@/components/_ShareComponent/GridSpan_NewComponent";
import { apiAdminCollaboration } from "@/service/api-admin/api-admin-collaboration"; import { apiAdminCollaboration } from "@/service/api-admin/api-admin-collaboration";
import { Octicons } from "@expo/vector-icons";
import { router, useFocusEffect } from "expo-router"; import { router, useFocusEffect } from "expo-router";
import _ from "lodash"; import _ from "lodash";
import { useCallback, useState } from "react"; import { useCallback, useState } from "react";
@@ -34,7 +31,7 @@ export default function AdminCollaborationGroup() {
const response = await apiAdminCollaboration({ const response = await apiAdminCollaboration({
category: "group", category: "group",
}); });
if (response.success) { if (response.success) {
setList(response.data); setList(response.data);
} }
@@ -51,10 +48,19 @@ export default function AdminCollaborationGroup() {
<StackCustom> <StackCustom>
<AdminComp_BoxTitle title="Group" /> <AdminComp_BoxTitle title="Group" />
<> <>
<AdminTitleTable <GridSpan_NewComponent
title1="Aksi" span1={6}
title2="Jumlah peserta" span2={6}
title3="Nama group" text1={
<TextCustom bold truncate align="center">
Jumlah Anggota
</TextCustom>
}
text2={
<TextCustom bold truncate>
Nama Group
</TextCustom>
}
/> />
<Divider /> <Divider />
@@ -67,31 +73,27 @@ export default function AdminCollaborationGroup() {
) : ( ) : (
list?.map((item: any, index: number) => ( list?.map((item: any, index: number) => (
<View key={index}> <View key={index}>
<AdminTableValue <ClickableCustom
value1={ onPress={() => {
<ActionIcon router.push(`/admin/collaboration/${item.id}/group`);
icon={ }}
<Octicons >
name="eye" <GridSpan_NewComponent
size={ICON_SIZE_BUTTON} span1={6}
color="black" span2={6}
/> text1={
} <TextCustom truncate={1} align="center">
onPress={() => { {item?.ProjectCollaboration_AnggotaRoomChat?.length ||
router.push(`/admin/collaboration/${item.id}/group`); "-"}
}} </TextCustom>
/> }
} text2={
value2={ <TextCustom truncate={2}>
<TextCustom truncate={1}> {item?.name || "-"}
{item?.ProjectCollaboration_AnggotaRoomChat?.length || </TextCustom>
"-"} }
</TextCustom> />
} </ClickableCustom>
value3={
<TextCustom truncate={2}>{item?.name || "-"}</TextCustom>
}
/>
</View> </View>
)) ))
)} )}

View File

@@ -1,6 +1,8 @@
import { import {
ActionIcon, ActionIcon,
ClickableCustom,
LoaderCustom, LoaderCustom,
Spacing,
StackCustom, StackCustom,
TextCustom, TextCustom,
ViewWrapper, ViewWrapper,
@@ -9,6 +11,7 @@ import AdminComp_BoxTitle from "@/components/_ShareComponent/Admin/BoxTitlePage"
import AdminTitleTable from "@/components/_ShareComponent/Admin/TableTitle"; import AdminTitleTable from "@/components/_ShareComponent/Admin/TableTitle";
import AdminTableValue from "@/components/_ShareComponent/Admin/TableValue"; import AdminTableValue from "@/components/_ShareComponent/Admin/TableValue";
import AdminTitlePage from "@/components/_ShareComponent/Admin/TitlePage"; import AdminTitlePage from "@/components/_ShareComponent/Admin/TitlePage";
import { GridSpan_NewComponent } from "@/components/_ShareComponent/GridSpan_NewComponent";
import { ICON_SIZE_BUTTON } from "@/constants/constans-value"; import { ICON_SIZE_BUTTON } from "@/constants/constans-value";
import { apiAdminCollaboration } from "@/service/api-admin/api-admin-collaboration"; import { apiAdminCollaboration } from "@/service/api-admin/api-admin-collaboration";
import { Octicons } from "@expo/vector-icons"; import { Octicons } from "@expo/vector-icons";
@@ -51,11 +54,7 @@ export default function AdminCollaborationPublish() {
<StackCustom> <StackCustom>
<AdminComp_BoxTitle title="Publish" /> <AdminComp_BoxTitle title="Publish" />
<AdminTitleTable <GridSpan_NewComponent text1={<TextCustom bold>Username</TextCustom>} text2={<TextCustom bold>Judul Proyek</TextCustom>} />
title1="Aksi"
title2="Username"
title3="Judul Proyek"
/>
{/* <Spacing height={10} /> */} {/* <Spacing height={10} /> */}
<Divider /> <Divider />
@@ -68,32 +67,26 @@ export default function AdminCollaborationPublish() {
) : ( ) : (
list?.map((item: any, index: number) => ( list?.map((item: any, index: number) => (
<View key={index}> <View key={index}>
<AdminTableValue <ClickableCustom
value1={ onPress={() => {
<ActionIcon router.push(`/admin/collaboration/${item?.id}/publish`);
icon={ }}
<Octicons >
name="eye" <GridSpan_NewComponent
size={ICON_SIZE_BUTTON} text1={
color="black" <TextCustom truncate={1}>
/> {item?.Author?.username || "-"}{" "}
} </TextCustom>
onPress={() => { }
router.push(`/admin/collaboration/${item?.id}/publish`); text2={
}} <TextCustom truncate={2}>
/> {item?.title || "-"}
} </TextCustom>
value2={ }
<TextCustom align="center" truncate={1}> />
{item?.Author?.username || "-"}{" "} </ClickableCustom>
</TextCustom> <Spacing height={8}/>
} <Divider/>
value3={
<TextCustom align="center" truncate={2}>
{item?.title || "-"}
</TextCustom>
}
/>
</View> </View>
)) ))
)} )}

View File

@@ -18,7 +18,7 @@ import { IconDot, IconList } from "@/components/_Icon/IconComponent";
import AdminBackButtonAntTitle from "@/components/_ShareComponent/Admin/BackButtonAntTitle"; import AdminBackButtonAntTitle from "@/components/_ShareComponent/Admin/BackButtonAntTitle";
import AdminButtonReject from "@/components/_ShareComponent/Admin/ButtonReject"; import AdminButtonReject from "@/components/_ShareComponent/Admin/ButtonReject";
import AdminButtonReview from "@/components/_ShareComponent/Admin/ButtonReview"; import AdminButtonReview from "@/components/_ShareComponent/Admin/ButtonReview";
import { GridDetail_4_8 } from "@/components/_ShareComponent/GridDetail_4_8"; import { GridSpan_4_8 } from "@/components/_ShareComponent/GridSpan_4_8";
import ReportBox from "@/components/Box/ReportBox"; import ReportBox from "@/components/Box/ReportBox";
import { ICON_SIZE_BUTTON, TEXT_SIZE_LARGE } from "@/constants/constans-value"; import { ICON_SIZE_BUTTON, TEXT_SIZE_LARGE } from "@/constants/constans-value";
import AdminDonation_BoxOfDonationStory from "@/screens/Admin/Donation/BoxOfDonationStory"; import AdminDonation_BoxOfDonationStory from "@/screens/Admin/Donation/BoxOfDonationStory";
@@ -195,7 +195,7 @@ export default function AdminDonationDetail() {
<StackCustom gap={5}> <StackCustom gap={5}>
{listPencarianDana.map((item, i) => ( {listPencarianDana.map((item, i) => (
<GridDetail_4_8 <GridSpan_4_8
key={i} key={i}
label={<TextCustom bold>{item.label}</TextCustom>} label={<TextCustom bold>{item.label}</TextCustom>}
value={<TextCustom>{item.value}</TextCustom>} value={<TextCustom>{item.value}</TextCustom>}
@@ -236,7 +236,7 @@ export default function AdminDonationDetail() {
<Spacing /> <Spacing />
<StackCustom gap={"xs"}> <StackCustom gap={"xs"}>
<GridDetail_4_8 <GridSpan_4_8
label={<TextCustom bold>Jumlah Donatur</TextCustom>} label={<TextCustom bold>Jumlah Donatur</TextCustom>}
value={ value={
<TextCustom> <TextCustom>
@@ -244,7 +244,7 @@ export default function AdminDonationDetail() {
</TextCustom> </TextCustom>
} }
/> />
<GridDetail_4_8 <GridSpan_4_8
label={<TextCustom bold>Dana Terkumpul</TextCustom>} label={<TextCustom bold>Dana Terkumpul</TextCustom>}
value={ value={
<TextCustom> <TextCustom>
@@ -261,7 +261,7 @@ export default function AdminDonationDetail() {
<StackCustom> <StackCustom>
<DummyLandscapeImage imageId={data?.imageId || ""} /> <DummyLandscapeImage imageId={data?.imageId || ""} />
{listData.map((item, i) => ( {listData.map((item, i) => (
<GridDetail_4_8 <GridSpan_4_8
key={i} key={i}
label={<TextCustom bold>{item.label}</TextCustom>} label={<TextCustom bold>{item.label}</TextCustom>}
value={<TextCustom>{item.value}</TextCustom>} value={<TextCustom>{item.value}</TextCustom>}

View File

@@ -8,7 +8,7 @@ import {
ViewWrapper, ViewWrapper,
} from "@/components"; } from "@/components";
import AdminBackButtonAntTitle from "@/components/_ShareComponent/Admin/BackButtonAntTitle"; import AdminBackButtonAntTitle from "@/components/_ShareComponent/Admin/BackButtonAntTitle";
import { GridDetail_4_8 } from "@/components/_ShareComponent/GridDetail_4_8"; import { GridSpan_4_8 } from "@/components/_ShareComponent/GridSpan_4_8";
import { import {
apiAdminDonationInvoiceDetailById, apiAdminDonationInvoiceDetailById,
apiAdminDonationInvoiceUpdateById, apiAdminDonationInvoiceUpdateById,
@@ -177,7 +177,7 @@ export default function AdminDonasiTransactionDetail() {
<BaseBox> <BaseBox>
<StackCustom> <StackCustom>
{listData.map((item, index) => ( {listData.map((item, index) => (
<GridDetail_4_8 <GridSpan_4_8
key={index} key={index}
label={<TextCustom bold>{item.label}</TextCustom>} label={<TextCustom bold>{item.label}</TextCustom>}
value={<TextCustom>{item.value}</TextCustom>} value={<TextCustom>{item.value}</TextCustom>}

View File

@@ -7,7 +7,7 @@ import {
ViewWrapper, ViewWrapper,
} from "@/components"; } from "@/components";
import AdminBackButtonAntTitle from "@/components/_ShareComponent/Admin/BackButtonAntTitle"; import AdminBackButtonAntTitle from "@/components/_ShareComponent/Admin/BackButtonAntTitle";
import { GridDetail_4_8 } from "@/components/_ShareComponent/GridDetail_4_8"; import { GridSpan_4_8 } from "@/components/_ShareComponent/GridSpan_4_8";
import { apiAdminDonationDisbursementOfFundsListById } from "@/service/api-admin/api-admin-donation"; import { apiAdminDonationDisbursementOfFundsListById } from "@/service/api-admin/api-admin-donation";
import { dateTimeView } from "@/utils/dateTimeView"; import { dateTimeView } from "@/utils/dateTimeView";
import { formatCurrencyDisplay } from "@/utils/formatCurrencyDisplay"; import { formatCurrencyDisplay } from "@/utils/formatCurrencyDisplay";
@@ -67,7 +67,7 @@ export default function AdminDonationDetailDisbursementOfFunds() {
<BaseBox> <BaseBox>
<StackCustom> <StackCustom>
{listData?.map((item, index) => ( {listData?.map((item, index) => (
<GridDetail_4_8 <GridSpan_4_8
key={index} key={index}
label={<TextCustom bold>{item.label}</TextCustom>} label={<TextCustom bold>{item.label}</TextCustom>}
value={<TextCustom>{item.value}</TextCustom>} value={<TextCustom>{item.value}</TextCustom>}

View File

@@ -1,17 +1,56 @@
import { import {
BoxButtonOnFooter, BoxButtonOnFooter,
ButtonCustom, ButtonCustom,
StackCustom,
TextCustom,
TextInputCustom, TextInputCustom,
ViewWrapper, ViewWrapper,
} from "@/components"; } from "@/components";
import AdminBackButtonAntTitle from "@/components/_ShareComponent/Admin/BackButtonAntTitle"; import AdminBackButtonAntTitle from "@/components/_ShareComponent/Admin/BackButtonAntTitle";
import { MainColor } from "@/constants/color-palet";
import { apiAdminMasterDonationCategoryCreate } from "@/service/api-admin/api-master-admin";
import { useRouter } from "expo-router"; import { useRouter } from "expo-router";
import { useState } from "react";
import { Switch } from "react-native-paper";
import Toast from "react-native-toast-message";
export default function AdminDonationCategoryCreate() { export default function AdminDonationCategoryCreate() {
const router = useRouter(); const router = useRouter();
const [loading, setLoading] = useState(false);
const [data, setData] = useState({
name: "",
active: false,
});
const onSubmit = async () => {
try {
setLoading(true);
const response = await apiAdminMasterDonationCategoryCreate({ data });
if (response.success) {
Toast.show({
type: "success",
text2: "Data berhasil disimpan",
});
router.back();
return;
}
Toast.show({
type: "error",
text1: "Gagal menyimpan data",
});
} catch (error) {
console.log("[Error]", error);
} finally {
setLoading(false);
}
};
const buttonSubmit = ( const buttonSubmit = (
<BoxButtonOnFooter> <BoxButtonOnFooter>
<ButtonCustom onPress={() => router.back()}>Simpan</ButtonCustom> <ButtonCustom isLoading={loading} onPress={onSubmit}>
Simpan
</ButtonCustom>
</BoxButtonOnFooter> </BoxButtonOnFooter>
); );
return ( return (
@@ -20,7 +59,23 @@ export default function AdminDonationCategoryCreate() {
headerComponent={<AdminBackButtonAntTitle title="Tambah Kategori" />} headerComponent={<AdminBackButtonAntTitle title="Tambah Kategori" />}
footerComponent={buttonSubmit} footerComponent={buttonSubmit}
> >
<TextInputCustom placeholder="Masukkan Kategori" /> <TextInputCustom
label=""
placeholder="Masukkan Kategori"
value={data.name}
onChangeText={(text) => setData({ ...data, name: text })}
/>
<StackCustom gap={"sm"}>
<TextCustom>Status</TextCustom>
<Switch
style={{
alignSelf: "flex-start",
}}
color={MainColor.yellow}
value={data.active}
onValueChange={(value) => setData({ ...data, active: value })}
/>
</StackCustom>
</ViewWrapper> </ViewWrapper>
</> </>
); );

View File

@@ -1,21 +1,76 @@
import { import {
AlertDefaultSystem,
BoxButtonOnFooter, BoxButtonOnFooter,
ButtonCustom, ButtonCustom,
StackCustom,
TextCustom,
TextInputCustom, TextInputCustom,
ViewWrapper, ViewWrapper,
} from "@/components"; } from "@/components";
import AdminBackButtonAntTitle from "@/components/_ShareComponent/Admin/BackButtonAntTitle"; import AdminBackButtonAntTitle from "@/components/_ShareComponent/Admin/BackButtonAntTitle";
import { MainColor } from "@/constants/color-palet";
import {
apiAdminMasterDonationCategoryById,
apiAdminMasterDonationCategoryUpdate,
} from "@/service/api-admin/api-master-admin";
import { useLocalSearchParams, useRouter } from "expo-router"; import { useLocalSearchParams, useRouter } from "expo-router";
import { useState } from "react"; import { useCallback, useEffect, useState } from "react";
import { Switch } from "react-native-paper";
export default function AdminDonationCategoryUpdate() { export default function AdminDonationCategoryUpdate() {
const router = useRouter();
const { id } = useLocalSearchParams(); const { id } = useLocalSearchParams();
const [value, setValue] = useState(id); const [value, setValue] = useState(id);
const router = useRouter(); const [data, setData] = useState<any>(null);
const [isLoading, setIsLoading] = useState(false);
useEffect(() => {
const fetchData = async () => {
const response = await apiAdminMasterDonationCategoryById({
id: id as any,
});
console.log(JSON.stringify(response.data, null, 2));
setData(response.data);
};
fetchData();
}, [id]);
const handlerSubmit = async () => {
try {
setIsLoading(true);
const response = await apiAdminMasterDonationCategoryUpdate({
id: id as any,
data: data,
});
console.log(JSON.stringify(response.data, null, 2));
router.back();
} catch (error) {
console.log(error);
} finally {
setIsLoading(false);
}
};
const buttonSubmit = ( const buttonSubmit = (
<BoxButtonOnFooter> <BoxButtonOnFooter>
<ButtonCustom onPress={() => router.back()}>Update</ButtonCustom> <ButtonCustom
disabled={isLoading || data?.name === ""}
isLoading={isLoading}
onPress={() => {
AlertDefaultSystem({
title: "Update Data",
message: "Apakah anda yakin ingin mengupdate data ini?",
textLeft: "Batal",
textRight: "Ya",
onPressLeft: () => {},
onPressRight: () => handlerSubmit(),
});
}}
>
Update
</ButtonCustom>
</BoxButtonOnFooter> </BoxButtonOnFooter>
); );
return ( return (
@@ -25,10 +80,28 @@ export default function AdminDonationCategoryUpdate() {
footerComponent={buttonSubmit} footerComponent={buttonSubmit}
> >
<TextInputCustom <TextInputCustom
label="Nama Kategori"
placeholder="Masukkan Kategori" placeholder="Masukkan Kategori"
value={value as any} value={data?.name}
onChangeText={setValue} onChangeText={(value) => setData({ ...data, name: value })}
/> />
<StackCustom
gap={"sm"}
style={{
alignContent: "flex-start",
}}
>
<TextCustom>Status</TextCustom>
<Switch
style={{
alignSelf: "flex-start",
}}
color={MainColor.yellow}
value={data?.active}
onValueChange={(value) => setData({ ...data, active: value })}
/>
</StackCustom>
</ViewWrapper> </ViewWrapper>
</> </>
); );

View File

@@ -1,27 +1,65 @@
import { import {
ActionIcon, BadgeCustom,
BaseBox, CenterCustom,
CenterCustom, ClickableCustom,
Spacing, Spacing,
StackCustom, StackCustom,
TextCustom, TextCustom,
ViewWrapper, ViewWrapper
} from "@/components"; } from "@/components";
import { IconEdit } from "@/components/_Icon";
import AdminActionIconPlus from "@/components/_ShareComponent/Admin/ActionIconPlus"; import AdminActionIconPlus from "@/components/_ShareComponent/Admin/ActionIconPlus";
import AdminComp_BoxTitle from "@/components/_ShareComponent/Admin/BoxTitlePage"; import AdminComp_BoxTitle from "@/components/_ShareComponent/Admin/BoxTitlePage";
import AdminTitlePage from "@/components/_ShareComponent/Admin/TitlePage"; import AdminTitlePage from "@/components/_ShareComponent/Admin/TitlePage";
import { GridView_3_3_6 } from "@/components/_ShareComponent/GridView_3_3_6"; import { GridSpan_4_8 } from "@/components/_ShareComponent/GridSpan_4_8";
import { MainColor } from "@/constants/color-palet"; import { apiAdminMasterDonationCategory } from "@/service/api-admin/api-master-admin";
import { ICON_SIZE_BUTTON } from "@/constants/constans-value"; import { colorActivationForBadge } from "@/utils/colorActivationForBadge";
import { View } from "react-native"; import { router, useFocusEffect } from "expo-router";
import { Divider, Switch } from "react-native-paper"; import { useCallback, useState } from "react";
import { router } from "expo-router"; import { RefreshControl, View } from "react-native";
import { Divider } from "react-native-paper";
export default function AdminDonationCategory() { export default function AdminDonationCategory() {
const [listData, setListData] = useState<any[]>([]);
const [refreshing, setRefreshing] = useState(false);
const [loading, setLoading] = useState(false);
useFocusEffect(
useCallback(() => {
fetchMaster();
}, [])
);
const fetchMaster = async () => {
try {
setLoading(true);
const response = await apiAdminMasterDonationCategory();
if (response.success) {
console.log(JSON.stringify(response.data, null, 2));
setListData(response.data);
} else {
setListData([]);
}
} catch (error) {
console.log("[Error]", error);
} finally {
setLoading(false);
}
};
const onRefresh = async () => {
setRefreshing(true);
await fetchMaster();
setRefreshing(false);
};
return ( return (
<> <>
<ViewWrapper headerComponent={<AdminTitlePage title="Donasi" />}> <ViewWrapper
refreshControl={
<RefreshControl refreshing={refreshing} onRefresh={onRefresh} />
}
headerComponent={<AdminTitlePage title="Donasi" />}
>
<AdminComp_BoxTitle <AdminComp_BoxTitle
title="Kategori" title="Kategori"
rightComponent={ rightComponent={
@@ -33,81 +71,65 @@ export default function AdminDonationCategory() {
} }
/> />
<BaseBox> <View>
<GridView_3_3_6 <GridSpan_4_8
component1={ label={<TextCustom bold>Status</TextCustom>}
<TextCustom bold align="center"> value={<TextCustom bold>Kategori</TextCustom>}
Aksi
</TextCustom>
}
component2={<TextCustom bold>Status</TextCustom>}
component3={<TextCustom bold>Kategori</TextCustom>}
/> />
{/* <Grid>
<Grid.Col style={{ paddingLeft: 10 }} span={4}>
<TextCustom bold>Status</TextCustom>
</Grid.Col>
<Grid.Col span={8}>
<TextCustom bold>Kategori</TextCustom>
</Grid.Col>
</Grid> */}
<Divider /> <Divider />
<Spacing /> <Spacing />
<StackCustom> <StackCustom>
{listData.map((item, index) => ( {listData.map((item, index) => (
<View key={index}> <ClickableCustom
<GridView_3_3_6 onPress={() => {
component1={ router.push(`/admin/donation/category-update?id=${item.id}`);
}}
key={index}
>
<GridSpan_4_8
label={
<CenterCustom> <CenterCustom>
<ActionIcon <BadgeCustom
icon={ color={colorActivationForBadge({
<IconEdit size={ICON_SIZE_BUTTON} color="black" /> status: item.active,
} })}
onPress={() => { >
router.push(`/admin/donation/category-update?id=${index}`); {item.active ? "Aktif" : "Tidak Aktif"}
}} </BadgeCustom>
/>
</CenterCustom> </CenterCustom>
} }
component2={ value={<TextCustom>{item.name}</TextCustom>}
<Switch
value={true}
onValueChange={(item) => {
console.log(item);
}}
color={MainColor.yellow}
/>
}
component3={<TextCustom bold>{item.label}</TextCustom>}
/> />
<Spacing height={10} /> {/* <Grid containerStyle={{ paddingBottom: 10 }}>
<Grid.Col span={4} style={{ paddingLeft: 10 }}>
<CenterCustom>
<BadgeCustom
color={item.active ? MainColor.green : MainColor.red}
>
{item.active ? "Aktif" : "Tidak Aktif"}
</BadgeCustom>
</CenterCustom>
</Grid.Col>
<Grid.Col span={8}>
<TextCustom bold>{item.name}</TextCustom>
</Grid.Col>
</Grid> */}
<Divider /> <Divider />
</View> </ClickableCustom>
))} ))}
</StackCustom> </StackCustom>
</BaseBox> </View>
</ViewWrapper> </ViewWrapper>
</> </>
); );
} }
const listData = [
{
label: "Kegiatan Sosial",
value: "kegiatan_sosial",
},
{
label: "Pendidikan",
value: "pendidikan",
},
{
label: "Kesehatan",
value: "kesehatan",
},
{
label: "Kebudayaan",
value: "kebudayaan",
},
{
label: "Bencana Alami",
value: "bencana_alami",
},
{
label: "Lainnya",
value: "lainnya",
},
];

View File

@@ -1,22 +1,22 @@
/* eslint-disable react-hooks/exhaustive-deps */ /* eslint-disable react-hooks/exhaustive-deps */
import { import {
ActionIcon, ActionIcon,
AlertDefaultSystem, AlertDefaultSystem,
BadgeCustom, BadgeCustom,
BaseBox, BaseBox,
DrawerCustom, DrawerCustom,
LoaderCustom, LoaderCustom,
MenuDrawerDynamicGrid, MenuDrawerDynamicGrid,
Spacing, Spacing,
StackCustom, StackCustom,
TextCustom, TextCustom,
ViewWrapper, ViewWrapper,
} from "@/components"; } from "@/components";
import { IconDot, IconList } from "@/components/_Icon/IconComponent"; import { IconDot, IconList } from "@/components/_Icon/IconComponent";
import AdminBackButtonAntTitle from "@/components/_ShareComponent/Admin/BackButtonAntTitle"; import AdminBackButtonAntTitle from "@/components/_ShareComponent/Admin/BackButtonAntTitle";
import AdminButtonReject from "@/components/_ShareComponent/Admin/ButtonReject"; import AdminButtonReject from "@/components/_ShareComponent/Admin/ButtonReject";
import AdminButtonReview from "@/components/_ShareComponent/Admin/ButtonReview"; import AdminButtonReview from "@/components/_ShareComponent/Admin/ButtonReview";
import { GridDetail_4_8 } from "@/components/_ShareComponent/GridDetail_4_8"; import { GridSpan_4_8 } from "@/components/_ShareComponent/GridSpan_4_8";
import ReportBox from "@/components/Box/ReportBox"; import ReportBox from "@/components/Box/ReportBox";
import { ICON_SIZE_BUTTON } from "@/constants/constans-value"; import { ICON_SIZE_BUTTON } from "@/constants/constans-value";
import { useAuth } from "@/hooks/use-auth"; import { useAuth } from "@/hooks/use-auth";
@@ -38,7 +38,12 @@ export default function AdminEventDetail() {
const [data, setData] = React.useState<any | null>(null); const [data, setData] = React.useState<any | null>(null);
const [loadData, setLoadData] = React.useState(false); const [loadData, setLoadData] = React.useState(false);
const deepLinkURL = `${DEEP_LINK_URL}/--/event/${id}/confirmation?userId=${user?.id}`; 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( useFocusEffect(
useCallback(() => { useCallback(() => {
onLoadData(); onLoadData();
@@ -156,7 +161,7 @@ export default function AdminEventDetail() {
<BaseBox> <BaseBox>
<StackCustom> <StackCustom>
{listData.map((item, i) => ( {listData.map((item, i) => (
<GridDetail_4_8 <GridSpan_4_8
key={i} key={i}
label={<TextCustom bold>{item.label}</TextCustom>} label={<TextCustom bold>{item.label}</TextCustom>}
value={<TextCustom>{item.value}</TextCustom>} value={<TextCustom>{item.value}</TextCustom>}
@@ -181,7 +186,7 @@ export default function AdminEventDetail() {
<LoaderCustom /> <LoaderCustom />
) : ( ) : (
<QRCode <QRCode
value={deepLinkURL} value={isDevLink}
size={200} size={200}
// logo={require("@/assets/images/logo-hipmi.png")} // logo={require("@/assets/images/logo-hipmi.png")}
// logoSize={70} // logoSize={70}
@@ -190,6 +195,8 @@ export default function AdminEventDetail() {
// color="black" // color="black"
/> />
)} )}
<TextCustom align="center">{isDevLink}</TextCustom>
</StackCustom> </StackCustom>
</BaseBox> </BaseBox>
)} )}

View File

@@ -10,14 +10,17 @@ import {
} from "@/components"; } from "@/components";
import AdminBackButtonAntTitle from "@/components/_ShareComponent/Admin/BackButtonAntTitle"; import AdminBackButtonAntTitle from "@/components/_ShareComponent/Admin/BackButtonAntTitle";
import { apiAdminEventListOfParticipants } from "@/service/api-admin/api-admin-event"; import { apiAdminEventListOfParticipants } from "@/service/api-admin/api-admin-event";
import dayjs, { Dayjs } from "dayjs";
import { useFocusEffect, useLocalSearchParams } from "expo-router"; import { useFocusEffect, useLocalSearchParams } from "expo-router";
import _ from "lodash"; import _ from "lodash";
import { View } from "moti";
import { useCallback, useState } from "react"; import { useCallback, useState } from "react";
export default function AdminEventListOfParticipants() { export default function AdminEventListOfParticipants() {
const { id } = useLocalSearchParams(); const { id } = useLocalSearchParams();
const [listData, setListData] = useState<any[] | null>(null); const [listData, setListData] = useState<any[] | null>(null);
const [loadData, setLoadData] = useState(false); const [loadData, setLoadData] = useState(false);
const [startDate, setStartDate] = useState<Dayjs | undefined>();
useFocusEffect( useFocusEffect(
useCallback(() => { useCallback(() => {
@@ -32,8 +35,11 @@ export default function AdminEventListOfParticipants() {
id: id as string, id: id as string,
}); });
console.log("[DATA]", JSON.stringify(response, null, 2));
if (response.success) { if (response.success) {
setListData(response.data); setListData(response.data);
setStartDate(dayjs(response.data.Event.tanggal));
} }
} catch (error) { } catch (error) {
console.log("[ERROR]", error); console.log("[ERROR]", error);
@@ -42,7 +48,6 @@ export default function AdminEventListOfParticipants() {
} }
}; };
return ( return (
<> <>
<ViewWrapper <ViewWrapper
@@ -60,17 +65,35 @@ export default function AdminEventListOfParticipants() {
<Grid> <Grid>
<Grid.Col span={6}> <Grid.Col span={6}>
<StackCustom gap={"sm"}> <StackCustom gap={"sm"}>
<TextCustom bold truncate>{item?.User?.username}</TextCustom> <TextCustom bold truncate>
{item?.User?.username}
</TextCustom>
<TextCustom>+{item?.User?.nomor}</TextCustom> <TextCustom>+{item?.User?.nomor}</TextCustom>
</StackCustom> </StackCustom>
</Grid.Col> </Grid.Col>
<Grid.Col span={6} style={{ justifyContent: "center" }}> <Grid.Col span={6} style={{ justifyContent: "center" }}>
<BadgeCustom {startDate &&
style={{ alignSelf: "flex-end" }} startDate.subtract(1, "hour").diff(dayjs()) < 0 ? (
color={item?.isPresent ? "green" : "red"} <BadgeCustom
> style={{ alignSelf: "flex-end" }}
{item?.isPresent ? "Hadir" : "Tidak Hadir"} color={item?.isPresent ? "green" : "red"}
</BadgeCustom> >
{item?.isPresent ? "Hadir" : "Tidak Hadir"}
</BadgeCustom>
) : (
<View
style={{
justifyContent: "flex-end",
}}
>
<BadgeCustom
style={{ alignSelf: "flex-end" }}
color="gray"
>
-
</BadgeCustom>
</View>
)}
</Grid.Col> </Grid.Col>
</Grid> </Grid>
</BaseBox> </BaseBox>

View File

@@ -1,11 +1,12 @@
/* eslint-disable react-hooks/exhaustive-deps */ /* eslint-disable react-hooks/exhaustive-deps */
import { import {
ActionIcon, ActionIcon,
ClickableCustom,
LoaderCustom, LoaderCustom,
SearchInput, SearchInput,
StackCustom, StackCustom,
TextCustom, TextCustom,
ViewWrapper ViewWrapper,
} from "@/components"; } from "@/components";
import AdminComp_BoxTitle from "@/components/_ShareComponent/Admin/BoxTitlePage"; import AdminComp_BoxTitle from "@/components/_ShareComponent/Admin/BoxTitlePage";
import AdminTitleTable from "@/components/_ShareComponent/Admin/TableTitle"; import AdminTitleTable from "@/components/_ShareComponent/Admin/TableTitle";
@@ -13,6 +14,7 @@ import AdminTableValue from "@/components/_ShareComponent/Admin/TableValue";
import AdminTitlePage from "@/components/_ShareComponent/Admin/TitlePage"; import AdminTitlePage from "@/components/_ShareComponent/Admin/TitlePage";
import { ICON_SIZE_BUTTON } from "@/constants/constans-value"; import { ICON_SIZE_BUTTON } from "@/constants/constans-value";
import { apiAdminEvent } from "@/service/api-admin/api-admin-event"; import { apiAdminEvent } from "@/service/api-admin/api-admin-event";
import { dateTimeView } from "@/utils/dateTimeView";
import { Octicons } from "@expo/vector-icons"; import { Octicons } from "@expo/vector-icons";
import { router, useFocusEffect, useLocalSearchParams } from "expo-router"; import { router, useFocusEffect, useLocalSearchParams } from "expo-router";
import _ from "lodash"; import _ from "lodash";
@@ -74,8 +76,8 @@ export default function AdminEventStatus() {
<StackCustom gap={"sm"}> <StackCustom gap={"sm"}>
<AdminTitleTable <AdminTitleTable
title1="Aksi" title1="Username"
title2="Username" title2="Tanggal"
title3="Judul Event" title3="Judul Event"
/> />
<Divider /> <Divider />
@@ -83,36 +85,47 @@ export default function AdminEventStatus() {
{loadData ? ( {loadData ? (
<LoaderCustom /> <LoaderCustom />
) : _.isEmpty(listData) ? ( ) : _.isEmpty(listData) ? (
<TextCustom align="center" size="small" color="gray">Belum ada data</TextCustom> <TextCustom align="center" size="small" color="gray">
Belum ada data
</TextCustom>
) : ( ) : (
listData?.map((item, index) => ( listData?.map((item, index) => (
<AdminTableValue <ClickableCustom
key={index} key={index}
value1={ onPress={() => {
<ActionIcon router.push(`/admin/event/${item.id}/${status}`);
icon={ }}
<Octicons >
name="eye" <AdminTableValue
size={ICON_SIZE_BUTTON} key={index}
color="black" value1={
/> <TextCustom truncate={1}>
} {item?.Author?.username || "-"}
onPress={() => { </TextCustom>
router.push(`/admin/event/${item.id}/${status}`); // <ActionIcon
}} // icon={
/> // <Octicons
} // name="eye"
value2={ // size={ICON_SIZE_BUTTON}
<TextCustom truncate={1}> // color="black"
{item?.Author?.username || "-"} // />
</TextCustom> // }
} // onPress={() => {
value3={ // router.push(`/admin/event/${item.id}/${status}`);
<TextCustom align="center" truncate={2}> // }}
{item?.title || "-"} // />
</TextCustom> }
} value2={
/> <TextCustom truncate={1}>
{dateTimeView({ date: item?.tanggal })}
</TextCustom>
}
value3={
<TextCustom truncate={2}>{item?.title || "-"}</TextCustom>
}
/>
<Divider/>
</ClickableCustom>
)) ))
)} )}
</StackCustom> </StackCustom>

View File

@@ -11,7 +11,7 @@ import {
} from "@/components"; } from "@/components";
import { IconDot } from "@/components/_Icon/IconComponent"; import { IconDot } from "@/components/_Icon/IconComponent";
import AdminBackButtonAntTitle from "@/components/_ShareComponent/Admin/BackButtonAntTitle"; import AdminBackButtonAntTitle from "@/components/_ShareComponent/Admin/BackButtonAntTitle";
import { GridDetail_4_8 } from "@/components/_ShareComponent/GridDetail_4_8"; import { GridSpan_4_8 } from "@/components/_ShareComponent/GridSpan_4_8";
import { MainColor } from "@/constants/color-palet"; import { MainColor } from "@/constants/color-palet";
import { ICON_SIZE_XLARGE } from "@/constants/constans-value"; import { ICON_SIZE_XLARGE } from "@/constants/constans-value";
import { apiAdminForumPostingById } from "@/service/api-admin/api-admin-forum"; import { apiAdminForumPostingById } from "@/service/api-admin/api-admin-forum";
@@ -103,7 +103,7 @@ export default function AdminForumDetailPosting() {
<BaseBox> <BaseBox>
<StackCustom gap={"sm"}> <StackCustom gap={"sm"}>
{listDataAction.map((item, i) => ( {listDataAction.map((item, i) => (
<GridDetail_4_8 <GridSpan_4_8
key={i} key={i}
label={<TextCustom bold>{item.label}</TextCustom>} label={<TextCustom bold>{item.label}</TextCustom>}
value={<TextCustom>{item.value}</TextCustom>} value={<TextCustom>{item.value}</TextCustom>}

View File

@@ -3,6 +3,7 @@ import {
ActionIcon, ActionIcon,
AlertDefaultSystem, AlertDefaultSystem,
BaseBox, BaseBox,
CenterCustom,
DrawerCustom, DrawerCustom,
LoaderCustom, LoaderCustom,
MenuDrawerDynamicGrid, MenuDrawerDynamicGrid,
@@ -16,7 +17,8 @@ import AdminBackButtonAntTitle from "@/components/_ShareComponent/Admin/BackButt
import AdminComp_BoxTitle from "@/components/_ShareComponent/Admin/BoxTitlePage"; import AdminComp_BoxTitle from "@/components/_ShareComponent/Admin/BoxTitlePage";
import AdminTitleTable from "@/components/_ShareComponent/Admin/TableTitle"; import AdminTitleTable from "@/components/_ShareComponent/Admin/TableTitle";
import AdminTableValue from "@/components/_ShareComponent/Admin/TableValue"; import AdminTableValue from "@/components/_ShareComponent/Admin/TableValue";
import { GridDetail_4_8 } from "@/components/_ShareComponent/GridDetail_4_8"; import { GridSpan_4_8 } from "@/components/_ShareComponent/GridSpan_4_8";
import { GridSpan_NewComponent } from "@/components/_ShareComponent/GridSpan_NewComponent";
import { MainColor } from "@/constants/color-palet"; import { MainColor } from "@/constants/color-palet";
import { ICON_SIZE_BUTTON } from "@/constants/constans-value"; import { ICON_SIZE_BUTTON } from "@/constants/constans-value";
import { import {
@@ -27,6 +29,7 @@ import {
import { router, useFocusEffect, useLocalSearchParams } from "expo-router"; import { router, useFocusEffect, useLocalSearchParams } from "expo-router";
import _ from "lodash"; import _ from "lodash";
import { useCallback, useState } from "react"; import { useCallback, useState } from "react";
import { View } from "react-native";
import { Divider } from "react-native-paper"; import { Divider } from "react-native-paper";
import Toast from "react-native-toast-message"; import Toast from "react-native-toast-message";
@@ -95,24 +98,24 @@ export default function AdminForumReportComment() {
> >
<BaseBox> <BaseBox>
<StackCustom gap={"sm"}> <StackCustom gap={"sm"}>
<GridDetail_4_8 <GridSpan_NewComponent
label={<TextCustom bold>Username</TextCustom>} text1={<TextCustom bold>Username</TextCustom>}
value={<TextCustom>{data?.Author?.username || "-"}</TextCustom>} text2={<TextCustom>{data?.Author?.username || "-"}</TextCustom>}
/> />
<GridDetail_4_8 <GridSpan_NewComponent
label={<TextCustom bold>Komentar</TextCustom>} text1={<TextCustom bold>Komentar</TextCustom>}
value={<TextCustom>{data?.komentar || "-"}</TextCustom>} text2={<TextCustom>{data?.komentar || "-"}</TextCustom>}
/> />
</StackCustom> </StackCustom>
</BaseBox> </BaseBox>
<AdminComp_BoxTitle title="Daftar Report Komentar" /> <AdminComp_BoxTitle title="Daftar Report Komentar" />
<StackCustom> <StackCustom gap={"sm"}>
<AdminTitleTable <GridSpan_NewComponent
title1="Aksi" text1={<TextCustom bold align="center">Aksi</TextCustom>}
title2="Pelapor" text2={<TextCustom bold>Pelapor</TextCustom>}
title3="Kategori Report" text3={<TextCustom bold>Kategori Report</TextCustom>}
/> />
<Divider /> <Divider />
{loadList ? ( {loadList ? (
@@ -123,34 +126,39 @@ export default function AdminForumReportComment() {
</TextCustom> </TextCustom>
) : ( ) : (
listReport?.map((item: any, index: number) => ( listReport?.map((item: any, index: number) => (
<AdminTableValue <View key={index}>
key={index} <GridSpan_NewComponent
value1={ text1={
<ActionIcon <CenterCustom>
icon={<IconView size={ICON_SIZE_BUTTON} color="black" />} <ActionIcon
onPress={() => { icon={<IconView size={ICON_SIZE_BUTTON} color="black" />}
setOpenDrawerAction(true); onPress={() => {
setSelectedReport({ setOpenDrawerAction(true);
id: item.id, setSelectedReport({
username: item.User?.username, id: item.id,
kategori: item.ForumMaster_KategoriReport?.title, username: item.User?.username,
keterangan: item.ForumMaster_KategoriReport?.deskripsi, kategori: item.ForumMaster_KategoriReport?.title,
deskripsi: item.deskripsi, keterangan:
}); item.ForumMaster_KategoriReport?.deskripsi,
}} deskripsi: item.deskripsi,
/> });
} }}
value2={ />
<TextCustom truncate={1}> </CenterCustom>
{item?.User?.username || "-"} }
</TextCustom> text2={
} <TextCustom truncate={1}>
value3={ {item?.User?.username || "-"}
<TextCustom truncate={2} align="center"> </TextCustom>
{item?.ForumMaster_KategoriReport?.title || "-"} }
</TextCustom> text3={
} <TextCustom truncate={2}>
/> {item?.ForumMaster_KategoriReport?.title || "-"}
</TextCustom>
}
/>
<Divider />
</View>
)) ))
)} )}
</StackCustom> </StackCustom>
@@ -208,20 +216,20 @@ export default function AdminForumReportComment() {
height={"auto"} height={"auto"}
> >
<StackCustom> <StackCustom>
<GridDetail_4_8 <GridSpan_4_8
label={<TextCustom bold>Pelapor</TextCustom>} label={<TextCustom bold>Pelapor</TextCustom>}
value={<TextCustom>{selectedReport?.username || "-"}</TextCustom>} value={<TextCustom>{selectedReport?.username || "-"}</TextCustom>}
/> />
{selectedReport?.kategori && ( {selectedReport?.kategori && (
<> <>
<GridDetail_4_8 <GridSpan_4_8
label={<TextCustom bold>Kategori Report</TextCustom>} label={<TextCustom bold>Kategori Report</TextCustom>}
value={ value={
<TextCustom>{selectedReport?.kategori || "-"}</TextCustom> <TextCustom>{selectedReport?.kategori || "-"}</TextCustom>
} }
/> />
<GridDetail_4_8 <GridSpan_4_8
label={<TextCustom bold>Keterangan</TextCustom>} label={<TextCustom bold>Keterangan</TextCustom>}
value={ value={
<TextCustom>{selectedReport?.keterangan || "-"}</TextCustom> <TextCustom>{selectedReport?.keterangan || "-"}</TextCustom>
@@ -231,7 +239,7 @@ export default function AdminForumReportComment() {
)} )}
{selectedReport?.deskripsi && ( {selectedReport?.deskripsi && (
<GridDetail_4_8 <GridSpan_4_8
label={<TextCustom bold>Deskripsi</TextCustom>} label={<TextCustom bold>Deskripsi</TextCustom>}
value={ value={
<TextCustom>{selectedReport?.deskripsi || "-"}</TextCustom> <TextCustom>{selectedReport?.deskripsi || "-"}</TextCustom>

View File

@@ -4,6 +4,7 @@ import {
AlertDefaultSystem, AlertDefaultSystem,
BadgeCustom, BadgeCustom,
BaseBox, BaseBox,
CenterCustom,
DrawerCustom, DrawerCustom,
LoaderCustom, LoaderCustom,
MenuDrawerDynamicGrid, MenuDrawerDynamicGrid,
@@ -17,7 +18,8 @@ import AdminBackButtonAntTitle from "@/components/_ShareComponent/Admin/BackButt
import AdminComp_BoxTitle from "@/components/_ShareComponent/Admin/BoxTitlePage"; import AdminComp_BoxTitle from "@/components/_ShareComponent/Admin/BoxTitlePage";
import AdminTitleTable from "@/components/_ShareComponent/Admin/TableTitle"; import AdminTitleTable from "@/components/_ShareComponent/Admin/TableTitle";
import AdminTableValue from "@/components/_ShareComponent/Admin/TableValue"; import AdminTableValue from "@/components/_ShareComponent/Admin/TableValue";
import { GridDetail_4_8 } from "@/components/_ShareComponent/GridDetail_4_8"; import { GridSpan_4_8 } from "@/components/_ShareComponent/GridSpan_4_8";
import { GridSpan_NewComponent } from "@/components/_ShareComponent/GridSpan_NewComponent";
import { MainColor } from "@/constants/color-palet"; import { MainColor } from "@/constants/color-palet";
import { ICON_SIZE_BUTTON } from "@/constants/constans-value"; import { ICON_SIZE_BUTTON } from "@/constants/constans-value";
import { import {
@@ -28,6 +30,7 @@ import {
import { router, useFocusEffect, useLocalSearchParams } from "expo-router"; import { router, useFocusEffect, useLocalSearchParams } from "expo-router";
import _ from "lodash"; import _ from "lodash";
import { useCallback, useState } from "react"; import { useCallback, useState } from "react";
import { View } from "react-native";
import { Divider } from "react-native-paper"; import { Divider } from "react-native-paper";
import Toast from "react-native-toast-message"; import Toast from "react-native-toast-message";
@@ -95,14 +98,14 @@ export default function AdminForumReportPosting() {
> >
<BaseBox> <BaseBox>
<StackCustom gap={"sm"}> <StackCustom gap={"sm"}>
<GridDetail_4_8 <GridSpan_NewComponent
label={<TextCustom bold>Username</TextCustom>} text1={<TextCustom bold>Username</TextCustom>}
value={<TextCustom>{data?.Author?.username || "-"}</TextCustom>} text2={<TextCustom>{data?.Author?.username || "-"}</TextCustom>}
/> />
<GridDetail_4_8 <GridSpan_NewComponent
label={<TextCustom bold>Status</TextCustom>} text1={<TextCustom bold>Status</TextCustom>}
value={ text2={
data && data?.ForumMaster_StatusPosting?.status ? ( data && data?.ForumMaster_StatusPosting?.status ? (
<BadgeCustom <BadgeCustom
color={ color={
@@ -121,19 +124,23 @@ export default function AdminForumReportPosting() {
} }
/> />
<GridDetail_4_8 <GridSpan_NewComponent
label={<TextCustom bold>Postingan</TextCustom>} text1={<TextCustom bold>Postingan</TextCustom>}
value={<TextCustom>{data?.diskusi || "-"}</TextCustom>} text2={<TextCustom>{data?.diskusi || "-"}</TextCustom>}
/> />
</StackCustom> </StackCustom>
</BaseBox> </BaseBox>
<AdminComp_BoxTitle title="Daftar Report Posting" /> <AdminComp_BoxTitle title="Daftar Report Posting" />
<StackCustom gap={"sm"}> <StackCustom gap={"sm"}>
<AdminTitleTable <GridSpan_NewComponent
title1="Aksi" text1={
title2="Pelapor" <TextCustom bold align="center">
title3="Kategori Report" Aksi
</TextCustom>
}
text2={<TextCustom bold>Pelapor</TextCustom>}
text3={<TextCustom bold>Kategori Report</TextCustom>}
/> />
<Divider /> <Divider />
{loadListReport ? ( {loadListReport ? (
@@ -144,34 +151,41 @@ export default function AdminForumReportPosting() {
</TextCustom> </TextCustom>
) : ( ) : (
listReport?.map((item: any, index: number) => ( listReport?.map((item: any, index: number) => (
<AdminTableValue <View key={index}>
key={index} <GridSpan_NewComponent
value1={ text1={
<ActionIcon <CenterCustom>
icon={<IconView size={ICON_SIZE_BUTTON} color="black" />} <ActionIcon
onPress={() => { icon={
setOpenDrawerAction(true); <IconView size={ICON_SIZE_BUTTON} color="black" />
setSelectedReport({ }
id: item?.id, onPress={() => {
username: item?.User?.username, setOpenDrawerAction(true);
kategori: item?.ForumMaster_KategoriReport?.title, setSelectedReport({
keterangan: item?.ForumMaster_KategoriReport?.deskripsi, id: item?.id,
deskripsi: item?.deskripsi, username: item?.User?.username,
}); kategori: item?.ForumMaster_KategoriReport?.title,
}} keterangan:
/> item?.ForumMaster_KategoriReport?.deskripsi,
} deskripsi: item?.deskripsi,
value2={ });
<TextCustom truncate={1}> }}
{item?.User?.username || "-"} />
</TextCustom> </CenterCustom>
} }
value3={ text2={
<TextCustom truncate={2} align="center"> <TextCustom truncate>
{item?.ForumMaster_KategoriReport?.title || "-"} {item?.User?.username || "-"}
</TextCustom> </TextCustom>
} }
/> text3={
<TextCustom truncate={2}>
{item?.ForumMaster_KategoriReport?.title || "-"}
</TextCustom>
}
/>
<Divider />
</View>
)) ))
)} )}
</StackCustom> </StackCustom>
@@ -229,20 +243,20 @@ export default function AdminForumReportPosting() {
height={"auto"} height={"auto"}
> >
<StackCustom> <StackCustom>
<GridDetail_4_8 <GridSpan_4_8
label={<TextCustom bold>Pelapor</TextCustom>} label={<TextCustom bold>Pelapor</TextCustom>}
value={<TextCustom>{selectedReport?.username || "-"}</TextCustom>} value={<TextCustom>{selectedReport?.username || "-"}</TextCustom>}
/> />
{selectedReport?.kategori && ( {selectedReport?.kategori && (
<> <>
<GridDetail_4_8 <GridSpan_4_8
label={<TextCustom bold>Kategori Report</TextCustom>} label={<TextCustom bold>Kategori Report</TextCustom>}
value={ value={
<TextCustom>{selectedReport?.kategori || "-"}</TextCustom> <TextCustom>{selectedReport?.kategori || "-"}</TextCustom>
} }
/> />
<GridDetail_4_8 <GridSpan_4_8
label={<TextCustom bold>Keterangan</TextCustom>} label={<TextCustom bold>Keterangan</TextCustom>}
value={ value={
<TextCustom>{selectedReport?.keterangan || "-"}</TextCustom> <TextCustom>{selectedReport?.keterangan || "-"}</TextCustom>
@@ -252,7 +266,7 @@ export default function AdminForumReportPosting() {
)} )}
{selectedReport?.deskripsi && ( {selectedReport?.deskripsi && (
<GridDetail_4_8 <GridSpan_4_8
label={<TextCustom bold>Deskripsi</TextCustom>} label={<TextCustom bold>Deskripsi</TextCustom>}
value={ value={
<TextCustom>{selectedReport?.deskripsi || "-"}</TextCustom> <TextCustom>{selectedReport?.deskripsi || "-"}</TextCustom>

View File

@@ -1,22 +1,22 @@
/* eslint-disable react-hooks/exhaustive-deps */ /* eslint-disable react-hooks/exhaustive-deps */
import { import {
ActionIcon, ClickableCustom,
LoaderCustom, LoaderCustom,
SearchInput, SearchInput,
Spacing,
StackCustom, StackCustom,
TextCustom, TextCustom,
ViewWrapper, ViewWrapper,
} from "@/components"; } from "@/components";
import { IconView } from "@/components/_Icon/IconComponent";
import AdminComp_BoxTitle from "@/components/_ShareComponent/Admin/BoxTitlePage"; import AdminComp_BoxTitle from "@/components/_ShareComponent/Admin/BoxTitlePage";
import AdminTitleTable from "@/components/_ShareComponent/Admin/TableTitle";
import AdminTableValue from "@/components/_ShareComponent/Admin/TableValue";
import AdminTitlePage from "@/components/_ShareComponent/Admin/TitlePage"; import AdminTitlePage from "@/components/_ShareComponent/Admin/TitlePage";
import { ICON_SIZE_BUTTON } from "@/constants/constans-value"; import { GridSpan_4_8 } from "@/components/_ShareComponent/GridSpan_4_8";
import { GridSpan_NewComponent } from "@/components/_ShareComponent/GridSpan_NewComponent";
import { apiAdminForum } from "@/service/api-admin/api-admin-forum"; import { apiAdminForum } from "@/service/api-admin/api-admin-forum";
import { router, useFocusEffect } from "expo-router"; import { router, useFocusEffect } from "expo-router";
import _ from "lodash"; import _ from "lodash";
import React, { useCallback, useState } from "react"; import { useCallback, useState } from "react";
import { View } from "react-native";
import { Divider } from "react-native-paper"; import { Divider } from "react-native-paper";
export default function AdminForumPosting() { export default function AdminForumPosting() {
@@ -37,7 +37,9 @@ export default function AdminForumPosting() {
category: "posting", category: "posting",
search: search, search: search,
}); });
console.log("DATA", JSON.stringify(response, null, 2));
if (response.success) { if (response.success) {
setList(response.data); setList(response.data);
} }
@@ -51,7 +53,7 @@ export default function AdminForumPosting() {
const rightComponent = ( const rightComponent = (
<SearchInput <SearchInput
containerStyle={{ width: "100%", marginBottom: 0 }} containerStyle={{ width: "100%", marginBottom: 0 }}
placeholder="Cari" placeholder="Cari postingan"
value={search} value={search}
onChangeText={setSearch} onChangeText={setSearch}
/> />
@@ -61,9 +63,15 @@ export default function AdminForumPosting() {
<> <>
<ViewWrapper headerComponent={<AdminTitlePage title="Forum" />}> <ViewWrapper headerComponent={<AdminTitlePage title="Forum" />}>
<AdminComp_BoxTitle title={"Posting"} rightComponent={rightComponent} /> <AdminComp_BoxTitle title={"Posting"} rightComponent={rightComponent} />
<GridSpan_NewComponent
text1={<TextCustom bold truncate>Username</TextCustom>}
text2={<TextCustom bold truncate> Postingan</TextCustom>}
text3={<TextCustom bold align="center" truncate> Report Posting</TextCustom>}
text4={<TextCustom bold align="center" truncate> Komentar</TextCustom>}
/>
<Divider />
<Spacing />
<StackCustom> <StackCustom>
<AdminTitleTable title1="Aksi" title2="Username" title3="Postingan" />
<Divider />
{loadList ? ( {loadList ? (
<LoaderCustom /> <LoaderCustom />
) : _.isEmpty(list) ? ( ) : _.isEmpty(list) ? (
@@ -72,25 +80,38 @@ export default function AdminForumPosting() {
</TextCustom> </TextCustom>
) : ( ) : (
list?.map((item: any, index: number) => ( list?.map((item: any, index: number) => (
<AdminTableValue <View key={index}>
key={index} <ClickableCustom
value1={ onPress={() => {
<ActionIcon router.push(`/admin/forum/${item.id}`);
icon={<IconView size={ICON_SIZE_BUTTON} color="black" />} }}
onPress={() => { >
router.push(`/admin/forum/${item?.id}`); <GridSpan_NewComponent
}} text1={
<TextCustom truncate={1}>
{item?.Author?.username || "-"}
</TextCustom>
}
text2={
<TextCustom truncate>
{item?.diskusi || "-"}
</TextCustom>
}
text3={
<TextCustom align="center" truncate={2}>
{item?.reportPosting || "-"}
</TextCustom>
}
text4={
<TextCustom align="center" truncate={2}>
{item?.komentar || "-"}
</TextCustom>
}
/> />
}
value2={ </ClickableCustom>
<TextCustom truncate={1}> <Divider />
{item?.Author?.username || "-"} </View>
</TextCustom>
}
value3={
<TextCustom truncate={2}>{item?.diskusi || "-"}</TextCustom>
}
/>
)) ))
)} )}
</StackCustom> </StackCustom>

View File

@@ -1,8 +1,10 @@
/* eslint-disable react-hooks/exhaustive-deps */ /* eslint-disable react-hooks/exhaustive-deps */
import { import {
ActionIcon, ActionIcon,
ClickableCustom,
LoaderCustom, LoaderCustom,
SearchInput, SearchInput,
Spacing,
StackCustom, StackCustom,
TextCustom, TextCustom,
ViewWrapper, ViewWrapper,
@@ -12,12 +14,14 @@ import AdminComp_BoxTitle from "@/components/_ShareComponent/Admin/BoxTitlePage"
import AdminTitleTable from "@/components/_ShareComponent/Admin/TableTitle"; import AdminTitleTable from "@/components/_ShareComponent/Admin/TableTitle";
import AdminTableValue from "@/components/_ShareComponent/Admin/TableValue"; import AdminTableValue from "@/components/_ShareComponent/Admin/TableValue";
import AdminTitlePage from "@/components/_ShareComponent/Admin/TitlePage"; import AdminTitlePage from "@/components/_ShareComponent/Admin/TitlePage";
import { GridSpan_NewComponent } from "@/components/_ShareComponent/GridSpan_NewComponent";
import { MainColor } from "@/constants/color-palet"; import { MainColor } from "@/constants/color-palet";
import { ICON_SIZE_BUTTON } from "@/constants/constans-value"; import { ICON_SIZE_BUTTON } from "@/constants/constans-value";
import { apiAdminForum } from "@/service/api-admin/api-admin-forum"; import { apiAdminForum } from "@/service/api-admin/api-admin-forum";
import { router, useFocusEffect } from "expo-router"; import { router, useFocusEffect } from "expo-router";
import _ from "lodash"; import _ from "lodash";
import { useCallback, useState } from "react"; import { useCallback, useState } from "react";
import { View } from "react-native";
import { Divider } from "react-native-paper"; import { Divider } from "react-native-paper";
export default function AdminForumReportComment() { export default function AdminForumReportComment() {
@@ -67,13 +71,26 @@ export default function AdminForumReportComment() {
rightComponent={rightComponent} rightComponent={rightComponent}
/> />
<StackCustom gap={"sm"}> <GridSpan_NewComponent
<AdminTitleTable text1={
title1="Aksi" <TextCustom bold truncate>
title2="Pelapor" Pelapor
title3="Jenis Laporan" </TextCustom>
/> }
<Divider /> text2={
<TextCustom bold truncate>
Komentar
</TextCustom>
}
text3={
<TextCustom bold truncate>
Jenis Laporan
</TextCustom>
}
/>
<Divider />
<Spacing />
<StackCustom gap={"lg"}>
{loadList ? ( {loadList ? (
<LoaderCustom /> <LoaderCustom />
) : _.isEmpty(listData) ? ( ) : _.isEmpty(listData) ? (
@@ -82,34 +99,35 @@ export default function AdminForumReportComment() {
</TextCustom> </TextCustom>
) : ( ) : (
listData?.map((item: any, index: number) => ( listData?.map((item: any, index: number) => (
<AdminTableValue <View key={index}>
key={index} <ClickableCustom
value1={ onPress={() => {
<ActionIcon router.push(
icon={ `/admin/forum/${item?.Forum_Komentar?.id}/list-report-comment`
<IconView );
size={ICON_SIZE_BUTTON} }}
color={MainColor.black} >
/> <GridSpan_NewComponent
text1={
<TextCustom truncate={1}>
{item?.User?.username || "-"}
</TextCustom>
}
text2={
<TextCustom truncate={2}>
{item?.Forum_Komentar?.komentar || "-"}
</TextCustom>
}
text3={
<TextCustom truncate={2}>
{item?.ForumMaster_KategoriReport?.title || "-"}
</TextCustom>
} }
onPress={() => {
router.push(
`/admin/forum/${item?.Forum_Komentar?.id}/list-report-comment`
);
}}
/> />
} </ClickableCustom>
value2={ <Spacing />
<TextCustom truncate={1}> <Divider />
{item?.User?.username || "-"} </View>
</TextCustom>
}
value3={
<TextCustom truncate={2} align="center">
{item?.ForumMaster_KategoriReport?.title || "-"}
</TextCustom>
}
/>
)) ))
)} )}
</StackCustom> </StackCustom>

View File

@@ -1,24 +1,27 @@
/* eslint-disable react-hooks/exhaustive-deps */ /* eslint-disable react-hooks/exhaustive-deps */
import { import {
ActionIcon, ActionIcon,
ClickableCustom,
Divider, Divider,
LoaderCustom, LoaderCustom,
SearchInput, SearchInput,
StackCustom, StackCustom,
TextCustom, TextCustom,
ViewWrapper ViewWrapper,
} from "@/components"; } from "@/components";
import { IconView } from "@/components/_Icon/IconComponent"; import { IconView } from "@/components/_Icon/IconComponent";
import AdminComp_BoxTitle from "@/components/_ShareComponent/Admin/BoxTitlePage"; import AdminComp_BoxTitle from "@/components/_ShareComponent/Admin/BoxTitlePage";
import AdminTitleTable from "@/components/_ShareComponent/Admin/TableTitle"; import AdminTitleTable from "@/components/_ShareComponent/Admin/TableTitle";
import AdminTableValue from "@/components/_ShareComponent/Admin/TableValue"; import AdminTableValue from "@/components/_ShareComponent/Admin/TableValue";
import AdminTitlePage from "@/components/_ShareComponent/Admin/TitlePage"; import AdminTitlePage from "@/components/_ShareComponent/Admin/TitlePage";
import { GridSpan_NewComponent } from "@/components/_ShareComponent/GridSpan_NewComponent";
import { MainColor } from "@/constants/color-palet"; import { MainColor } from "@/constants/color-palet";
import { ICON_SIZE_BUTTON } from "@/constants/constans-value"; import { ICON_SIZE_BUTTON } from "@/constants/constans-value";
import { apiAdminForum } from "@/service/api-admin/api-admin-forum"; import { apiAdminForum } from "@/service/api-admin/api-admin-forum";
import { router, useFocusEffect } from "expo-router"; import { router, useFocusEffect } from "expo-router";
import _ from "lodash"; import _ from "lodash";
import { useCallback, useState } from "react"; import { useCallback, useState } from "react";
import { View } from "react-native";
export default function AdminForumReportPosting() { export default function AdminForumReportPosting() {
const [listData, setListData] = useState<any[] | null>(null); const [listData, setListData] = useState<any[] | null>(null);
@@ -67,46 +70,51 @@ export default function AdminForumReportPosting() {
rightComponent={rightComponent} rightComponent={rightComponent}
/> />
<StackCustom gap={"sm"}> <GridSpan_NewComponent
<AdminTitleTable title1="Aksi" title2="Pelapor" title3="Postingan" /> text1={
<TextCustom bold truncate>
<Divider /> Username
</TextCustom>
}
text2={
<TextCustom bold truncate>
Postingan
</TextCustom>
}
/>
<Divider />
<StackCustom>
{loadList ? ( {loadList ? (
<LoaderCustom /> <LoaderCustom />
) : _.isEmpty(listData) ? ( ) : _.isEmpty(listData) ? (
<TextCustom align="center" color="gray"> <TextCustom align="center" color="gray">
Belum ada data Belum ada data
</TextCustom> </TextCustom>
) : ( ) : (
listData?.map((item: any, index: number) => ( listData?.map((item: any, index: number) => (
<AdminTableValue <View key={index}>
key={index} <ClickableCustom
value1={ onPress={() => {
<ActionIcon router.push(
icon={ `/admin/forum/${item?.Forum_Posting?.id}/list-report-posting`
<IconView );
size={ICON_SIZE_BUTTON} }}
color={MainColor.black} >
/> <GridSpan_NewComponent
text1={
<TextCustom truncate={1}>
{item?.User?.username || "-"}
</TextCustom>
}
text2={
<TextCustom truncate={1}>
{item?.Forum_Posting?.diskusi || "-"}
</TextCustom>
} }
onPress={() => {
router.push(
`/admin/forum/${item?.Forum_Posting?.id}/list-report-posting`
);
}}
/> />
} </ClickableCustom>
value2={ <Divider />
<TextCustom truncate={1}> </View>
{item?.User?.username || "-"}
</TextCustom>
}
value3={
<TextCustom truncate={2} align="center">
{item?.Forum_Posting?.diskusi || "-"}
</TextCustom>
}
/>
)) ))
)} )}
</StackCustom> </StackCustom>

View File

@@ -19,7 +19,7 @@ import { IconDot, IconList } from "@/components/_Icon/IconComponent";
import AdminBackButtonAntTitle from "@/components/_ShareComponent/Admin/BackButtonAntTitle"; import AdminBackButtonAntTitle from "@/components/_ShareComponent/Admin/BackButtonAntTitle";
import AdminButtonReject from "@/components/_ShareComponent/Admin/ButtonReject"; import AdminButtonReject from "@/components/_ShareComponent/Admin/ButtonReject";
import AdminButtonReview from "@/components/_ShareComponent/Admin/ButtonReview"; import AdminButtonReview from "@/components/_ShareComponent/Admin/ButtonReview";
import { GridDetail_4_8 } from "@/components/_ShareComponent/GridDetail_4_8"; import { GridSpan_4_8 } from "@/components/_ShareComponent/GridSpan_4_8";
import ReportBox from "@/components/Box/ReportBox"; import ReportBox from "@/components/Box/ReportBox";
import { MainColor } from "@/constants/color-palet"; import { MainColor } from "@/constants/color-palet";
import { ICON_SIZE_BUTTON } from "@/constants/constans-value"; import { ICON_SIZE_BUTTON } from "@/constants/constans-value";
@@ -183,7 +183,7 @@ export default function AdminInvestmentDetail() {
/> />
<Spacing /> <Spacing />
<StackCustom gap={"xs"}> <StackCustom gap={"xs"}>
<GridDetail_4_8 <GridSpan_4_8
label={<TextCustom bold>Sisa Saham</TextCustom>} label={<TextCustom bold>Sisa Saham</TextCustom>}
value={ value={
<TextCustom> <TextCustom>
@@ -191,7 +191,7 @@ export default function AdminInvestmentDetail() {
</TextCustom> </TextCustom>
} }
/> />
<GridDetail_4_8 <GridSpan_4_8
label={<TextCustom bold>Validasi Transaksi</TextCustom>} label={<TextCustom bold>Validasi Transaksi</TextCustom>}
value={ value={
<TextCustom> <TextCustom>
@@ -207,7 +207,7 @@ export default function AdminInvestmentDetail() {
<StackCustom> <StackCustom>
<DummyLandscapeImage imageId={data?.imageId} /> <DummyLandscapeImage imageId={data?.imageId} />
{listData.map((item, i) => ( {listData.map((item, i) => (
<GridDetail_4_8 <GridSpan_4_8
key={i} key={i}
label={<TextCustom bold>{item.label}</TextCustom>} label={<TextCustom bold>{item.label}</TextCustom>}
value={<TextCustom>{item.value}</TextCustom>} value={<TextCustom>{item.value}</TextCustom>}
@@ -218,7 +218,7 @@ export default function AdminInvestmentDetail() {
<BaseBox> <BaseBox>
<StackCustom> <StackCustom>
<GridDetail_4_8 <GridSpan_4_8
label={<TextCustom bold>File Prospektus</TextCustom>} label={<TextCustom bold>File Prospektus</TextCustom>}
value={ value={
<ButtonCustom <ButtonCustom
@@ -238,7 +238,7 @@ export default function AdminInvestmentDetail() {
</ButtonCustom> </ButtonCustom>
} }
/> />
<GridDetail_4_8 <GridSpan_4_8
label={<TextCustom bold>File Dokumen</TextCustom>} label={<TextCustom bold>File Dokumen</TextCustom>}
value={ value={
<StackCustom> <StackCustom>

View File

@@ -10,7 +10,7 @@ import {
ViewWrapper, ViewWrapper,
} from "@/components"; } from "@/components";
import AdminBackButtonAntTitle from "@/components/_ShareComponent/Admin/BackButtonAntTitle"; import AdminBackButtonAntTitle from "@/components/_ShareComponent/Admin/BackButtonAntTitle";
import { GridDetail_4_8 } from "@/components/_ShareComponent/GridDetail_4_8"; import { GridSpan_4_8 } from "@/components/_ShareComponent/GridSpan_4_8";
import GridTwoView from "@/components/_ShareComponent/GridTwoView"; import GridTwoView from "@/components/_ShareComponent/GridTwoView";
import { MainColor } from "@/constants/color-palet"; import { MainColor } from "@/constants/color-palet";
import { import {
@@ -225,7 +225,7 @@ export default function AdminInvestmentTransactionDetail() {
<BaseBox> <BaseBox>
<StackCustom> <StackCustom>
{listData.map((item, index) => ( {listData.map((item, index) => (
<GridDetail_4_8 <GridSpan_4_8
key={index} key={index}
label={<TextCustom bold>{item.label}</TextCustom>} label={<TextCustom bold>{item.label}</TextCustom>}
value={<TextCustom>{item.value}</TextCustom>} value={<TextCustom>{item.value}</TextCustom>}

View File

@@ -76,7 +76,7 @@ export default function SuperAdmin_ListUser() {
</TextCustom> </TextCustom>
} }
component2={ component2={
<TextCustom align="center" bold> <TextCustom bold>
Username Username
</TextCustom> </TextCustom>
} }

View File

@@ -73,11 +73,7 @@ export default function AdminUserAccess() {
Aksi Aksi
</TextCustom> </TextCustom>
} }
component2={ component2={<TextCustom bold>Username</TextCustom>}
<TextCustom align="center" bold>
Username
</TextCustom>
}
component3={ component3={
<TextCustom align="center" bold> <TextCustom align="center" bold>
Status Akses Status Akses

View File

@@ -1,19 +1,19 @@
/* eslint-disable react-hooks/exhaustive-deps */ /* eslint-disable react-hooks/exhaustive-deps */
import { import {
AlertDefaultSystem, AlertDefaultSystem,
BadgeCustom, BadgeCustom,
BaseBox, BaseBox,
CircleContainer, CircleContainer,
Grid, Grid,
Spacing, Spacing,
StackCustom, StackCustom,
TextCustom, TextCustom,
ViewWrapper, ViewWrapper,
} from "@/components"; } from "@/components";
import AdminBackButtonAntTitle from "@/components/_ShareComponent/Admin/BackButtonAntTitle"; import AdminBackButtonAntTitle from "@/components/_ShareComponent/Admin/BackButtonAntTitle";
import AdminButtonReject from "@/components/_ShareComponent/Admin/ButtonReject"; import AdminButtonReject from "@/components/_ShareComponent/Admin/ButtonReject";
import AdminButtonReview from "@/components/_ShareComponent/Admin/ButtonReview"; import AdminButtonReview from "@/components/_ShareComponent/Admin/ButtonReview";
import { GridDetail_4_8 } from "@/components/_ShareComponent/GridDetail_4_8"; import { GridSpan_4_8 } from "@/components/_ShareComponent/GridSpan_4_8";
import ReportBox from "@/components/Box/ReportBox"; import ReportBox from "@/components/Box/ReportBox";
import { MainColor } from "@/constants/color-palet"; import { MainColor } from "@/constants/color-palet";
import funUpdateStatusVoting from "@/screens/Admin/Voting/funUpdateStatus"; import funUpdateStatusVoting from "@/screens/Admin/Voting/funUpdateStatus";
@@ -169,7 +169,7 @@ export default function AdminVotingDetail() {
<BaseBox> <BaseBox>
<StackCustom> <StackCustom>
{listData.map((item, i) => ( {listData.map((item, i) => (
<GridDetail_4_8 <GridSpan_4_8
key={i} key={i}
label={<TextCustom bold>{item.label}</TextCustom>} label={<TextCustom bold>{item.label}</TextCustom>}
value={<TextCustom>{item.value}</TextCustom>} value={<TextCustom>{item.value}</TextCustom>}

View File

@@ -103,7 +103,7 @@ export default function AdminVotingStatus() {
</TextCustom> </TextCustom>
} }
value3={ value3={
<TextCustom align="center" truncate={2}> <TextCustom truncate={2}>
{item?.title || "-"} {item?.title || "-"}
</TextCustom> </TextCustom>
} }

View File

@@ -91,7 +91,7 @@ export default function AdminVotingHistory() {
} }
value2={<TextCustom truncate={1}>{item?.Author?.username || "-"}</TextCustom>} value2={<TextCustom truncate={1}>{item?.Author?.username || "-"}</TextCustom>}
value3={ value3={
<TextCustom align="center" truncate={2}> <TextCustom truncate={2}>
{item?.title || "-"} {item?.title || "-"}
</TextCustom> </TextCustom>
} }

View File

@@ -0,0 +1,116 @@
import {
BoxButtonOnFooter,
ButtonCustom,
CheckboxCustom,
InformationBox,
StackCustom,
ViewWrapper
} from "@/components";
import { MainColor } from "@/constants/color-palet";
import { useAuth } from "@/hooks/use-auth";
import { apiAcceptTermService, BASE_URL } from "@/service/api-config";
import { GStyles } from "@/styles/global-styles";
import { openBrowser } from "@/utils/openBrower";
import { Stack } from "expo-router";
import { useState } from "react";
import { Text, View } from "react-native";
import Toast from "react-native-toast-message";
export default function TermsAgreement() {
const { user, logout } = useAuth();
const [term, setTerm] = useState(false);
const [isLoading, setIsLoading] = useState(false);
const url = BASE_URL;
const handleSubmit = async () => {
try {
setIsLoading(true);
const response = await apiAcceptTermService({
data: {
id: user?.id as string,
termsOfServiceAccepted: term,
},
});
if (!response.success) {
Toast.show({
type: "error",
text1: "Gagal",
text2: response.message,
});
return;
}
Toast.show({
type: "success",
text1: "Anda berhasil menerima syarat & ketentuan",
text2: "Silahkan login kembali",
});
setTimeout(() => {
logout();
}, 2000);
} catch (error) {
console.log("error", error);
} finally {
setIsLoading(false);
}
};
const footerComponent = (
<BoxButtonOnFooter>
<ButtonCustom
onPress={handleSubmit}
disabled={!term}
isLoading={isLoading}
>
Setuju
</ButtonCustom>
</BoxButtonOnFooter>
);
return (
<>
<Stack.Screen
options={{
title: "Terms & Conditions",
}}
/>
<ViewWrapper footerComponent={footerComponent}>
<StackCustom>
<InformationBox text="Anda dialihkan ke halaman syarat & ketentuan, karena Anda belum menerima persetujuan syarat & ketentuan." />
<View
style={{
flexDirection: "row",
alignItems: "center",
marginTop: 16,
marginBottom: 16,
paddingInline: 10,
}}
>
<CheckboxCustom value={term} onChange={() => setTerm(!term)} />
<Text style={GStyles.textLabel}>
Saya setuju dengan{" "}
<Text
style={{
color: MainColor.yellow,
textDecorationLine: "underline",
}}
onPress={() => {
const toUrl = `${url}/terms-of-service.html`;
openBrowser(toUrl);
}}
>
Syarat & Ketentuan
</Text>{" "}
yang melarang konten tidak pantas dan perilaku merugikan.
</Text>
</View>
</StackCustom>
</ViewWrapper>
</>
);
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 MiB

After

Width:  |  Height:  |  Size: 509 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 MiB

128
bun.lock
View File

@@ -12,6 +12,7 @@
"@react-navigation/elements": "^2.3.8", "@react-navigation/elements": "^2.3.8",
"@react-navigation/native": "^7.1.6", "@react-navigation/native": "^7.1.6",
"@react-navigation/native-stack": "^7.3.10", "@react-navigation/native-stack": "^7.3.10",
"@rnmapbox/maps": "^10.2.7",
"@types/lodash": "^4.17.20", "@types/lodash": "^4.17.20",
"@types/react-native-vector-icons": "^6.4.18", "@types/react-native-vector-icons": "^6.4.18",
"axios": "^1.11.0", "axios": "^1.11.0",
@@ -19,22 +20,27 @@
"expo": "^54.0.0", "expo": "^54.0.0",
"expo-camera": "~17.0.7", "expo-camera": "~17.0.7",
"expo-clipboard": "~8.0.7", "expo-clipboard": "~8.0.7",
"expo-constants": "~18.0.8", "expo-constants": "^18.0.10",
"expo-dev-client": "~6.0.12", "expo-dev-client": "~6.0.12",
"expo-device": "^8.0.9",
"expo-document-picker": "~14.0.7", "expo-document-picker": "~14.0.7",
"expo-file-system": "^19.0.15", "expo-file-system": "^19.0.15",
"expo-font": "~14.0.8", "expo-font": "~14.0.8",
"expo-haptics": "~15.0.7", "expo-haptics": "~15.0.7",
"expo-image": "~3.0.8", "expo-image": "~3.0.8",
"expo-image-picker": "~17.0.8", "expo-image-picker": "~17.0.8",
"expo-linear-gradient": "~15.0.7",
"expo-linking": "~8.0.8", "expo-linking": "~8.0.8",
"expo-location": "~19.0.7",
"expo-notifications": "^0.32.13",
"expo-router": "~6.0.1", "expo-router": "~6.0.1",
"expo-splash-screen": "~31.0.9", "expo-splash-screen": "~31.0.9",
"expo-status-bar": "~3.0.8", "expo-status-bar": "~3.0.8",
"expo-symbols": "~1.0.7", "expo-symbols": "~1.0.7",
"expo-system-ui": "~6.0.7", "expo-system-ui": "~6.0.7",
"expo-web-browser": "~15.0.7", "expo-web-browser": "~15.0.9",
"lodash": "^4.17.21", "lodash": "^4.17.21",
"moti": "^0.30.0",
"react": "19.1.0", "react": "19.1.0",
"react-dom": "19.1.0", "react-dom": "19.1.0",
"react-native": "0.81.4", "react-native": "0.81.4",
@@ -336,6 +342,10 @@
"@emnapi/wasi-threads": ["@emnapi/wasi-threads@1.0.2", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-5n3nTJblwRi8LlXkJ9eBzu+kZR8Yxcc7ubakyQTFzPMtIhFpUBRbsnc2Dv88IZDIbCDlBiWrknhB4Lsz7mg6BA=="], "@emnapi/wasi-threads": ["@emnapi/wasi-threads@1.0.2", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-5n3nTJblwRi8LlXkJ9eBzu+kZR8Yxcc7ubakyQTFzPMtIhFpUBRbsnc2Dv88IZDIbCDlBiWrknhB4Lsz7mg6BA=="],
"@emotion/is-prop-valid": ["@emotion/is-prop-valid@0.8.8", "", { "dependencies": { "@emotion/memoize": "0.7.4" } }, "sha512-u5WtneEAr5IDG2Wv65yhunPSMLIpuKsbuOktRojfrEiEvRyC85LgPMZI63cr7NUqT8ZIGdSVg8ZKGxIug4lXcA=="],
"@emotion/memoize": ["@emotion/memoize@0.7.4", "", {}, "sha512-Ja/Vfqe3HpuzRsG1oBtWTHk2PGZ7GR+2Vz5iYGelAw8dx32K0y7PjVuxK6z1nMpZOqAFsRUPCkK1YjJ56qJlgw=="],
"@eslint-community/eslint-utils": ["@eslint-community/eslint-utils@4.7.0", "", { "dependencies": { "eslint-visitor-keys": "^3.4.3" }, "peerDependencies": { "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } }, "sha512-dyybb3AcajC7uha6CvhdVRJqaKyn7w2YKqKyAN37NKYgZT36w+iRb0Dymmc5qEJ549c/S31cMMSFd75bteCpCw=="], "@eslint-community/eslint-utils": ["@eslint-community/eslint-utils@4.7.0", "", { "dependencies": { "eslint-visitor-keys": "^3.4.3" }, "peerDependencies": { "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } }, "sha512-dyybb3AcajC7uha6CvhdVRJqaKyn7w2YKqKyAN37NKYgZT36w+iRb0Dymmc5qEJ549c/S31cMMSFd75bteCpCw=="],
"@eslint-community/regexpp": ["@eslint-community/regexpp@4.12.1", "", {}, "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ=="], "@eslint-community/regexpp": ["@eslint-community/regexpp@4.12.1", "", {}, "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ=="],
@@ -416,6 +426,8 @@
"@humanwhocodes/retry": ["@humanwhocodes/retry@0.4.3", "", {}, "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ=="], "@humanwhocodes/retry": ["@humanwhocodes/retry@0.4.3", "", {}, "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ=="],
"@ide/backoff": ["@ide/backoff@1.0.0", "", {}, "sha512-F0YfUDjvT+Mtt/R4xdl2X0EYCHMMiJqNLdxHD++jDT5ydEFIyqbCHh51Qx2E211dgZprPKhV7sHmnXKpLuvc5g=="],
"@isaacs/cliui": ["@isaacs/cliui@8.0.2", "", { "dependencies": { "string-width": "^5.1.2", "string-width-cjs": "npm:string-width@^4.2.0", "strip-ansi": "^7.0.1", "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", "wrap-ansi": "^8.1.0", "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" } }, "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA=="], "@isaacs/cliui": ["@isaacs/cliui@8.0.2", "", { "dependencies": { "string-width": "^5.1.2", "string-width-cjs": "npm:string-width@^4.2.0", "strip-ansi": "^7.0.1", "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", "wrap-ansi": "^8.1.0", "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" } }, "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA=="],
"@isaacs/fs-minipass": ["@isaacs/fs-minipass@4.0.1", "", { "dependencies": { "minipass": "^7.0.4" } }, "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w=="], "@isaacs/fs-minipass": ["@isaacs/fs-minipass@4.0.1", "", { "dependencies": { "minipass": "^7.0.4" } }, "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w=="],
@@ -472,6 +484,18 @@
"@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.25", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ=="], "@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.25", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ=="],
"@motionone/animation": ["@motionone/animation@10.18.0", "", { "dependencies": { "@motionone/easing": "^10.18.0", "@motionone/types": "^10.17.1", "@motionone/utils": "^10.18.0", "tslib": "^2.3.1" } }, "sha512-9z2p5GFGCm0gBsZbi8rVMOAJCtw1WqBTIPw3ozk06gDvZInBPIsQcHgYogEJ4yuHJ+akuW8g1SEIOpTOvYs8hw=="],
"@motionone/dom": ["@motionone/dom@10.12.0", "", { "dependencies": { "@motionone/animation": "^10.12.0", "@motionone/generators": "^10.12.0", "@motionone/types": "^10.12.0", "@motionone/utils": "^10.12.0", "hey-listen": "^1.0.8", "tslib": "^2.3.1" } }, "sha512-UdPTtLMAktHiqV0atOczNYyDd/d8Cf5fFsd1tua03PqTwwCe/6lwhLSQ8a7TbnQ5SN0gm44N1slBfj+ORIhrqw=="],
"@motionone/easing": ["@motionone/easing@10.18.0", "", { "dependencies": { "@motionone/utils": "^10.18.0", "tslib": "^2.3.1" } }, "sha512-VcjByo7XpdLS4o9T8t99JtgxkdMcNWD3yHU/n6CLEz3bkmKDRZyYQ/wmSf6daum8ZXqfUAgFeCZSpJZIMxaCzg=="],
"@motionone/generators": ["@motionone/generators@10.18.0", "", { "dependencies": { "@motionone/types": "^10.17.1", "@motionone/utils": "^10.18.0", "tslib": "^2.3.1" } }, "sha512-+qfkC2DtkDj4tHPu+AFKVfR/C30O1vYdvsGYaR13W/1cczPrrcjdvYCj0VLFuRMN+lP1xvpNZHCRNM4fBzn1jg=="],
"@motionone/types": ["@motionone/types@10.17.1", "", {}, "sha512-KaC4kgiODDz8hswCrS0btrVrzyU2CSQKO7Ps90ibBVSQmjkrt2teqta6/sOG59v7+dPnKMAg13jyqtMKV2yJ7A=="],
"@motionone/utils": ["@motionone/utils@10.18.0", "", { "dependencies": { "@motionone/types": "^10.17.1", "hey-listen": "^1.0.8", "tslib": "^2.3.1" } }, "sha512-3XVF7sgyTSI2KWvTf6uLlBJ5iAgRgmvp3bpuOiQJvInd4nZ19ET8lX5unn30SlmRH7hXbBbH+Gxd0m0klJ3Xtw=="],
"@napi-rs/wasm-runtime": ["@napi-rs/wasm-runtime@0.2.11", "", { "dependencies": { "@emnapi/core": "^1.4.3", "@emnapi/runtime": "^1.4.3", "@tybys/wasm-util": "^0.9.0" } }, "sha512-9DPkXtvHydrcOsopiYpUgPHpmj0HWZKMUnL2dZqpvC42lsratuBG06V5ipyno0fUek5VlFsNQ+AcFATSrJXgMA=="], "@napi-rs/wasm-runtime": ["@napi-rs/wasm-runtime@0.2.11", "", { "dependencies": { "@emnapi/core": "^1.4.3", "@emnapi/runtime": "^1.4.3", "@tybys/wasm-util": "^0.9.0" } }, "sha512-9DPkXtvHydrcOsopiYpUgPHpmj0HWZKMUnL2dZqpvC42lsratuBG06V5ipyno0fUek5VlFsNQ+AcFATSrJXgMA=="],
"@nicolo-ribaudo/chokidar-2": ["@nicolo-ribaudo/chokidar-2@2.1.8-no-fsevents.3", "", {}, "sha512-s88O1aVtXftvp5bCPB7WnmXc5IwOZZ7YPuwNPt+GtOOXpPvad1LfbmjYv+qII7zP6RU2QGnqve27dnLycEnyEQ=="], "@nicolo-ribaudo/chokidar-2": ["@nicolo-ribaudo/chokidar-2@2.1.8-no-fsevents.3", "", {}, "sha512-s88O1aVtXftvp5bCPB7WnmXc5IwOZZ7YPuwNPt+GtOOXpPvad1LfbmjYv+qII7zP6RU2QGnqve27dnLycEnyEQ=="],
@@ -570,6 +594,8 @@
"@react-navigation/routers": ["@react-navigation/routers@7.4.1", "", { "dependencies": { "nanoid": "^3.3.11" } }, "sha512-42mZrMzQ0LfKxUb5OHIurYrPYyRsXFLolucILrvm21f0O40Sw0Ufh1bnn/jRqnxZZu7wvpUGIGYM8nS9zVE1Aw=="], "@react-navigation/routers": ["@react-navigation/routers@7.4.1", "", { "dependencies": { "nanoid": "^3.3.11" } }, "sha512-42mZrMzQ0LfKxUb5OHIurYrPYyRsXFLolucILrvm21f0O40Sw0Ufh1bnn/jRqnxZZu7wvpUGIGYM8nS9zVE1Aw=="],
"@rnmapbox/maps": ["@rnmapbox/maps@10.2.7", "", { "dependencies": { "@turf/along": "6.5.0", "@turf/distance": "6.5.0", "@turf/helpers": "6.5.0", "@turf/length": "6.5.0", "@turf/nearest-point-on-line": "6.5.0", "@types/geojson": "^7946.0.7", "debounce": "^2.2.0" }, "peerDependencies": { "expo": ">=47.0.0", "mapbox-gl": "^2.9.0", "react": ">=17.0.0", "react-dom": ">= 17.0.0", "react-native": ">=0.69" }, "optionalPeers": ["expo", "mapbox-gl", "react-dom"] }, "sha512-CJZuBKz2EiHjpJsyPz0jZOcm0jniDJdkeboeuyrcCIGe53Cw8gCFM6hxWOTJTL04o7idbNxD54jD4BQKxs6b1A=="],
"@rtsao/scc": ["@rtsao/scc@1.1.0", "", {}, "sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g=="], "@rtsao/scc": ["@rtsao/scc@1.1.0", "", {}, "sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g=="],
"@sinclair/typebox": ["@sinclair/typebox@0.27.8", "", {}, "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA=="], "@sinclair/typebox": ["@sinclair/typebox@0.27.8", "", {}, "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA=="],
@@ -584,6 +610,30 @@
"@tsconfig/node18": ["@tsconfig/node18@18.2.4", "", {}, "sha512-5xxU8vVs9/FNcvm3gE07fPbn9tl6tqGGWA9tSlwsUEkBxtRnTsNmwrV8gasZ9F/EobaSv9+nu8AxUKccw77JpQ=="], "@tsconfig/node18": ["@tsconfig/node18@18.2.4", "", {}, "sha512-5xxU8vVs9/FNcvm3gE07fPbn9tl6tqGGWA9tSlwsUEkBxtRnTsNmwrV8gasZ9F/EobaSv9+nu8AxUKccw77JpQ=="],
"@turf/along": ["@turf/along@6.5.0", "", { "dependencies": { "@turf/bearing": "^6.5.0", "@turf/destination": "^6.5.0", "@turf/distance": "^6.5.0", "@turf/helpers": "^6.5.0", "@turf/invariant": "^6.5.0" } }, "sha512-LLyWQ0AARqJCmMcIEAXF4GEu8usmd4Kbz3qk1Oy5HoRNpZX47+i5exQtmIWKdqJ1MMhW26fCTXgpsEs5zgJ5gw=="],
"@turf/bbox": ["@turf/bbox@7.3.0", "", { "dependencies": { "@turf/helpers": "7.3.0", "@turf/meta": "7.3.0", "@types/geojson": "^7946.0.10", "tslib": "^2.8.1" } }, "sha512-EC5GSUJlhXSiCVCEmgCSheZYm0s1ouKzUNqeEOsEYlqTbMAZ19RWgsg/xH2tjnuUw2JP9eGAUzQnCFX6JEV53w=="],
"@turf/bearing": ["@turf/bearing@6.5.0", "", { "dependencies": { "@turf/helpers": "^6.5.0", "@turf/invariant": "^6.5.0" } }, "sha512-dxINYhIEMzgDOztyMZc20I7ssYVNEpSv04VbMo5YPQsqa80KO3TFvbuCahMsCAW5z8Tncc8dwBlEFrmRjJG33A=="],
"@turf/destination": ["@turf/destination@6.5.0", "", { "dependencies": { "@turf/helpers": "^6.5.0", "@turf/invariant": "^6.5.0" } }, "sha512-4cnWQlNC8d1tItOz9B4pmJdWpXqS0vEvv65bI/Pj/genJnsL7evI0/Xw42RvEGROS481MPiU80xzvwxEvhQiMQ=="],
"@turf/distance": ["@turf/distance@6.5.0", "", { "dependencies": { "@turf/helpers": "^6.5.0", "@turf/invariant": "^6.5.0" } }, "sha512-xzykSLfoURec5qvQJcfifw/1mJa+5UwByZZ5TZ8iaqjGYN0vomhV9aiSLeYdUGtYRESZ+DYC/OzY+4RclZYgMg=="],
"@turf/helpers": ["@turf/helpers@6.5.0", "", {}, "sha512-VbI1dV5bLFzohYYdgqwikdMVpe7pJ9X3E+dlr425wa2/sMJqYDhTO++ec38/pcPvPE6oD9WEEeU3Xu3gza+VPw=="],
"@turf/invariant": ["@turf/invariant@6.5.0", "", { "dependencies": { "@turf/helpers": "^6.5.0" } }, "sha512-Wv8PRNCtPD31UVbdJE/KVAWKe7l6US+lJItRR/HOEW3eh+U/JwRCSUl/KZ7bmjM/C+zLNoreM2TU6OoLACs4eg=="],
"@turf/length": ["@turf/length@6.5.0", "", { "dependencies": { "@turf/distance": "^6.5.0", "@turf/helpers": "^6.5.0", "@turf/meta": "^6.5.0" } }, "sha512-5pL5/pnw52fck3oRsHDcSGrj9HibvtlrZ0QNy2OcW8qBFDNgZ4jtl6U7eATVoyWPKBHszW3dWETW+iLV7UARig=="],
"@turf/line-intersect": ["@turf/line-intersect@6.5.0", "", { "dependencies": { "@turf/helpers": "^6.5.0", "@turf/invariant": "^6.5.0", "@turf/line-segment": "^6.5.0", "@turf/meta": "^6.5.0", "geojson-rbush": "3.x" } }, "sha512-CS6R1tZvVQD390G9Ea4pmpM6mJGPWoL82jD46y0q1KSor9s6HupMIo1kY4Ny+AEYQl9jd21V3Scz20eldpbTVA=="],
"@turf/line-segment": ["@turf/line-segment@6.5.0", "", { "dependencies": { "@turf/helpers": "^6.5.0", "@turf/invariant": "^6.5.0", "@turf/meta": "^6.5.0" } }, "sha512-jI625Ho4jSuJESNq66Mmi290ZJ5pPZiQZruPVpmHkUw257Pew0alMmb6YrqYNnLUuiVVONxAAKXUVeeUGtycfw=="],
"@turf/meta": ["@turf/meta@6.5.0", "", { "dependencies": { "@turf/helpers": "^6.5.0" } }, "sha512-RrArvtsV0vdsCBegoBtOalgdSOfkBrTJ07VkpiCnq/491W67hnMWmDu7e6Ztw0C3WldRYTXkg3SumfdzZxLBHA=="],
"@turf/nearest-point-on-line": ["@turf/nearest-point-on-line@6.5.0", "", { "dependencies": { "@turf/bearing": "^6.5.0", "@turf/destination": "^6.5.0", "@turf/distance": "^6.5.0", "@turf/helpers": "^6.5.0", "@turf/invariant": "^6.5.0", "@turf/line-intersect": "^6.5.0", "@turf/meta": "^6.5.0" } }, "sha512-WthrvddddvmymnC+Vf7BrkHGbDOUu6Z3/6bFYUGv1kxw8tiZ6n83/VG6kHz4poHOfS0RaNflzXSkmCi64fLBlg=="],
"@tybys/wasm-util": ["@tybys/wasm-util@0.9.0", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-6+7nlbMVX/PVDCwaIQ8nTOPveOcFLSt8GcXdx8hD0bt39uWxYT88uXzqTd4fTvqta7oeUJqudepapKNt2DYJFw=="], "@tybys/wasm-util": ["@tybys/wasm-util@0.9.0", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-6+7nlbMVX/PVDCwaIQ8nTOPveOcFLSt8GcXdx8hD0bt39uWxYT88uXzqTd4fTvqta7oeUJqudepapKNt2DYJFw=="],
"@types/babel__core": ["@types/babel__core@7.20.5", "", { "dependencies": { "@babel/parser": "^7.20.7", "@babel/types": "^7.20.7", "@types/babel__generator": "*", "@types/babel__template": "*", "@types/babel__traverse": "*" } }, "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA=="], "@types/babel__core": ["@types/babel__core@7.20.5", "", { "dependencies": { "@babel/parser": "^7.20.7", "@babel/types": "^7.20.7", "@types/babel__generator": "*", "@types/babel__template": "*", "@types/babel__traverse": "*" } }, "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA=="],
@@ -800,6 +850,8 @@
"asap": ["asap@2.0.6", "", {}, "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA=="], "asap": ["asap@2.0.6", "", {}, "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA=="],
"assert": ["assert@2.1.0", "", { "dependencies": { "call-bind": "^1.0.2", "is-nan": "^1.3.2", "object-is": "^1.1.5", "object.assign": "^4.1.4", "util": "^0.12.5" } }, "sha512-eLHpSK/Y4nhMJ07gDaAzoX/XAKS8PSaojml3M0DM4JpV1LAi5JOJ/p6H/XWrl8L+DzVEvVCW1z3vWAaB9oTsQw=="],
"async-function": ["async-function@1.0.0", "", {}, "sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA=="], "async-function": ["async-function@1.0.0", "", {}, "sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA=="],
"async-limiter": ["async-limiter@1.0.1", "", {}, "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ=="], "async-limiter": ["async-limiter@1.0.1", "", {}, "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ=="],
@@ -838,6 +890,8 @@
"babel-preset-jest": ["babel-preset-jest@29.6.3", "", { "dependencies": { "babel-plugin-jest-hoist": "^29.6.3", "babel-preset-current-node-syntax": "^1.0.0" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA=="], "babel-preset-jest": ["babel-preset-jest@29.6.3", "", { "dependencies": { "babel-plugin-jest-hoist": "^29.6.3", "babel-preset-current-node-syntax": "^1.0.0" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA=="],
"badgin": ["badgin@1.2.3", "", {}, "sha512-NQGA7LcfCpSzIbGRbkgjgdWkjy7HI+Th5VLxTJfW5EeaAf3fnS+xWQaQOCYiny+q6QSvxqoSO04vCx+4u++EJw=="],
"balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="], "balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="],
"base64-js": ["base64-js@1.5.1", "", {}, "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="], "base64-js": ["base64-js@1.5.1", "", {}, "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="],
@@ -976,6 +1030,8 @@
"dayjs": ["dayjs@1.11.13", "", {}, "sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg=="], "dayjs": ["dayjs@1.11.13", "", {}, "sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg=="],
"debounce": ["debounce@2.2.0", "", {}, "sha512-Xks6RUDLZFdz8LIdR6q0MTH44k7FikOmnh5xkSjMig6ch45afc8sjTjRQf3P6ax8dMgcQrYO/AR2RGWURrruqw=="],
"debug": ["debug@4.4.1", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ=="], "debug": ["debug@4.4.1", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ=="],
"decamelize": ["decamelize@1.2.0", "", {}, "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA=="], "decamelize": ["decamelize@1.2.0", "", {}, "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA=="],
@@ -1150,13 +1206,15 @@
"expo": ["expo@54.0.2", "", { "dependencies": { "@babel/runtime": "^7.20.0", "@expo/cli": "54.0.2", "@expo/config": "~12.0.8", "@expo/config-plugins": "~54.0.1", "@expo/devtools": "0.1.7", "@expo/fingerprint": "0.15.0", "@expo/metro": "~0.1.1", "@expo/metro-config": "54.0.2", "@expo/vector-icons": "^15.0.2", "@ungap/structured-clone": "^1.3.0", "babel-preset-expo": "~54.0.0", "expo-asset": "~12.0.8", "expo-constants": "~18.0.8", "expo-file-system": "~19.0.12", "expo-font": "~14.0.8", "expo-keep-awake": "~15.0.7", "expo-modules-autolinking": "3.0.10", "expo-modules-core": "3.0.15", "pretty-format": "^29.7.0", "react-refresh": "^0.14.2", "whatwg-url-without-unicode": "8.0.0-3" }, "peerDependencies": { "@expo/dom-webview": "*", "@expo/metro-runtime": "*", "react": "*", "react-native": "*", "react-native-webview": "*" }, "optionalPeers": ["@expo/dom-webview", "@expo/metro-runtime", "react-native-webview"], "bin": { "expo": "bin/cli", "fingerprint": "bin/fingerprint", "expo-modules-autolinking": "bin/autolinking" } }, "sha512-0YcsvMuiZlVFVZRdD4PlhwsYrTmcN1qm5b1IRSLIeLZjH6ZnQwBb3KBSnK8WRC9V6EUPSbuLGpNT5AEewrtakQ=="], "expo": ["expo@54.0.2", "", { "dependencies": { "@babel/runtime": "^7.20.0", "@expo/cli": "54.0.2", "@expo/config": "~12.0.8", "@expo/config-plugins": "~54.0.1", "@expo/devtools": "0.1.7", "@expo/fingerprint": "0.15.0", "@expo/metro": "~0.1.1", "@expo/metro-config": "54.0.2", "@expo/vector-icons": "^15.0.2", "@ungap/structured-clone": "^1.3.0", "babel-preset-expo": "~54.0.0", "expo-asset": "~12.0.8", "expo-constants": "~18.0.8", "expo-file-system": "~19.0.12", "expo-font": "~14.0.8", "expo-keep-awake": "~15.0.7", "expo-modules-autolinking": "3.0.10", "expo-modules-core": "3.0.15", "pretty-format": "^29.7.0", "react-refresh": "^0.14.2", "whatwg-url-without-unicode": "8.0.0-3" }, "peerDependencies": { "@expo/dom-webview": "*", "@expo/metro-runtime": "*", "react": "*", "react-native": "*", "react-native-webview": "*" }, "optionalPeers": ["@expo/dom-webview", "@expo/metro-runtime", "react-native-webview"], "bin": { "expo": "bin/cli", "fingerprint": "bin/fingerprint", "expo-modules-autolinking": "bin/autolinking" } }, "sha512-0YcsvMuiZlVFVZRdD4PlhwsYrTmcN1qm5b1IRSLIeLZjH6ZnQwBb3KBSnK8WRC9V6EUPSbuLGpNT5AEewrtakQ=="],
"expo-application": ["expo-application@7.0.7", "", { "peerDependencies": { "expo": "*" } }, "sha512-Jt1/qqnoDUbZ+bK91+dHaZ1vrPDtRBOltRa681EeedkisqguuEeUx4UHqwVyDK2oHWsK6lO3ojetoA4h8OmNcg=="],
"expo-asset": ["expo-asset@12.0.8", "", { "dependencies": { "@expo/image-utils": "^0.8.7", "expo-constants": "~18.0.8" }, "peerDependencies": { "expo": "*", "react": "*", "react-native": "*" } }, "sha512-jj2U8zw9+7orST2rlQGULYiqPoECOuUyffs2NguGrq84bYbkM041T7TOMXH2raPVJnM9lEAP54ezI6XL+GVYqw=="], "expo-asset": ["expo-asset@12.0.8", "", { "dependencies": { "@expo/image-utils": "^0.8.7", "expo-constants": "~18.0.8" }, "peerDependencies": { "expo": "*", "react": "*", "react-native": "*" } }, "sha512-jj2U8zw9+7orST2rlQGULYiqPoECOuUyffs2NguGrq84bYbkM041T7TOMXH2raPVJnM9lEAP54ezI6XL+GVYqw=="],
"expo-camera": ["expo-camera@17.0.7", "", { "dependencies": { "invariant": "^2.2.4" }, "peerDependencies": { "expo": "*", "react": "*", "react-native": "*", "react-native-web": "*" }, "optionalPeers": ["react-native-web"] }, "sha512-jdZfijfFjlVAuuIkDheA41YKpigPjqsN0juRvgyr7Lcyz+fvwZ3/RP50/n/hvuozH657wHxPfiyVVFa00z8TcQ=="], "expo-camera": ["expo-camera@17.0.7", "", { "dependencies": { "invariant": "^2.2.4" }, "peerDependencies": { "expo": "*", "react": "*", "react-native": "*", "react-native-web": "*" }, "optionalPeers": ["react-native-web"] }, "sha512-jdZfijfFjlVAuuIkDheA41YKpigPjqsN0juRvgyr7Lcyz+fvwZ3/RP50/n/hvuozH657wHxPfiyVVFa00z8TcQ=="],
"expo-clipboard": ["expo-clipboard@8.0.7", "", { "peerDependencies": { "expo": "*", "react": "*", "react-native": "*" } }, "sha512-zvlfFV+wB2QQrQnHWlo0EKHAkdi2tycLtE+EXFUWTPZYkgu1XcH+aiKfd4ul7Z0SDF+1IuwoiW9AA9eO35aj3Q=="], "expo-clipboard": ["expo-clipboard@8.0.7", "", { "peerDependencies": { "expo": "*", "react": "*", "react-native": "*" } }, "sha512-zvlfFV+wB2QQrQnHWlo0EKHAkdi2tycLtE+EXFUWTPZYkgu1XcH+aiKfd4ul7Z0SDF+1IuwoiW9AA9eO35aj3Q=="],
"expo-constants": ["expo-constants@18.0.8", "", { "dependencies": { "@expo/config": "~12.0.8", "@expo/env": "~2.0.7" }, "peerDependencies": { "expo": "*", "react-native": "*" } }, "sha512-Tetphsx6RVImCTZeBAclRQMy0WOODY3y6qrUoc88YGUBVm8fAKkErCSWxLTCc6nFcJxdoOMYi62LgNIUFjZCLA=="], "expo-constants": ["expo-constants@18.0.10", "", { "dependencies": { "@expo/config": "~12.0.10", "@expo/env": "~2.0.7" }, "peerDependencies": { "expo": "*", "react-native": "*" } }, "sha512-Rhtv+X974k0Cahmvx6p7ER5+pNhBC0XbP1lRviL2J1Xl4sT2FBaIuIxF/0I0CbhOsySf0ksqc5caFweAy9Ewiw=="],
"expo-dev-client": ["expo-dev-client@6.0.12", "", { "dependencies": { "expo-dev-launcher": "6.0.11", "expo-dev-menu": "7.0.11", "expo-dev-menu-interface": "2.0.0", "expo-manifests": "~1.0.8", "expo-updates-interface": "~2.0.0" }, "peerDependencies": { "expo": "*" } }, "sha512-Knr2abq0r6ALASsZtrX9QD4V0vP4ZL18iDVF5lgr6iFYawbuqQHuJRktIUETimu6qLusJK8Z3kZRabAdNqT+qw=="], "expo-dev-client": ["expo-dev-client@6.0.12", "", { "dependencies": { "expo-dev-launcher": "6.0.11", "expo-dev-menu": "7.0.11", "expo-dev-menu-interface": "2.0.0", "expo-manifests": "~1.0.8", "expo-updates-interface": "~2.0.0" }, "peerDependencies": { "expo": "*" } }, "sha512-Knr2abq0r6ALASsZtrX9QD4V0vP4ZL18iDVF5lgr6iFYawbuqQHuJRktIUETimu6qLusJK8Z3kZRabAdNqT+qw=="],
@@ -1166,6 +1224,8 @@
"expo-dev-menu-interface": ["expo-dev-menu-interface@2.0.0", "", { "peerDependencies": { "expo": "*" } }, "sha512-BvAMPt6x+vyXpThsyjjOYyjwfjREV4OOpQkZ0tNl+nGpsPfcY9mc6DRACoWnH9KpLzyIt3BOgh3cuy/h/OxQjw=="], "expo-dev-menu-interface": ["expo-dev-menu-interface@2.0.0", "", { "peerDependencies": { "expo": "*" } }, "sha512-BvAMPt6x+vyXpThsyjjOYyjwfjREV4OOpQkZ0tNl+nGpsPfcY9mc6DRACoWnH9KpLzyIt3BOgh3cuy/h/OxQjw=="],
"expo-device": ["expo-device@8.0.9", "", { "dependencies": { "ua-parser-js": "^0.7.33" }, "peerDependencies": { "expo": "*" } }, "sha512-XqRpaljDNAYZGZzMpC+b9KZfzfydtkwx3pJAp6ODDH+O/5wjAw+mLc5wQMGJCx8/aqVmMsAokec7iebxDPFZDA=="],
"expo-document-picker": ["expo-document-picker@14.0.7", "", { "peerDependencies": { "expo": "*" } }, "sha512-81Jh8RDD0GYBUoSTmIBq30hXXjmkDV1ZY2BNIp1+3HR5PDSh2WmdhD/Ezz5YFsv46hIXHsQc+Kh1q8vn6OLT9Q=="], "expo-document-picker": ["expo-document-picker@14.0.7", "", { "peerDependencies": { "expo": "*" } }, "sha512-81Jh8RDD0GYBUoSTmIBq30hXXjmkDV1ZY2BNIp1+3HR5PDSh2WmdhD/Ezz5YFsv46hIXHsQc+Kh1q8vn6OLT9Q=="],
"expo-file-system": ["expo-file-system@19.0.15", "", { "peerDependencies": { "expo": "*", "react-native": "*" } }, "sha512-sRLW+3PVJDiuoCE2LuteHhC7OxPjh1cfqLylf1YG1TDEbbQXnzwjfsKeRm6dslEPZLkMWfSLYIrVbnuq5mF7kQ=="], "expo-file-system": ["expo-file-system@19.0.15", "", { "peerDependencies": { "expo": "*", "react-native": "*" } }, "sha512-sRLW+3PVJDiuoCE2LuteHhC7OxPjh1cfqLylf1YG1TDEbbQXnzwjfsKeRm6dslEPZLkMWfSLYIrVbnuq5mF7kQ=="],
@@ -1184,8 +1244,12 @@
"expo-keep-awake": ["expo-keep-awake@15.0.7", "", { "peerDependencies": { "expo": "*", "react": "*" } }, "sha512-CgBNcWVPnrIVII5G54QDqoE125l+zmqR4HR8q+MQaCfHet+dYpS5vX5zii/RMayzGN4jPgA4XYIQ28ePKFjHoA=="], "expo-keep-awake": ["expo-keep-awake@15.0.7", "", { "peerDependencies": { "expo": "*", "react": "*" } }, "sha512-CgBNcWVPnrIVII5G54QDqoE125l+zmqR4HR8q+MQaCfHet+dYpS5vX5zii/RMayzGN4jPgA4XYIQ28ePKFjHoA=="],
"expo-linear-gradient": ["expo-linear-gradient@15.0.7", "", { "peerDependencies": { "expo": "*", "react": "*", "react-native": "*" } }, "sha512-yF+y+9Shpr/OQFfy/wglB/0bykFMbwHBTuMRa5Of/r2P1wbkcacx8rg0JsUWkXH/rn2i2iWdubyqlxSJa3ggZA=="],
"expo-linking": ["expo-linking@8.0.8", "", { "dependencies": { "expo-constants": "~18.0.8", "invariant": "^2.2.4" }, "peerDependencies": { "react": "*", "react-native": "*" } }, "sha512-MyeMcbFDKhXh4sDD1EHwd0uxFQNAc6VCrwBkNvvvufUsTYFq3glTA9Y8a+x78CPpjNqwNAamu74yIaIz7IEJyg=="], "expo-linking": ["expo-linking@8.0.8", "", { "dependencies": { "expo-constants": "~18.0.8", "invariant": "^2.2.4" }, "peerDependencies": { "react": "*", "react-native": "*" } }, "sha512-MyeMcbFDKhXh4sDD1EHwd0uxFQNAc6VCrwBkNvvvufUsTYFq3glTA9Y8a+x78CPpjNqwNAamu74yIaIz7IEJyg=="],
"expo-location": ["expo-location@19.0.7", "", { "peerDependencies": { "expo": "*" } }, "sha512-YNkh4r9E6ECbPkBCAMG5A5yHDgS0pw+Rzyd0l2ZQlCtjkhlODB55nMCKr5CZnUI0mXTkaSm8CwfoCO8n2MpYfg=="],
"expo-manifests": ["expo-manifests@1.0.8", "", { "dependencies": { "@expo/config": "~12.0.8", "expo-json-utils": "~0.15.0" }, "peerDependencies": { "expo": "*" } }, "sha512-nA5PwU2uiUd+2nkDWf9e71AuFAtbrb330g/ecvuu52bmaXtN8J8oiilc9BDvAX0gg2fbtOaZdEdjBYopt1jdlQ=="], "expo-manifests": ["expo-manifests@1.0.8", "", { "dependencies": { "@expo/config": "~12.0.8", "expo-json-utils": "~0.15.0" }, "peerDependencies": { "expo": "*" } }, "sha512-nA5PwU2uiUd+2nkDWf9e71AuFAtbrb330g/ecvuu52bmaXtN8J8oiilc9BDvAX0gg2fbtOaZdEdjBYopt1jdlQ=="],
"expo-module-scripts": ["expo-module-scripts@4.1.10", "", { "dependencies": { "@babel/cli": "^7.23.4", "@babel/plugin-transform-export-namespace-from": "^7.23.4", "@babel/preset-env": "^7.23.8", "@babel/preset-typescript": "^7.23.3", "@expo/npm-proofread": "^1.0.1", "@testing-library/react-native": "^13.1.0", "@tsconfig/node18": "^18.2.2", "@types/jest": "^29.2.1", "babel-plugin-dynamic-import-node": "^2.3.3", "babel-preset-expo": "~13.2.3", "commander": "^12.1.0", "eslint-config-universe": "^15.0.3", "glob": "^10.4.2", "jest-expo": "~53.0.9", "jest-snapshot-prettier": "npm:prettier@^2", "jest-watch-typeahead": "2.2.1", "resolve-workspace-root": "^2.0.0", "ts-jest": "~29.0.4", "typescript": "^5.8.3" }, "bin": { "expo-module": "bin/expo-module.js" } }, "sha512-fQVXVgxqUOz1cnnNumNLm0eI+Y8IhYNa056ad0vxEhcMui6FjS1+beZNHiaClGwd/NQb5RjlT48ABL3XSGHwxQ=="], "expo-module-scripts": ["expo-module-scripts@4.1.10", "", { "dependencies": { "@babel/cli": "^7.23.4", "@babel/plugin-transform-export-namespace-from": "^7.23.4", "@babel/preset-env": "^7.23.8", "@babel/preset-typescript": "^7.23.3", "@expo/npm-proofread": "^1.0.1", "@testing-library/react-native": "^13.1.0", "@tsconfig/node18": "^18.2.2", "@types/jest": "^29.2.1", "babel-plugin-dynamic-import-node": "^2.3.3", "babel-preset-expo": "~13.2.3", "commander": "^12.1.0", "eslint-config-universe": "^15.0.3", "glob": "^10.4.2", "jest-expo": "~53.0.9", "jest-snapshot-prettier": "npm:prettier@^2", "jest-watch-typeahead": "2.2.1", "resolve-workspace-root": "^2.0.0", "ts-jest": "~29.0.4", "typescript": "^5.8.3" }, "bin": { "expo-module": "bin/expo-module.js" } }, "sha512-fQVXVgxqUOz1cnnNumNLm0eI+Y8IhYNa056ad0vxEhcMui6FjS1+beZNHiaClGwd/NQb5RjlT48ABL3XSGHwxQ=="],
@@ -1194,6 +1258,8 @@
"expo-modules-core": ["expo-modules-core@3.0.15", "", { "dependencies": { "invariant": "^2.2.4" }, "peerDependencies": { "react": "*", "react-native": "*" } }, "sha512-vGI7osd0/IjprldD08k4bckWSu7ID4HhZNP68l/UtilONQ8XZig8mWJd/Fm7i7KGvE3HyuF+HOXE9l671no42Q=="], "expo-modules-core": ["expo-modules-core@3.0.15", "", { "dependencies": { "invariant": "^2.2.4" }, "peerDependencies": { "react": "*", "react-native": "*" } }, "sha512-vGI7osd0/IjprldD08k4bckWSu7ID4HhZNP68l/UtilONQ8XZig8mWJd/Fm7i7KGvE3HyuF+HOXE9l671no42Q=="],
"expo-notifications": ["expo-notifications@0.32.13", "", { "dependencies": { "@expo/image-utils": "^0.8.7", "@ide/backoff": "^1.0.0", "abort-controller": "^3.0.0", "assert": "^2.0.0", "badgin": "^1.1.5", "expo-application": "~7.0.7", "expo-constants": "~18.0.10" }, "peerDependencies": { "expo": "*", "react": "*", "react-native": "*" } }, "sha512-PL0R1ulLVUgAswlXtRDKxBlcipNM3YA6+P5nB5JIhXbsjLJ7y+EKVaEhHhbaGzuK1QVsRQSJNm/4oISX+vsmFQ=="],
"expo-router": ["expo-router@6.0.1", "", { "dependencies": { "@expo/metro-runtime": "6.1.1", "@expo/schema-utils": "^0.1.7", "@expo/server": "^0.7.4", "@radix-ui/react-slot": "1.2.0", "@radix-ui/react-tabs": "^1.1.12", "@react-navigation/bottom-tabs": "^7.4.0", "@react-navigation/native": "^7.1.8", "@react-navigation/native-stack": "^7.3.16", "client-only": "^0.0.1", "debug": "^4.3.4", "escape-string-regexp": "^4.0.0", "fast-deep-equal": "^3.1.3", "invariant": "^2.2.4", "nanoid": "^3.3.8", "query-string": "^7.1.3", "react-fast-compare": "^3.2.2", "react-native-is-edge-to-edge": "^1.1.6", "semver": "~7.6.3", "server-only": "^0.0.1", "sf-symbols-typescript": "^2.1.0", "shallowequal": "^1.1.0", "use-latest-callback": "^0.2.1", "vaul": "^1.1.2" }, "peerDependencies": { "@react-navigation/drawer": "^7.5.0", "@testing-library/react-native": ">= 12.0.0", "expo": "*", "expo-constants": "^18.0.8", "expo-linking": "^8.0.8", "react": "*", "react-dom": "*", "react-native": "*", "react-native-gesture-handler": "*", "react-native-reanimated": "*", "react-native-safe-area-context": ">= 5.4.0", "react-native-screens": "*", "react-native-web": "*", "react-server-dom-webpack": ">= 19.0.0" }, "optionalPeers": ["@react-navigation/drawer", "@testing-library/react-native", "react-dom", "react-native-gesture-handler", "react-native-reanimated", "react-native-web", "react-server-dom-webpack"] }, "sha512-5wXkWyNMqUbjCWH0PRkOM0P6UsgLVdgchDkiLz5FY7HfU00ToBcxij965bqtlaATBgoaIo4DuLu6EgxewrKJ8Q=="], "expo-router": ["expo-router@6.0.1", "", { "dependencies": { "@expo/metro-runtime": "6.1.1", "@expo/schema-utils": "^0.1.7", "@expo/server": "^0.7.4", "@radix-ui/react-slot": "1.2.0", "@radix-ui/react-tabs": "^1.1.12", "@react-navigation/bottom-tabs": "^7.4.0", "@react-navigation/native": "^7.1.8", "@react-navigation/native-stack": "^7.3.16", "client-only": "^0.0.1", "debug": "^4.3.4", "escape-string-regexp": "^4.0.0", "fast-deep-equal": "^3.1.3", "invariant": "^2.2.4", "nanoid": "^3.3.8", "query-string": "^7.1.3", "react-fast-compare": "^3.2.2", "react-native-is-edge-to-edge": "^1.1.6", "semver": "~7.6.3", "server-only": "^0.0.1", "sf-symbols-typescript": "^2.1.0", "shallowequal": "^1.1.0", "use-latest-callback": "^0.2.1", "vaul": "^1.1.2" }, "peerDependencies": { "@react-navigation/drawer": "^7.5.0", "@testing-library/react-native": ">= 12.0.0", "expo": "*", "expo-constants": "^18.0.8", "expo-linking": "^8.0.8", "react": "*", "react-dom": "*", "react-native": "*", "react-native-gesture-handler": "*", "react-native-reanimated": "*", "react-native-safe-area-context": ">= 5.4.0", "react-native-screens": "*", "react-native-web": "*", "react-server-dom-webpack": ">= 19.0.0" }, "optionalPeers": ["@react-navigation/drawer", "@testing-library/react-native", "react-dom", "react-native-gesture-handler", "react-native-reanimated", "react-native-web", "react-server-dom-webpack"] }, "sha512-5wXkWyNMqUbjCWH0PRkOM0P6UsgLVdgchDkiLz5FY7HfU00ToBcxij965bqtlaATBgoaIo4DuLu6EgxewrKJ8Q=="],
"expo-splash-screen": ["expo-splash-screen@31.0.9", "", { "dependencies": { "@expo/prebuild-config": "^54.0.1" }, "peerDependencies": { "expo": "*" } }, "sha512-pYLWFrEHn/c8e1a8oDzrlcyYI08oG4i37KA+VN5wwoC1DsQ0rm3kyAk0bmoydV1mBzNfXQFYbA1BGftXJl1f0w=="], "expo-splash-screen": ["expo-splash-screen@31.0.9", "", { "dependencies": { "@expo/prebuild-config": "^54.0.1" }, "peerDependencies": { "expo": "*" } }, "sha512-pYLWFrEHn/c8e1a8oDzrlcyYI08oG4i37KA+VN5wwoC1DsQ0rm3kyAk0bmoydV1mBzNfXQFYbA1BGftXJl1f0w=="],
@@ -1206,7 +1272,7 @@
"expo-updates-interface": ["expo-updates-interface@2.0.0", "", { "peerDependencies": { "expo": "*" } }, "sha512-pTzAIufEZdVPKql6iMi5ylVSPqV1qbEopz9G6TSECQmnNde2nwq42PxdFBaUEd8IZJ/fdJLQnOT3m6+XJ5s7jg=="], "expo-updates-interface": ["expo-updates-interface@2.0.0", "", { "peerDependencies": { "expo": "*" } }, "sha512-pTzAIufEZdVPKql6iMi5ylVSPqV1qbEopz9G6TSECQmnNde2nwq42PxdFBaUEd8IZJ/fdJLQnOT3m6+XJ5s7jg=="],
"expo-web-browser": ["expo-web-browser@15.0.7", "", { "peerDependencies": { "expo": "*", "react-native": "*" } }, "sha512-eXnfO3FQ2WthTA8uEPNJ7SDRfPaLIU/P2k082HGEYIHAFZMwh2o9Wo+SDVytO3E95TAv1qwhggUjOrczYzxteQ=="], "expo-web-browser": ["expo-web-browser@15.0.9", "", { "peerDependencies": { "expo": "*", "react-native": "*" } }, "sha512-Dj8kNFO+oXsxqCDNlUT/GhOrJnm10kAElH++3RplLydogFm5jTzXYWDEeNIDmV+F+BzGYs+sIhxiBf7RyaxXZg=="],
"exponential-backoff": ["exponential-backoff@3.1.2", "", {}, "sha512-8QxYTVXUkuy7fIIoitQkPwGonB8F3Zj8eEO8Sqg9Zv/bkI7RJAzowee4gr81Hak/dUTpA2Z7VfQgoijjPNlUZA=="], "exponential-backoff": ["exponential-backoff@3.1.2", "", {}, "sha512-8QxYTVXUkuy7fIIoitQkPwGonB8F3Zj8eEO8Sqg9Zv/bkI7RJAzowee4gr81Hak/dUTpA2Z7VfQgoijjPNlUZA=="],
@@ -1258,6 +1324,10 @@
"form-data": ["form-data@4.0.4", "", { "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", "es-set-tostringtag": "^2.1.0", "hasown": "^2.0.2", "mime-types": "^2.1.12" } }, "sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow=="], "form-data": ["form-data@4.0.4", "", { "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", "es-set-tostringtag": "^2.1.0", "hasown": "^2.0.2", "mime-types": "^2.1.12" } }, "sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow=="],
"framer-motion": ["framer-motion@6.5.1", "", { "dependencies": { "@motionone/dom": "10.12.0", "framesync": "6.0.1", "hey-listen": "^1.0.8", "popmotion": "11.0.3", "style-value-types": "5.0.0", "tslib": "^2.1.0" }, "optionalDependencies": { "@emotion/is-prop-valid": "^0.8.2" }, "peerDependencies": { "react": ">=16.8 || ^17.0.0 || ^18.0.0", "react-dom": ">=16.8 || ^17.0.0 || ^18.0.0" } }, "sha512-o1BGqqposwi7cgDrtg0dNONhkmPsUFDaLcKXigzuTFC5x58mE8iyTazxSudFzmT6MEyJKfjjU8ItoMe3W+3fiw=="],
"framesync": ["framesync@6.0.1", "", { "dependencies": { "tslib": "^2.1.0" } }, "sha512-fUY88kXvGiIItgNC7wcTOl0SNRCVXMKSWW2Yzfmn7EKNc+MpCzcz9DhdHcdjbrtN3c6R4H5dTY2jiCpPdysEjA=="],
"freeport-async": ["freeport-async@2.0.0", "", {}, "sha512-K7od3Uw45AJg00XUmy15+Hae2hOcgKcmN3/EF6Y7i01O0gaqiRx8sUSpsb9+BRNL8RPBrhzPsVfy8q9ADlJuWQ=="], "freeport-async": ["freeport-async@2.0.0", "", {}, "sha512-K7od3Uw45AJg00XUmy15+Hae2hOcgKcmN3/EF6Y7i01O0gaqiRx8sUSpsb9+BRNL8RPBrhzPsVfy8q9ADlJuWQ=="],
"fresh": ["fresh@0.5.2", "", {}, "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q=="], "fresh": ["fresh@0.5.2", "", {}, "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q=="],
@@ -1276,6 +1346,8 @@
"gensync": ["gensync@1.0.0-beta.2", "", {}, "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg=="], "gensync": ["gensync@1.0.0-beta.2", "", {}, "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg=="],
"geojson-rbush": ["geojson-rbush@3.2.0", "", { "dependencies": { "@turf/bbox": "*", "@turf/helpers": "6.x", "@turf/meta": "6.x", "@types/geojson": "7946.0.8", "rbush": "^3.0.1" } }, "sha512-oVltQTXolxvsz1sZnutlSuLDEcQAKYC/uXt9zDzJJ6bu0W+baTI8LZBaTup5afzibEH4N3jlq2p+a152wlBJ7w=="],
"get-caller-file": ["get-caller-file@2.0.5", "", {}, "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg=="], "get-caller-file": ["get-caller-file@2.0.5", "", {}, "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg=="],
"get-intrinsic": ["get-intrinsic@1.3.0", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.2", "es-define-property": "^1.0.1", "es-errors": "^1.3.0", "es-object-atoms": "^1.1.1", "function-bind": "^1.1.2", "get-proto": "^1.0.1", "gopd": "^1.2.0", "has-symbols": "^1.1.0", "hasown": "^2.0.2", "math-intrinsics": "^1.1.0" } }, "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ=="], "get-intrinsic": ["get-intrinsic@1.3.0", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.2", "es-define-property": "^1.0.1", "es-errors": "^1.3.0", "es-object-atoms": "^1.1.1", "function-bind": "^1.1.2", "get-proto": "^1.0.1", "gopd": "^1.2.0", "has-symbols": "^1.1.0", "hasown": "^2.0.2", "math-intrinsics": "^1.1.0" } }, "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ=="],
@@ -1332,6 +1404,8 @@
"hermes-parser": ["hermes-parser@0.29.1", "", { "dependencies": { "hermes-estree": "0.29.1" } }, "sha512-xBHWmUtRC5e/UL0tI7Ivt2riA/YBq9+SiYFU7C1oBa/j2jYGlIF9043oak1F47ihuDIxQ5nbsKueYJDRY02UgA=="], "hermes-parser": ["hermes-parser@0.29.1", "", { "dependencies": { "hermes-estree": "0.29.1" } }, "sha512-xBHWmUtRC5e/UL0tI7Ivt2riA/YBq9+SiYFU7C1oBa/j2jYGlIF9043oak1F47ihuDIxQ5nbsKueYJDRY02UgA=="],
"hey-listen": ["hey-listen@1.0.8", "", {}, "sha512-COpmrF2NOg4TBWUJ5UVyaCU2A88wEMkUPK4hNqyCkqHbxT92BbvfjoSozkAIIm6XhicGlJHhFdullInrdhwU8Q=="],
"hoist-non-react-statics": ["hoist-non-react-statics@3.3.2", "", { "dependencies": { "react-is": "^16.7.0" } }, "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw=="], "hoist-non-react-statics": ["hoist-non-react-statics@3.3.2", "", { "dependencies": { "react-is": "^16.7.0" } }, "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw=="],
"hosted-git-info": ["hosted-git-info@7.0.2", "", { "dependencies": { "lru-cache": "^10.0.1" } }, "sha512-puUZAUKT5m8Zzvs72XWy3HtvVbTWljRE66cP60bxJzAqf2DgICo7lYTY2IHUmLnNpjYvw5bvmoHvPc0QO2a62w=="], "hosted-git-info": ["hosted-git-info@7.0.2", "", { "dependencies": { "lru-cache": "^10.0.1" } }, "sha512-puUZAUKT5m8Zzvs72XWy3HtvVbTWljRE66cP60bxJzAqf2DgICo7lYTY2IHUmLnNpjYvw5bvmoHvPc0QO2a62w=="],
@@ -1378,6 +1452,8 @@
"invariant": ["invariant@2.2.4", "", { "dependencies": { "loose-envify": "^1.0.0" } }, "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA=="], "invariant": ["invariant@2.2.4", "", { "dependencies": { "loose-envify": "^1.0.0" } }, "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA=="],
"is-arguments": ["is-arguments@1.2.0", "", { "dependencies": { "call-bound": "^1.0.2", "has-tostringtag": "^1.0.2" } }, "sha512-7bVbi0huj/wrIAOzb8U1aszg9kdi3KN/CyU19CTI7tAoZYEZoL9yCDXpbXN+uPsuWnP02cyug1gleqq+TU+YCA=="],
"is-array-buffer": ["is-array-buffer@3.0.5", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.3", "get-intrinsic": "^1.2.6" } }, "sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A=="], "is-array-buffer": ["is-array-buffer@3.0.5", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.3", "get-intrinsic": "^1.2.6" } }, "sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A=="],
"is-arrayish": ["is-arrayish@0.3.2", "", {}, "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ=="], "is-arrayish": ["is-arrayish@0.3.2", "", {}, "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ=="],
@@ -1418,6 +1494,8 @@
"is-map": ["is-map@2.0.3", "", {}, "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw=="], "is-map": ["is-map@2.0.3", "", {}, "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw=="],
"is-nan": ["is-nan@1.3.2", "", { "dependencies": { "call-bind": "^1.0.0", "define-properties": "^1.1.3" } }, "sha512-E+zBKpQ2t6MEo1VsonYmluk9NxGrbzpeeLC2xIViuO2EjU2xsXsBPwTr3Ykv9l08UYEVEdWeRZNouaZqF6RN0w=="],
"is-negative-zero": ["is-negative-zero@2.0.3", "", {}, "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw=="], "is-negative-zero": ["is-negative-zero@2.0.3", "", {}, "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw=="],
"is-number": ["is-number@7.0.0", "", {}, "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng=="], "is-number": ["is-number@7.0.0", "", {}, "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng=="],
@@ -1682,6 +1760,8 @@
"mkdirp": ["mkdirp@3.0.1", "", { "bin": "dist/cjs/src/bin.js" }, "sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg=="], "mkdirp": ["mkdirp@3.0.1", "", { "bin": "dist/cjs/src/bin.js" }, "sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg=="],
"moti": ["moti@0.30.0", "", { "dependencies": { "framer-motion": "^6.5.1" }, "peerDependencies": { "react-native-reanimated": "*" } }, "sha512-YN78mcefo8kvJaL+TZNyusq6YA2aMFvBPl8WiLPy4eb4wqgOFggJOjP9bUr2YO8PrAt0uusmRG8K4RPL4OhCsA=="],
"ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="], "ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="],
"mz": ["mz@2.7.0", "", { "dependencies": { "any-promise": "^1.0.0", "object-assign": "^4.0.1", "thenify-all": "^1.0.0" } }, "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q=="], "mz": ["mz@2.7.0", "", { "dependencies": { "any-promise": "^1.0.0", "object-assign": "^4.0.1", "thenify-all": "^1.0.0" } }, "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q=="],
@@ -1724,6 +1804,8 @@
"object-inspect": ["object-inspect@1.13.4", "", {}, "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew=="], "object-inspect": ["object-inspect@1.13.4", "", {}, "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew=="],
"object-is": ["object-is@1.1.6", "", { "dependencies": { "call-bind": "^1.0.7", "define-properties": "^1.2.1" } }, "sha512-F8cZ+KfGlSGi09lJT7/Nd6KJZ9ygtvYC0/UYYLI9nmQKLMnydpB9yvbv9K1uSkEu7FU9vYPmVwLg328tX+ot3Q=="],
"object-keys": ["object-keys@1.1.1", "", {}, "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA=="], "object-keys": ["object-keys@1.1.1", "", {}, "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA=="],
"object.assign": ["object.assign@4.1.7", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.3", "define-properties": "^1.2.1", "es-object-atoms": "^1.0.0", "has-symbols": "^1.1.0", "object-keys": "^1.1.1" } }, "sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw=="], "object.assign": ["object.assign@4.1.7", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.3", "define-properties": "^1.2.1", "es-object-atoms": "^1.0.0", "has-symbols": "^1.1.0", "object-keys": "^1.1.1" } }, "sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw=="],
@@ -1796,6 +1878,8 @@
"pngjs": ["pngjs@5.0.0", "", {}, "sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw=="], "pngjs": ["pngjs@5.0.0", "", {}, "sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw=="],
"popmotion": ["popmotion@11.0.3", "", { "dependencies": { "framesync": "6.0.1", "hey-listen": "^1.0.8", "style-value-types": "5.0.0", "tslib": "^2.1.0" } }, "sha512-Y55FLdj3UxkR7Vl3s7Qr4e9m0onSnP8W7d/xQLsoJM40vs6UKHFdygs6SWryasTZYqugMjm3BepCF4CWXDiHgA=="],
"possible-typed-array-names": ["possible-typed-array-names@1.1.0", "", {}, "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg=="], "possible-typed-array-names": ["possible-typed-array-names@1.1.0", "", {}, "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg=="],
"postcss": ["postcss@8.4.49", "", { "dependencies": { "nanoid": "^3.3.7", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA=="], "postcss": ["postcss@8.4.49", "", { "dependencies": { "nanoid": "^3.3.7", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA=="],
@@ -1842,10 +1926,14 @@
"queue-microtask": ["queue-microtask@1.2.3", "", {}, "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A=="], "queue-microtask": ["queue-microtask@1.2.3", "", {}, "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A=="],
"quickselect": ["quickselect@2.0.0", "", {}, "sha512-RKJ22hX8mHe3Y6wH/N3wCM6BWtjaxIyyUIkpHOvfFnxdI4yD4tBXEBKSbriGujF6jnSVkJrffuo6vxACiSSxIw=="],
"randombytes": ["randombytes@2.1.0", "", { "dependencies": { "safe-buffer": "^5.1.0" } }, "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ=="], "randombytes": ["randombytes@2.1.0", "", { "dependencies": { "safe-buffer": "^5.1.0" } }, "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ=="],
"range-parser": ["range-parser@1.2.1", "", {}, "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg=="], "range-parser": ["range-parser@1.2.1", "", {}, "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg=="],
"rbush": ["rbush@3.0.1", "", { "dependencies": { "quickselect": "^2.0.0" } }, "sha512-XRaVO0YecOpEuIvbhbpTrZgoiI6xBlz6hnlr6EHhd+0x9ase6EmeN+hdwwUaJvLcsFFQ8iWVF1GAK1yB0BWi0w=="],
"rc": ["rc@1.2.8", "", { "dependencies": { "deep-extend": "^0.6.0", "ini": "~1.3.0", "minimist": "^1.2.0", "strip-json-comments": "~2.0.1" }, "bin": "cli.js" }, "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw=="], "rc": ["rc@1.2.8", "", { "dependencies": { "deep-extend": "^0.6.0", "ini": "~1.3.0", "minimist": "^1.2.0", "strip-json-comments": "~2.0.1" }, "bin": "cli.js" }, "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw=="],
"react": ["react@19.1.0", "", {}, "sha512-FS+XFBNvn3GTAWq26joslQgWNoFu08F4kl0J4CgdNKADkdSGXQyTCnKteIAJy96Br6YbpEU1LSzV5dYtjMkMDg=="], "react": ["react@19.1.0", "", {}, "sha512-FS+XFBNvn3GTAWq26joslQgWNoFu08F4kl0J4CgdNKADkdSGXQyTCnKteIAJy96Br6YbpEU1LSzV5dYtjMkMDg=="],
@@ -2104,6 +2192,8 @@
"structured-headers": ["structured-headers@0.4.1", "", {}, "sha512-0MP/Cxx5SzeeZ10p/bZI0S6MpgD+yxAhi1BOQ34jgnMXsCq3j1t6tQnZu+KdlL7dvJTLT3g9xN8tl10TqgFMcg=="], "structured-headers": ["structured-headers@0.4.1", "", {}, "sha512-0MP/Cxx5SzeeZ10p/bZI0S6MpgD+yxAhi1BOQ34jgnMXsCq3j1t6tQnZu+KdlL7dvJTLT3g9xN8tl10TqgFMcg=="],
"style-value-types": ["style-value-types@5.0.0", "", { "dependencies": { "hey-listen": "^1.0.8", "tslib": "^2.1.0" } }, "sha512-08yq36Ikn4kx4YU6RD7jWEv27v4V+PUsOGa4n/as8Et3CuODMJQ00ENeAVXAeydX4Z2j1XHZF1K2sX4mGl18fA=="],
"styleq": ["styleq@0.1.3", "", {}, "sha512-3ZUifmCDCQanjeej1f6kyl/BeP/Vae5EYkQ9iJfUm/QwZvlgnZzyflqAsAWYURdtea8Vkvswu2GrC57h3qffcA=="], "styleq": ["styleq@0.1.3", "", {}, "sha512-3ZUifmCDCQanjeej1f6kyl/BeP/Vae5EYkQ9iJfUm/QwZvlgnZzyflqAsAWYURdtea8Vkvswu2GrC57h3qffcA=="],
"sucrase": ["sucrase@3.35.0", "", { "dependencies": { "@jridgewell/gen-mapping": "^0.3.2", "commander": "^4.0.0", "glob": "^10.3.10", "lines-and-columns": "^1.1.6", "mz": "^2.7.0", "pirates": "^4.0.1", "ts-interface-checker": "^0.1.9" }, "bin": { "sucrase": "bin/sucrase", "sucrase-node": "bin/sucrase-node" } }, "sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA=="], "sucrase": ["sucrase@3.35.0", "", { "dependencies": { "@jridgewell/gen-mapping": "^0.3.2", "commander": "^4.0.0", "glob": "^10.3.10", "lines-and-columns": "^1.1.6", "mz": "^2.7.0", "pirates": "^4.0.1", "ts-interface-checker": "^0.1.9" }, "bin": { "sucrase": "bin/sucrase", "sucrase-node": "bin/sucrase-node" } }, "sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA=="],
@@ -2180,7 +2270,7 @@
"typescript": ["typescript@5.9.2", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A=="], "typescript": ["typescript@5.9.2", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A=="],
"ua-parser-js": ["ua-parser-js@1.0.40", "", { "bin": "script/cli.js" }, "sha512-z6PJ8Lml+v3ichVojCiB8toQJBuwR42ySM4ezjXIqXK3M0HczmKQ3LF4rhU55PfD99KEEXQG6yb7iOMyvYuHew=="], "ua-parser-js": ["ua-parser-js@0.7.41", "", { "bin": { "ua-parser-js": "script/cli.js" } }, "sha512-O3oYyCMPYgNNHuO7Jjk3uacJWZF8loBgwrfd/5LE/HyZ3lUIOdniQ7DNXJcIgZbwioZxk0fLfI4EVnetdiX5jg=="],
"unbox-primitive": ["unbox-primitive@1.1.0", "", { "dependencies": { "call-bound": "^1.0.3", "has-bigints": "^1.0.2", "has-symbols": "^1.1.0", "which-boxed-primitive": "^1.1.1" } }, "sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw=="], "unbox-primitive": ["unbox-primitive@1.1.0", "", { "dependencies": { "call-bound": "^1.0.3", "has-bigints": "^1.0.2", "has-symbols": "^1.1.0", "which-boxed-primitive": "^1.1.1" } }, "sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw=="],
@@ -2218,6 +2308,8 @@
"use-sync-external-store": ["use-sync-external-store@1.5.0", "", { "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-Rb46I4cGGVBmjamjphe8L/UnvJD+uPPtTkNvX5mZgqdbavhI4EbgIWJiIHXJ8bc/i9EQGPRh4DwEURJ552Do0A=="], "use-sync-external-store": ["use-sync-external-store@1.5.0", "", { "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-Rb46I4cGGVBmjamjphe8L/UnvJD+uPPtTkNvX5mZgqdbavhI4EbgIWJiIHXJ8bc/i9EQGPRh4DwEURJ552Do0A=="],
"util": ["util@0.12.5", "", { "dependencies": { "inherits": "^2.0.3", "is-arguments": "^1.0.4", "is-generator-function": "^1.0.7", "is-typed-array": "^1.1.3", "which-typed-array": "^1.1.2" } }, "sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA=="],
"utils-merge": ["utils-merge@1.0.1", "", {}, "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA=="], "utils-merge": ["utils-merge@1.0.1", "", {}, "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA=="],
"uuid": ["uuid@7.0.3", "", { "bin": "dist/bin/uuid" }, "sha512-DPSke0pXhTZgoF/d+WSt2QaKMCFSfx7QegxEWT+JOuHF5aWrKEn0G+ztjuJg/gG8/ItK+rbPCD/yNv8yyih6Cg=="], "uuid": ["uuid@7.0.3", "", { "bin": "dist/bin/uuid" }, "sha512-DPSke0pXhTZgoF/d+WSt2QaKMCFSfx7QegxEWT+JOuHF5aWrKEn0G+ztjuJg/gG8/ItK+rbPCD/yNv8yyih6Cg=="],
@@ -2478,6 +2570,10 @@
"@testing-library/react-native/pretty-format": ["pretty-format@30.0.5", "", { "dependencies": { "@jest/schemas": "30.0.5", "ansi-styles": "^5.2.0", "react-is": "^18.3.1" } }, "sha512-D1tKtYvByrBkFLe2wHJl2bwMJIiT8rW+XA+TiataH79/FszLQMrpGEvzUVkzPau7OCO0Qnrhpe87PqtOAIB8Yw=="], "@testing-library/react-native/pretty-format": ["pretty-format@30.0.5", "", { "dependencies": { "@jest/schemas": "30.0.5", "ansi-styles": "^5.2.0", "react-is": "^18.3.1" } }, "sha512-D1tKtYvByrBkFLe2wHJl2bwMJIiT8rW+XA+TiataH79/FszLQMrpGEvzUVkzPau7OCO0Qnrhpe87PqtOAIB8Yw=="],
"@turf/bbox/@turf/helpers": ["@turf/helpers@7.3.0", "", { "dependencies": { "@types/geojson": "^7946.0.10", "tslib": "^2.8.1" } }, "sha512-5kWdgwI6e2vGbkt2qOD+Z2BiKQ7dfKN/PtWRLCpvzyOO59rk19R53CHi8nUT/Y1vQLgWmT6eNpiKwsWwPZGIdg=="],
"@turf/bbox/@turf/meta": ["@turf/meta@7.3.0", "", { "dependencies": { "@turf/helpers": "7.3.0", "@types/geojson": "^7946.0.10" } }, "sha512-fTLqdQqRm8qA2zHHUbBMY++YT9LDQejLG7OD70XF2dwg9nPiF9mUxO7nrsDp2IY8vNmH9OTAiMtlIjb0ssYccg=="],
"@types/react-native/@types/react": ["@types/react@19.0.14", "", { "dependencies": { "csstype": "^3.0.2" } }, "sha512-ixLZ7zG7j1fM0DijL9hDArwhwcCb4vqmePgwtV0GfnkHRSCUEv4LvzarcTdhoqgyMznUx/EhoTUv31CKZzkQlw=="], "@types/react-native/@types/react": ["@types/react@19.0.14", "", { "dependencies": { "csstype": "^3.0.2" } }, "sha512-ixLZ7zG7j1fM0DijL9hDArwhwcCb4vqmePgwtV0GfnkHRSCUEv4LvzarcTdhoqgyMznUx/EhoTUv31CKZzkQlw=="],
"@types/react-native-vector-icons/@types/react": ["@types/react@19.0.14", "", { "dependencies": { "csstype": "^3.0.2" } }, "sha512-ixLZ7zG7j1fM0DijL9hDArwhwcCb4vqmePgwtV0GfnkHRSCUEv4LvzarcTdhoqgyMznUx/EhoTUv31CKZzkQlw=="], "@types/react-native-vector-icons/@types/react": ["@types/react@19.0.14", "", { "dependencies": { "csstype": "^3.0.2" } }, "sha512-ixLZ7zG7j1fM0DijL9hDArwhwcCb4vqmePgwtV0GfnkHRSCUEv4LvzarcTdhoqgyMznUx/EhoTUv31CKZzkQlw=="],
@@ -2564,8 +2660,16 @@
"expo/babel-preset-expo": ["babel-preset-expo@54.0.0", "", { "dependencies": { "@babel/helper-module-imports": "^7.25.9", "@babel/plugin-proposal-decorators": "^7.12.9", "@babel/plugin-proposal-export-default-from": "^7.24.7", "@babel/plugin-syntax-export-default-from": "^7.24.7", "@babel/plugin-transform-class-static-block": "^7.27.1", "@babel/plugin-transform-export-namespace-from": "^7.25.9", "@babel/plugin-transform-flow-strip-types": "^7.25.2", "@babel/plugin-transform-modules-commonjs": "^7.24.8", "@babel/plugin-transform-object-rest-spread": "^7.24.7", "@babel/plugin-transform-parameters": "^7.24.7", "@babel/plugin-transform-private-methods": "^7.24.7", "@babel/plugin-transform-private-property-in-object": "^7.24.7", "@babel/plugin-transform-runtime": "^7.24.7", "@babel/preset-react": "^7.22.15", "@babel/preset-typescript": "^7.23.0", "@react-native/babel-preset": "0.81.4", "babel-plugin-react-compiler": "^19.1.0-rc.2", "babel-plugin-react-native-web": "~0.21.0", "babel-plugin-syntax-hermes-parser": "^0.25.1", "babel-plugin-transform-flow-enums": "^0.0.2", "debug": "^4.3.4", "resolve-from": "^5.0.0" }, "peerDependencies": { "@babel/runtime": "^7.20.0", "expo": "*", "react-refresh": ">=0.14.0 <1.0.0" }, "optionalPeers": ["@babel/runtime", "expo"] }, "sha512-a0Ej4ik6xzvtrA4Ivblov3XVvfntIoqnXOy2jG2k/3hzWqzrJxKyY2gUW9ZCMAicGevj2ju28q+TsK29uTe0eQ=="], "expo/babel-preset-expo": ["babel-preset-expo@54.0.0", "", { "dependencies": { "@babel/helper-module-imports": "^7.25.9", "@babel/plugin-proposal-decorators": "^7.12.9", "@babel/plugin-proposal-export-default-from": "^7.24.7", "@babel/plugin-syntax-export-default-from": "^7.24.7", "@babel/plugin-transform-class-static-block": "^7.27.1", "@babel/plugin-transform-export-namespace-from": "^7.25.9", "@babel/plugin-transform-flow-strip-types": "^7.25.2", "@babel/plugin-transform-modules-commonjs": "^7.24.8", "@babel/plugin-transform-object-rest-spread": "^7.24.7", "@babel/plugin-transform-parameters": "^7.24.7", "@babel/plugin-transform-private-methods": "^7.24.7", "@babel/plugin-transform-private-property-in-object": "^7.24.7", "@babel/plugin-transform-runtime": "^7.24.7", "@babel/preset-react": "^7.22.15", "@babel/preset-typescript": "^7.23.0", "@react-native/babel-preset": "0.81.4", "babel-plugin-react-compiler": "^19.1.0-rc.2", "babel-plugin-react-native-web": "~0.21.0", "babel-plugin-syntax-hermes-parser": "^0.25.1", "babel-plugin-transform-flow-enums": "^0.0.2", "debug": "^4.3.4", "resolve-from": "^5.0.0" }, "peerDependencies": { "@babel/runtime": "^7.20.0", "expo": "*", "react-refresh": ">=0.14.0 <1.0.0" }, "optionalPeers": ["@babel/runtime", "expo"] }, "sha512-a0Ej4ik6xzvtrA4Ivblov3XVvfntIoqnXOy2jG2k/3hzWqzrJxKyY2gUW9ZCMAicGevj2ju28q+TsK29uTe0eQ=="],
"expo/expo-constants": ["expo-constants@18.0.8", "", { "dependencies": { "@expo/config": "~12.0.8", "@expo/env": "~2.0.7" }, "peerDependencies": { "expo": "*", "react-native": "*" } }, "sha512-Tetphsx6RVImCTZeBAclRQMy0WOODY3y6qrUoc88YGUBVm8fAKkErCSWxLTCc6nFcJxdoOMYi62LgNIUFjZCLA=="],
"expo/expo-file-system": ["expo-file-system@19.0.12", "", { "peerDependencies": { "expo": "*", "react-native": "*" } }, "sha512-gqpxpnjfhzXLcqMOi49isB5S1Af49P9410fsaFfnLZWN3X6Dwc8EplDwbaolOI/wnGwP81P+/nDn5RNmU6m7mQ=="], "expo/expo-file-system": ["expo-file-system@19.0.12", "", { "peerDependencies": { "expo": "*", "react-native": "*" } }, "sha512-gqpxpnjfhzXLcqMOi49isB5S1Af49P9410fsaFfnLZWN3X6Dwc8EplDwbaolOI/wnGwP81P+/nDn5RNmU6m7mQ=="],
"expo-asset/expo-constants": ["expo-constants@18.0.8", "", { "dependencies": { "@expo/config": "~12.0.8", "@expo/env": "~2.0.7" }, "peerDependencies": { "expo": "*", "react-native": "*" } }, "sha512-Tetphsx6RVImCTZeBAclRQMy0WOODY3y6qrUoc88YGUBVm8fAKkErCSWxLTCc6nFcJxdoOMYi62LgNIUFjZCLA=="],
"expo-constants/@expo/config": ["@expo/config@12.0.10", "", { "dependencies": { "@babel/code-frame": "~7.10.4", "@expo/config-plugins": "~54.0.2", "@expo/config-types": "^54.0.8", "@expo/json-file": "^10.0.7", "deepmerge": "^4.3.1", "getenv": "^2.0.0", "glob": "^10.4.2", "require-from-string": "^2.0.2", "resolve-from": "^5.0.0", "resolve-workspace-root": "^2.0.0", "semver": "^7.6.0", "slugify": "^1.3.4", "sucrase": "3.35.0" } }, "sha512-lJMof5Nqakq1DxGYlghYB/ogSBjmv4Fxn1ovyDmcjlRsQdFCXgu06gEUogkhPtc9wBt9WlTTfqENln5HHyLW6w=="],
"expo-linking/expo-constants": ["expo-constants@18.0.8", "", { "dependencies": { "@expo/config": "~12.0.8", "@expo/env": "~2.0.7" }, "peerDependencies": { "expo": "*", "react-native": "*" } }, "sha512-Tetphsx6RVImCTZeBAclRQMy0WOODY3y6qrUoc88YGUBVm8fAKkErCSWxLTCc6nFcJxdoOMYi62LgNIUFjZCLA=="],
"expo-module-scripts/typescript": ["typescript@5.8.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ=="], "expo-module-scripts/typescript": ["typescript@5.8.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ=="],
"expo-modules-autolinking/commander": ["commander@7.2.0", "", {}, "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw=="], "expo-modules-autolinking/commander": ["commander@7.2.0", "", {}, "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw=="],
@@ -2578,6 +2682,8 @@
"fbjs/promise": ["promise@7.3.1", "", { "dependencies": { "asap": "~2.0.3" } }, "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg=="], "fbjs/promise": ["promise@7.3.1", "", { "dependencies": { "asap": "~2.0.3" } }, "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg=="],
"fbjs/ua-parser-js": ["ua-parser-js@1.0.40", "", { "bin": "script/cli.js" }, "sha512-z6PJ8Lml+v3ichVojCiB8toQJBuwR42ySM4ezjXIqXK3M0HczmKQ3LF4rhU55PfD99KEEXQG6yb7iOMyvYuHew=="],
"finalhandler/debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" } }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="], "finalhandler/debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" } }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="],
"finalhandler/encodeurl": ["encodeurl@1.0.2", "", {}, "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w=="], "finalhandler/encodeurl": ["encodeurl@1.0.2", "", {}, "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w=="],
@@ -2586,6 +2692,8 @@
"finalhandler/statuses": ["statuses@1.5.0", "", {}, "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA=="], "finalhandler/statuses": ["statuses@1.5.0", "", {}, "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA=="],
"geojson-rbush/@types/geojson": ["@types/geojson@7946.0.8", "", {}, "sha512-1rkryxURpr6aWP7R786/UQOkJ3PcpQiWkAXBmdWc7ryFWqN6a4xfK7BtjXvFBKO9LjQ+MWQSWxYeZX1OApnArA=="],
"glob/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="], "glob/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="],
"hoist-non-react-statics/react-is": ["react-is@16.13.1", "", {}, "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="], "hoist-non-react-statics/react-is": ["react-is@16.13.1", "", {}, "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="],
@@ -2946,6 +3054,14 @@
"expect/jest-matcher-utils/jest-diff": ["jest-diff@29.7.0", "", { "dependencies": { "chalk": "^4.0.0", "diff-sequences": "^29.6.3", "jest-get-type": "^29.6.3", "pretty-format": "^29.7.0" } }, "sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw=="], "expect/jest-matcher-utils/jest-diff": ["jest-diff@29.7.0", "", { "dependencies": { "chalk": "^4.0.0", "diff-sequences": "^29.6.3", "jest-get-type": "^29.6.3", "pretty-format": "^29.7.0" } }, "sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw=="],
"expo-constants/@expo/config/@babel/code-frame": ["@babel/code-frame@7.10.4", "", { "dependencies": { "@babel/highlight": "^7.10.4" } }, "sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg=="],
"expo-constants/@expo/config/@expo/config-plugins": ["@expo/config-plugins@54.0.2", "", { "dependencies": { "@expo/config-types": "^54.0.8", "@expo/json-file": "~10.0.7", "@expo/plist": "^0.4.7", "@expo/sdk-runtime-versions": "^1.0.0", "chalk": "^4.1.2", "debug": "^4.3.5", "getenv": "^2.0.0", "glob": "^10.4.2", "resolve-from": "^5.0.0", "semver": "^7.5.4", "slash": "^3.0.0", "slugify": "^1.6.6", "xcode": "^3.0.1", "xml2js": "0.6.0" } }, "sha512-jD4qxFcURQUVsUFGMcbo63a/AnviK8WUGard+yrdQE3ZrB/aurn68SlApjirQQLEizhjI5Ar2ufqflOBlNpyPg=="],
"expo-constants/@expo/config/@expo/json-file": ["@expo/json-file@10.0.7", "", { "dependencies": { "@babel/code-frame": "~7.10.4", "json5": "^2.2.3" } }, "sha512-z2OTC0XNO6riZu98EjdNHC05l51ySeTto6GP7oSQrCvQgG9ARBwD1YvMQaVZ9wU7p/4LzSf1O7tckL3B45fPpw=="],
"expo-constants/@expo/config/semver": ["semver@7.7.2", "", { "bin": "bin/semver.js" }, "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA=="],
"expo/babel-preset-expo/@react-native/babel-preset": ["@react-native/babel-preset@0.81.4", "", { "dependencies": { "@babel/core": "^7.25.2", "@babel/plugin-proposal-export-default-from": "^7.24.7", "@babel/plugin-syntax-dynamic-import": "^7.8.3", "@babel/plugin-syntax-export-default-from": "^7.24.7", "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", "@babel/plugin-syntax-optional-chaining": "^7.8.3", "@babel/plugin-transform-arrow-functions": "^7.24.7", "@babel/plugin-transform-async-generator-functions": "^7.25.4", "@babel/plugin-transform-async-to-generator": "^7.24.7", "@babel/plugin-transform-block-scoping": "^7.25.0", "@babel/plugin-transform-class-properties": "^7.25.4", "@babel/plugin-transform-classes": "^7.25.4", "@babel/plugin-transform-computed-properties": "^7.24.7", "@babel/plugin-transform-destructuring": "^7.24.8", "@babel/plugin-transform-flow-strip-types": "^7.25.2", "@babel/plugin-transform-for-of": "^7.24.7", "@babel/plugin-transform-function-name": "^7.25.1", "@babel/plugin-transform-literals": "^7.25.2", "@babel/plugin-transform-logical-assignment-operators": "^7.24.7", "@babel/plugin-transform-modules-commonjs": "^7.24.8", "@babel/plugin-transform-named-capturing-groups-regex": "^7.24.7", "@babel/plugin-transform-nullish-coalescing-operator": "^7.24.7", "@babel/plugin-transform-numeric-separator": "^7.24.7", "@babel/plugin-transform-object-rest-spread": "^7.24.7", "@babel/plugin-transform-optional-catch-binding": "^7.24.7", "@babel/plugin-transform-optional-chaining": "^7.24.8", "@babel/plugin-transform-parameters": "^7.24.7", "@babel/plugin-transform-private-methods": "^7.24.7", "@babel/plugin-transform-private-property-in-object": "^7.24.7", "@babel/plugin-transform-react-display-name": "^7.24.7", "@babel/plugin-transform-react-jsx": "^7.25.2", "@babel/plugin-transform-react-jsx-self": "^7.24.7", "@babel/plugin-transform-react-jsx-source": "^7.24.7", "@babel/plugin-transform-regenerator": "^7.24.7", "@babel/plugin-transform-runtime": "^7.24.7", "@babel/plugin-transform-shorthand-properties": "^7.24.7", "@babel/plugin-transform-spread": "^7.24.7", "@babel/plugin-transform-sticky-regex": "^7.24.7", "@babel/plugin-transform-typescript": "^7.25.2", "@babel/plugin-transform-unicode-regex": "^7.24.7", "@babel/template": "^7.25.0", "@react-native/babel-plugin-codegen": "0.81.4", "babel-plugin-syntax-hermes-parser": "0.29.1", "babel-plugin-transform-flow-enums": "^0.0.2", "react-refresh": "^0.14.0" } }, "sha512-VYj0c/cTjQJn/RJ5G6P0L9wuYSbU9yGbPYDHCKstlQZQWkk+L9V8ZDbxdJBTIei9Xl3KPQ1odQ4QaeW+4v+AZg=="], "expo/babel-preset-expo/@react-native/babel-preset": ["@react-native/babel-preset@0.81.4", "", { "dependencies": { "@babel/core": "^7.25.2", "@babel/plugin-proposal-export-default-from": "^7.24.7", "@babel/plugin-syntax-dynamic-import": "^7.8.3", "@babel/plugin-syntax-export-default-from": "^7.24.7", "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", "@babel/plugin-syntax-optional-chaining": "^7.8.3", "@babel/plugin-transform-arrow-functions": "^7.24.7", "@babel/plugin-transform-async-generator-functions": "^7.25.4", "@babel/plugin-transform-async-to-generator": "^7.24.7", "@babel/plugin-transform-block-scoping": "^7.25.0", "@babel/plugin-transform-class-properties": "^7.25.4", "@babel/plugin-transform-classes": "^7.25.4", "@babel/plugin-transform-computed-properties": "^7.24.7", "@babel/plugin-transform-destructuring": "^7.24.8", "@babel/plugin-transform-flow-strip-types": "^7.25.2", "@babel/plugin-transform-for-of": "^7.24.7", "@babel/plugin-transform-function-name": "^7.25.1", "@babel/plugin-transform-literals": "^7.25.2", "@babel/plugin-transform-logical-assignment-operators": "^7.24.7", "@babel/plugin-transform-modules-commonjs": "^7.24.8", "@babel/plugin-transform-named-capturing-groups-regex": "^7.24.7", "@babel/plugin-transform-nullish-coalescing-operator": "^7.24.7", "@babel/plugin-transform-numeric-separator": "^7.24.7", "@babel/plugin-transform-object-rest-spread": "^7.24.7", "@babel/plugin-transform-optional-catch-binding": "^7.24.7", "@babel/plugin-transform-optional-chaining": "^7.24.8", "@babel/plugin-transform-parameters": "^7.24.7", "@babel/plugin-transform-private-methods": "^7.24.7", "@babel/plugin-transform-private-property-in-object": "^7.24.7", "@babel/plugin-transform-react-display-name": "^7.24.7", "@babel/plugin-transform-react-jsx": "^7.25.2", "@babel/plugin-transform-react-jsx-self": "^7.24.7", "@babel/plugin-transform-react-jsx-source": "^7.24.7", "@babel/plugin-transform-regenerator": "^7.24.7", "@babel/plugin-transform-runtime": "^7.24.7", "@babel/plugin-transform-shorthand-properties": "^7.24.7", "@babel/plugin-transform-spread": "^7.24.7", "@babel/plugin-transform-sticky-regex": "^7.24.7", "@babel/plugin-transform-typescript": "^7.25.2", "@babel/plugin-transform-unicode-regex": "^7.24.7", "@babel/template": "^7.25.0", "@react-native/babel-plugin-codegen": "0.81.4", "babel-plugin-syntax-hermes-parser": "0.29.1", "babel-plugin-transform-flow-enums": "^0.0.2", "react-refresh": "^0.14.0" } }, "sha512-VYj0c/cTjQJn/RJ5G6P0L9wuYSbU9yGbPYDHCKstlQZQWkk+L9V8ZDbxdJBTIei9Xl3KPQ1odQ4QaeW+4v+AZg=="],
"expo/babel-preset-expo/babel-plugin-react-native-web": ["babel-plugin-react-native-web@0.21.1", "", {}, "sha512-7XywfJ5QIRMwjOL+pwJt2w47Jmi5fFLvK7/So4fV4jIN6PcRbylCp9/l3cJY4VJbSz3lnWTeHDTD1LKIc1C09Q=="], "expo/babel-preset-expo/babel-plugin-react-native-web": ["babel-plugin-react-native-web@0.21.1", "", {}, "sha512-7XywfJ5QIRMwjOL+pwJt2w47Jmi5fFLvK7/So4fV4jIN6PcRbylCp9/l3cJY4VJbSz3lnWTeHDTD1LKIc1C09Q=="],
@@ -3128,6 +3244,8 @@
"babel-preset-expo/babel-plugin-syntax-hermes-parser/hermes-parser/hermes-estree": ["hermes-estree@0.25.1", "", {}, "sha512-0wUoCcLp+5Ev5pDW2OriHC2MJCbwLwuRx+gAqMTOkGKJJiBCLjtrvy4PWUGn6MIVefecRpzoOZ/UV6iGdOr+Cw=="], "babel-preset-expo/babel-plugin-syntax-hermes-parser/hermes-parser/hermes-estree": ["hermes-estree@0.25.1", "", {}, "sha512-0wUoCcLp+5Ev5pDW2OriHC2MJCbwLwuRx+gAqMTOkGKJJiBCLjtrvy4PWUGn6MIVefecRpzoOZ/UV6iGdOr+Cw=="],
"expo-constants/@expo/config/@expo/config-plugins/slash": ["slash@3.0.0", "", {}, "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q=="],
"expo/babel-preset-expo/@react-native/babel-preset/@react-native/babel-plugin-codegen": ["@react-native/babel-plugin-codegen@0.81.4", "", { "dependencies": { "@babel/traverse": "^7.25.3", "@react-native/codegen": "0.81.4" } }, "sha512-6ztXf2Tl2iWznyI/Da/N2Eqymt0Mnn69GCLnEFxFbNdk0HxHPZBNWU9shTXhsLWOL7HATSqwg/bB1+3kY1q+mA=="], "expo/babel-preset-expo/@react-native/babel-preset/@react-native/babel-plugin-codegen": ["@react-native/babel-plugin-codegen@0.81.4", "", { "dependencies": { "@babel/traverse": "^7.25.3", "@react-native/codegen": "0.81.4" } }, "sha512-6ztXf2Tl2iWznyI/Da/N2Eqymt0Mnn69GCLnEFxFbNdk0HxHPZBNWU9shTXhsLWOL7HATSqwg/bB1+3kY1q+mA=="],
"expo/babel-preset-expo/@react-native/babel-preset/babel-plugin-syntax-hermes-parser": ["babel-plugin-syntax-hermes-parser@0.29.1", "", { "dependencies": { "hermes-parser": "0.29.1" } }, "sha512-2WFYnoWGdmih1I1J5eIqxATOeycOqRwYxAQBu3cUu/rhwInwHUg7k60AFNbuGjSDL8tje5GDrAnxzRLcu2pYcA=="], "expo/babel-preset-expo/@react-native/babel-preset/babel-plugin-syntax-hermes-parser": ["babel-plugin-syntax-hermes-parser@0.29.1", "", { "dependencies": { "hermes-parser": "0.29.1" } }, "sha512-2WFYnoWGdmih1I1J5eIqxATOeycOqRwYxAQBu3cUu/rhwInwHUg7k60AFNbuGjSDL8tje5GDrAnxzRLcu2pYcA=="],

View File

@@ -0,0 +1,16 @@
import { Alert } from "react-native";
export default function AlertWarning({
title = "Peringatan Bagi Pengguna !",
description = "Konten yang Anda masukkan mengandung kata-kata yang tidak sesuai dengan pedoman komunitas kami. Mohon gunakan bahasa yang sopan dan menghargai sesama pengguna. Jika kata tersebut sebenarnya lumrah, mohon maaf—kemungkinan sistem kami belum mengenalnya sebagai wajar.",
}: {
title?: string
description?: string;
}) {
return Alert.alert(title, description, [
{
text: "Tutup",
onPress: () => {},
},
]);
}

View File

@@ -32,9 +32,10 @@ const FloatingButton: React.FC<FloatingButtonProps> = ({
const styles = StyleSheet.create({ const styles = StyleSheet.create({
fab: { fab: {
position: "absolute", position: "absolute",
margin: 16, margin: "auto",
right: 0, right: 0,
bottom: 0, // bottom: 10,
top: -20,
backgroundColor: AccentColor.softblue, // Warna Twitter biru backgroundColor: AccentColor.softblue, // Warna Twitter biru
borderRadius: 50, borderRadius: 50,
borderColor: AccentColor.blue, borderColor: AccentColor.blue,

View File

@@ -7,7 +7,7 @@ import DateTimePicker, {
} from "@react-native-community/datetimepicker"; } from "@react-native-community/datetimepicker";
import dayjs from "dayjs"; import dayjs from "dayjs";
import React, { useState } from "react"; import React, { useState } from "react";
import { StyleProp, Text, View, ViewStyle } from "react-native"; import { Button, StyleProp, Text, View, ViewStyle } from "react-native";
import ClickableCustom from "../Clickable/ClickableCustom"; import ClickableCustom from "../Clickable/ClickableCustom";
import TextCustom from "../Text/TextCustom"; import TextCustom from "../Text/TextCustom";
@@ -129,24 +129,64 @@ const DateTimeInput_IOS: React.FC<DateTimeInputProps> = ({
borderWidth: 1, borderWidth: 1,
}} }}
> >
<View style={{ alignItems: "flex-end" }}> {/* <View style={{ alignItems: "flex-start" }}>
<Ionicons <Ionicons
name="close" name="close"
size={20} size={20}
color="black" color="black"
onPress={() => setShow(false)} onPress={() => {
setShow(false);
setSelectedDate(undefined);
}}
/> />
</View> </View> */}
<DateTimePicker <DateTimePicker
value={selectedDate || new Date()} value={selectedDate || new Date()}
mode={"datetime"} mode={"datetime"}
display="inline" display="spinner"
onChange={handleConfirm} onChange={handleConfirm}
minimumDate={minimumDate} minimumDate={minimumDate}
maximumDate={maximumDate} maximumDate={maximumDate}
themeVariant="light" themeVariant="light"
/> />
<View style={{ flexDirection: "row", gap: 10 }}>
<ClickableCustom
onPress={() => {
setShow(false)
setSelectedDate(undefined)
}}
style={{
alignItems: "center",
justifyContent: "center",
padding: 12,
borderRadius: 10,
backgroundColor: MainColor.placeholder,
marginTop: 10,
width: "48%",
}}
>
<TextCustom color="black">Batal</TextCustom>
</ClickableCustom>
<ClickableCustom
onPress={() => {
setShow(false)
onChange(selectedDate as any)
}}
style={{
alignItems: "center",
justifyContent: "center",
padding: 12,
borderRadius: 10,
backgroundColor: MainColor.darkblue,
marginTop: 10,
width: "48%",
}}
>
<TextCustom>OK</TextCustom>
</ClickableCustom>
</View>
</View> </View>
</> </>
)} )}

View File

@@ -109,6 +109,7 @@ const styles = StyleSheet.create({
flexDirection: "row", flexDirection: "row",
flexWrap: "wrap", flexWrap: "wrap",
justifyContent: "flex-start", justifyContent: "flex-start",
marginInline: 0.1 // marginInline: 0.1
margin: 0.1
}, },
}); });

View File

@@ -87,7 +87,7 @@ const SelectCustom: React.FC<SelectProps> = ({
borderRadius, borderRadius,
flexDirection: "row", flexDirection: "row",
alignItems: "center", alignItems: "center",
paddingHorizontal: 10, // paddingHorizontal: 0,
height: 50, height: 50,
}, },

View File

@@ -1,3 +1,4 @@
import { AccentColor, MainColor } from "@/constants/color-palet";
import { GStyles } from "@/styles/global-styles"; import { GStyles } from "@/styles/global-styles";
import React, { useEffect, useState } from "react"; import React, { useEffect, useState } from "react";
import { import {
@@ -6,7 +7,9 @@ import {
Text, Text,
View, View,
ViewStyle, ViewStyle,
useColorScheme,
} from "react-native"; } from "react-native";
import { PlaceholderColor } from "@/constants/color-palet";
type IconType = React.ReactNode | string; type IconType = React.ReactNode | string;
@@ -48,7 +51,7 @@ const TextAreaCustom: React.FC<TextAreaCustomProps> = ({
minRows = 4, minRows = 4,
maxRows = 6, maxRows = 6,
showCount = false, showCount = false,
maxLength, maxLength = 1000,
value, value,
onChangeText, onChangeText,
height = 100, height = 100,
@@ -78,6 +81,9 @@ const TextAreaCustom: React.FC<TextAreaCustomProps> = ({
); );
}; };
const colorScheme = useColorScheme();
const theme = PlaceholderColor[colorScheme || "light"];
return ( return (
<View style={[GStyles.inputContainerArea]}> <View style={[GStyles.inputContainerArea]}>
{label && ( {label && (
@@ -109,6 +115,7 @@ const TextAreaCustom: React.FC<TextAreaCustomProps> = ({
GStyles.textAreaInput, GStyles.textAreaInput,
{ color: fontColor }, { color: fontColor },
]} ]}
placeholderTextColor={theme.placeholder}
editable={!disabled} editable={!disabled}
value={value as string} value={value as string}
onChangeText={onChangeText} onChangeText={onChangeText}

View File

@@ -1,3 +1,4 @@
import { PlaceholderColor } from "@/constants/color-palet";
import { GStyles } from "@/styles/global-styles"; import { GStyles } from "@/styles/global-styles";
import Ionicons from "@expo/vector-icons/Ionicons"; import Ionicons from "@expo/vector-icons/Ionicons";
import React, { useState } from "react"; import React, { useState } from "react";
@@ -8,8 +9,10 @@ import {
TouchableOpacity, TouchableOpacity,
View, View,
ViewStyle, ViewStyle,
useColorScheme
} from "react-native"; } from "react-native";
type IconType = React.ReactNode | string; type IconType = React.ReactNode | string;
type Props = { type Props = {
@@ -74,6 +77,9 @@ const TextInputCustom = ({
} }
}; };
const colorScheme = useColorScheme();
const theme = PlaceholderColor[colorScheme || "light"];
return ( return (
<View style={[GStyles.inputContainerArea, containerStyle]}> <View style={[GStyles.inputContainerArea, containerStyle]}>
{label && ( {label && (
@@ -100,12 +106,14 @@ const TextInputCustom = ({
{ color: fontColor }, { color: fontColor },
disabled && GStyles.inputPlaceholderDisabled, // <-- placeholder saat disabled disabled && GStyles.inputPlaceholderDisabled, // <-- placeholder saat disabled
]} ]}
placeholderTextColor={theme.placeholder}
editable={!disabled} editable={!disabled}
secureTextEntry={secureTextEntry && !isPasswordVisible} secureTextEntry={secureTextEntry && !isPasswordVisible}
keyboardType={keyboardType} keyboardType={keyboardType}
onChangeText={handleTextChange} onChangeText={handleTextChange}
maxLength={maxLength} maxLength={maxLength}
{...rest} {...rest}
/> />
{secureTextEntry && ( {secureTextEntry && (
<TouchableOpacity <TouchableOpacity

View File

@@ -15,7 +15,7 @@ export default function AdminButtonReject({
<> <>
<ButtonCustom <ButtonCustom
iconLeft={<IconReject size={16} />} iconLeft={<IconReject size={16} />}
backgroundColor={MainColor.red} backgroundColor={MainColor.orange}
textColor="white" textColor="white"
onPress={onReject} onPress={onReject}
isLoading={isLoading} isLoading={isLoading}

View File

@@ -1,17 +1,23 @@
import Grid from "@/components/Grid/GridCustom"; import Grid from "@/components/Grid/GridCustom";
import React from "react"; import React from "react";
import { View } from "react-native"; import { StyleProp, View, ViewStyle } from "react-native";
import { Divider } from "react-native-paper"; import { Divider } from "react-native-paper";
export default function AdminTableValue({ export default function AdminTableValue({
value1, value1,
value2, value2,
value3, value3,
style1,
style2,
style3,
bottomLine = false, bottomLine = false,
}: { }: {
value1: React.ReactNode; value1: React.ReactNode;
value2: React.ReactNode; value2: React.ReactNode;
value3: React.ReactNode; value3: React.ReactNode;
style1?: ViewStyle;
style2?: ViewStyle;
style3?: ViewStyle;
bottomLine?: boolean; bottomLine?: boolean;
}) { }) {
return ( return (
@@ -25,6 +31,7 @@ export default function AdminTableValue({
justifyContent: "center", justifyContent: "center",
paddingLeft: 10, paddingLeft: 10,
paddingRight: 10, paddingRight: 10,
...style1,
}} }}
> >
{value1} {value1}
@@ -36,6 +43,7 @@ export default function AdminTableValue({
justifyContent: "center", justifyContent: "center",
paddingLeft: 10, paddingLeft: 10,
paddingRight: 10, paddingRight: 10,
...style2,
}} }}
> >
{value2} {value2}
@@ -44,9 +52,10 @@ export default function AdminTableValue({
span={6} span={6}
style={{ style={{
justifyContent: "center", justifyContent: "center",
alignItems: "center", alignItems: "flex-start",
paddingLeft: 10, paddingLeft: 10,
paddingRight: 10, paddingRight: 10,
...style3,
}} }}
> >
{value3} {value3}

View File

@@ -1,20 +0,0 @@
import { Grid } from "@/components";
export const GridDetail_4_8 = ({
label,
value,
}: {
label: React.ReactNode;
value: React.ReactNode;
}) => {
return (
<Grid>
<Grid.Col span={4} style={{ justifyContent: "center", paddingRight: 10 }}>
{label}
</Grid.Col>
<Grid.Col span={8} style={{ justifyContent: "center" }}>
{value}
</Grid.Col>
</Grid>
);
};

View File

@@ -0,0 +1,27 @@
import { Grid } from "@/components";
export const GridSpan_4_8 = ({
label: text1,
value: text2,
}: {
label: React.ReactNode;
value: React.ReactNode;
}) => {
return (
<Grid>
<Grid.Col
span={4}
style={{
justifyContent: "flex-start",
paddingRight: 8,
paddingLeft: 8,
}}
>
{text1}
</Grid.Col>
<Grid.Col span={8} style={{ justifyContent: "center", paddingRight: 8 }}>
{text2}
</Grid.Col>
</Grid>
);
};

View File

@@ -0,0 +1,54 @@
import { Grid } from "@/components";
export const GridSpan_NewComponent = ({
text1,
text2,
text3,
text4,
span1,
span2,
}: {
text1: React.ReactNode;
text2: React.ReactNode;
text3?: React.ReactNode;
text4?: React.ReactNode;
span1?: number;
span2?: number;
}) => {
return (
<Grid>
<Grid.Col
span={span1 ? span1 : text4 ? 3 : 4}
style={{
justifyContent: "flex-start",
paddingRight: 5,
paddingLeft: 3,
}}
>
{text1}
</Grid.Col>
<Grid.Col
span={span2 ? span2 : text4 ? 3 : text3 ? 4 : 8}
style={{ justifyContent: "flex-start", paddingRight: 5 }}
>
{text2}
</Grid.Col>
{text3 && (
<Grid.Col
span={text4 ? 3 : 4}
style={{ justifyContent: "flex-start", paddingRight: 5 }}
>
{text3}
</Grid.Col>
)}
{text4 && (
<Grid.Col
span={3}
style={{ justifyContent: "flex-start", paddingRight: 5 }}
>
{text4}
</Grid.Col>
)}
</Grid>
);
};

View File

@@ -0,0 +1,20 @@
import { View } from "react-native";
import TextCustom from "../Text/TextCustom";
// Komponen Empty
const ListEmptyComponent = ({ search }: { search?: string }) => (
<View
style={{
flex: 1,
justifyContent: "center",
alignItems: "center",
padding: 20,
}}
>
<TextCustom align="center" color="gray">
{search ? "Tidak ada hasil pencarian" : "Tidak ada data"}
</TextCustom>
</View>
);
export default ListEmptyComponent;

View File

@@ -0,0 +1,11 @@
import { View } from "react-native";
import LoaderCustom from "../Loader/LoaderCustom";
const ListLoaderFooterComponent = () =>(
<View style={{ paddingVertical: 16, alignItems: "center" }}>
<LoaderCustom />
</View>
)
export default ListLoaderFooterComponent;

View File

@@ -0,0 +1,21 @@
import { View } from "react-native";
import StackCustom from "../Stack/StackCustom";
import SkeletonCustom from "./SkeletonCustom";
const ListSkeletonComponent = ({
length = 5,
height = 100,
}: {
length?: number;
height?: number;
}) => (
<View style={{ flex: 1 }}>
<StackCustom>
{Array.from({ length }).map((_, i) => (
<SkeletonCustom height={height} key={i} />
))}
</StackCustom>
</View>
);
export default ListSkeletonComponent;

View File

@@ -0,0 +1,188 @@
// @/components/NewWrapper.tsx
import { MainColor } from "@/constants/color-palet";
import { OS_HEIGHT } from "@/constants/constans-value";
import { GStyles } from "@/styles/global-styles";
import {
ImageBackground,
Keyboard,
KeyboardAvoidingView,
Platform,
ScrollView,
FlatList,
TouchableWithoutFeedback,
View,
StyleProp,
ViewStyle,
} from "react-native";
import {
NativeSafeAreaViewProps,
SafeAreaView,
} from "react-native-safe-area-context";
import type { ScrollViewProps, FlatListProps } from "react-native";
// --- ✅ Tambahkan refreshControl ke BaseProps ---
interface BaseProps {
withBackground?: boolean;
headerComponent?: React.ReactNode;
footerComponent?: React.ReactNode;
floatingButton?: React.ReactNode;
hideFooter?: boolean;
edgesFooter?: NativeSafeAreaViewProps["edges"];
style?: StyleProp<ViewStyle>;
refreshControl?: ScrollViewProps["refreshControl"]; // ✅ dipakai di kedua mode
}
interface StaticModeProps extends BaseProps {
children: React.ReactNode;
listData?: never;
renderItem?: never;
}
interface ListModeProps extends BaseProps {
children?: never;
listData?: any[];
renderItem?: FlatListProps<any>["renderItem"];
onEndReached?: () => void;
// ✅ Gunakan tipe yang kompatibel dengan FlatList
ListHeaderComponent?: React.ReactElement | null;
ListFooterComponent?: React.ReactElement | null;
ListEmptyComponent?: React.ReactElement | null;
keyExtractor?: FlatListProps<any>["keyExtractor"];
}
type NewWrapperProps = StaticModeProps | ListModeProps;
const NewWrapper = (props: NewWrapperProps) => {
const {
withBackground = false,
headerComponent,
footerComponent,
floatingButton,
hideFooter = false,
edgesFooter = [],
style,
refreshControl, // ✅ sekarang ada di BaseProps
} = props;
const assetBackground = require("../../assets/images/main-background.png");
const renderContainer = (content: React.ReactNode) => {
if (withBackground) {
return (
<ImageBackground
source={assetBackground}
resizeMode="cover"
style={GStyles.imageBackground}
>
<View style={[GStyles.containerWithBackground, style]}>
{content}
</View>
</ImageBackground>
);
}
return <View style={[GStyles.container, style]}>{content}</View>;
};
// 🔹 Mode Dinamis
if ("listData" in props) {
const listProps = props as ListModeProps;
return (
<KeyboardAvoidingView
behavior={Platform.OS === "ios" ? "padding" : "height"}
style={{ flex: 1, backgroundColor: MainColor.darkblue }}
>
{headerComponent && (
<View style={GStyles.stickyHeader}>{headerComponent}</View>
)}
<View style={[GStyles.container, style]}>
<FlatList
data={listProps.listData}
renderItem={listProps.renderItem}
keyExtractor={
listProps.keyExtractor ||
((item) => {
if (item.id == null) {
console.warn("Item tanpa 'id':", item);
return `fallback-${JSON.stringify(item)}`;
}
return String(item.id);
})
}
refreshControl={refreshControl} // ✅ dari BaseProps
onEndReached={listProps.onEndReached}
onEndReachedThreshold={0.5}
ListHeaderComponent={listProps.ListHeaderComponent}
ListFooterComponent={listProps.ListFooterComponent}
ListEmptyComponent={listProps.ListEmptyComponent}
contentContainerStyle={{ flexGrow: 1 }}
keyboardShouldPersistTaps="handled"
/>
</View>
{footerComponent ? (
<SafeAreaView
edges={Platform.OS === "ios" ? edgesFooter : ["bottom"]}
style={{ backgroundColor: MainColor.darkblue, height: OS_HEIGHT }}
>
{footerComponent}
</SafeAreaView>
) : hideFooter ? null : (
<SafeAreaView
edges={["bottom"]}
style={{ backgroundColor: MainColor.darkblue }}
/>
)}
{floatingButton && (
<View style={GStyles.floatingContainer}>{floatingButton}</View>
)}
</KeyboardAvoidingView>
);
}
// 🔹 Mode Statis
const staticProps = props as StaticModeProps;
return (
<KeyboardAvoidingView
behavior={Platform.OS === "ios" ? "padding" : "height"}
style={{ flex: 1, backgroundColor: MainColor.darkblue }}
>
{headerComponent && (
<View style={GStyles.stickyHeader}>{headerComponent}</View>
)}
<ScrollView
contentContainerStyle={{ flexGrow: 1 }}
keyboardShouldPersistTaps="handled"
refreshControl={refreshControl} // ✅ sekarang valid
>
<TouchableWithoutFeedback onPress={Keyboard.dismiss}>
{renderContainer(staticProps.children)}
</TouchableWithoutFeedback>
</ScrollView>
{footerComponent ? (
<SafeAreaView
edges={Platform.OS === "ios" ? edgesFooter : ["bottom"]}
style={{ backgroundColor: MainColor.darkblue, height: OS_HEIGHT }}
>
{footerComponent}
</SafeAreaView>
) : hideFooter ? null : (
<SafeAreaView
edges={["bottom"]}
style={{ backgroundColor: MainColor.darkblue }}
/>
)}
{floatingButton && (
<View style={GStyles.floatingContainer}>{floatingButton}</View>
)}
</KeyboardAvoidingView>
);
};
export default NewWrapper;

View File

@@ -0,0 +1,59 @@
// components/CustomSkeleton.tsx
import React from "react";
import { View, StyleProp, ViewStyle, DimensionValue } from "react-native";
import { MotiView } from "moti";
import { AccentColor, MainColor } from "@/constants/color-palet";
interface CustomSkeletonProps {
isLoading?: boolean;
style?: StyleProp<ViewStyle>;
width?: DimensionValue;
height?: DimensionValue;
radius?: number;
}
const CustomSkeleton: React.FC<CustomSkeletonProps> = ({
isLoading = true,
style,
width = "100%",
height = 16,
radius = 8,
}) => {
if (!isLoading) return null;
return (
<View
style={[
{
width,
height,
borderRadius: radius,
backgroundColor: AccentColor.darkblue,
overflow: "hidden",
position: "relative",
},
style,
]}
>
<MotiView
from={{ translateY: -100 }}
animate={{ translateY: 100 }}
transition={{
duration: 1200,
repeat: Infinity,
type: "timing",
}}
style={{
position: "absolute",
left: 0,
right: 0,
height: 100,
backgroundColor: MainColor.soft_darkblue,
borderRadius: 4,
}}
/>
</View>
);
};
export default CustomSkeleton;

View File

@@ -11,6 +11,7 @@ import {
View, View,
StyleProp, StyleProp,
ViewStyle, ViewStyle,
ScrollViewProps,
} from "react-native"; } from "react-native";
import { NativeSafeAreaViewProps, SafeAreaView } from "react-native-safe-area-context"; import { NativeSafeAreaViewProps, SafeAreaView } from "react-native-safe-area-context";
@@ -23,6 +24,7 @@ interface ViewWrapperProps {
hideFooter?: boolean; hideFooter?: boolean;
edgesFooter?: NativeSafeAreaViewProps["edges"]; edgesFooter?: NativeSafeAreaViewProps["edges"];
style?: StyleProp<ViewStyle>; style?: StyleProp<ViewStyle>;
refreshControl?: ScrollViewProps["refreshControl"];
} }
/** /**
@@ -40,6 +42,7 @@ const ViewWrapper = ({
hideFooter = false, hideFooter = false,
edgesFooter =[], edgesFooter =[],
style, style,
refreshControl,
}: ViewWrapperProps) => { }: ViewWrapperProps) => {
const assetBackground = require("../../assets/images/main-background.png"); const assetBackground = require("../../assets/images/main-background.png");
@@ -57,6 +60,7 @@ const ViewWrapper = ({
<ScrollView <ScrollView
contentContainerStyle={{ flexGrow: 1 }} contentContainerStyle={{ flexGrow: 1 }}
keyboardShouldPersistTaps="handled" keyboardShouldPersistTaps="handled"
refreshControl={refreshControl}
> >
<TouchableWithoutFeedback onPress={Keyboard.dismiss}> <TouchableWithoutFeedback onPress={Keyboard.dismiss}>
<View style={{ flex: 1 }}> <View style={{ flex: 1 }}>

View File

@@ -59,6 +59,7 @@ import ViewWrapper from "./_ShareComponent/ViewWrapper";
import SearchInput from "./_ShareComponent/SearchInput"; import SearchInput from "./_ShareComponent/SearchInput";
import DummyLandscapeImage from "./_ShareComponent/DummyLandscapeImage"; import DummyLandscapeImage from "./_ShareComponent/DummyLandscapeImage";
import GridComponentView from "./_ShareComponent/GridSectionView"; import GridComponentView from "./_ShareComponent/GridSectionView";
import NewWrapper from "./_ShareComponent/NewWrapper";
// Progress // Progress
import ProgressCustom from "./Progress/ProgressCustom"; import ProgressCustom from "./Progress/ProgressCustom";
// Loader // Loader
@@ -119,6 +120,7 @@ export {
DummyLandscapeImage, DummyLandscapeImage,
GridComponentView, GridComponentView,
Spacing, Spacing,
NewWrapper,
// Stack // Stack
StackCustom, StackCustom,
TabBarBackground, TabBarBackground,

View File

@@ -45,3 +45,23 @@ export const AdminColor = {
// Warna Asli: #002e59 // Warna Asli: #002e59
// Warna Lebih Gelap: #001f3b // Warna Lebih Gelap: #001f3b
// Warna Tergelap: #001323 // Warna Tergelap: #001323
export const PlaceholderColor = {
light: {
text: "#000",
placeholder: "#666",
border: "#ccc",
background: "#fff",
error: "#d00",
icon: "#555",
},
dark: {
text: "#fff",
placeholder: "#aaa",
border: "#444",
background: "#1a1a1a",
error: "#ff4d4d",
icon: "#ccc",
},
};

View File

@@ -24,6 +24,7 @@ type AuthContextType = {
registerUser: (userData: { registerUser: (userData: {
username: string; username: string;
nomor: string; nomor: string;
termsOfServiceAccepted: boolean;
}) => Promise<void>; }) => Promise<void>;
userData: (token: string) => Promise<any>; userData: (token: string) => Promise<any>;
}; };
@@ -71,8 +72,31 @@ export const AuthProvider = ({ children }: { children: React.ReactNode }) => {
const loginWithNomor = async (nomor: string) => { const loginWithNomor = async (nomor: string) => {
setIsLoading(true); setIsLoading(true);
try { try {
console.log("[Masuk provider]", nomor);
const response = await apiLogin({ nomor: nomor }); const response = await apiLogin({ nomor: nomor });
await AsyncStorage.setItem("kode_otp", response.kodeId); console.log("[RESPONSE AUTH]", JSON.stringify(response));
if (response.success) {
console.log("[Keluar provider]", nomor);
Toast.show({
type: "success",
text1: "Sukses",
text2: "Kode OTP berhasil dikirim",
});
await AsyncStorage.setItem("kode_otp", response.kodeId);
router.push(`/verification?nomor=${nomor}`);
return;
} else {
router.push(`/register?nomor=${nomor}`);
Toast.show({
type: "info",
text1: "Info",
text2: "Silahkan mendaftar",
});
return;
}
} catch (error: any) { } catch (error: any) {
throw new Error(error.response?.data?.message || "Gagal kirim OTP"); throw new Error(error.response?.data?.message || "Gagal kirim OTP");
} finally { } finally {
@@ -80,13 +104,26 @@ export const AuthProvider = ({ children }: { children: React.ReactNode }) => {
} }
}; };
// const loginWithNomor = async (nomor: string) => {
// setIsLoading(true);
// try {
// const response = await apiLogin({ nomor: nomor });
// await AsyncStorage.setItem("kode_otp", response.kodeId);
// } catch (error: any) {
// throw new Error(error.response?.data?.message || "Gagal kirim OTP");
// } finally {
// setIsLoading(false);
// }
// };
// --- 2. Validasi OTP & cek user --- // --- 2. Validasi OTP & cek user ---
const validateOtp = async (nomor: string) => { const validateOtp = async (nomor: string) => {
try { try {
setIsLoading(true); setIsLoading(true);
const response = await apiValidationCode({ nomor: nomor }); const response = await apiValidationCode({ nomor: nomor });
const { token } = response; const { token } = response;
console.log("[RESPONSE VALIDASI OTP]", JSON.stringify(response, null, 2));
if (response.success) { if (response.success) {
setToken(token); setToken(token);
await AsyncStorage.setItem("authToken", token); await AsyncStorage.setItem("authToken", token);
@@ -103,20 +140,23 @@ export const AuthProvider = ({ children }: { children: React.ReactNode }) => {
if (response.active) { if (response.active) {
if (response.roleId === "1") { if (response.roleId === "1") {
return "/(application)/(user)/home"; router.replace("/(application)/(user)/home");
return;
} else { } else {
return "/(application)/admin/dashboard"; router.replace("/(application)/admin/dashboard");
return;
} }
} else { } else {
return "/(application)/(user)/waiting-room"; router.replace("/(application)/(user)/waiting-room");
return;
} }
} else { } else {
Toast.show({ Toast.show({
type: "info", type: "info",
text1: "Anda belum terdaftar", text1: "Terjadi kesalahan",
text2: "Silahkan daftar terlebih dahulu", text2: "Silahkan coba lagi",
}); });
return `/register?nomor=${nomor}`; return;
} }
} catch (error: any) { } catch (error: any) {
console.log("Error validasi otp >>", (error as Error).message || error); console.log("Error validasi otp >>", (error as Error).message || error);
@@ -131,6 +171,10 @@ export const AuthProvider = ({ children }: { children: React.ReactNode }) => {
// --- 3. Ambil data user --- // --- 3. Ambil data user ---
const userData = async (token: string) => { const userData = async (token: string) => {
try { try {
if (!token) {
throw new Error("Token tidak ditemukan");
}
setIsLoading(true); setIsLoading(true);
const response = await apiConfig.get(`/mobile?token=${token}`, { const response = await apiConfig.get(`/mobile?token=${token}`, {
headers: { headers: {
@@ -144,7 +188,10 @@ export const AuthProvider = ({ children }: { children: React.ReactNode }) => {
await AsyncStorage.setItem("userData", JSON.stringify(dataUser)); await AsyncStorage.setItem("userData", JSON.stringify(dataUser));
return dataUser; return dataUser;
} catch (error: any) { } catch (error: any) {
console.log(error.response?.data?.message + "user" || "Gagal mengambil data user"); console.log(
"[LOAD USER DATA]",
error.response?.data?.message + "user" || "Gagal mengambil data user"
);
} finally { } finally {
setIsLoading(false); setIsLoading(false);
} }
@@ -154,12 +201,13 @@ export const AuthProvider = ({ children }: { children: React.ReactNode }) => {
const registerUser = async (userData: { const registerUser = async (userData: {
username: string; username: string;
nomor: string; nomor: string;
termsOfServiceAccepted: boolean;
}) => { }) => {
setIsLoading(true); setIsLoading(true);
try { try {
const response = await apiRegister({ data: userData }); const response = await apiRegister({ data: userData });
console.log("[REGISTER FETCH]", JSON.stringify(response, null, 2));
const { token } = response;
if (!response.success) { if (!response.success) {
Toast.show({ Toast.show({
type: "info", type: "info",
@@ -170,23 +218,63 @@ export const AuthProvider = ({ children }: { children: React.ReactNode }) => {
return; return;
} }
setToken(token);
await AsyncStorage.setItem("authToken", token);
Toast.show({ Toast.show({
type: "success", type: "success",
text1: "Sukses", text1: "Sukses",
text2: "Anda berhasil terdaftar", text2: "Anda berhasil terdaftar",
}); });
router.replace("/(application)/(user)/waiting-room"); router.replace(`/verification?nomor=${userData.nomor}`);
return; return;
} catch (error: any) { } catch (error: any) {
Toast.show({
type: "error",
text1: "Error",
text2: error.response?.data?.message || "Gagal mendaftar",
});
console.log("Error register", error); console.log("Error register", error);
} finally { } finally {
setIsLoading(false); setIsLoading(false);
} }
}; };
// const registerUser = async (userData: {
// username: string;
// nomor: string;
// termsOfServiceAccepted: boolean;
// }) => {
// setIsLoading(true);
// try {
// const response = await apiRegister({ data: userData });
// console.log("response", response);
// const { token } = response;
// if (!response.success) {
// Toast.show({
// type: "info",
// text1: "Info",
// text2: response.message,
// });
// return;
// }
// setToken(token);
// await AsyncStorage.setItem("authToken", token);
// Toast.show({
// type: "success",
// text1: "Sukses",
// text2: "Anda berhasil terdaftar",
// });
// router.replace("/(application)/(user)/waiting-room");
// return;
// } catch (error: any) {
// console.log("Error register", error);
// } finally {
// setIsLoading(false);
// }
// };
// --- 5. Logout --- // --- 5. Logout ---
const logout = async () => { const logout = async () => {
try { try {
setIsLoading(true); setIsLoading(true);

29
google-services.json Normal file
View File

@@ -0,0 +1,29 @@
{
"project_info": {
"project_number": "608461535079",
"project_id": "hipmi-badung-connect",
"storage_bucket": "hipmi-badung-connect.firebasestorage.app"
},
"client": [
{
"client_info": {
"mobilesdk_app_id": "1:608461535079:android:4ff12ddc283fb3746761c2",
"android_client_info": {
"package_name": "com.bip.hipmimobileapp"
}
},
"oauth_client": [],
"api_key": [
{
"current_key": "AIzaSyBiDtIk3Q9zffFwIdJ5cjqY7e4390JGSkM"
}
],
"services": {
"appinvite_service": {
"other_platform_oauth_client": []
}
}
}
],
"configuration_version": "1"
}

View File

@@ -11,4 +11,5 @@ Exp: open ios/HIPMIBADUNG.xcworkspace
### Other ### Other
perubahan versi : npm version patch perubahan versi : npm version patch
ios: bunx expo prebuild --platform ios
android: bunx expo prebuild --platform android

View File

@@ -0,0 +1,97 @@
// @/hooks/use-paginated-api.ts
import { useCallback, useState, useEffect, useRef } from "react";
interface UsePaginatedApiProps {
fetcher: (params: { page: number; search?: string }) => Promise<any[]>;
initialSearch?: string; // mengatur nilai awal dari state
pageSize?: number;
dependencies?: any[]; // untuk refresh saat deps berubah (misal: user.id)
}
export const usePaginatedApi = ({
fetcher,
initialSearch = "",
pageSize = 5,
dependencies = [],
}: UsePaginatedApiProps) => {
const [data, setData] = useState<any[]>([]);
const [loading, setLoading] = useState(true);
const [refreshing, setRefreshing] = useState(false);
const [hasMore, setHasMore] = useState(true);
const [page, setPage] = useState(1);
const [search, setSearch] = useState(initialSearch);
const refreshingRef = useRef<boolean>(false);
const loadingRef = useRef<boolean>(false);
const fetchRef = useRef(false);
const fetchData = useCallback(
async (pageNumber: number, clear: boolean) => {
const isRefresh = clear;
// 🔒 Proteksi: jangan jalankan jika sedang refreshing (untuk refresh)
if (isRefresh && refreshingRef.current) return;
// 🔒 Proteksi: jangan jalankan loadMore jika sedang loading
if (!isRefresh && loadingRef.current) return;
const setLoadingState = (isLoading: boolean) => {
if (isRefresh) {
setRefreshing(isLoading);
refreshingRef.current = isLoading;
} else {
setLoading(isLoading);
loadingRef.current = isLoading;
}
};
setLoadingState(true);
try {
const newData = await fetcher({ page: pageNumber, search });
setData((prev) => {
const current = Array.isArray(prev) ? prev : [];
return clear ? newData : [...current, ...newData];
});
setHasMore(newData.length === pageSize);
setPage(pageNumber);
} catch (error) {
console.error("[usePaginatedApi] Error:", error);
setHasMore(false);
} finally {
setLoadingState(false);
}
},
[search, hasMore, pageSize, ...dependencies]
);
const onRefresh = useCallback(() => {
fetchData(1, true);
}, [fetchData]);
const loadMore = useCallback(() => {
if (hasMore && !loading && !refreshing) {
fetchData(page + 1, false);
}
}, [hasMore, loading, refreshing, page, fetchData]);
// Reset & fetch ulang saat search atau deps berubah
useEffect(() => {
if (fetchRef.current) return; // hindari double initial
fetchRef.current = true;
setPage(1);
setData([]);
setHasMore(true);
fetchData(1, true);
}, [search, ...dependencies]);
return {
data,
loading,
refreshing,
hasMore,
search,
setSearch,
onRefresh,
loadMore,
};
};

View File

@@ -272,14 +272,22 @@
); );
inputPaths = ( inputPaths = (
"${PODS_ROOT}/Target Support Files/Pods-HIPMIBadungConnect/Pods-HIPMIBadungConnect-frameworks.sh", "${PODS_ROOT}/Target Support Files/Pods-HIPMIBadungConnect/Pods-HIPMIBadungConnect-frameworks.sh",
"${BUILT_PRODUCTS_DIR}/MapboxMaps/MapboxMaps.framework",
"${PODS_XCFRAMEWORKS_BUILD_DIR}/MapboxCommon/MapboxCommon.framework/MapboxCommon",
"${PODS_XCFRAMEWORKS_BUILD_DIR}/MapboxCoreMaps/MapboxCoreMaps.framework/MapboxCoreMaps",
"${PODS_XCFRAMEWORKS_BUILD_DIR}/React-Core-prebuilt/React.framework/React", "${PODS_XCFRAMEWORKS_BUILD_DIR}/React-Core-prebuilt/React.framework/React",
"${PODS_XCFRAMEWORKS_BUILD_DIR}/ReactNativeDependencies/ReactNativeDependencies.framework/ReactNativeDependencies", "${PODS_XCFRAMEWORKS_BUILD_DIR}/ReactNativeDependencies/ReactNativeDependencies.framework/ReactNativeDependencies",
"${PODS_XCFRAMEWORKS_BUILD_DIR}/Turf/Turf.framework/Turf",
"${PODS_XCFRAMEWORKS_BUILD_DIR}/hermes-engine/Pre-built/hermes.framework/hermes", "${PODS_XCFRAMEWORKS_BUILD_DIR}/hermes-engine/Pre-built/hermes.framework/hermes",
); );
name = "[CP] Embed Pods Frameworks"; name = "[CP] Embed Pods Frameworks";
outputPaths = ( outputPaths = (
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/MapboxMaps.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/MapboxCommon.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/MapboxCoreMaps.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/React.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/React.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/ReactNativeDependencies.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/ReactNativeDependencies.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Turf.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/hermes.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/hermes.framework",
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
@@ -294,8 +302,11 @@
); );
inputPaths = ( inputPaths = (
"${PODS_ROOT}/Target Support Files/Pods-HIPMIBadungConnect/Pods-HIPMIBadungConnect-resources.sh", "${PODS_ROOT}/Target Support Files/Pods-HIPMIBadungConnect/Pods-HIPMIBadungConnect-resources.sh",
"${PODS_CONFIGURATION_BUILD_DIR}/EXApplication/ExpoApplication_privacy.bundle",
"${PODS_CONFIGURATION_BUILD_DIR}/EXConstants/EXConstants.bundle", "${PODS_CONFIGURATION_BUILD_DIR}/EXConstants/EXConstants.bundle",
"${PODS_CONFIGURATION_BUILD_DIR}/EXConstants/ExpoConstants_privacy.bundle", "${PODS_CONFIGURATION_BUILD_DIR}/EXConstants/ExpoConstants_privacy.bundle",
"${PODS_CONFIGURATION_BUILD_DIR}/EXNotifications/ExpoNotifications_privacy.bundle",
"${PODS_CONFIGURATION_BUILD_DIR}/ExpoDevice/ExpoDevice_privacy.bundle",
"${PODS_CONFIGURATION_BUILD_DIR}/ExpoFileSystem/ExpoFileSystem_privacy.bundle", "${PODS_CONFIGURATION_BUILD_DIR}/ExpoFileSystem/ExpoFileSystem_privacy.bundle",
"${PODS_CONFIGURATION_BUILD_DIR}/ExpoSystemUI/ExpoSystemUI_privacy.bundle", "${PODS_CONFIGURATION_BUILD_DIR}/ExpoSystemUI/ExpoSystemUI_privacy.bundle",
"${PODS_CONFIGURATION_BUILD_DIR}/RNCAsyncStorage/RNCAsyncStorage_resources.bundle", "${PODS_CONFIGURATION_BUILD_DIR}/RNCAsyncStorage/RNCAsyncStorage_resources.bundle",
@@ -328,8 +339,11 @@
); );
name = "[CP] Copy Pods Resources"; name = "[CP] Copy Pods Resources";
outputPaths = ( outputPaths = (
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/ExpoApplication_privacy.bundle",
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/EXConstants.bundle", "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/EXConstants.bundle",
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/ExpoConstants_privacy.bundle", "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/ExpoConstants_privacy.bundle",
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/ExpoNotifications_privacy.bundle",
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/ExpoDevice_privacy.bundle",
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/ExpoFileSystem_privacy.bundle", "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/ExpoFileSystem_privacy.bundle",
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/ExpoSystemUI_privacy.bundle", "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/ExpoSystemUI_privacy.bundle",
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/RNCAsyncStorage_resources.bundle", "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/RNCAsyncStorage_resources.bundle",
@@ -387,7 +401,7 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = HIPMIBadungConnect/HIPMIBadungConnect.entitlements; CODE_SIGN_ENTITLEMENTS = HIPMIBadungConnect/HIPMIBadungConnect.entitlements;
CURRENT_PROJECT_VERSION = 1; CURRENT_PROJECT_VERSION = 3;
DEVELOPMENT_TEAM = BMY6GT6W3D; DEVELOPMENT_TEAM = BMY6GT6W3D;
ENABLE_BITCODE = NO; ENABLE_BITCODE = NO;
GCC_PREPROCESSOR_DEFINITIONS = ( GCC_PREPROCESSOR_DEFINITIONS = (
@@ -408,7 +422,7 @@
); );
OTHER_SWIFT_FLAGS = "$(inherited) -D EXPO_CONFIGURATION_DEBUG"; OTHER_SWIFT_FLAGS = "$(inherited) -D EXPO_CONFIGURATION_DEBUG";
PRODUCT_BUNDLE_IDENTIFIER = "com.anonymous.hipmi-mobile"; PRODUCT_BUNDLE_IDENTIFIER = "com.anonymous.hipmi-mobile";
PRODUCT_NAME = HIPMIBadungConnect; PRODUCT_NAME = "HIPMIBadungConnect";
SWIFT_OBJC_BRIDGING_HEADER = "HIPMIBadungConnect/HIPMIBadungConnect-Bridging-Header.h"; SWIFT_OBJC_BRIDGING_HEADER = "HIPMIBadungConnect/HIPMIBadungConnect-Bridging-Header.h";
SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 5.0; SWIFT_VERSION = 5.0;
@@ -424,7 +438,7 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = HIPMIBadungConnect/HIPMIBadungConnect.entitlements; CODE_SIGN_ENTITLEMENTS = HIPMIBadungConnect/HIPMIBadungConnect.entitlements;
CURRENT_PROJECT_VERSION = 1; CURRENT_PROJECT_VERSION = 3;
DEVELOPMENT_TEAM = BMY6GT6W3D; DEVELOPMENT_TEAM = BMY6GT6W3D;
INFOPLIST_FILE = HIPMIBadungConnect/Info.plist; INFOPLIST_FILE = HIPMIBadungConnect/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 15.1; IPHONEOS_DEPLOYMENT_TARGET = 15.1;
@@ -440,7 +454,7 @@
); );
OTHER_SWIFT_FLAGS = "$(inherited) -D EXPO_CONFIGURATION_RELEASE"; OTHER_SWIFT_FLAGS = "$(inherited) -D EXPO_CONFIGURATION_RELEASE";
PRODUCT_BUNDLE_IDENTIFIER = "com.anonymous.hipmi-mobile"; PRODUCT_BUNDLE_IDENTIFIER = "com.anonymous.hipmi-mobile";
PRODUCT_NAME = HIPMIBadungConnect; PRODUCT_NAME = "HIPMIBadungConnect";
SWIFT_OBJC_BRIDGING_HEADER = "HIPMIBadungConnect/HIPMIBadungConnect-Bridging-Header.h"; SWIFT_OBJC_BRIDGING_HEADER = "HIPMIBadungConnect/HIPMIBadungConnect-Bridging-Header.h";
SWIFT_VERSION = 5.0; SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2"; TARGETED_DEVICE_FAMILY = "1,2";

View File

@@ -1,5 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0"> <plist version="1.0">
<dict/> <dict>
<key>aps-environment</key>
<string>development</string>
<key>com.apple.developer.associated-domains</key>
<array>
<string>applinks:cld-dkr-staging-hipmi.wibudev.com</string>
</array>
</dict>
</plist> </plist>

View File

@@ -1,95 +1,101 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0"> <plist version="1.0">
<dict> <dict>
<key>CADisableMinimumFrameDurationOnPhone</key> <key>CADisableMinimumFrameDurationOnPhone</key>
<true/> <true/>
<key>CFBundleDevelopmentRegion</key> <key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string> <string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleDisplayName</key> <key>CFBundleDisplayName</key>
<string>HIPMI Badung Connect</string> <string>HIPMI Badung Connect</string>
<key>CFBundleExecutable</key> <key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string> <string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key> <key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string> <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key> <key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string> <string>6.0</string>
<key>CFBundleName</key> <key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string> <string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key> <key>CFBundlePackageType</key>
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string> <string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
<key>CFBundleShortVersionString</key> <key>CFBundleShortVersionString</key>
<string>1.0.0</string> <string>1.0.1</string>
<key>CFBundleSignature</key> <key>CFBundleSignature</key>
<string>????</string> <string>????</string>
<key>CFBundleURLTypes</key> <key>CFBundleURLTypes</key>
<array> <array>
<dict> <dict>
<key>CFBundleURLSchemes</key> <key>CFBundleURLSchemes</key>
<array> <array>
<string>hipmimobile</string> <string>hipmimobile</string>
<string>com.anonymous.hipmi-mobile</string> <string>com.anonymous.hipmi-mobile</string>
</array> </array>
</dict> </dict>
<dict> <dict>
<key>CFBundleURLSchemes</key> <key>CFBundleURLSchemes</key>
<array> <array>
<string>exp+hipmi-mobile</string> <string>exp+hipmi-mobile</string>
</array> </array>
</dict> </dict>
</array> </array>
<key>CFBundleVersion</key> <key>CFBundleVersion</key>
<string>1</string> <string>14</string>
<key>ITSAppUsesNonExemptEncryption</key> <key>ITSAppUsesNonExemptEncryption</key>
<false/> <false/>
<key>LSMinimumSystemVersion</key> <key>LSMinimumSystemVersion</key>
<string>12.0</string> <string>12.0</string>
<key>LSRequiresIPhoneOS</key> <key>LSRequiresIPhoneOS</key>
<true/> <true/>
<key>NSAppTransportSecurity</key> <key>NSAppTransportSecurity</key>
<dict> <dict>
<key>NSAllowsArbitraryLoads</key> <key>NSAllowsArbitraryLoads</key>
<false/> <false/>
<key>NSAllowsLocalNetworking</key> <key>NSAllowsLocalNetworking</key>
<true/> <true/>
</dict> </dict>
<key>NSCameraUsageDescription</key> <key>NSCameraUsageDescription</key>
<string>Allow $(PRODUCT_NAME) to access your camera</string> <string>Allow $(PRODUCT_NAME) to access your camera</string>
<key>NSMicrophoneUsageDescription</key> <key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>Allow $(PRODUCT_NAME) to access your microphone</string> <string>Allow $(PRODUCT_NAME) to access your location</string>
<key>NSPhotoLibraryUsageDescription</key> <key>NSLocationAlwaysUsageDescription</key>
<string>Allow $(PRODUCT_NAME) to access your photos</string> <string>Allow $(PRODUCT_NAME) to access your location</string>
<key>NSUserActivityTypes</key> <key>NSLocationWhenInUseUsageDescription</key>
<array> <string>Aplikasi membutuhkan akses lokasi untuk menampilkan peta.</string>
<string>$(PRODUCT_BUNDLE_IDENTIFIER).expo.index_route</string> <key>NSMicrophoneUsageDescription</key>
</array> <string>Allow $(PRODUCT_NAME) to access your microphone</string>
<key>RCTNewArchEnabled</key> <key>NSPhotoLibraryUsageDescription</key>
<true/> <string>Untuk mengunggah dokumen dan media bisnis seperti foto profil, logo usaha, poster lowongan, atau bukti transaksi di berbagai fitur aplikasi: Profile, Portofolio, Job Vacancy, Investasi, dan Donasi.</string>
<key>UILaunchStoryboardName</key> <key>NSUserActivityTypes</key>
<string>SplashScreen</string> <array>
<key>UIRequiredDeviceCapabilities</key> <string>$(PRODUCT_BUNDLE_IDENTIFIER).expo.index_route</string>
<array> </array>
<string>arm64</string> <key>RCTNewArchEnabled</key>
</array> <true/>
<key>UIRequiresFullScreen</key> <key>UILaunchStoryboardName</key>
<false/> <string>SplashScreen</string>
<key>UIStatusBarStyle</key> <key>UIRequiredDeviceCapabilities</key>
<string>UIStatusBarStyleDefault</string> <array>
<key>UISupportedInterfaceOrientations</key> <string>arm64</string>
<array> </array>
<string>UIInterfaceOrientationPortrait</string> <key>UIRequiresFullScreen</key>
<string>UIInterfaceOrientationPortraitUpsideDown</string> <false/>
</array> <key>UIStatusBarStyle</key>
<key>UISupportedInterfaceOrientations~ipad</key> <string>UIStatusBarStyleDefault</string>
<array> <key>UISupportedInterfaceOrientations</key>
<string>UIInterfaceOrientationPortrait</string> <array>
<string>UIInterfaceOrientationPortraitUpsideDown</string> <string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationLandscapeLeft</string> <string>UIInterfaceOrientationPortraitUpsideDown</string>
<string>UIInterfaceOrientationLandscapeRight</string> </array>
</array> <key>UISupportedInterfaceOrientations~ipad</key>
<key>UIUserInterfaceStyle</key> <array>
<string>Automatic</string> <string>UIInterfaceOrientationPortrait</string>
<key>UIViewControllerBasedStatusBarAppearance</key> <string>UIInterfaceOrientationPortraitUpsideDown</string>
<false/> <string>UIInterfaceOrientationLandscapeLeft</string>
</dict> <string>UIInterfaceOrientationLandscapeRight</string>
</plist> </array>
<key>UIUserInterfaceStyle</key>
<string>Automatic</string>
<key>UIViewControllerBasedStatusBarAppearance</key>
<false/>
</dict>
</plist>

View File

@@ -4,6 +4,16 @@
<dict> <dict>
<key>NSPrivacyAccessedAPITypes</key> <key>NSPrivacyAccessedAPITypes</key>
<array> <array>
<dict>
<key>NSPrivacyAccessedAPIType</key>
<string>NSPrivacyAccessedAPICategoryFileTimestamp</string>
<key>NSPrivacyAccessedAPITypeReasons</key>
<array>
<string>C617.1</string>
<string>0A2A.1</string>
<string>3B52.1</string>
</array>
</dict>
<dict> <dict>
<key>NSPrivacyAccessedAPIType</key> <key>NSPrivacyAccessedAPIType</key>
<string>NSPrivacyAccessedAPICategoryUserDefaults</string> <string>NSPrivacyAccessedAPICategoryUserDefaults</string>
@@ -14,12 +24,10 @@
</dict> </dict>
<dict> <dict>
<key>NSPrivacyAccessedAPIType</key> <key>NSPrivacyAccessedAPIType</key>
<string>NSPrivacyAccessedAPICategoryFileTimestamp</string> <string>NSPrivacyAccessedAPICategorySystemBootTime</string>
<key>NSPrivacyAccessedAPITypeReasons</key> <key>NSPrivacyAccessedAPITypeReasons</key>
<array> <array>
<string>0A2A.1</string> <string>35F9.1</string>
<string>3B52.1</string>
<string>C617.1</string>
</array> </array>
</dict> </dict>
<dict> <dict>
@@ -31,14 +39,6 @@
<string>85F4.1</string> <string>85F4.1</string>
</array> </array>
</dict> </dict>
<dict>
<key>NSPrivacyAccessedAPIType</key>
<string>NSPrivacyAccessedAPICategorySystemBootTime</string>
<key>NSPrivacyAccessedAPITypeReasons</key>
<array>
<string>35F9.1</string>
</array>
</dict>
</array> </array>
<key>NSPrivacyCollectedDataTypes</key> <key>NSPrivacyCollectedDataTypes</key>
<array/> <array/>

View File

@@ -33,6 +33,13 @@ target 'HIPMIBadungConnect' do
use_frameworks! :linkage => podfile_properties['ios.useFrameworks'].to_sym if podfile_properties['ios.useFrameworks'] use_frameworks! :linkage => podfile_properties['ios.useFrameworks'].to_sym if podfile_properties['ios.useFrameworks']
use_frameworks! :linkage => ENV['USE_FRAMEWORKS'].to_sym if ENV['USE_FRAMEWORKS'] use_frameworks! :linkage => ENV['USE_FRAMEWORKS'].to_sym if ENV['USE_FRAMEWORKS']
# @generated begin pre_installer - expo prebuild (DO NOT MODIFY) sync-c8812095000d6054b846ce74840f0ffb540c2757
pre_install do |installer|
# @generated begin @rnmapbox/maps-pre_installer - expo prebuild (DO NOT MODIFY) sync-ea4905840bf9fcea0acc62e92aa2e784f9d760f8
$RNMapboxMaps.pre_install(installer)
# @generated end @rnmapbox/maps-pre_installer
end
# @generated end pre_installer
use_react_native!( use_react_native!(
:path => config[:reactNativePath], :path => config[:reactNativePath],
:hermes_enabled => podfile_properties['expo.jsEngine'] == nil || podfile_properties['expo.jsEngine'] == 'hermes', :hermes_enabled => podfile_properties['expo.jsEngine'] == nil || podfile_properties['expo.jsEngine'] == 'hermes',
@@ -42,6 +49,9 @@ target 'HIPMIBadungConnect' do
) )
post_install do |installer| post_install do |installer|
# @generated begin @rnmapbox/maps-post_installer - expo prebuild (DO NOT MODIFY) sync-c4e8f90e96f6b6c6ea9241dd7b52ab5f57f7bf36
$RNMapboxMaps.post_install(installer)
# @generated end @rnmapbox/maps-post_installer
react_native_post_install( react_native_post_install(
installer, installer,
config[:reactNativePath], config[:reactNativePath],

View File

@@ -1,5 +1,7 @@
PODS: PODS:
- EXConstants (18.0.8): - EXApplication (7.0.7):
- ExpoModulesCore
- EXConstants (18.0.10):
- ExpoModulesCore - ExpoModulesCore
- EXImageLoader (6.0.0): - EXImageLoader (6.0.0):
- ExpoModulesCore - ExpoModulesCore
@@ -7,6 +9,8 @@ PODS:
- EXJSONUtils (0.15.0) - EXJSONUtils (0.15.0)
- EXManifests (1.0.8): - EXManifests (1.0.8):
- ExpoModulesCore - ExpoModulesCore
- EXNotifications (0.32.13):
- ExpoModulesCore
- Expo (54.0.2): - Expo (54.0.2):
- ExpoModulesCore - ExpoModulesCore
- hermes-engine - hermes-engine
@@ -211,6 +215,8 @@ PODS:
- ZXingObjC/PDF417 - ZXingObjC/PDF417
- ExpoClipboard (8.0.7): - ExpoClipboard (8.0.7):
- ExpoModulesCore - ExpoModulesCore
- ExpoDevice (8.0.9):
- ExpoModulesCore
- ExpoDocumentPicker (14.0.7): - ExpoDocumentPicker (14.0.7):
- ExpoModulesCore - ExpoModulesCore
- ExpoFileSystem (19.0.15): - ExpoFileSystem (19.0.15):
@@ -235,6 +241,8 @@ PODS:
- ExpoModulesCore - ExpoModulesCore
- ExpoLinking (8.0.8): - ExpoLinking (8.0.8):
- ExpoModulesCore - ExpoModulesCore
- ExpoLocation (19.0.7):
- ExpoModulesCore
- ExpoModulesCore (3.0.15): - ExpoModulesCore (3.0.15):
- hermes-engine - hermes-engine
- RCTRequired - RCTRequired
@@ -264,7 +272,7 @@ PODS:
- ExpoModulesCore - ExpoModulesCore
- ExpoSystemUI (6.0.7): - ExpoSystemUI (6.0.7):
- ExpoModulesCore - ExpoModulesCore
- ExpoWebBrowser (15.0.7): - ExpoWebBrowser (15.0.9):
- ExpoModulesCore - ExpoModulesCore
- EXUpdatesInterface (2.0.0): - EXUpdatesInterface (2.0.0):
- ExpoModulesCore - ExpoModulesCore
@@ -289,6 +297,14 @@ PODS:
- libwebp/sharpyuv (1.5.0) - libwebp/sharpyuv (1.5.0)
- libwebp/webp (1.5.0): - libwebp/webp (1.5.0):
- libwebp/sharpyuv - libwebp/sharpyuv
- MapboxCommon (24.15.4):
- Turf (= 4.0.0)
- MapboxCoreMaps (11.15.4):
- MapboxCommon (= 24.15.4)
- MapboxMaps (11.15.4):
- MapboxCommon (= 24.15.4)
- MapboxCoreMaps (= 11.15.4)
- Turf (= 4.0.0)
- RCTDeprecation (0.81.4) - RCTDeprecation (0.81.4)
- RCTRequired (0.81.4) - RCTRequired (0.81.4)
- RCTTypeSafety (0.81.4): - RCTTypeSafety (0.81.4):
@@ -2144,6 +2160,33 @@ PODS:
- ReactCommon/turbomodule/core - ReactCommon/turbomodule/core
- ReactNativeDependencies - ReactNativeDependencies
- Yoga - Yoga
- rnmapbox-maps (10.2.7):
- MapboxMaps (~> 11.15.2)
- React
- React-Core
- rnmapbox-maps/DynamicLibrary (= 10.2.7)
- Turf
- rnmapbox-maps/DynamicLibrary (10.2.7):
- hermes-engine
- MapboxMaps (~> 11.15.2)
- RCTRequired
- RCTTypeSafety
- React
- React-Core
- React-Core-prebuilt
- React-featureflags
- React-ImageManager
- React-jsi
- React-NativeModulesApple
- React-RCTFabric
- React-renderercss
- React-rendererdebug
- ReactCodegen
- ReactCommon/turbomodule/bridging
- ReactCommon/turbomodule/core
- ReactNativeDependencies
- Turf
- Yoga
- RNReanimated (4.1.0): - RNReanimated (4.1.0):
- hermes-engine - hermes-engine
- RCTRequired - RCTRequired
@@ -2414,6 +2457,7 @@ PODS:
- SDWebImageWebPCoder (0.14.6): - SDWebImageWebPCoder (0.14.6):
- libwebp (~> 1.0) - libwebp (~> 1.0)
- SDWebImage/Core (~> 5.17) - SDWebImage/Core (~> 5.17)
- Turf (4.0.0)
- Yoga (0.0.0) - Yoga (0.0.0)
- ZXingObjC/Core (3.6.9) - ZXingObjC/Core (3.6.9)
- ZXingObjC/OneD (3.6.9): - ZXingObjC/OneD (3.6.9):
@@ -2422,10 +2466,12 @@ PODS:
- ZXingObjC/Core - ZXingObjC/Core
DEPENDENCIES: DEPENDENCIES:
- EXApplication (from `../node_modules/expo-application/ios`)
- EXConstants (from `../node_modules/expo-constants/ios`) - EXConstants (from `../node_modules/expo-constants/ios`)
- EXImageLoader (from `../node_modules/expo-image-loader/ios`) - EXImageLoader (from `../node_modules/expo-image-loader/ios`)
- EXJSONUtils (from `../node_modules/expo-json-utils/ios`) - EXJSONUtils (from `../node_modules/expo-json-utils/ios`)
- EXManifests (from `../node_modules/expo-manifests/ios`) - EXManifests (from `../node_modules/expo-manifests/ios`)
- EXNotifications (from `../node_modules/expo-notifications/ios`)
- Expo (from `../node_modules/expo`) - Expo (from `../node_modules/expo`)
- expo-dev-client (from `../node_modules/expo-dev-client/ios`) - expo-dev-client (from `../node_modules/expo-dev-client/ios`)
- expo-dev-launcher (from `../node_modules/expo-dev-launcher`) - expo-dev-launcher (from `../node_modules/expo-dev-launcher`)
@@ -2434,6 +2480,7 @@ DEPENDENCIES:
- ExpoAsset (from `../node_modules/expo-asset/ios`) - ExpoAsset (from `../node_modules/expo-asset/ios`)
- ExpoCamera (from `../node_modules/expo-camera/ios`) - ExpoCamera (from `../node_modules/expo-camera/ios`)
- ExpoClipboard (from `../node_modules/expo-clipboard/ios`) - ExpoClipboard (from `../node_modules/expo-clipboard/ios`)
- ExpoDevice (from `../node_modules/expo-device/ios`)
- ExpoDocumentPicker (from `../node_modules/expo-document-picker/ios`) - ExpoDocumentPicker (from `../node_modules/expo-document-picker/ios`)
- ExpoFileSystem (from `../node_modules/expo-file-system/ios`) - ExpoFileSystem (from `../node_modules/expo-file-system/ios`)
- ExpoFont (from `../node_modules/expo-font/ios`) - ExpoFont (from `../node_modules/expo-font/ios`)
@@ -2443,6 +2490,7 @@ DEPENDENCIES:
- ExpoImagePicker (from `../node_modules/expo-image-picker/ios`) - ExpoImagePicker (from `../node_modules/expo-image-picker/ios`)
- ExpoKeepAwake (from `../node_modules/expo-keep-awake/ios`) - ExpoKeepAwake (from `../node_modules/expo-keep-awake/ios`)
- ExpoLinking (from `../node_modules/expo-linking/ios`) - ExpoLinking (from `../node_modules/expo-linking/ios`)
- ExpoLocation (from `../node_modules/expo-location/ios`)
- ExpoModulesCore (from `../node_modules/expo-modules-core`) - ExpoModulesCore (from `../node_modules/expo-modules-core`)
- ExpoSplashScreen (from `../node_modules/expo-splash-screen/ios`) - ExpoSplashScreen (from `../node_modules/expo-splash-screen/ios`)
- ExpoSymbols (from `../node_modules/expo-symbols/ios`) - ExpoSymbols (from `../node_modules/expo-symbols/ios`)
@@ -2524,6 +2572,7 @@ DEPENDENCIES:
- "RNCAsyncStorage (from `../node_modules/@react-native-async-storage/async-storage`)" - "RNCAsyncStorage (from `../node_modules/@react-native-async-storage/async-storage`)"
- "RNDateTimePicker (from `../node_modules/@react-native-community/datetimepicker`)" - "RNDateTimePicker (from `../node_modules/@react-native-community/datetimepicker`)"
- RNGestureHandler (from `../node_modules/react-native-gesture-handler`) - RNGestureHandler (from `../node_modules/react-native-gesture-handler`)
- "rnmapbox-maps (from `../node_modules/@rnmapbox/maps`)"
- RNReanimated (from `../node_modules/react-native-reanimated`) - RNReanimated (from `../node_modules/react-native-reanimated`)
- RNScreens (from `../node_modules/react-native-screens`) - RNScreens (from `../node_modules/react-native-screens`)
- RNSVG (from `../node_modules/react-native-svg`) - RNSVG (from `../node_modules/react-native-svg`)
@@ -2536,13 +2585,19 @@ SPEC REPOS:
- libavif - libavif
- libdav1d - libdav1d
- libwebp - libwebp
- MapboxCommon
- MapboxCoreMaps
- MapboxMaps
- SDWebImage - SDWebImage
- SDWebImageAVIFCoder - SDWebImageAVIFCoder
- SDWebImageSVGCoder - SDWebImageSVGCoder
- SDWebImageWebPCoder - SDWebImageWebPCoder
- Turf
- ZXingObjC - ZXingObjC
EXTERNAL SOURCES: EXTERNAL SOURCES:
EXApplication:
:path: "../node_modules/expo-application/ios"
EXConstants: EXConstants:
:path: "../node_modules/expo-constants/ios" :path: "../node_modules/expo-constants/ios"
EXImageLoader: EXImageLoader:
@@ -2551,6 +2606,8 @@ EXTERNAL SOURCES:
:path: "../node_modules/expo-json-utils/ios" :path: "../node_modules/expo-json-utils/ios"
EXManifests: EXManifests:
:path: "../node_modules/expo-manifests/ios" :path: "../node_modules/expo-manifests/ios"
EXNotifications:
:path: "../node_modules/expo-notifications/ios"
Expo: Expo:
:path: "../node_modules/expo" :path: "../node_modules/expo"
expo-dev-client: expo-dev-client:
@@ -2567,6 +2624,8 @@ EXTERNAL SOURCES:
:path: "../node_modules/expo-camera/ios" :path: "../node_modules/expo-camera/ios"
ExpoClipboard: ExpoClipboard:
:path: "../node_modules/expo-clipboard/ios" :path: "../node_modules/expo-clipboard/ios"
ExpoDevice:
:path: "../node_modules/expo-device/ios"
ExpoDocumentPicker: ExpoDocumentPicker:
:path: "../node_modules/expo-document-picker/ios" :path: "../node_modules/expo-document-picker/ios"
ExpoFileSystem: ExpoFileSystem:
@@ -2585,6 +2644,8 @@ EXTERNAL SOURCES:
:path: "../node_modules/expo-keep-awake/ios" :path: "../node_modules/expo-keep-awake/ios"
ExpoLinking: ExpoLinking:
:path: "../node_modules/expo-linking/ios" :path: "../node_modules/expo-linking/ios"
ExpoLocation:
:path: "../node_modules/expo-location/ios"
ExpoModulesCore: ExpoModulesCore:
:path: "../node_modules/expo-modules-core" :path: "../node_modules/expo-modules-core"
ExpoSplashScreen: ExpoSplashScreen:
@@ -2746,6 +2807,8 @@ EXTERNAL SOURCES:
:path: "../node_modules/@react-native-community/datetimepicker" :path: "../node_modules/@react-native-community/datetimepicker"
RNGestureHandler: RNGestureHandler:
:path: "../node_modules/react-native-gesture-handler" :path: "../node_modules/react-native-gesture-handler"
rnmapbox-maps:
:path: "../node_modules/@rnmapbox/maps"
RNReanimated: RNReanimated:
:path: "../node_modules/react-native-reanimated" :path: "../node_modules/react-native-reanimated"
RNScreens: RNScreens:
@@ -2760,10 +2823,12 @@ EXTERNAL SOURCES:
:path: "../node_modules/react-native/ReactCommon/yoga" :path: "../node_modules/react-native/ReactCommon/yoga"
SPEC CHECKSUMS: SPEC CHECKSUMS:
EXConstants: 7e4654405af367ff908c863fe77a8a22d60bd37d EXApplication: 296622817d459f46b6c5fe8691f4aac44d2b79e7
EXConstants: fd688cef4e401dcf798a021cfb5d87c890c30ba3
EXImageLoader: 189e3476581efe3ad4d1d3fb4735b7179eb26f05 EXImageLoader: 189e3476581efe3ad4d1d3fb4735b7179eb26f05
EXJSONUtils: 1d3e4590438c3ee593684186007028a14b3686cd EXJSONUtils: 1d3e4590438c3ee593684186007028a14b3686cd
EXManifests: 224345a575fca389073c416297b6348163f28d1a EXManifests: 224345a575fca389073c416297b6348163f28d1a
EXNotifications: a62e1f8e3edd258dc3b155d3caa49f32920f1c6c
Expo: 9e6ddfbc1f5aefde22029899293c701f1d34c2b1 Expo: 9e6ddfbc1f5aefde22029899293c701f1d34c2b1
expo-dev-client: f3434d6ca09ecb14ae48c2a3912bdbb07464cc85 expo-dev-client: f3434d6ca09ecb14ae48c2a3912bdbb07464cc85
expo-dev-launcher: b9538b1e0dc3fd2ddad75017b6ee9c8dfb206925 expo-dev-launcher: b9538b1e0dc3fd2ddad75017b6ee9c8dfb206925
@@ -2772,6 +2837,7 @@ SPEC CHECKSUMS:
ExpoAsset: 84810d6fed8179f04d4a7a4a6b37028bbd726e26 ExpoAsset: 84810d6fed8179f04d4a7a4a6b37028bbd726e26
ExpoCamera: ae1d6691b05b753261a845536d2b19a9788a8750 ExpoCamera: ae1d6691b05b753261a845536d2b19a9788a8750
ExpoClipboard: af650d14765f19c60ce2a1eaf9dfe6445eff7365 ExpoClipboard: af650d14765f19c60ce2a1eaf9dfe6445eff7365
ExpoDevice: 148accb4071873d19fba80a2506c58ffa433d620
ExpoDocumentPicker: 2200eefc2817f19315fa18f0147e0b80ece86926 ExpoDocumentPicker: 2200eefc2817f19315fa18f0147e0b80ece86926
ExpoFileSystem: 5fb091ea11198e109ceef2bdef2e6e66523e62c4 ExpoFileSystem: 5fb091ea11198e109ceef2bdef2e6e66523e62c4
ExpoFont: 86ceec09ffed1c99cfee36ceb79ba149074901b5 ExpoFont: 86ceec09ffed1c99cfee36ceb79ba149074901b5
@@ -2781,17 +2847,21 @@ SPEC CHECKSUMS:
ExpoImagePicker: d251aab45a1b1857e4156fed88511b278b4eee1c ExpoImagePicker: d251aab45a1b1857e4156fed88511b278b4eee1c
ExpoKeepAwake: 1a2e820692e933c94a565ec3fbbe38ac31658ffe ExpoKeepAwake: 1a2e820692e933c94a565ec3fbbe38ac31658ffe
ExpoLinking: f051f28e50ea9269ff539317c166adec81d9342d ExpoLinking: f051f28e50ea9269ff539317c166adec81d9342d
ExpoLocation: 93d7faa0c2adbd5a04686af0c1a61bc6ed3ee2f7
ExpoModulesCore: 9281d8f1cda9d0c37dbce34c26014212b22eb8c0 ExpoModulesCore: 9281d8f1cda9d0c37dbce34c26014212b22eb8c0
ExpoSplashScreen: 0634b705953e6934a5156397162eefc1ee5d6a7c ExpoSplashScreen: 0634b705953e6934a5156397162eefc1ee5d6a7c
ExpoSymbols: 1ae04ce686de719b9720453b988d8bc5bf776c68 ExpoSymbols: 1ae04ce686de719b9720453b988d8bc5bf776c68
ExpoSystemUI: 6cd74248a2282adf6dec488a75fa532d69dee314 ExpoSystemUI: 6cd74248a2282adf6dec488a75fa532d69dee314
ExpoWebBrowser: 533bc2a1b188eec1c10e4926decf658f1687b5e5 ExpoWebBrowser: b973e1351fdcf5fec0c400997b1851f5a8219ec3
EXUpdatesInterface: 5adf50cb41e079c861da6d9b4b954c3db9a50734 EXUpdatesInterface: 5adf50cb41e079c861da6d9b4b954c3db9a50734
FBLazyVector: 9e0cd874afd81d9a4d36679daca991b58b260d42 FBLazyVector: 9e0cd874afd81d9a4d36679daca991b58b260d42
hermes-engine: 35c763d57c9832d0eef764316ca1c4d043581394 hermes-engine: 35c763d57c9832d0eef764316ca1c4d043581394
libavif: 84bbb62fb232c3018d6f1bab79beea87e35de7b7 libavif: 84bbb62fb232c3018d6f1bab79beea87e35de7b7
libdav1d: 23581a4d8ec811ff171ed5e2e05cd27bad64c39f libdav1d: 23581a4d8ec811ff171ed5e2e05cd27bad64c39f
libwebp: 02b23773aedb6ff1fd38cec7a77b81414c6842a8 libwebp: 02b23773aedb6ff1fd38cec7a77b81414c6842a8
MapboxCommon: 975faa94b893bb64a1d28b09d9d6d820e1030a26
MapboxCoreMaps: 105af9894d850290fbb466e9f9a133f5d175abf1
MapboxMaps: e97e59d6ba48bb6f695a4c1dc2f174cb24743cd4
RCTDeprecation: 7487d6dda857ccd4cb3dd6ecfccdc3170e85dcbc RCTDeprecation: 7487d6dda857ccd4cb3dd6ecfccdc3170e85dcbc
RCTRequired: 54128b7df8be566881d48c7234724a78cb9b6157 RCTRequired: 54128b7df8be566881d48c7234724a78cb9b6157
RCTTypeSafety: d2b07797a79e45d7b19e1cd2f53c79ab419fe217 RCTTypeSafety: d2b07797a79e45d7b19e1cd2f53c79ab419fe217
@@ -2864,6 +2934,7 @@ SPEC CHECKSUMS:
RNCAsyncStorage: 3a4f5e2777dae1688b781a487923a08569e27fe4 RNCAsyncStorage: 3a4f5e2777dae1688b781a487923a08569e27fe4
RNDateTimePicker: be0e44bcb9ed0607c7c5f47dbedd88cf091f6791 RNDateTimePicker: be0e44bcb9ed0607c7c5f47dbedd88cf091f6791
RNGestureHandler: 2914750df066d89bf9d8f48a10ad5f0051108ac3 RNGestureHandler: 2914750df066d89bf9d8f48a10ad5f0051108ac3
rnmapbox-maps: 3c20ce786a7991498445c32de4fe4244e32aa0ee
RNReanimated: 8d3a14606ad49f022c17d9e12a2d339e9e5ad9b0 RNReanimated: 8d3a14606ad49f022c17d9e12a2d339e9e5ad9b0
RNScreens: d8d6f1792f6e7ac12b0190d33d8d390efc0c1845 RNScreens: d8d6f1792f6e7ac12b0190d33d8d390efc0c1845
RNSVG: 31d6639663c249b7d5abc9728dde2041eb2a3c34 RNSVG: 31d6639663c249b7d5abc9728dde2041eb2a3c34
@@ -2873,9 +2944,10 @@ SPEC CHECKSUMS:
SDWebImageAVIFCoder: 00310d246aab3232ce77f1d8f0076f8c4b021d90 SDWebImageAVIFCoder: 00310d246aab3232ce77f1d8f0076f8c4b021d90
SDWebImageSVGCoder: 15a300a97ec1c8ac958f009c02220ac0402e936c SDWebImageSVGCoder: 15a300a97ec1c8ac958f009c02220ac0402e936c
SDWebImageWebPCoder: e38c0a70396191361d60c092933e22c20d5b1380 SDWebImageWebPCoder: e38c0a70396191361d60c092933e22c20d5b1380
Turf: c9eb11a65d96af58cac523460fd40fec5061b081
Yoga: 051f086b5ccf465ff2ed38a2cf5a558ae01aaaa1 Yoga: 051f086b5ccf465ff2ed38a2cf5a558ae01aaaa1
ZXingObjC: 8898711ab495761b2dbbdec76d90164a6d7e14c5 ZXingObjC: 8898711ab495761b2dbbdec76d90164a6d7e14c5
PODFILE CHECKSUM: 08ec3cea5bbb38596b0b014c2569f7bd48b51230 PODFILE CHECKSUM: 961e5122c387eef49538723a9e3e7a469ca4144f
COCOAPODS: 1.16.2 COCOAPODS: 1.16.2

View File

@@ -19,6 +19,7 @@
"@react-navigation/elements": "^2.3.8", "@react-navigation/elements": "^2.3.8",
"@react-navigation/native": "^7.1.6", "@react-navigation/native": "^7.1.6",
"@react-navigation/native-stack": "^7.3.10", "@react-navigation/native-stack": "^7.3.10",
"@rnmapbox/maps": "^10.2.7",
"@types/lodash": "^4.17.20", "@types/lodash": "^4.17.20",
"@types/react-native-vector-icons": "^6.4.18", "@types/react-native-vector-icons": "^6.4.18",
"axios": "^1.11.0", "axios": "^1.11.0",
@@ -26,22 +27,27 @@
"expo": "^54.0.0", "expo": "^54.0.0",
"expo-camera": "~17.0.7", "expo-camera": "~17.0.7",
"expo-clipboard": "~8.0.7", "expo-clipboard": "~8.0.7",
"expo-constants": "~18.0.8", "expo-constants": "^18.0.10",
"expo-dev-client": "~6.0.12", "expo-dev-client": "~6.0.12",
"expo-device": "^8.0.9",
"expo-document-picker": "~14.0.7", "expo-document-picker": "~14.0.7",
"expo-file-system": "^19.0.15", "expo-file-system": "^19.0.15",
"expo-font": "~14.0.8", "expo-font": "~14.0.8",
"expo-haptics": "~15.0.7", "expo-haptics": "~15.0.7",
"expo-image": "~3.0.8", "expo-image": "~3.0.8",
"expo-image-picker": "~17.0.8", "expo-image-picker": "~17.0.8",
"expo-linear-gradient": "~15.0.7",
"expo-linking": "~8.0.8", "expo-linking": "~8.0.8",
"expo-location": "~19.0.7",
"expo-notifications": "^0.32.13",
"expo-router": "~6.0.1", "expo-router": "~6.0.1",
"expo-splash-screen": "~31.0.9", "expo-splash-screen": "~31.0.9",
"expo-status-bar": "~3.0.8", "expo-status-bar": "~3.0.8",
"expo-symbols": "~1.0.7", "expo-symbols": "~1.0.7",
"expo-system-ui": "~6.0.7", "expo-system-ui": "~6.0.7",
"expo-web-browser": "~15.0.7", "expo-web-browser": "~15.0.9",
"lodash": "^4.17.21", "lodash": "^4.17.21",
"moti": "^0.30.0",
"react": "19.1.0", "react": "19.1.0",
"react-dom": "19.1.0", "react-dom": "19.1.0",
"react-native": "0.81.4", "react-native": "0.81.4",

View File

@@ -1,3 +1,4 @@
import { NewWrapper } from "@/components";
import ButtonCustom from "@/components/Button/ButtonCustom"; import ButtonCustom from "@/components/Button/ButtonCustom";
import Spacing from "@/components/_ShareComponent/Spacing"; import Spacing from "@/components/_ShareComponent/Spacing";
import ViewWrapper from "@/components/_ShareComponent/ViewWrapper"; import ViewWrapper from "@/components/_ShareComponent/ViewWrapper";
@@ -5,9 +6,11 @@ import { MainColor } from "@/constants/color-palet";
import { useAuth } from "@/hooks/use-auth"; import { useAuth } from "@/hooks/use-auth";
import { apiVersion } from "@/service/api-config"; import { apiVersion } from "@/service/api-config";
import { GStyles } from "@/styles/global-styles"; import { GStyles } from "@/styles/global-styles";
import { Redirect, router } from "expo-router"; import versionBadge from "@/utils/viersionBadge";
import VersionBadge from "@/utils/viersionBadge";
import { Redirect } from "expo-router";
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import { Text, View } from "react-native"; import { RefreshControl, Text, View } from "react-native";
import PhoneInput, { ICountry } from "react-native-international-phone-number"; import PhoneInput, { ICountry } from "react-native-international-phone-number";
import Toast from "react-native-toast-message"; import Toast from "react-native-toast-message";
@@ -16,6 +19,7 @@ export default function LoginView() {
const [selectedCountry, setSelectedCountry] = useState<null | ICountry>(null); const [selectedCountry, setSelectedCountry] = useState<null | ICountry>(null);
const [inputValue, setInputValue] = useState<string>(""); const [inputValue, setInputValue] = useState<string>("");
const [loading, setLoading] = useState<boolean>(false); const [loading, setLoading] = useState<boolean>(false);
const [refreshing, setRefreshing] = useState<boolean>(false);
const { loginWithNomor, token, isAdmin, isUserActive } = useAuth(); const { loginWithNomor, token, isAdmin, isUserActive } = useAuth();
@@ -25,7 +29,18 @@ export default function LoginView() {
async function onLoadVersion() { async function onLoadVersion() {
const res = await apiVersion(); const res = await apiVersion();
setVersion(res.data);
if (res.success) {
setVersion(versionBadge());
}
}
async function handleRefresh() {
setRefreshing(true);
await onLoadVersion();
setInputValue("");
setLoading(false);
setRefreshing(false);
} }
function handleInputValue(phoneNumber: string) { function handleInputValue(phoneNumber: string) {
@@ -66,21 +81,13 @@ export default function LoginView() {
if (!isValid) return; if (!isValid) return;
const callingCode = selectedCountry?.callingCode.replace(/^\+/, "") || ""; const callingCode = selectedCountry?.callingCode.replace(/^\+/, "") || "";
const fixNumber = inputValue.replace(/\s+/g, ""); let fixNumber = inputValue.replace(/\s+/g, "").replace(/^0+/, "");
const realNumber = callingCode + fixNumber; const realNumber = callingCode + fixNumber;
try { try {
setLoading(true); setLoading(true);
// const response = await apiLogin({ nomor: realNumber });
await loginWithNomor(realNumber); await loginWithNomor(realNumber);
Toast.show({
type: "success",
text1: "Sukses",
text2: "Kode OTP berhasil dikirim",
});
router.navigate(`/verification?nomor=${realNumber}`);
} catch (error) { } catch (error) {
console.log("Error login", error); console.log("Error login", error);
Toast.show({ Toast.show({
@@ -91,6 +98,30 @@ export default function LoginView() {
} finally { } finally {
setLoading(false); setLoading(false);
} }
// try {
// setLoading(true);
// // const response = await apiLogin({ nomor: realNumber });
// const response = await loginWithNomor(realNumber);
// console.log("[RESPONSE]", response);
// Toast.show({
// type: "success",
// text1: "Sukses",
// text2: "Kode OTP berhasil dikirim",
// });
// // router.navigate(`/verification?nomor=${realNumber}`);
// } catch (error) {
// console.log("Error login", error);
// Toast.show({
// type: "error",
// text1: "Error",
// text2: error as string,
// });
// } finally {
// setLoading(false);
// }
} }
if (token && token !== "" && !isUserActive) { if (token && token !== "" && !isUserActive) {
@@ -102,11 +133,20 @@ export default function LoginView() {
} }
if (token && token !== "" && isAdmin) { if (token && token !== "" && isAdmin) {
return <Redirect href={"/(application)/admin/dashboard"} />; // Akan di aktifkan jika sudah losos review
// return <Redirect href={"/(application)/admin/dashboard"} />;
// Sementara gunakan ini
return <Redirect href={"/(application)/(user)/home"} />;
} }
return ( return (
<ViewWrapper withBackground> <NewWrapper
withBackground
refreshControl={
<RefreshControl refreshing={refreshing} onRefresh={handleRefresh} />
}
>
<View style={GStyles.authContainer}> <View style={GStyles.authContainer}>
<View> <View>
<View style={GStyles.authContainerTitle}> <View style={GStyles.authContainerTitle}>
@@ -150,6 +190,6 @@ export default function LoginView() {
Coba Coba
</ButtonCustom> */} </ButtonCustom> */}
</View> </View>
</ViewWrapper> </NewWrapper>
); );
} }

View File

@@ -1,10 +1,13 @@
import { CheckboxCustom } from "@/components";
import Spacing from "@/components/_ShareComponent/Spacing"; import Spacing from "@/components/_ShareComponent/Spacing";
import ViewWrapper from "@/components/_ShareComponent/ViewWrapper"; import ViewWrapper from "@/components/_ShareComponent/ViewWrapper";
import ButtonCustom from "@/components/Button/ButtonCustom"; import ButtonCustom from "@/components/Button/ButtonCustom";
import TextInputCustom from "@/components/TextInput/TextInputCustom"; import TextInputCustom from "@/components/TextInput/TextInputCustom";
import { MainColor } from "@/constants/color-palet"; import { MainColor } from "@/constants/color-palet";
import { useAuth } from "@/hooks/use-auth"; import { useAuth } from "@/hooks/use-auth";
import { BASE_URL } from "@/service/api-config";
import { GStyles } from "@/styles/global-styles"; import { GStyles } from "@/styles/global-styles";
import { openBrowser } from "@/utils/openBrower";
import { MaterialCommunityIcons } from "@expo/vector-icons"; import { MaterialCommunityIcons } from "@expo/vector-icons";
import { useLocalSearchParams } from "expo-router"; import { useLocalSearchParams } from "expo-router";
import { useState } from "react"; import { useState } from "react";
@@ -14,7 +17,8 @@ import Toast from "react-native-toast-message";
export default function RegisterView() { export default function RegisterView() {
const { nomor } = useLocalSearchParams(); const { nomor } = useLocalSearchParams();
const [username, setUsername] = useState(""); const [username, setUsername] = useState("");
const [term, setTerm] = useState(false);
const url = BASE_URL;
const { registerUser, isLoading } = useAuth(); const { registerUser, isLoading } = useAuth();
const validasiData = () => { const validasiData = () => {
@@ -61,6 +65,7 @@ export default function RegisterView() {
await registerUser({ await registerUser({
nomor: nomor as string, nomor: nomor as string,
username: usernameLower, username: usernameLower,
termsOfServiceAccepted: term,
}); });
} }
@@ -96,7 +101,39 @@ export default function RegisterView() {
} }
/> />
<ButtonCustom isLoading={isLoading} onPress={handleRegister}> <View
style={{
flexDirection: "row",
alignItems: "center",
marginTop: 16,
marginBottom: 16,
}}
>
<CheckboxCustom value={term} onChange={() => setTerm(!term)} />
<Text style={GStyles.textLabel}>
Saya setuju dengan{" "}
<Text
style={{
color: MainColor.yellow,
textDecorationLine: "underline",
}}
onPress={() => {
const toUrl = `${url}/terms-of-service.html`;
openBrowser(toUrl);
}}
>
Syarat & Ketentuan
</Text>{" "}
yang melarang konten tidak pantas dan perilaku merugikan.
</Text>
</View>
<ButtonCustom
disabled={!term}
isLoading={isLoading}
onPress={handleRegister}
>
Daftar Daftar
</ButtonCustom> </ButtonCustom>
</View> </View>

View File

@@ -5,6 +5,7 @@ import { MainColor } from "@/constants/color-palet";
import { useAuth } from "@/hooks/use-auth"; import { useAuth } from "@/hooks/use-auth";
import { apiCheckCodeOtp } from "@/service/api-config"; import { apiCheckCodeOtp } from "@/service/api-config";
import { GStyles } from "@/styles/global-styles"; import { GStyles } from "@/styles/global-styles";
import { registerForPushNotificationsAsync } from "@/utils/notifications";
import AsyncStorage from "@react-native-async-storage/async-storage"; import AsyncStorage from "@react-native-async-storage/async-storage";
import { router, useLocalSearchParams } from "expo-router"; import { router, useLocalSearchParams } from "expo-router";
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
@@ -16,6 +17,8 @@ import Toast from "react-native-toast-message";
export default function VerificationView() { export default function VerificationView() {
const { nomor } = useLocalSearchParams<{ nomor: string }>(); const { nomor } = useLocalSearchParams<{ nomor: string }>();
console.log("[NOMOR]", nomor);
const [inputOtp, setInputOtp] = useState<string>(""); const [inputOtp, setInputOtp] = useState<string>("");
const [userNumber, setUserNumber] = useState<string>(""); const [userNumber, setUserNumber] = useState<string>("");
const [loading, setLoading] = useState<boolean>(false); const [loading, setLoading] = useState<boolean>(false);
@@ -28,7 +31,7 @@ export default function VerificationView() {
nomor === "6282340374412"; nomor === "6282340374412";
// --- Context --- // --- Context ---
const { validateOtp, isLoading } = useAuth(); const { validateOtp, isLoading, loginWithNomor } = useAuth();
useEffect(() => { useEffect(() => {
setUserNumber(nomor?.replace(/^\+/, "") || ""); setUserNumber(nomor?.replace(/^\+/, "") || "");
@@ -51,7 +54,7 @@ export default function VerificationView() {
try { try {
const response = await apiCheckCodeOtp({ kodeId }); const response = await apiCheckCodeOtp({ kodeId });
console.log( console.log(
"Response check code otp >>", "[OTP] >>",
JSON.stringify(response.otp, null, 2) JSON.stringify(response.otp, null, 2)
); );
// Kita tidak perlu simpan codeOtp di state karena verifikasi dilakukan di backend // Kita tidak perlu simpan codeOtp di state karena verifikasi dilakukan di backend
@@ -70,6 +73,9 @@ export default function VerificationView() {
try { try {
setLoading(true); setLoading(true);
await loginWithNomor(nomor as string);
setRecodeOtp(true);
// ❌ Kamu tidak punya nomor di sini, jadi pastikan `nomor` tersedia // ❌ Kamu tidak punya nomor di sini, jadi pastikan `nomor` tersedia
// Sebaiknya simpan nomor saat login, atau gunakan dari `useLocalSearchParams` // Sebaiknya simpan nomor saat login, atau gunakan dari `useLocalSearchParams`
router.setParams({ nomor }); // opsional router.setParams({ nomor }); // opsional
@@ -85,8 +91,9 @@ export default function VerificationView() {
// ✅ VERIFIKASI OTOMATIS UNTUK APPLE REVIEW // ✅ VERIFIKASI OTOMATIS UNTUK APPLE REVIEW
if (inputOtp === "1234") { if (inputOtp === "1234") {
try { try {
const response = await validateOtp(nomor as string); await validateOtp(nomor as string);
router.replace(response);
return;
} catch (error) { } catch (error) {
console.log("Error verification", error); console.log("Error verification", error);
Toast.show({ type: "error", text1: "Gagal verifikasi" }); Toast.show({ type: "error", text1: "Gagal verifikasi" });
@@ -99,8 +106,8 @@ export default function VerificationView() {
// 🔁 VERIFIKASI NORMAL (untuk pengguna sungguhan) // 🔁 VERIFIKASI NORMAL (untuk pengguna sungguhan)
try { try {
const response = await validateOtp(nomor as string); await validateOtp(nomor as string);
router.replace(response); return
} catch (error) { } catch (error) {
console.log("Error verification", error); console.log("Error verification", error);
Toast.show({ type: "error", text1: "Gagal verifikasi" }); Toast.show({ type: "error", text1: "Gagal verifikasi" });

View File

@@ -25,7 +25,7 @@ function Collaboration_BoxPublishSection({
name={data?.Author?.username || "Username"} name={data?.Author?.username || "Username"}
rightComponent={rightComponentAvatar} rightComponent={rightComponentAvatar}
avatar={data?.Author?.Profile?.imageId} avatar={data?.Author?.Profile?.imageId}
withBottomLine // withBottomLine
/> />
<StackCustom style={{paddingBlock: 10}}> <StackCustom style={{paddingBlock: 10}}>

View File

@@ -50,7 +50,7 @@ export default function Event_BoxDetailPublishSection({
<Grid.Col span={4}> <Grid.Col span={4}>
<TextCustom bold>{item.title}</TextCustom> <TextCustom bold>{item.title}</TextCustom>
</Grid.Col> </Grid.Col>
<Grid.Col span={8}> <Grid.Col span={8} style={{ paddingLeft: 10 }}>
<TextCustom>{item.value}</TextCustom> <TextCustom>{item.value}</TextCustom>
</Grid.Col> </Grid.Col>
</Grid> </Grid>

Some files were not shown because too many files have changed in this diff Show More