diff --git a/backend/public/downloads/yotrip-latest.apk b/backend/public/downloads/yotrip-latest.apk index e04b1c6..5a62155 100644 Binary files a/backend/public/downloads/yotrip-latest.apk and b/backend/public/downloads/yotrip-latest.apk differ diff --git a/frontend/dist/index.html b/frontend/dist/index.html index a653a34..8766eb7 100644 --- a/frontend/dist/index.html +++ b/frontend/dist/index.html @@ -21,13 +21,13 @@ - + - + - - + + diff --git a/frontend/src/pages/LandingPage.tsx b/frontend/src/pages/LandingPage.tsx index 9cd8b85..474f835 100644 --- a/frontend/src/pages/LandingPage.tsx +++ b/frontend/src/pages/LandingPage.tsx @@ -1,5 +1,5 @@ import React, { useState, useRef, useEffect } from 'react'; -import { Compass, Map as MapIcon, Camera, ShieldAlert, Image as ImageIcon, X } from 'lucide-react'; +import { Compass, Map as MapIcon, Camera as CameraIcon, ShieldAlert, Image as ImageIcon, X } from 'lucide-react'; import { LoginModal } from '../components/LoginModal'; import { ReportBusinessModal } from '../components/ReportBusinessModal'; import { TagSelectModal } from '../components/TagSelectModal'; @@ -15,6 +15,8 @@ import { processImageModeration } from '../hooks/useImageModeration'; import { useTranslation } from '../hooks/useTranslation'; import { processAndResizeImage } from '../utils/imageProcessor'; import { getDeviceLocation } from '../utils/geolocation'; +import { Capacitor } from '@capacitor/core'; +import { Camera, CameraResultType, CameraSource } from '@capacitor/camera'; interface LandingPageProps { onContinue?: () => void; @@ -188,12 +190,7 @@ export const LandingPage: React.FC = ({ return () => clearInterval(interval); }, [publicPhotos]); - const handleFileChange = async (event: React.ChangeEvent) => { - const file = event.target.files?.[0]; - if (!file) return; - - notify({ title: 'Đang xử lý...', message: 'Vui lòng chờ trong giây lát.', type: 'info' }); - + const processAndUploadFile = async (file: File) => { try { // Process image: Reads EXIF data and forces 2K resizing on device memory const { file: processedFile, latitude: exifLat, longitude: exifLng } = await processAndResizeImage(file); @@ -262,12 +259,50 @@ export const LandingPage: React.FC = ({ setIsTagsModalOpen(true); } catch (error: any) { notify({ title: 'Lỗi', message: error.message, type: 'error' }); - } finally { - // Reset input để có thể chọn lại cùng 1 file - if (event.target) event.target.value = ''; } }; + const handleNativePhotoPick = async (source: CameraSource) => { + try { + const image = await Camera.getPhoto({ + quality: 90, + allowEditing: false, + resultType: CameraResultType.Uri, + source: source, + saveToGallery: source === CameraSource.Camera // Tự động lưu ảnh gốc vào thư viện nếu chụp bằng Camera + }); + + if (image && image.webPath) { + notify({ title: 'Đang xử lý...', message: 'Vui lòng chờ trong giây lát.', type: 'info' }); + + // Convert Capacitor webPath resource back to standard File instance + const response = await fetch(image.webPath); + const blob = await response.blob(); + const originalName = `photo-${Date.now()}.${image.format}`; + const file = new File([blob], originalName, { type: `image/${image.format}` }); + + // Process this file using our standard handler + await processAndUploadFile(file); + } + } catch (error: any) { + console.error('Lỗi chọn ảnh native:', error); + if (error?.message !== 'User cancelled photos app' && error?.message !== 'User cancelled camera') { + notify({ + title: 'Lỗi', + message: 'Không thể truy cập máy ảnh hoặc thư viện ảnh.', + type: 'error' + }); + } + } + }; + + const handleFileChange = async (event: React.ChangeEvent) => { + const file = event.target.files?.[0]; + if (!file) return; + await processAndUploadFile(file); + if (event.target) event.target.value = ''; + }; + const handleConfirmTags = async (selectedTags: string[]) => { if (!pendingPhotoFile) return; @@ -675,7 +710,7 @@ export const LandingPage: React.FC = ({ onClick={() => setIsPhotoSourceModalOpen(true)} className="flex-1 flex items-center justify-center gap-2 bg-white/20 backdrop-blur-lg hover:bg-white/30 text-white font-bold py-3.5 rounded-2xl transition-all shadow-2xl border border-white/30 active:scale-95 text-xs sm:text-sm whitespace-nowrap" > - + {t('shortCamera') || 'Chụp ảnh'} @@ -748,12 +783,16 @@ export const LandingPage: React.FC = ({