fix: chọn camera hay thư viện

This commit is contained in:
2026-06-23 18:42:56 +07:00
parent a64af5f9cf
commit f355b9471a
5 changed files with 79 additions and 2 deletions
+79 -2
View File
@@ -1,5 +1,5 @@
import React, { useState, useRef, useEffect } from 'react';
import { LogIn, Compass, Map as MapIcon, Camera, ShieldAlert } from 'lucide-react';
import { LogIn, Compass, Map as MapIcon, Camera, ShieldAlert, Image as ImageIcon, X } from 'lucide-react';
import { LoginModal } from '../components/LoginModal';
import { ReportBusinessModal } from '../components/ReportBusinessModal';
import { TagSelectModal } from '../components/TagSelectModal';
@@ -21,7 +21,10 @@ export const LandingPage: React.FC<LandingPageProps> = ({ onGoToSignup, onGoToMa
const [isLoginModalOpen, setIsLoginModalOpen] = useState(false);
const [isReportModalOpen, setIsReportModalOpen] = useState(false);
const [isTagsModalOpen, setIsTagsModalOpen] = useState(false);
const [isPhotoSourceModalOpen, setIsPhotoSourceModalOpen] = useState(false);
const fileInputRef = useRef<HTMLInputElement>(null);
const cameraInputRef = useRef<HTMLInputElement>(null);
const galleryInputRef = useRef<HTMLInputElement>(null);
const [pendingPhotoFile, setPendingPhotoFile] = useState<File | null>(null);
const [pendingPhotoLocation, setPendingPhotoLocation] = useState<GeolocationPosition | null>(null);
const [photoPreviewUrl, setPhotoPreviewUrl] = useState<string>('');
@@ -557,6 +560,25 @@ return (
capture="environment"
className="hidden"
/>
{/* Camera input - capture="environment" for rear camera */}
<input
type="file"
ref={cameraInputRef}
onChange={handleFileChange}
accept="image/*"
capture="environment"
className="hidden"
/>
{/* Gallery input - no capture attribute for file picker */}
<input
type="file"
ref={galleryInputRef}
onChange={handleFileChange}
accept="image/*"
className="hidden"
/>
{/* Unified Bottom Container: Gallery thumbnails on top, action buttons below */}
<div className="absolute bottom-[calc(1.5rem+env(safe-area-inset-bottom,0px))] left-1/2 -translate-x-1/2 z-20 w-full px-4 flex flex-col items-center gap-4 max-w-md">
@@ -607,7 +629,7 @@ return (
</button>
<button
onClick={() => fileInputRef.current?.click()}
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"
>
<Camera className="w-4.5 h-4.5" />
@@ -655,6 +677,61 @@ return (
onConfirm={handleConfirmTags}
photoUrl={photoPreviewUrl}
/>
{/* Photo Source Selection Modal */}
{isPhotoSourceModalOpen && (
<div className="fixed inset-0 z-[9999] flex items-center justify-center bg-black/50 backdrop-blur-sm p-4">
<div className="bg-[var(--surface)] rounded-3xl shadow-2xl max-w-sm w-full overflow-hidden animate-in fade-in zoom-in-95 duration-200">
{/* Header */}
<div className="bg-gradient-to-r from-blue-600 to-blue-500 px-6 py-6 flex items-center justify-between">
<h2 className="text-xl font-bold text-white">Chụp hoặc tải nh</h2>
<button
onClick={() => setIsPhotoSourceModalOpen(false)}
className="p-1.5 hover:bg-white/20 rounded-full transition-colors"
>
<X className="w-5 h-5 text-white" />
</button>
</div>
{/* Content */}
<div className="p-6 space-y-3">
{/* Camera Button */}
<button
onClick={() => {
setIsPhotoSourceModalOpen(false);
cameraInputRef.current?.click();
}}
className="w-full flex items-center gap-4 p-4 bg-[var(--background)] hover:bg-[var(--background-alt)] border border-[var(--border)] rounded-2xl transition-all active:scale-95"
>
<div className="flex-shrink-0 p-3 bg-blue-100 rounded-full">
<Camera className="w-6 h-6 text-blue-600" />
</div>
<div className="flex-1 text-left">
<div className="font-bold text-[var(--text-primary)]">Chụp nh bằng camera</div>
<div className="text-sm text-[var(--text-muted)]">Dùng camera thiết bị của bạn</div>
</div>
</button>
{/* Gallery Button */}
<button
onClick={() => {
setIsPhotoSourceModalOpen(false);
galleryInputRef.current?.click();
}}
className="w-full flex items-center gap-4 p-4 bg-[var(--background)] hover:bg-[var(--background-alt)] border border-[var(--border)] rounded-2xl transition-all active:scale-95"
>
<div className="flex-shrink-0 p-3 bg-emerald-100 rounded-full">
<ImageIcon className="w-6 h-6 text-emerald-600" />
</div>
<div className="flex-1 text-left">
<div className="font-bold text-[var(--text-primary)]">Tải nh từ thư viện</div>
<div className="text-sm text-[var(--text-muted)]">Chọn nh từ thiết bị của bạn</div>
</div>
</button>
</div>
</div>
</div>
)}
</div>
);
};