feat: Implement task addition modal with escape key handling and z-index adjustments
This commit is contained in:
@@ -12,6 +12,7 @@ export default function ProjectTasksSection({ projectId }) {
|
||||
const [taskNotes, setTaskNotes] = useState({});
|
||||
const [newNote, setNewNote] = useState({});
|
||||
const [loadingNotes, setLoadingNotes] = useState({});
|
||||
const [showAddTaskModal, setShowAddTaskModal] = useState(false);
|
||||
useEffect(() => {
|
||||
const fetchProjectTasks = async () => {
|
||||
try {
|
||||
@@ -46,6 +47,67 @@ export default function ProjectTasksSection({ projectId }) {
|
||||
|
||||
fetchProjectTasks();
|
||||
}, [projectId]);
|
||||
// Handle escape key to close modal
|
||||
useEffect(() => {
|
||||
const handleEscape = (e) => {
|
||||
if (e.key === "Escape" && showAddTaskModal) {
|
||||
setShowAddTaskModal(false);
|
||||
}
|
||||
};
|
||||
|
||||
document.addEventListener("keydown", handleEscape);
|
||||
return () => document.removeEventListener("keydown", handleEscape);
|
||||
}, [showAddTaskModal]);
|
||||
// Prevent body scroll when modal is open and handle map z-index
|
||||
useEffect(() => {
|
||||
if (showAddTaskModal) {
|
||||
// Prevent body scroll
|
||||
document.body.style.overflow = "hidden";
|
||||
|
||||
// Find and temporarily lower z-index of leaflet containers
|
||||
const leafletContainers = document.querySelectorAll(".leaflet-container");
|
||||
leafletContainers.forEach((container) => {
|
||||
container.style.zIndex = "1";
|
||||
});
|
||||
|
||||
// Also handle navigation and other potential high z-index elements
|
||||
const navElements = document.querySelectorAll("nav");
|
||||
navElements.forEach((nav) => {
|
||||
nav.style.position = "relative";
|
||||
nav.style.zIndex = "1";
|
||||
});
|
||||
} else {
|
||||
// Restore body scroll
|
||||
document.body.style.overflow = "unset";
|
||||
|
||||
// Restore leaflet container z-index
|
||||
const leafletContainers = document.querySelectorAll(".leaflet-container");
|
||||
leafletContainers.forEach((container) => {
|
||||
container.style.zIndex = "";
|
||||
});
|
||||
|
||||
// Restore navigation z-index
|
||||
const navElements = document.querySelectorAll("nav");
|
||||
navElements.forEach((nav) => {
|
||||
nav.style.position = "";
|
||||
nav.style.zIndex = "";
|
||||
});
|
||||
}
|
||||
|
||||
// Cleanup function
|
||||
return () => {
|
||||
document.body.style.overflow = "unset";
|
||||
const leafletContainers = document.querySelectorAll(".leaflet-container");
|
||||
leafletContainers.forEach((container) => {
|
||||
container.style.zIndex = "";
|
||||
});
|
||||
const navElements = document.querySelectorAll("nav");
|
||||
navElements.forEach((nav) => {
|
||||
nav.style.position = "";
|
||||
nav.style.zIndex = "";
|
||||
});
|
||||
};
|
||||
}, [showAddTaskModal]);
|
||||
const refetchTasks = async () => {
|
||||
try {
|
||||
const res = await fetch(`/api/project-tasks?project_id=${projectId}`);
|
||||
@@ -76,6 +138,7 @@ export default function ProjectTasksSection({ projectId }) {
|
||||
};
|
||||
const handleTaskAdded = () => {
|
||||
refetchTasks(); // Refresh the list
|
||||
setShowAddTaskModal(false); // Close the modal
|
||||
};
|
||||
|
||||
const handleStatusChange = async (taskId, newStatus) => {
|
||||
@@ -197,24 +260,79 @@ export default function ProjectTasksSection({ projectId }) {
|
||||
<div className="space-y-6">
|
||||
<div className="flex items-center justify-between">
|
||||
<h2 className="text-xl font-semibold text-gray-900">Project Tasks</h2>
|
||||
<Badge variant="default" className="text-sm">
|
||||
{projectTasks.length} {projectTasks.length === 1 ? "task" : "tasks"}
|
||||
</Badge>
|
||||
</div>
|
||||
|
||||
{/* Add New Task Card */}
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<h3 className="text-lg font-medium text-gray-900">Add New Task</h3>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<ProjectTaskForm
|
||||
projectId={projectId}
|
||||
onTaskAdded={handleTaskAdded}
|
||||
/>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<div className="flex items-center gap-3">
|
||||
<Badge variant="default" className="text-sm">
|
||||
{projectTasks.length} {projectTasks.length === 1 ? "task" : "tasks"}
|
||||
</Badge>
|
||||
<Button
|
||||
variant="primary"
|
||||
size="sm"
|
||||
onClick={() => setShowAddTaskModal(true)}
|
||||
>
|
||||
<svg
|
||||
className="w-4 h-4 mr-2"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth={2}
|
||||
d="M12 4v16m8-8H4"
|
||||
/>
|
||||
</svg>
|
||||
Add Task
|
||||
</Button>
|
||||
</div>
|
||||
</div>{" "}
|
||||
{/* Add Task Modal */}
|
||||
{showAddTaskModal && (
|
||||
<div
|
||||
className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center"
|
||||
style={{ zIndex: 99999 }}
|
||||
onClick={(e) => {
|
||||
if (e.target === e.currentTarget) {
|
||||
setShowAddTaskModal(false);
|
||||
}
|
||||
}}
|
||||
>
|
||||
<div
|
||||
className="bg-white rounded-lg shadow-xl max-w-2xl w-full mx-4 max-h-[90vh] overflow-y-auto"
|
||||
style={{ zIndex: 100000 }}
|
||||
>
|
||||
<div className="flex items-center justify-between p-6 border-b">
|
||||
<h3 className="text-lg font-semibold text-gray-900">
|
||||
Add New Task
|
||||
</h3>
|
||||
<button
|
||||
onClick={() => setShowAddTaskModal(false)}
|
||||
className="text-gray-400 hover:text-gray-600 transition-colors"
|
||||
>
|
||||
<svg
|
||||
className="w-6 h-6"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth={2}
|
||||
d="M6 18L18 6M6 6l12 12"
|
||||
/>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
<div className="p-6">
|
||||
<ProjectTaskForm
|
||||
projectId={projectId}
|
||||
onTaskAdded={handleTaskAdded}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{/* Current Tasks */}
|
||||
<Card>
|
||||
<CardHeader>
|
||||
|
||||
Reference in New Issue
Block a user