diff --git a/app/(application)/coba/index.tsx b/app/(application)/coba/index.tsx
index 65e2c9e..3731644 100644
--- a/app/(application)/coba/index.tsx
+++ b/app/(application)/coba/index.tsx
@@ -1,3 +1,4 @@
+/* eslint-disable @typescript-eslint/no-unused-vars */
import React from "react";
import {
View,
@@ -11,6 +12,8 @@ import { Ionicons } from "@expo/vector-icons";
import { router, Stack } from "expo-router";
import EventDetailScreen from "./double-scroll";
import LeftButtonCustom from "@/components/Button/BackButton";
+import CustomUploadButton from "./upload-button";
+import { SafeAreaView } from "react-native-safe-area-context";
const { width } = Dimensions.get("window");
@@ -117,14 +120,38 @@ const CustomTabNavigator = () => {
const ActiveComponent = getActiveComponent();
+ const handleImageUpload = (file: any) => {
+ console.log("Gambar dipilih:", file);
+ // Upload ke server
+ };
+
+ const handlePdfOrPngUpload = (file: any) => {
+ console.log("PDF atau PNG dipilih:", file);
+ };
+
return (
<>
-
-
+
+
+
+
+
+
+ {/* Hanya PDF atau PNG */}
+
+
>
//
// {/* Content Area */}
diff --git a/app/(application)/coba/upload-button.tsx b/app/(application)/coba/upload-button.tsx
new file mode 100644
index 0000000..494d014
--- /dev/null
+++ b/app/(application)/coba/upload-button.tsx
@@ -0,0 +1,99 @@
+// components/CustomUploadButton.tsx
+import React from 'react';
+import { Button, Alert, View, StyleSheet } from 'react-native';
+import * as DocumentPicker from 'expo-document-picker';
+import { isValidFileType, getMimeType } from '../../../utils/fileValidation';
+
+interface UploadButtonProps {
+ allowedExtensions: string[];
+ buttonTitle?: string;
+ onFileSelected?: (file: {
+ uri: string;
+ name: string;
+ size: number | null;
+ mimeType: string;
+ }) => void;
+}
+
+const CustomUploadButton: React.FC = ({
+ allowedExtensions,
+ buttonTitle = 'Pilih File',
+ onFileSelected,
+}) => {
+ const handlePickFile = async () => {
+ try {
+ // Coba filter dengan MIME type jika memungkinkan
+ const typeFilter = getMimeTypeFilter(allowedExtensions);
+
+ const result = await DocumentPicker.getDocumentAsync({
+ type: typeFilter, // Ini membantu memfilter di UI pemilih
+ copyToCacheDirectory: true,
+ });
+
+ if (result.canceled) {
+ Alert.alert('Dibatalkan', 'Tidak ada file yang dipilih.');
+ return;
+ }
+
+ const file = result.assets[0];
+ const { uri, name, size } = file;
+
+ // Validasi ekstensi secara manual (cadangan jika MIME tidak akurat)
+ if (!isValidFileType(name, allowedExtensions)) {
+ Alert.alert(
+ 'Format Tidak Didukung',
+ `Hanya file dengan ekstensi berikut yang diperbolehkan: ${allowedExtensions.join(', ')}`
+ );
+ return;
+ }
+
+ const mimeType = getMimeType(name);
+
+ // Kirim data file ke komponen induk
+ if (onFileSelected) {
+ onFileSelected({ uri, name, size: size || null, mimeType });
+ }
+
+ Alert.alert('Berhasil', `File ${name} berhasil dipilih!`);
+ } catch (error) {
+ console.error('Error picking file:', error);
+ Alert.alert('Error', 'Terjadi kesalahan saat memilih file.');
+ }
+ };
+
+ return (
+
+
+
+ );
+};
+
+// Fungsi bantu untuk menghasilkan MIME type filter dari ekstensi
+const getMimeTypeFilter = (extensions: string[]): string => {
+ const mimeTypes: string[] = [];
+ extensions.forEach((ext) => {
+ switch (ext.toLowerCase()) {
+ case 'jpg':
+ case 'jpeg':
+ if (!mimeTypes.includes('image/jpeg')) mimeTypes.push('image/jpeg');
+ break;
+ case 'png':
+ if (!mimeTypes.includes('image/png')) mimeTypes.push('image/png');
+ break;
+ case 'pdf':
+ if (!mimeTypes.includes('application/pdf')) mimeTypes.push('application/pdf');
+ break;
+ default:
+ mimeTypes.push('*/*'); // fallback
+ }
+ });
+ return mimeTypes.length > 0 ? mimeTypes.join(',') : '*/*';
+};
+
+const styles = StyleSheet.create({
+ container: {
+ marginVertical: 10,
+ },
+});
+
+export default CustomUploadButton;
\ No newline at end of file
diff --git a/bun.lock b/bun.lock
index af418e5..1bce108 100644
--- a/bun.lock
+++ b/bun.lock
@@ -18,6 +18,8 @@
"expo-camera": "~16.1.10",
"expo-clipboard": "~7.1.5",
"expo-constants": "~17.1.7",
+ "expo-document-picker": "~13.1.6",
+ "expo-file-system": "~18.1.11",
"expo-font": "~13.3.2",
"expo-haptics": "~14.1.4",
"expo-image": "~2.3.2",
@@ -833,6 +835,8 @@
"expo-constants": ["expo-constants@17.1.7", "", { "dependencies": { "@expo/config": "~11.0.12", "@expo/env": "~1.0.7" }, "peerDependencies": { "expo": "*", "react-native": "*" } }, "sha512-byBjGsJ6T6FrLlhOBxw4EaiMXrZEn/MlUYIj/JAd+FS7ll5X/S4qVRbIimSJtdW47hXMq0zxPfJX6njtA56hHA=="],
+ "expo-document-picker": ["expo-document-picker@13.1.6", "", { "peerDependencies": { "expo": "*" } }, "sha512-8FTQPDOkyCvFN/i4xyqzH7ELW4AsB6B3XBZQjn1FEdqpozo6rpNJRr7sWFU/93WrLgA9FJEKpKbyr6XxczK6BA=="],
+
"expo-file-system": ["expo-file-system@18.1.11", "", { "peerDependencies": { "expo": "*", "react-native": "*" } }, "sha512-HJw/m0nVOKeqeRjPjGdvm+zBi5/NxcdPf8M8P3G2JFvH5Z8vBWqVDic2O58jnT1OFEy0XXzoH9UqFu7cHg9DTQ=="],
"expo-font": ["expo-font@13.3.2", "", { "dependencies": { "fontfaceobserver": "^2.1.0" }, "peerDependencies": { "expo": "*", "react": "*" } }, "sha512-wUlMdpqURmQ/CNKK/+BIHkDA5nGjMqNlYmW0pJFXY/KE/OG80Qcavdu2sHsL4efAIiNGvYdBS10WztuQYU4X0A=="],
diff --git a/package.json b/package.json
index b790716..2e57b6f 100644
--- a/package.json
+++ b/package.json
@@ -25,6 +25,8 @@
"expo-camera": "~16.1.10",
"expo-clipboard": "~7.1.5",
"expo-constants": "~17.1.7",
+ "expo-document-picker": "~13.1.6",
+ "expo-file-system": "~18.1.11",
"expo-font": "~13.3.2",
"expo-haptics": "~14.1.4",
"expo-image": "~2.3.2",
diff --git a/utils/fileValidation.ts b/utils/fileValidation.ts
new file mode 100644
index 0000000..6ae2010
--- /dev/null
+++ b/utils/fileValidation.ts
@@ -0,0 +1,34 @@
+// utils/fileValidation.ts
+const ALLOWED_TYPES: Record = {
+ image: ["jpeg", "jpg", "png"],
+ document: ["pdf", "png"],
+ pdf: ["pdf"],
+ png: ["png"],
+};
+
+export const isValidFileType = (
+ fileName: string,
+ allowedExtensions: string[]
+): boolean => {
+ const extension = fileName.split(".").pop()?.toLowerCase();
+ return !!extension && allowedExtensions.includes(extension);
+};
+
+// Helper: Dapatkan MIME type berdasarkan ekstensi (opsional)
+export const getMimeType = (fileName: string): string => {
+ const ext = fileName.split(".").pop()?.toLowerCase();
+ switch (ext) {
+ case "jpg":
+ return "image/jpg";
+ case "jpeg":
+ return "image/jpeg";
+ case "png":
+ return "image/png";
+ case "pdf":
+ return "application/pdf";
+ default:
+ return "application/octet-stream";
+ }
+};
+
+export default ALLOWED_TYPES;