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
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+2 -2
View File
@@ -21,8 +21,8 @@
<meta name="twitter:title" content="Travel Planner - Lên kế hoạch chuyến đi của bạn" />
<meta name="twitter:description" content="Khám phá những hành trình tuyệt vời và chia sẻ khoảnh khắc đẹp với cộng đồng du lịch." />
<meta name="twitter:image" content="https://yotrip.labz.io.vn/background.avif" />
<script type="module" crossorigin src="/assets/index-D6jMbgMg.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-nLng8wU9.css">
<script type="module" crossorigin src="/assets/index-C49gWVYr.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-D3gckKlS.css">
</head>
<body>
<div id="root"></div>
+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ị