upload file is working
This commit is contained in:
@@ -43,24 +43,6 @@ class ApiClient {
|
||||
async delete<T>(endpoint: string): Promise<T> {
|
||||
return this.request<T>(endpoint, { method: 'DELETE' });
|
||||
}
|
||||
|
||||
async uploadFile<T>(endpoint: string, formData: FormData): Promise<T> {
|
||||
const url = `${this.baseUrl}${endpoint}`;
|
||||
const response = await fetch(url, {
|
||||
method: 'POST',
|
||||
body: formData,
|
||||
headers: {
|
||||
'Content-Type': 'multipart/form-data',
|
||||
},
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
const error: ApiError = await response.json();
|
||||
throw new Error(error.error?.message || 'Upload failed');
|
||||
}
|
||||
|
||||
return response.json();
|
||||
}
|
||||
}
|
||||
|
||||
export const apiClient = new ApiClient(API_BASE_URL);
|
||||
|
||||
+6
-1
@@ -7,9 +7,14 @@
|
||||
"icon": "./assets/icon.png",
|
||||
"userInterfaceStyle": "light",
|
||||
"ios": {
|
||||
"supportsTablet": true
|
||||
"supportsTablet": true,
|
||||
"infoPlist": {
|
||||
"NSCameraUsageDescription": "VaultDrop a besoin d'accéder à votre caméra pour scanner des documents.",
|
||||
"NSPhotoLibraryUsageDescription": "VaultDrop a besoin d'accéder à votre galerie pour sélectionner des photos."
|
||||
}
|
||||
},
|
||||
"android": {
|
||||
"permissions": ["CAMERA", "READ_EXTERNAL_STORAGE", "WRITE_EXTERNAL_STORAGE"],
|
||||
"adaptiveIcon": {
|
||||
"backgroundColor": "#E6F4FE",
|
||||
"foregroundImage": "./assets/android-icon-foreground.png",
|
||||
|
||||
@@ -47,7 +47,7 @@ export function HomeScreen() {
|
||||
<FlatList
|
||||
data={data?.data || []}
|
||||
renderItem={renderItem}
|
||||
keyExtractor={(item) => item.id}
|
||||
keyExtractor={(item) => item.name}
|
||||
contentContainerStyle={styles.list}
|
||||
/>
|
||||
|
||||
|
||||
+10
-8
@@ -1,20 +1,22 @@
|
||||
import React from 'react';
|
||||
import { View, Text, StyleSheet, TouchableOpacity, Alert } from 'react-native';
|
||||
import * as ImagePicker from 'react-native-image-picker';
|
||||
import * as ImagePicker from 'expo-image-picker';
|
||||
|
||||
export function ScanScreen() {
|
||||
const takePhoto = async () => {
|
||||
try {
|
||||
const result = await ImagePicker.launchCamera({
|
||||
mediaType: 'photo',
|
||||
const { status } = await ImagePicker.requestCameraPermissionsAsync();
|
||||
if (status !== 'granted') {
|
||||
Alert.alert('Permission requise', "L'accès à la caméra est nécessaire pour scanner un document.");
|
||||
return;
|
||||
}
|
||||
|
||||
const result = await ImagePicker.launchCameraAsync({
|
||||
mediaTypes: ['images'],
|
||||
quality: 1,
|
||||
});
|
||||
|
||||
if (result.didCancel) return;
|
||||
if (result.errorCode) {
|
||||
Alert.alert('Erreur', result.errorMessage || "Impossible d'accéder à la caméra");
|
||||
return;
|
||||
}
|
||||
if (result.canceled) return;
|
||||
|
||||
if (result.assets && result.assets[0]) {
|
||||
console.log('Photo taken:', result.assets[0]);
|
||||
|
||||
+13
-11
@@ -1,6 +1,6 @@
|
||||
import React, { useState } from 'react';
|
||||
import { View, Text, StyleSheet, TouchableOpacity, Alert } from 'react-native';
|
||||
import * as ImagePicker from 'react-native-image-picker';
|
||||
import * as ImagePicker from 'expo-image-picker';
|
||||
import { useUpload } from '../hooks/useUpload';
|
||||
import { UploadProgress } from '../components/UploadProgress';
|
||||
|
||||
@@ -11,28 +11,30 @@ export function UploadScreen() {
|
||||
|
||||
const pickImage = async () => {
|
||||
try {
|
||||
const result = await ImagePicker.launchImageLibrary({
|
||||
mediaType: 'photo',
|
||||
quality: 1,
|
||||
});
|
||||
|
||||
if (result.didCancel) return;
|
||||
if (result.errorCode) {
|
||||
Alert.alert('Erreur', result.errorMessage || "Impossible d'accéder à la galerie");
|
||||
const { status } = await ImagePicker.requestMediaLibraryPermissionsAsync();
|
||||
if (status !== 'granted') {
|
||||
Alert.alert('Permission requise', "L'accès à la galerie est nécessaire pour sélectionner une photo.");
|
||||
return;
|
||||
}
|
||||
console.log('yes')
|
||||
const result = await ImagePicker.launchImageLibraryAsync({
|
||||
mediaTypes: ['images'],
|
||||
quality: 1,
|
||||
});
|
||||
console.log(result)
|
||||
if (result.canceled) return;
|
||||
|
||||
if (result.assets && result.assets[0]) {
|
||||
setUploadStatus('uploading');
|
||||
const asset = result.assets[0];
|
||||
const file = {
|
||||
uri: asset.uri,
|
||||
type: asset.type || 'image/jpeg',
|
||||
type: asset.mimeType || 'image/jpeg',
|
||||
name: asset.fileName || 'photo.jpg',
|
||||
};
|
||||
|
||||
try {
|
||||
const response = await upload.mutateAsync(file as any);
|
||||
const response = await upload.mutateAsync(file);
|
||||
setUploadStatus('processing');
|
||||
console.log('Upload success:', response);
|
||||
setUploadStatus('success');
|
||||
|
||||
@@ -15,6 +15,8 @@ export function FileCard({ file, onPress }: FileCardProps) {
|
||||
return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
|
||||
};
|
||||
|
||||
console.log(file)
|
||||
|
||||
return (
|
||||
<TouchableOpacity style={styles.container} onPress={() => onPress?.(file)}>
|
||||
<View style={styles.header}>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
export const API_BASE_URL = process.env.EXPO_PUBLIC_API_BASE_URL || 'http://localhost:8080/api/v1';
|
||||
export const API_BASE_URL = process.env.EXPO_PUBLIC_API_BASE_URL || 'http://192.168.1.142:8080/api/v1';
|
||||
|
||||
export const ENDPOINTS = {
|
||||
FILES: '/files',
|
||||
|
||||
@@ -1,20 +1,23 @@
|
||||
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
|
||||
import { File, UploadType } from 'expo-file-system';
|
||||
import { apiClient } from '../api/client';
|
||||
import { ENDPOINTS } from '../constants/api';
|
||||
import { API_BASE_URL, ENDPOINTS } from '../constants/api';
|
||||
import { OcrJob } from '../types';
|
||||
|
||||
export function useUpload() {
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
return useMutation({
|
||||
mutationFn: async (file: File) => {
|
||||
const formData = new FormData();
|
||||
formData.append('file', file);
|
||||
mutationFn: async (file: { uri: string; type: string; name: string }) => {
|
||||
const fsFile = new File(file.uri);
|
||||
const result = await fsFile.upload(`${API_BASE_URL}${ENDPOINTS.UPLOAD}`, {
|
||||
httpMethod: 'POST',
|
||||
uploadType: UploadType.MULTIPART,
|
||||
fieldName: 'file',
|
||||
mimeType: file.type,
|
||||
});
|
||||
|
||||
return apiClient.uploadFile<{ id: string; ocrJobId: string }>(
|
||||
ENDPOINTS.UPLOAD,
|
||||
formData
|
||||
);
|
||||
return JSON.parse(result.body) as { id: string; ocrJobId: string };
|
||||
},
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: ['files'] });
|
||||
|
||||
Generated
+33
-21
@@ -12,10 +12,11 @@
|
||||
"@react-navigation/native-stack": "^7.17.10",
|
||||
"@tanstack/react-query": "^5.101.2",
|
||||
"expo": "~57.0.4",
|
||||
"expo-file-system": "~57.0.0",
|
||||
"expo-image-picker": "~57.0.2",
|
||||
"expo-status-bar": "~57.0.0",
|
||||
"react": "19.2.3",
|
||||
"react-native": "0.86.0",
|
||||
"react-native-image-picker": "^8.2.1",
|
||||
"react-native-mmkv": "^4.3.2",
|
||||
"react-native-safe-area-context": "~5.7.0",
|
||||
"react-native-screens": "4.25.2"
|
||||
@@ -2797,6 +2798,37 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/expo-file-system": {
|
||||
"version": "57.0.0",
|
||||
"resolved": "https://registry.npmjs.org/expo-file-system/-/expo-file-system-57.0.0.tgz",
|
||||
"integrity": "sha512-G+eytNuNGMiS7dbdj1j0nAYMowXnNr1vpO+jss6nQvBlRxshcGBFMtk8xfc67ynz0MUVkzod7WwKO7Vf1iOaJw==",
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"expo": "*",
|
||||
"react-native": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/expo-image-loader": {
|
||||
"version": "57.0.0",
|
||||
"resolved": "https://registry.npmjs.org/expo-image-loader/-/expo-image-loader-57.0.0.tgz",
|
||||
"integrity": "sha512-EhwnoPC4T/EMdB7Nsg7qITzhO/qB0hUnmVghmtAKQwwDVaLWWYCGE4NLkes3zk9Ub451SmS/swgPp4PCPzOlnw==",
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"expo": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/expo-image-picker": {
|
||||
"version": "57.0.2",
|
||||
"resolved": "https://registry.npmjs.org/expo-image-picker/-/expo-image-picker-57.0.2.tgz",
|
||||
"integrity": "sha512-XW+C5weIthkOLCJZzExeRJf9pcWfaXNHSDm76gmZVhDUVIHdi9IS3eihAIF0WA0fBo9ogIfQs/iep/c6CzIMKg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"expo-image-loader": "~57.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"expo": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/expo-modules-autolinking": {
|
||||
"version": "57.0.5",
|
||||
"resolved": "https://registry.npmjs.org/expo-modules-autolinking/-/expo-modules-autolinking-57.0.5.tgz",
|
||||
@@ -3177,16 +3209,6 @@
|
||||
"react-native": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/expo/node_modules/expo-file-system": {
|
||||
"version": "57.0.0",
|
||||
"resolved": "https://registry.npmjs.org/expo-file-system/-/expo-file-system-57.0.0.tgz",
|
||||
"integrity": "sha512-G+eytNuNGMiS7dbdj1j0nAYMowXnNr1vpO+jss6nQvBlRxshcGBFMtk8xfc67ynz0MUVkzod7WwKO7Vf1iOaJw==",
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"expo": "*",
|
||||
"react-native": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/expo/node_modules/expo-font": {
|
||||
"version": "57.0.0",
|
||||
"resolved": "https://registry.npmjs.org/expo-font/-/expo-font-57.0.0.tgz",
|
||||
@@ -5225,16 +5247,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/react-native-image-picker": {
|
||||
"version": "8.2.1",
|
||||
"resolved": "https://registry.npmjs.org/react-native-image-picker/-/react-native-image-picker-8.2.1.tgz",
|
||||
"integrity": "sha512-FBeGYJGFDjMdGCcyubDJgBAPCQ4L1D3hwLXyUU91jY9ahOZMTbluceVvRmrEKqnDPFJ0gF1NVhJ0nr1nROFLdg==",
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"react": "*",
|
||||
"react-native": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/react-native-mmkv": {
|
||||
"version": "4.3.2",
|
||||
"resolved": "https://registry.npmjs.org/react-native-mmkv/-/react-native-mmkv-4.3.2.tgz",
|
||||
|
||||
+2
-1
@@ -7,10 +7,11 @@
|
||||
"@react-navigation/native-stack": "^7.17.10",
|
||||
"@tanstack/react-query": "^5.101.2",
|
||||
"expo": "~57.0.4",
|
||||
"expo-file-system": "~57.0.0",
|
||||
"expo-image-picker": "~57.0.2",
|
||||
"expo-status-bar": "~57.0.0",
|
||||
"react": "19.2.3",
|
||||
"react-native": "0.86.0",
|
||||
"react-native-image-picker": "^8.2.1",
|
||||
"react-native-mmkv": "^4.3.2",
|
||||
"react-native-safe-area-context": "~5.7.0",
|
||||
"react-native-screens": "4.25.2"
|
||||
|
||||
Reference in New Issue
Block a user