fix: cách các modals hiển thị trên browser điện thoại

This commit is contained in:
2026-06-26 09:13:24 +07:00
parent 03ee337e28
commit 6d90a47c24
31 changed files with 789 additions and 532 deletions
+4 -4
View File
@@ -385,10 +385,10 @@ export const AddLocationModal = ({ isOpen, onClose, tourId, initialLegId, editin
};
return (
<div className="fixed inset-0 z-[2000] flex items-center justify-center p-4">
<div className="fixed inset-0 z-[2000] flex items-end sm:items-center justify-center p-0 sm:p-4">
<div className="absolute inset-0 bg-gray-900/60 backdrop-blur-sm" onClick={onClose} />
<div className="relative w-full max-w-lg bg-[var(--surface)] rounded-3xl shadow-2xl overflow-hidden p-8 max-h-[90vh] overflow-y-auto">
<div className="flex justify-between items-center mb-6">
<div className="relative w-full h-full sm:max-w-lg bg-[var(--surface)] rounded-t-2xl sm:rounded-3xl shadow-2xl overflow-hidden flex flex-col sm:max-h-[85vh] animate-in zoom-in-95 duration-200">
<div className="flex justify-between items-center mb-6 p-5 sm:p-8 pb-0 sm:pb-0 shrink-0">
<h2 className="text-2xl font-bold text-[var(--text-primary)] flex items-center gap-2">
<MapIcon className="w-6 h-6 text-blue-600" /> {titleText}
</h2>
@@ -473,7 +473,7 @@ export const AddLocationModal = ({ isOpen, onClose, tourId, initialLegId, editin
</button>
)}
<form onSubmit={handleSubmit} className="space-y-4">
<form onSubmit={handleSubmit} className="space-y-4 overflow-y-auto flex-1 text-left">
<div>
<label className="block text-sm font-bold text-[var(--text-secondary)] mb-1">Tên đa điểm</label>
<input
+7 -7
View File
@@ -214,10 +214,10 @@ export const AddMemberModal: React.FC<AddMemberModalProps> = ({ isOpen, onClose,
if (!isOpen || isPublicView) return null; // Do not render if public view
return (
<div className="fixed inset-0 z-[2000] flex items-center justify-center p-4">
<div className="fixed inset-0 z-[2000] flex items-end sm:items-center justify-center p-0 sm:p-4">
<div className="absolute inset-0 bg-gray-900/60 backdrop-blur-sm" onClick={onClose} />
<div className="relative w-full max-w-md bg-white rounded-3xl shadow-2xl overflow-hidden flex flex-col max-h-[90vh]">
<div className="p-5 border-b border-gray-100 flex justify-between items-center bg-gray-50/50">
<div className="relative w-full sm:max-w-md bg-white rounded-t-2xl sm:rounded-3xl shadow-2xl overflow-hidden flex flex-col h-full sm:h-auto sm:max-h-[85vh] animate-in zoom-in-95 duration-200">
<div className="p-5 border-b border-gray-100 flex justify-between items-center bg-gray-50/50 shrink-0">
<div>
<h2 className="text-lg font-bold text-gray-900 flex items-center gap-2">
<UserPlus className="w-5 h-5 text-blue-600" /> {canCreateDirectly ? 'Thành viên hành trình' : 'Mời tham gia tour'}
@@ -392,10 +392,10 @@ export const AddMemberModal: React.FC<AddMemberModalProps> = ({ isOpen, onClose,
{submitError}
</div>
)}
{loading ? (
<div className="flex justify-center py-10"><Loader2 className="w-8 h-8 animate-spin text-blue-600" /></div>
) : (
<div className="space-y-2 max-h-[30vh] overflow-y-auto pr-1">
{loading ? (
<div className="flex justify-center py-10"><Loader2 className="w-8 h-8 animate-spin text-blue-600" /></div>
) : (
<div className="space-y-2 max-h-[30vh] sm:max-h-[25vh] overflow-y-auto pr-1">
{query.trim() && canCreateDirectly && (
<button
type="button"
+4 -4
View File
@@ -172,10 +172,10 @@ export const AddPhotoModal: React.FC<AddPhotoModalProps> = ({ isOpen, onClose, t
return (
<div className="fixed inset-0 z-[2500] flex items-center justify-center p-4">
<div className="fixed inset-0 z-[2500] flex items-end sm:items-center justify-center p-0 sm:p-4">
<div className="absolute inset-0 bg-gray-900/60 backdrop-blur-sm" onClick={onClose} />
<div className="relative w-full max-w-lg bg-[var(--surface)] rounded-3xl shadow-2xl overflow-hidden p-8 max-h-[90vh] flex flex-col animate-in zoom-in-95 duration-200">
<div className="flex justify-between items-center mb-6">
<div className="relative w-full h-full sm:max-w-lg bg-[var(--surface)] rounded-t-2xl sm:rounded-3xl shadow-2xl overflow-hidden flex flex-col sm:max-h-[85vh] animate-in zoom-in-95 duration-200">
<div className="flex justify-between items-center mb-6 p-5 sm:p-8 pb-0 sm:pb-0 shrink-0">
<h2 className="text-2xl font-bold text-[var(--text-primary)] flex items-center gap-2">
<ImageIcon className="w-6 h-6 text-blue-600" /> Tải nh lên
</h2>
@@ -184,7 +184,7 @@ export const AddPhotoModal: React.FC<AddPhotoModalProps> = ({ isOpen, onClose, t
</button>
</div>
<form onSubmit={handleSubmit} className="flex-1 flex flex-col min-h-0">
<form onSubmit={handleSubmit} className="flex-1 flex flex-col min-h-0 p-5 sm:p-8 pt-0 sm:pt-0">
<div
onClick={() => fileInputRef.current?.click()}
className="border-2 border-dashed border-[var(--border)] rounded-[32px] p-10 flex flex-col items-center justify-center cursor-pointer hover:bg-[var(--background)]/50 hover:border-blue-200 transition-all mb-6 group"
+4 -4
View File
@@ -132,11 +132,11 @@ export const CommentModal: React.FC<CommentModalProps> = ({ isOpen, onClose, loc
if (!isOpen) return null;
return (
<div className="fixed inset-0 z-[5000] flex items-center justify-center p-4">
<div className="fixed inset-0 z-[5000] flex items-end sm:items-center justify-center p-0 sm:p-4">
<div className="absolute inset-0 bg-gray-900/60 backdrop-blur-sm animate-in fade-in duration-200" onClick={onClose} />
<div className="relative w-full max-w-md bg-[var(--surface)] rounded-[32px] shadow-2xl overflow-hidden flex flex-col max-h-[80vh] animate-in zoom-in-95 duration-200">
<div className="relative w-full h-full sm:max-w-md bg-[var(--surface)] rounded-t-2xl sm:rounded-[32px] shadow-2xl overflow-hidden flex flex-col sm:max-h-[85vh] animate-in zoom-in-95 duration-200">
{/* Header */}
<div className="p-6 border-b border-[var(--border)] flex justify-between items-center bg-[var(--surface)] sticky top-0 z-10">
<div className="p-6 border-b border-[var(--border)] flex justify-between items-center bg-[var(--surface)] sticky top-0 z-10 shrink-0">
<div>
<h3 className="text-xl font-black text-[var(--text-primary)] flex items-center gap-2">
<MessageSquare className="w-5 h-5 text-blue-600" />
@@ -186,7 +186,7 @@ export const CommentModal: React.FC<CommentModalProps> = ({ isOpen, onClose, loc
</div>
{/* Input Area */}
<div className="p-4 bg-[var(--surface)] border-t border-[var(--border)]">
<div className="p-4 bg-[var(--surface)] border-t border-[var(--border)] shrink-0">
<div className="relative flex items-center gap-2">
<input
type="text"
+4 -7
View File
@@ -13,13 +13,10 @@ export const ConfirmModal: React.FC<ConfirmModalProps> = ({ isOpen, title, messa
if (!isOpen) return null;
return (
<div className="fixed inset-0 z-[6000] flex items-center justify-center p-4">
{/* Backdrop */}
<div className="fixed inset-0 z-[6000] flex items-end sm:items-center justify-center p-0 sm:p-4">
<div className="absolute inset-0 bg-gray-900/60 backdrop-blur-sm animate-in fade-in duration-200" onClick={onCancel} />
{/* Modal Content */}
<div className="relative w-full max-w-sm bg-[var(--surface)] rounded-[32px] shadow-2xl p-8 animate-in zoom-in-95 duration-200">
<div className="flex justify-between items-center mb-4">
<div className="relative w-full sm:max-w-sm h-full sm:h-auto max-h-screen sm:max-h-[85vh] bg-[var(--surface)] rounded-t-2xl sm:rounded-2xl shadow-2xl p-6 sm:p-8 animate-in zoom-in-95 duration-200 flex flex-col">
<div className="flex justify-between items-center mb-4 shrink-0">
<div className="w-12 h-12 rounded-2xl bg-red-50 flex items-center justify-center text-red-500 shadow-inner">
<AlertTriangle className="w-6 h-6" />
</div>
@@ -33,7 +30,7 @@ export const ConfirmModal: React.FC<ConfirmModalProps> = ({ isOpen, title, messa
{message || 'Bạn có chắc chắn muốn thực hiện hành động này không?'}
</p>
<div className="grid grid-cols-2 gap-3">
<div className="grid grid-cols-2 gap-3 pt-2 mt-auto">
<button
onClick={onCancel}
className="py-4 bg-[var(--background)] hover:bg-[var(--background)] text-[var(--text-secondary)] font-bold rounded-2xl transition-all active:scale-95"
@@ -118,7 +118,7 @@ export const CoordinateSelectModal: React.FC<CoordinateSelectModalProps> = ({
};
return (
<div className="fixed inset-0 z-[6000] flex items-center justify-center p-4 animate-in fade-in duration-200">
<div className="fixed inset-0 z-[6000] flex items-end sm:items-center justify-center p-0 sm:p-4 animate-in fade-in duration-200">
{/* Backdrop */}
<div
className="absolute inset-0 bg-slate-900/60 backdrop-blur-sm"
@@ -126,7 +126,7 @@ export const CoordinateSelectModal: React.FC<CoordinateSelectModalProps> = ({
/>
{/* Content */}
<div className="relative w-full max-w-2xl h-[550px] bg-white dark:bg-slate-900 rounded-3xl shadow-2xl overflow-hidden flex flex-col border border-gray-100 dark:border-slate-800 animate-in zoom-in-95 duration-200">
<div className="relative w-full h-full sm:w-auto sm:max-w-2xl sm:h-[85vh] bg-white dark:bg-slate-900 rounded-t-2xl sm:rounded-3xl shadow-2xl overflow-hidden flex flex-col border border-gray-100 dark:border-slate-800 animate-in zoom-in-95 duration-200">
{/* Header */}
<div className="p-4 border-b border-gray-100 dark:border-slate-800/80 flex items-center justify-between bg-white dark:bg-slate-900 shrink-0">
<div className="flex items-center gap-2">
@@ -145,7 +145,7 @@ export const CoordinateSelectModal: React.FC<CoordinateSelectModalProps> = ({
</div>
{/* Map Body */}
<div className="flex-1 bg-gray-50 dark:bg-slate-950 relative min-h-[300px]" style={{ zIndex: 10 }}>
<div className="flex-1 bg-gray-50 dark:bg-slate-950 relative min-h-[300px] sm:min-h-0" style={{ zIndex: 10 }}>
{/* Floating Search Panel */}
<div className="absolute top-4 left-4 right-4 sm:right-auto z-[1000] sm:w-80 bg-white/95 dark:bg-slate-900/95 backdrop-blur-md rounded-2xl border border-slate-150 dark:border-slate-800 shadow-xl p-2 flex flex-col gap-1.5">
+3 -3
View File
@@ -101,10 +101,10 @@ export const CreateTourModal = ({ isOpen, onClose, onSuccess }: { isOpen: boolea
};
return (
<div className="fixed inset-0 z-[2000] flex items-center justify-center p-4">
<div className="fixed inset-0 z-[2000] flex items-end sm:items-center justify-center p-0 sm:p-4">
<div className="absolute inset-0 bg-gray-900/60 backdrop-blur-sm" onClick={onClose} />
<div className="relative w-full max-w-md bg-[var(--surface)] rounded-3xl shadow-2xl overflow-hidden flex flex-col max-h-[90vh]">
<div className="p-5 border-b border-[var(--border)] flex justify-between items-center bg-[var(--background)]/50">
<div className="relative w-full sm:max-w-md bg-[var(--surface)] rounded-t-2xl sm:rounded-3xl shadow-2xl overflow-hidden flex flex-col h-full sm:h-auto sm:max-h-[85vh] animate-in zoom-in-95 duration-200">
<div className="p-5 border-b border-[var(--border)] flex justify-between items-center bg-[var(--background)]/50 shrink-0">
<h2 className="text-xl font-bold text-[var(--text-primary)]">Tạo Tour mới</h2>
<button onClick={onClose} className="p-2 hover:bg-[var(--background)] rounded-full transition-colors"></button>
</div>
+111 -111
View File
@@ -631,124 +631,124 @@ export const ItineraryTimeline = ({
)}
{/* Modal Khai báo số chặng (Popover) */}
{isLegCountModalOpen && (
<div className="fixed inset-0 z-[4000] flex items-center justify-center p-4">
<div className="absolute inset-0 bg-gray-900/60 dark:bg-slate-950/60 backdrop-blur-sm animate-in fade-in duration-200" onClick={() => setIsLegCountModalOpen(false)} />
<div className="relative w-full max-w-sm bg-white dark:bg-slate-900 rounded-[32px] shadow-2xl p-8 animate-in zoom-in-95 duration-200">
<div className="flex justify-between items-center mb-6">
<h3 className="text-xl font-black text-gray-900 dark:text-white">Số chặng lộ trình</h3>
<button onClick={() => setIsLegCountModalOpen(false)} className="p-2 hover:bg-gray-100 dark:hover:bg-slate-800 rounded-full transition-colors">
<X className="w-5 h-5 text-gray-400 dark:text-slate-400" />
</button>
</div>
<p className="text-sm text-gray-500 dark:text-slate-400 mb-6 leading-relaxed">
Bạn muốn chia chuyến đi này thành bao nhiêu chặng nhỏ? (Tối đa 20 chặng)
</p>
{isLegCountModalOpen && (
<div className="fixed inset-0 z-[4000] flex items-end sm:items-center justify-center p-0 sm:p-4">
<div className="absolute inset-0 bg-gray-900/60 dark:bg-slate-950/60 backdrop-blur-sm animate-in fade-in duration-200" onClick={() => setIsLegCountModalOpen(false)} />
<div className="relative w-full sm:max-w-sm bg-white dark:bg-slate-900 rounded-t-2xl sm:rounded-[32px] shadow-2xl p-8 sm:p-8 h-full sm:h-auto sm:max-h-[85vh] animate-in zoom-in-95 duration-200 flex flex-col">
<div className="flex justify-between items-center mb-6 shrink-0">
<h3 className="text-xl font-black text-gray-900 dark:text-white">Số chặng lộ trình</h3>
<button onClick={() => setIsLegCountModalOpen(false)} className="p-2 hover:bg-gray-100 dark:hover:bg-slate-800 rounded-full transition-colors">
<X className="w-5 h-5 text-gray-400 dark:text-slate-400" />
</button>
</div>
<p className="text-sm text-gray-500 dark:text-slate-400 mb-6 leading-relaxed">
Bạn muốn chia chuyến đi này thành bao nhiêu chặng nhỏ? (Tối đa 20 chặng)
</p>
<div className="flex items-center justify-center gap-6 mb-8">
<button
onClick={() => setTempLegCount(Math.max(1, tempLegCount - 1))}
className="w-12 h-12 rounded-2xl border-2 border-gray-100 dark:border-slate-700 flex items-center justify-center text-2xl font-bold text-gray-400 dark:text-slate-400 hover:border-blue-200 dark:hover:border-blue-500 hover:text-blue-600 dark:hover:text-blue-400 transition-all"
>
-
</button>
<span className="text-4xl font-black text-blue-600 dark:text-blue-400 w-12 text-center">{tempLegCount}</span>
<button
onClick={() => setTempLegCount(Math.min(20, tempLegCount + 1))}
className="w-12 h-12 rounded-2xl border-2 border-gray-100 dark:border-slate-700 flex items-center justify-center text-2xl font-bold text-gray-400 dark:text-slate-400 hover:border-blue-200 dark:hover:border-blue-500 hover:text-blue-600 dark:hover:text-blue-400 transition-all"
>
+
</button>
</div>
<div className="flex items-center justify-center gap-6 mb-8">
<button
onClick={() => setTempLegCount(Math.max(1, tempLegCount - 1))}
className="w-12 h-12 rounded-2xl border-2 border-gray-100 dark:border-slate-700 flex items-center justify-center text-2xl font-bold text-gray-400 dark:text-slate-400 hover:border-blue-200 dark:hover:border-blue-500 hover:text-blue-600 dark:hover:text-blue-400 transition-all"
>
-
</button>
<span className="text-4xl font-black text-blue-600 dark:text-blue-400 w-12 text-center">{tempLegCount}</span>
<button
onClick={() => setTempLegCount(Math.min(20, tempLegCount + 1))}
className="w-12 h-12 rounded-2xl border-2 border-gray-100 dark:border-slate-700 flex items-center justify-center text-2xl font-bold text-gray-400 dark:text-slate-400 hover:border-blue-200 dark:hover:border-blue-500 hover:text-blue-600 dark:hover:text-blue-400 transition-all"
>
+
</button>
</div>
<button
onClick={confirmDeclareLegs}
className="w-full py-4 bg-blue-600 dark:bg-blue-700 hover:bg-blue-700 dark:hover:bg-blue-800 text-white font-bold rounded-2xl shadow-lg shadow-blue-100 dark:shadow-blue-950 transition-all active:scale-95"
>
Xác nhận
</button>
</div>
</div>
)}
<button
onClick={confirmDeclareLegs}
className="w-full py-4 bg-blue-600 dark:bg-blue-700 hover:bg-blue-700 dark:hover:bg-blue-800 text-white font-bold rounded-2xl shadow-lg shadow-blue-100 dark:shadow-blue-950 transition-all active:scale-95 mt-auto"
>
Xác nhận
</button>
</div>
</div>
)}
{/* Modal Chỉnh sửa Chặng (Popover) */}
{isEditModalOpen && (
<div className="fixed inset-0 z-[4000] flex items-center justify-center p-4">
<div className="absolute inset-0 bg-gray-900/60 dark:bg-slate-950/60 backdrop-blur-sm animate-in fade-in duration-200" onClick={() => setIsEditModalOpen(false)} />
<div className="relative w-full max-w-md bg-white dark:bg-slate-900 rounded-[32px] shadow-2xl p-8 animate-in zoom-in-95 duration-200">
<div className="flex justify-between items-center mb-6">
<h3 className="text-xl font-black text-gray-900 dark:text-white">Chỉnh sửa Chặng</h3>
<button onClick={() => setIsEditModalOpen(false)} className="p-2 hover:bg-gray-100 dark:hover:bg-slate-800 rounded-full transition-colors">
<X className="w-5 h-5 text-gray-400 dark:text-slate-400" />
</button>
</div>
<div className="space-y-5">
<div>
<label className="block text-xs font-black text-gray-400 dark:text-slate-400 uppercase tracking-widest mb-2 ml-1">Tên chặng</label>
<input
type="text"
value={editingLegData.note}
onChange={(e) => setEditingLegData({ ...editingLegData, note: e.target.value })}
placeholder="VD: Ngày 1: Khởi hành"
className="w-full px-5 py-4 bg-gray-50 dark:bg-slate-800 border border-gray-100 dark:border-slate-700 rounded-2xl focus:ring-2 focus:ring-blue-500 outline-none transition-all text-sm text-gray-800 dark:text-white"
/>
</div>
{isEditModalOpen && (
<div className="fixed inset-0 z-[4000] flex items-end sm:items-center justify-center p-0 sm:p-4">
<div className="absolute inset-0 bg-gray-900/60 dark:bg-slate-950/60 backdrop-blur-sm animate-in fade-in duration-200" onClick={() => setIsEditModalOpen(false)} />
<div className="relative w-full sm:max-w-md bg-white dark:bg-slate-900 rounded-t-2xl sm:rounded-[32px] shadow-2xl p-8 sm:p-8 h-full sm:h-auto sm:max-h-[85vh] animate-in zoom-in-95 duration-200 flex flex-col">
<div className="flex justify-between items-center mb-6 shrink-0">
<h3 className="text-xl font-black text-gray-900 dark:text-white">Chỉnh sửa Chặng</h3>
<button onClick={() => setIsEditModalOpen(false)} className="p-2 hover:bg-gray-100 dark:hover:bg-slate-800 rounded-full transition-colors">
<X className="w-5 h-5 text-gray-400 dark:text-slate-400" />
</button>
</div>
<div className="space-y-5 overflow-y-auto flex-1">
<div>
<label className="block text-xs font-black text-gray-400 dark:text-slate-400 uppercase tracking-widest mb-2 ml-1">Tên chặng</label>
<input
type="text"
value={editingLegData.note}
onChange={(e) => setEditingLegData({ ...editingLegData, note: e.target.value })}
placeholder="VD: Ngày 1: Khởi hành"
className="w-full px-5 py-4 bg-gray-50 dark:bg-slate-800 border border-gray-100 dark:border-slate-700 rounded-2xl focus:ring-2 focus:ring-blue-500 outline-none transition-all text-sm text-gray-800 dark:text-white"
/>
</div>
<div>
<label className="flex items-center gap-2 text-xs font-black text-gray-400 dark:text-slate-400 uppercase tracking-widest mb-2 ml-1">
<AlignLeft className="w-3 h-3" /> tả chi tiết
</label>
<textarea
value={editingLegData.description}
onChange={(e) => setEditingLegData({ ...editingLegData, description: e.target.value })}
placeholder="Mô tả các hoạt động chính trong chặng này..."
className="w-full px-5 py-4 bg-gray-50 dark:bg-slate-800 border border-gray-100 dark:border-slate-700 rounded-2xl focus:ring-2 focus:ring-blue-500 outline-none transition-all text-sm min-h-[120px] resize-none text-gray-800 dark:text-white"
/>
</div>
<div>
<label className="flex items-center gap-2 text-xs font-black text-gray-400 dark:text-slate-400 uppercase tracking-widest mb-2 ml-1">
<AlignLeft className="w-3 h-3" /> tả chi tiết
</label>
<textarea
value={editingLegData.description}
onChange={(e) => setEditingLegData({ ...editingLegData, description: e.target.value })}
placeholder="Mô tả các hoạt động chính trong chặng này..."
className="w-full px-5 py-4 bg-gray-50 dark:bg-slate-800 border border-gray-100 dark:border-slate-700 rounded-2xl focus:ring-2 focus:ring-blue-500 outline-none transition-all text-sm min-h-[120px] resize-none text-gray-800 dark:text-white"
/>
</div>
<div className="grid grid-cols-2 gap-4">
<div>
<label className="flex items-center gap-2 text-xs font-black text-gray-400 dark:text-slate-400 uppercase tracking-widest mb-2 ml-1">
<CalendarIcon className="w-3 h-3" /> Bắt đu
</label>
<input
type="date"
value={editingLegData.startDate}
onChange={(e) => setEditingLegData({ ...editingLegData, startDate: e.target.value })}
className="w-full px-5 py-4 bg-gray-50 dark:bg-slate-800 border border-gray-100 dark:border-slate-700 rounded-2xl focus:ring-2 focus:ring-blue-500 outline-none transition-all text-sm text-gray-800 dark:text-white"
/>
</div>
<div>
<label className="block text-xs font-black text-gray-400 dark:text-slate-400 uppercase tracking-widest mb-2 ml-1">Kết thúc</label>
<input
type="date"
value={editingLegData.endDate}
onChange={(e) => setEditingLegData({ ...editingLegData, endDate: e.target.value })}
className="w-full px-5 py-4 bg-gray-50 dark:bg-slate-800 border border-gray-100 dark:border-slate-700 rounded-2xl focus:ring-2 focus:ring-blue-500 outline-none transition-all text-sm text-gray-800 dark:text-white"
/>
</div>
</div>
</div>
<div className="grid grid-cols-2 gap-4">
<div>
<label className="flex items-center gap-2 text-xs font-black text-gray-400 dark:text-slate-400 uppercase tracking-widest mb-2 ml-1">
<CalendarIcon className="w-3 h-3" /> Bắt đu
</label>
<input
type="date"
value={editingLegData.startDate}
onChange={(e) => setEditingLegData({ ...editingLegData, startDate: e.target.value })}
className="w-full px-5 py-4 bg-gray-50 dark:bg-slate-800 border border-gray-100 dark:border-slate-700 rounded-2xl focus:ring-2 focus:ring-blue-500 outline-none transition-all text-sm text-gray-800 dark:text-white"
/>
</div>
<div>
<label className="block text-xs font-black text-gray-400 dark:text-slate-400 uppercase tracking-widest mb-2 ml-1">Kết thúc</label>
<input
type="date"
value={editingLegData.endDate}
onChange={(e) => setEditingLegData({ ...editingLegData, endDate: e.target.value })}
className="w-full px-5 py-4 bg-gray-50 dark:bg-slate-800 border border-gray-100 dark:border-slate-700 rounded-2xl focus:ring-2 focus:ring-blue-500 outline-none transition-all text-sm text-gray-800 dark:text-white"
/>
</div>
</div>
</div>
<div className="grid grid-cols-2 gap-3 mt-8">
<button
onClick={() => setIsEditModalOpen(false)}
className="py-4 bg-gray-100 dark:bg-slate-800 hover:bg-gray-200 dark:hover:bg-slate-700 text-gray-600 dark:text-slate-300 font-bold rounded-2xl transition-all active:scale-95"
>
Hủy
</button>
<button
onClick={saveLegEdit}
className="py-4 bg-blue-600 dark:bg-blue-700 hover:bg-blue-700 dark:hover:bg-blue-800 text-white font-bold rounded-2xl shadow-lg shadow-blue-100 dark:shadow-blue-950 transition-all active:scale-95"
>
Lưu thay đi
</button>
</div>
</div>
</div>
)}
<div className="grid grid-cols-2 gap-3 mt-8 shrink-0">
<button
onClick={() => setIsEditModalOpen(false)}
className="py-4 bg-gray-100 dark:bg-slate-800 hover:bg-gray-200 dark:hover:bg-slate-700 text-gray-600 dark:text-slate-300 font-bold rounded-2xl transition-all active:scale-95"
>
Hủy
</button>
<button
onClick={saveLegEdit}
className="py-4 bg-blue-600 dark:bg-blue-700 hover:bg-blue-700 dark:hover:bg-blue-800 text-white font-bold rounded-2xl shadow-lg shadow-blue-100 dark:shadow-blue-950 transition-all active:scale-95"
>
Lưu thay đi
</button>
</div>
</div>
</div>
)}
<CommentModal
isOpen={isCommentModalOpen}
onClose={() => setIsCommentModalOpen(false)}
@@ -208,10 +208,10 @@ export const JoinTourLoginModal: React.FC<JoinTourLoginModalProps> = ({
if (!isOpen) return null;
return (
<div className="fixed inset-0 z-[3000] flex items-center justify-center p-4 bg-black/50">
<div className="w-full max-w-md bg-[var(--surface)] rounded-[32px] shadow-2xl overflow-hidden animate-in zoom-in-95 duration-200">
<div className="fixed inset-0 z-[3000] flex items-end sm:items-center justify-center p-0 sm:p-4 bg-black/50">
<div className="w-full h-full sm:w-auto sm:max-w-md sm:h-auto sm:max-h-[85vh] bg-[var(--surface)] rounded-t-2xl sm:rounded-[32px] shadow-2xl overflow-hidden animate-in zoom-in-95 duration-200 flex flex-col">
{/* Header */}
<div className="relative h-32 bg-gradient-to-r from-blue-500 via-purple-500 to-pink-500 overflow-hidden">
<div className="relative h-32 bg-gradient-to-r from-blue-500 via-purple-500 to-pink-500 overflow-hidden shrink-0">
<div className="absolute inset-0 opacity-10">
<div className="absolute inset-0 bg-[radial-gradient(circle_at_20%_50%,rgba(255,255,255,.3)_0%,transparent_50%)]" />
</div>
@@ -227,11 +227,11 @@ export const JoinTourLoginModal: React.FC<JoinTourLoginModalProps> = ({
</div>
{/* Content */}
<div className="p-8">
<h2 className="text-3xl font-bold text-[var(--text-primary)] mb-2 text-center">
<div className="flex-1 overflow-y-auto p-5 sm:p-8">
<h2 className="text-2xl sm:text-3xl font-bold text-[var(--text-primary)] mb-2 text-center">
Gia nhập tour
</h2>
<p className="text-center text-[var(--text-secondary)] mb-6">
<p className="text-center text-[var(--text-secondary)] mb-4 sm:mb-6">
Đăng nhập đ tham gia chuyến du lịch này
</p>
@@ -242,11 +242,11 @@ export const JoinTourLoginModal: React.FC<JoinTourLoginModalProps> = ({
)}
{/* Google OAuth Button */}
<div className="mb-6 flex justify-center">
<div className="mb-4 sm:mb-6 flex justify-center">
<div id="google-signin-btn-join-tour" className="w-full" />
</div>
<div className="relative mb-6">
<div className="relative mb-4 sm:mb-6">
<div className="absolute inset-0 flex items-center">
<div className="w-full border-t border-[var(--border)]" />
</div>
@@ -311,7 +311,7 @@ export const JoinTourLoginModal: React.FC<JoinTourLoginModalProps> = ({
</form>
{/* Signup Link */}
<div className="mt-6 text-center text-sm text-[var(--text-secondary)]">
<div className="mt-4 sm:mt-6 text-center text-sm text-[var(--text-secondary)]">
Chưa tài khoản?{' '}
<button
onClick={() => {
@@ -114,12 +114,12 @@ export const LocationNavigationModal: React.FC<NavModalProps> = ({ isOpen, onClo
: [0, 0];
return (
<div className="fixed inset-0 z-50 flex items-center justify-center bg-black/60 backdrop-blur-sm p-4">
<div className="bg-slate-900 border border-slate-700 w-full max-w-4xl h-[80vh] rounded-2xl overflow-hidden flex flex-col shadow-2xl">
<div className="fixed inset-0 z-50 flex items-end sm:items-center justify-center bg-black/60 backdrop-blur-sm p-0 sm:p-4">
<div className="bg-slate-900 border border-slate-700 w-full h-full sm:w-auto sm:max-w-4xl sm:h-[85vh] rounded-t-2xl sm:rounded-2xl overflow-hidden flex flex-col shadow-2xl animate-in zoom-in-95 duration-200">
{/* Modal Header */}
<div className="p-4 bg-slate-800 border-b border-slate-700 flex items-center justify-between">
<div className="p-4 bg-slate-800 border-b border-slate-700 flex items-center justify-between shrink-0">
<div>
<h3 className="text-md font-bold text-white flex items-center gap-2">
<h3 className="text-md sm:text-lg font-bold text-white flex items-center gap-2">
📍 Chỉ đưng đến: <span className="text-blue-400">{routeData.destination?.name}</span>
</h3>
<p className="text-xs text-gray-400 mt-0.5">Tuyến đưng ngắn nhất từ vị trí hiện tại của bạn</p>
+3 -3
View File
@@ -164,7 +164,7 @@ export const LoginModal: React.FC<LoginModalProps> = ({ isOpen, onClose, onSwitc
};
return (
<div className="fixed inset-0 z-50 flex items-center justify-center p-4 sm:p-6">
<div className="fixed inset-0 z-50 flex items-end sm:items-center justify-center p-0 sm:p-4">
{/* Backdrop */}
<div
className="absolute inset-0 bg-gray-900/60 backdrop-blur-sm animate-in fade-in duration-300"
@@ -172,8 +172,8 @@ export const LoginModal: React.FC<LoginModalProps> = ({ isOpen, onClose, onSwitc
/>
{/* Modal Content */}
<div className="relative w-full max-w-md bg-[var(--surface)] rounded-3xl shadow-2xl overflow-hidden max-h-[90vh] overflow-y-auto animate-in zoom-in-95 duration-300">
<div className="p-8 sm:p-10">
<div className="relative w-full sm:max-w-md bg-[var(--surface)] rounded-t-2xl sm:rounded-3xl shadow-2xl overflow-hidden sm:max-h-[85vh] flex flex-col h-full animate-in zoom-in-95 duration-300">
<div className="p-8 sm:p-10 flex-1 overflow-y-auto">
<div className="flex justify-between items-start mb-8">
<div>
<h2 className="text-3xl font-bold text-[var(--text-primary)]">Đăng nhập</h2>
+4 -4
View File
@@ -439,16 +439,16 @@ export const MembersTab: React.FC<MembersTabProps> = ({
{/* Manual Merge Modal Selector */}
{assigningManualMember && (
<div className="fixed inset-0 z-[2000] flex items-center justify-center p-4">
<div className="fixed inset-0 z-[2000] flex items-end sm:items-center justify-center p-0 sm:p-4">
<div className="absolute inset-0 bg-gray-900/60 backdrop-blur-sm" onClick={() => setAssigningManualMember(null)} />
<div className="relative w-full max-w-md bg-white rounded-3xl shadow-2xl overflow-hidden flex flex-col max-h-[80vh] animate-in zoom-in-95 duration-200">
<div className="p-5 border-b border-gray-100 flex justify-between items-center bg-gray-50/50">
<div className="relative w-full sm:max-w-md bg-white rounded-t-2xl sm:rounded-3xl shadow-2xl overflow-hidden flex flex-col h-full sm:h-auto sm:max-h-[85vh] animate-in zoom-in-95 duration-200">
<div className="p-5 border-b border-gray-100 flex justify-between items-center bg-gray-50/50 shrink-0">
<div>
<h3 className="text-md font-bold text-gray-900 flex items-center gap-2">
<GitMerge className="w-5 h-5 text-indigo-600" /> Gán tài khoản hệ thống
</h3>
<p className="text-xs text-gray-500 mt-1">
Chọn một tài khoản hệ thống đ gán cho thành viên thủ công <strong>"{assigningManualMember.displayName}"</strong>.
Chọn một tài khoản hệ thống đ gán cho thành viên thủ c<strong>"{assigningManualMember.displayName}"</strong>.
</p>
</div>
<button
@@ -34,24 +34,24 @@ export const NotificationModal: React.FC<NotificationModalProps> = ({
};
return (
<div className="fixed inset-0 z-[3000] flex items-center justify-center p-4">
<div className="fixed inset-0 z-[3000] flex items-end sm:items-center justify-center p-0 sm:p-4">
{/* Backdrop */}
<div className="absolute inset-0 bg-gray-900/60 backdrop-blur-sm animate-in fade-in duration-200" onClick={onConfirm} />
{/* Modal Content */}
<div className="relative w-full max-w-sm bg-[var(--surface)] rounded-[32px] shadow-2xl overflow-hidden p-8 text-center animate-in zoom-in-95 duration-200">
<div className="flex justify-center mb-5">
<div className="relative w-full sm:max-w-sm bg-[var(--surface)] rounded-t-2xl sm:rounded-[32px] shadow-2xl overflow-hidden p-8 sm:p-8 h-full sm:h-auto sm:max-h-[85vh] flex flex-col animate-in zoom-in-95 duration-200">
<div className="flex justify-center mb-5 shrink-0">
{icons[type]}
</div>
<h2 className="text-xl font-black text-[var(--text-primary)] mb-2">{title}</h2>
<p className="text-[var(--text-muted)] text-sm leading-relaxed mb-8">
<p className="text-[var(--text-muted)] text-sm leading-relaxed mb-8 flex-1">
{message || "Bạn không được phép gỡ bỏ thành viên này!"}
</p>
<button
onClick={onConfirm}
className={`w-full py-4 text-white font-bold rounded-2xl transition-all shadow-lg active:scale-95 ${colors[type]}`}
className={`w-full py-4 text-white font-bold rounded-2xl transition-all shadow-lg active:scale-95 mt-auto ${colors[type]}`}
>
Đã hiểu
</button>
+2 -2
View File
@@ -819,7 +819,7 @@ export const PublicPhotoModal: React.FC<PublicPhotoModalProps> = ({
{isFullscreen && (
<div
className="fixed inset-0 z-[9999] bg-black/95 flex items-center justify-center cursor-zoom-out animate-in fade-in duration-200"
className="fixed inset-0 z-[9999] bg-black/95 flex items-end sm:items-center justify-center cursor-zoom-out animate-in fade-in duration-200"
onClick={() => setIsFullscreen(false)}
>
<button
@@ -833,7 +833,7 @@ export const PublicPhotoModal: React.FC<PublicPhotoModalProps> = ({
alt="Fullscreen photo"
onContextMenu={(e) => { if (!isLoggedIn) e.preventDefault(); }}
onDragStart={(e) => { if (!isLoggedIn) e.preventDefault(); }}
className={`max-w-full max-h-full object-contain select-none animate-in zoom-in-95 duration-200 ${
className={`max-w-full max-h-full sm:max-w-screen-md object-contain select-none animate-in zoom-in-95 duration-200 ${
!isLoggedIn ? 'pointer-events-none' : ''
}`}
/>
@@ -100,19 +100,14 @@ export const ReportBusinessModal: React.FC<ReportBusinessModalProps> = ({
}
};
return (
<div className="fixed inset-0 z-[3000] flex items-center justify-center p-4">
{/* Backdrop */}
<div
className="absolute inset-0 bg-gray-900/60 backdrop-blur-sm animate-in fade-in duration-300"
onClick={onClose}
/>
return (
<div className="fixed inset-0 z-[3000] flex items-end sm:items-center justify-center p-0 sm:p-4 bg-black/50">
{/* Content Container */}
<div className="relative w-full max-w-lg bg-white rounded-3xl shadow-2xl overflow-hidden animate-in zoom-in-95 duration-300 flex flex-col max-h-[90vh]">
<div className="relative w-full h-full sm:max-w-lg bg-white rounded-t-2xl sm:rounded-3xl shadow-2xl overflow-hidden animate-in zoom-in-95 duration-300 flex flex-col sm:max-h-[85vh]">
{/* Header */}
<div className="p-6 border-b border-gray-100 flex justify-between items-center bg-gray-50/50">
<div className="p-6 border-b border-gray-100 flex justify-between items-center bg-gray-50/50 shrink-0">
<div className="flex items-center gap-3">
<div className="p-2 bg-red-50 text-red-500 rounded-xl">
<ShieldAlert className="w-6 h-6" />
@@ -131,7 +126,7 @@ export const ReportBusinessModal: React.FC<ReportBusinessModalProps> = ({
</div>
{success ? (
<div className="p-10 flex flex-col items-center justify-center text-center space-y-4">
<div className="p-10 flex flex-col items-center justify-center text-center space-y-4 flex-1">
<div className="w-16 h-16 bg-emerald-100 text-emerald-600 rounded-full flex items-center justify-center shadow-lg animate-bounce">
<ShieldAlert className="w-8 h-8" />
</div>
@@ -147,7 +142,6 @@ export const ReportBusinessModal: React.FC<ReportBusinessModalProps> = ({
</div>
)}
{/* Loại hình */}
<div className="space-y-1.5">
<label className="text-xs font-bold text-gray-500 uppercase tracking-wider">{t('businessType')} *</label>
<select
@@ -162,7 +156,6 @@ export const ReportBusinessModal: React.FC<ReportBusinessModalProps> = ({
</select>
</div>
{/* Tên */}
<div className="space-y-1.5">
<label className="text-xs font-bold text-gray-500 uppercase tracking-wider">{t('businessName')} *</label>
<input
@@ -176,7 +169,6 @@ export const ReportBusinessModal: React.FC<ReportBusinessModalProps> = ({
</div>
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
{/* Số điện thoại */}
<div className="space-y-1.5">
<label className="text-xs font-bold text-gray-500 uppercase tracking-wider flex items-center gap-1">
<Phone className="w-3.5 h-3.5 text-gray-400" /> {t('businessPhone')}
@@ -190,7 +182,6 @@ export const ReportBusinessModal: React.FC<ReportBusinessModalProps> = ({
/>
</div>
{/* Email */}
<div className="space-y-1.5">
<label className="text-xs font-bold text-gray-500 uppercase tracking-wider flex items-center gap-1">
<Mail className="w-3.5 h-3.5 text-gray-400" /> {t('businessEmail')}
@@ -205,7 +196,6 @@ export const ReportBusinessModal: React.FC<ReportBusinessModalProps> = ({
</div>
</div>
{/* Địa chỉ */}
<div className="space-y-1.5">
<label className="text-xs font-bold text-gray-500 uppercase tracking-wider flex items-center gap-1">
<MapPin className="w-3.5 h-3.5 text-gray-400" /> {t('businessAddress')}
@@ -214,12 +204,11 @@ export const ReportBusinessModal: React.FC<ReportBusinessModalProps> = ({
type="text"
value={address}
onChange={(e) => setAddress(e.target.value)}
placeholder="VD: 123 Đường Trần Phú, Đà Lạt..."
placeholder="VD: 123 Đường Trần Phú, Đà Nẵng..."
className="w-full px-4 py-3 bg-gray-50 border border-gray-100 rounded-2xl focus:ring-2 focus:ring-blue-500 focus:bg-white outline-none transition-all text-sm text-gray-800"
/>
</div>
{/* Tọa độ địa lý */}
<div className="space-y-1.5 bg-blue-50/50 p-4 rounded-2xl border border-blue-100">
<div className="flex justify-between items-center mb-2">
<span className="text-xs font-bold text-blue-700 uppercase tracking-wider flex items-center gap-1.5">
@@ -259,7 +248,6 @@ export const ReportBusinessModal: React.FC<ReportBusinessModalProps> = ({
</div>
</div>
{/* Lý do */}
<div className="space-y-1.5">
<label className="text-xs font-bold text-gray-500 uppercase tracking-wider">{t('reportReason')} *</label>
<textarea
+7 -7
View File
@@ -66,16 +66,16 @@ export const TagSelectModal: React.FC<TagSelectModalProps> = ({ isOpen, onClose,
if (!isOpen) return null;
return (
<div className="fixed inset-0 z-[6000] flex items-center justify-center p-4">
return (
<div className="fixed inset-0 z-[6000] flex items-end sm:items-center justify-center p-0 sm:p-4">
<div
className="absolute inset-0 bg-slate-950/80 backdrop-blur-md"
onClick={handleClose}
/>
<div className="relative bg-white dark:bg-slate-900 rounded-3xl shadow-2xl max-w-md w-full max-h-[90vh] overflow-y-auto animate-in zoom-in-95 duration-300">
<div className="relative bg-white dark:bg-slate-900 w-full h-full sm:w-auto sm:max-w-md sm:h-auto sm:max-h-[85vh] rounded-t-2xl sm:rounded-3xl shadow-2xl flex flex-col overflow-hidden animate-in zoom-in-95 duration-300">
{/* Header */}
<div className="sticky top-0 bg-white dark:bg-slate-900 border-b border-gray-200 dark:border-slate-700 px-6 py-5 flex justify-between items-center">
<div className="sticky top-0 bg-white dark:bg-slate-900 border-b border-gray-200 dark:border-slate-700 px-6 py-5 flex justify-between items-center shrink-0">
<h2 className="text-xl font-bold text-gray-900 dark:text-white">
🏷 Lựa chọn thẻ
</h2>
@@ -87,8 +87,8 @@ export const TagSelectModal: React.FC<TagSelectModalProps> = ({ isOpen, onClose,
</button>
</div>
{/* Content */}
<div className="p-6 space-y-6">
{/* Content */}
<div className="p-6 space-y-6 overflow-y-auto flex-1">
{/* Image Preview */}
{photoUrl && (
<div className="flex justify-center">
@@ -201,7 +201,7 @@ export const TagSelectModal: React.FC<TagSelectModalProps> = ({ isOpen, onClose,
</div>
{/* Footer */}
<div className="sticky bottom-0 bg-white dark:bg-slate-900 border-t border-gray-200 dark:border-slate-700 px-6 py-4 flex gap-3">
<div className="sticky bottom-0 bg-white dark:bg-slate-900 border-t border-gray-200 dark:border-slate-700 px-6 py-4 flex gap-3 shrink-0">
<button
onClick={handleClose}
className="flex-1 px-4 py-3 rounded-xl border-2 border-gray-200 dark:border-slate-700 text-gray-900 dark:text-white font-bold hover:bg-gray-100 dark:hover:bg-slate-800 transition-colors"
@@ -797,13 +797,13 @@ export const UserManagementModal: React.FC<UserManagementModalProps> = ({ isOpen
}
};
return (
<div className="fixed inset-0 z-[2000] flex items-center justify-center p-4">
return (
<div className="fixed inset-0 z-[2000] flex items-end sm:items-center justify-center p-0 sm:p-4">
<div className="absolute inset-0 bg-gray-900/60 backdrop-blur-sm" onClick={onClose} />
<div className="relative w-full max-w-5xl bg-white rounded-3xl shadow-2xl overflow-hidden flex flex-col h-[85vh]">
<div className="relative w-full sm:max-w-5xl bg-white rounded-t-2xl sm:rounded-3xl shadow-2xl overflow-hidden flex flex-col h-full sm:h-auto sm:max-h-[85vh] animate-in zoom-in-95 duration-200">
{/* Header */}
<div className="p-6 border-b border-gray-100 flex justify-between items-center bg-gray-50/50">
<div className="p-6 sm:p-6 border-b border-gray-100 flex justify-between items-center bg-gray-50/50 shrink-0">
<div>
<h2 className="text-2xl font-bold text-gray-900 flex items-center gap-2">
<Shield className="w-6 h-6 text-blue-600" /> Hệ thống quản trị