mirror of
https://github.com/alexmickelson/canvasManagement.git
synced 2026-03-26 07:38:33 -06:00
crazy tooltips
This commit is contained in:
@@ -1,12 +1,13 @@
|
||||
import { IModuleItem } from "@/models/local/IModuleItem";
|
||||
import { getModuleItemUrl } from "@/services/urlUtils";
|
||||
import Link from "next/link";
|
||||
import { ReactNode } from "react";
|
||||
import { ReactNode, useEffect, useRef, useState } from "react";
|
||||
import { useCourseContext } from "../../context/courseContext";
|
||||
import {
|
||||
useDraggingContext,
|
||||
DraggableItem,
|
||||
} from "../../context/draggingContext";
|
||||
import { createPortal } from "react-dom";
|
||||
|
||||
export function ItemInDay({
|
||||
type,
|
||||
@@ -23,6 +24,8 @@ export function ItemInDay({
|
||||
}) {
|
||||
const { courseName } = useCourseContext();
|
||||
const { dragStart } = useDraggingContext();
|
||||
const linkRef = useRef<HTMLAnchorElement>(null);
|
||||
const [tooltipVisible, setTooltipVisible] = useState(false);
|
||||
return (
|
||||
<div className={" relative group "}>
|
||||
<Link
|
||||
@@ -50,24 +53,78 @@ export function ItemInDay({
|
||||
);
|
||||
dragStart();
|
||||
}}
|
||||
onMouseEnter={() => setTooltipVisible(true)}
|
||||
onMouseLeave={() => setTooltipVisible(false)}
|
||||
ref={linkRef}
|
||||
>
|
||||
{item.name}
|
||||
</Link>
|
||||
{status === "incomplete" && (
|
||||
<Tooltip
|
||||
message={message}
|
||||
targetRef={linkRef}
|
||||
visible={tooltipVisible && status === "incomplete"}
|
||||
/>
|
||||
{/* {status === "incomplete" && (
|
||||
<div
|
||||
className={
|
||||
" absolute opacity-0 transition-all duration-700 " +
|
||||
" group-hover:block group-hover:opacity-100" +
|
||||
" hidden group-hover:block group-hover:opacity-100" +
|
||||
" bg-gray-800 text-white text-sm " +
|
||||
" rounded py-1 px-2 " +
|
||||
" top-full mt-2 transform left-1/2 -translate-x-1/2 " +
|
||||
" whitespace-no-wrap min-w-full max-w-96 "
|
||||
" whitespace-no-wrap min-w-full max-w-96 overflow-visible "
|
||||
}
|
||||
role="tooltip"
|
||||
>
|
||||
{message}
|
||||
</div>
|
||||
)}
|
||||
)} */}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
const Tooltip: React.FC<{
|
||||
message: ReactNode;
|
||||
targetRef: React.RefObject<HTMLElement>;
|
||||
visible: boolean;
|
||||
}> = ({ message, targetRef, visible }) => {
|
||||
const [position, setPosition] = useState({ top: 0, left: 0 });
|
||||
|
||||
useEffect(() => {
|
||||
if (targetRef.current && visible) {
|
||||
const rect = targetRef.current.getBoundingClientRect();
|
||||
// Calculate tooltip position relative to the target
|
||||
setPosition({
|
||||
top: rect.bottom + window.scrollY + 10, // Adjust based on your needs
|
||||
left: rect.left + window.scrollX + rect.width / 2, // Center tooltip
|
||||
});
|
||||
}
|
||||
}, [targetRef, visible]);
|
||||
|
||||
// if (!visible) return null;
|
||||
|
||||
return createPortal(
|
||||
<div
|
||||
style={{
|
||||
top: position.top,
|
||||
left: position.left,
|
||||
}}
|
||||
className={
|
||||
" absolute -translate-x-1/2 " +
|
||||
" bg-gray-800 text-white text-sm " +
|
||||
" rounded py-1 px-2 " +
|
||||
" transition-all duration-700 " +
|
||||
(visible ? " opacity-100 " : " opacity-0 -z-50 ")
|
||||
// " hidden group-hover:block group-hover:opacity-100" +
|
||||
// " bg-gray-800 text-white text-sm " +
|
||||
// " rounded py-1 px-2 " +
|
||||
// " top-full mt-2 transform left-1/2 " +
|
||||
// " whitespace-no-wrap min-w-full max-w-96 overflow-visible "
|
||||
}
|
||||
role="tooltip"
|
||||
>
|
||||
{message}
|
||||
</div>,
|
||||
document.body // Render outside of overflow-hidden parent
|
||||
);
|
||||
};
|
||||
|
||||
@@ -34,14 +34,12 @@ export default function ExpandableModule({
|
||||
}: {
|
||||
moduleName: string;
|
||||
}) {
|
||||
const { data: assignmentNames } = useAssignmentNamesQuery(moduleName);
|
||||
const { data: quizNames } = useQuizNamesQuery(moduleName);
|
||||
const { data: pageNames } = usePageNamesQuery(moduleName);
|
||||
const { itemDropOnModule } = useDraggingContext();
|
||||
|
||||
const { data: assignments } = useAssignmentsQueries(
|
||||
moduleName,
|
||||
assignmentNames
|
||||
);
|
||||
const { data: quizzes } = useQuizzesQueries(moduleName, quizNames);
|
||||
const { data: pages } = usePagesQueries(moduleName, pageNames);
|
||||
|
||||
@@ -0,0 +1,152 @@
|
||||
import { useCourseContext } from "@/app/course/[courseName]/context/courseContext";
|
||||
import Modal from "@/components/Modal";
|
||||
import { Spinner } from "@/components/Spinner";
|
||||
import {
|
||||
useCanvasAssignmentsQuery,
|
||||
useAddAssignmentToCanvasMutation,
|
||||
useDeleteAssignmentFromCanvasMutation,
|
||||
useUpdateAssignmentInCanvasMutation,
|
||||
} from "@/hooks/canvas/canvasAssignmentHooks";
|
||||
import {
|
||||
useAssignmentQuery,
|
||||
useDeleteAssignmentMutation,
|
||||
} from "@/hooks/localCourse/assignmentHooks";
|
||||
import { useLocalCourseSettingsQuery } from "@/hooks/localCourse/localCoursesHooks";
|
||||
import { baseCanvasUrl } from "@/services/canvas/canvasServiceUtils";
|
||||
import { getCourseUrl } from "@/services/urlUtils";
|
||||
import Link from "next/link";
|
||||
import { useRouter } from "next/navigation";
|
||||
|
||||
export function AssignmentButtons({
|
||||
moduleName,
|
||||
assignmentName,
|
||||
toggleHelp,
|
||||
}: {
|
||||
assignmentName: string;
|
||||
moduleName: string;
|
||||
toggleHelp: () => void;
|
||||
}) {
|
||||
const router = useRouter();
|
||||
const { courseName } = useCourseContext();
|
||||
const { data: settings } = useLocalCourseSettingsQuery();
|
||||
const {
|
||||
data: canvasAssignments,
|
||||
isPending: canvasIsPending,
|
||||
isRefetching: canvasIsRefetching,
|
||||
} = useCanvasAssignmentsQuery();
|
||||
const {
|
||||
data: assignment,
|
||||
isPending: assignmentIsPending,
|
||||
isRefetching,
|
||||
} = useAssignmentQuery(moduleName, assignmentName);
|
||||
const addToCanvas = useAddAssignmentToCanvasMutation();
|
||||
const deleteFromCanvas = useDeleteAssignmentFromCanvasMutation();
|
||||
const updateAssignment = useUpdateAssignmentInCanvasMutation();
|
||||
const deleteLocal = useDeleteAssignmentMutation();
|
||||
|
||||
const assignmentInCanvas = canvasAssignments.find(
|
||||
(a) => a.name === assignmentName
|
||||
);
|
||||
|
||||
const anythingIsLoading =
|
||||
addToCanvas.isPending ||
|
||||
canvasIsPending ||
|
||||
assignmentIsPending ||
|
||||
isRefetching ||
|
||||
canvasIsRefetching ||
|
||||
deleteFromCanvas.isPending ||
|
||||
updateAssignment.isPending;
|
||||
|
||||
return (
|
||||
<div className="p-5 flex flex-row justify-between gap-3">
|
||||
<div>
|
||||
<button onClick={toggleHelp}>Toggle Help</button>
|
||||
</div>
|
||||
<div className="flex flex-row gap-3 justify-end">
|
||||
{anythingIsLoading && <Spinner />}
|
||||
{assignmentInCanvas && !assignmentInCanvas.published && (
|
||||
<div className="text-rose-300 my-auto">Not Published</div>
|
||||
)}
|
||||
{!assignmentInCanvas && (
|
||||
<button
|
||||
disabled={addToCanvas.isPending}
|
||||
onClick={() => addToCanvas.mutate({ assignment, moduleName })}
|
||||
>
|
||||
Add to canvas
|
||||
</button>
|
||||
)}
|
||||
{assignmentInCanvas && (
|
||||
<a
|
||||
className="btn"
|
||||
target="_blank"
|
||||
href={`${baseCanvasUrl}/courses/${settings.canvasId}/assignments/${assignmentInCanvas.id}`}
|
||||
>
|
||||
View in Canvas
|
||||
</a>
|
||||
)}
|
||||
{assignmentInCanvas && (
|
||||
<button
|
||||
className=""
|
||||
disabled={deleteFromCanvas.isPending}
|
||||
onClick={() =>
|
||||
updateAssignment.mutate({
|
||||
canvasAssignmentId: assignmentInCanvas.id,
|
||||
assignment,
|
||||
})
|
||||
}
|
||||
>
|
||||
Update in Canvas
|
||||
</button>
|
||||
)}
|
||||
{assignmentInCanvas && (
|
||||
<button
|
||||
className="btn-danger"
|
||||
disabled={deleteFromCanvas.isPending}
|
||||
onClick={() =>
|
||||
deleteFromCanvas.mutate({
|
||||
canvasAssignmentId: assignmentInCanvas.id,
|
||||
assignmentName: assignment.name,
|
||||
})
|
||||
}
|
||||
>
|
||||
Delete from Canvas
|
||||
</button>
|
||||
)}
|
||||
{!assignmentInCanvas && (
|
||||
<Modal
|
||||
buttonText="Delete Localy"
|
||||
buttonClass="btn-danger"
|
||||
modalWidth="w-1/5"
|
||||
>
|
||||
{({ closeModal }) => (
|
||||
<div>
|
||||
<div className="text-center">
|
||||
Are you sure you want to delete this quiz locally?
|
||||
</div>
|
||||
<br />
|
||||
<div className="flex justify-around gap-3">
|
||||
<button
|
||||
onClick={() => {
|
||||
deleteLocal
|
||||
.mutateAsync({ moduleName, assignmentName })
|
||||
.then(() => {
|
||||
router.push(getCourseUrl(courseName));
|
||||
});
|
||||
}}
|
||||
className="btn-danger"
|
||||
>
|
||||
Yes
|
||||
</button>
|
||||
<button onClick={closeModal}>No</button>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</Modal>
|
||||
)}
|
||||
<Link className="btn" href={getCourseUrl(courseName)} shallow={true}>
|
||||
Go Back
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -24,6 +24,7 @@ import { SuspenseAndErrorHandling } from "@/components/SuspenseAndErrorHandling"
|
||||
import { AssignmentSubmissionType } from "@/models/local/assignment/assignmentSubmissionType";
|
||||
import { LocalCourseSettings } from "@/models/local/localCourse";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { AssignmentButtons } from "./AssignmentButtons";
|
||||
|
||||
export default function EditAssignment({
|
||||
moduleName,
|
||||
@@ -141,104 +142,3 @@ Assignment Group Names:
|
||||
- ${groupNames}`;
|
||||
return helpString;
|
||||
}
|
||||
|
||||
function AssignmentButtons({
|
||||
moduleName,
|
||||
assignmentName,
|
||||
toggleHelp,
|
||||
}: {
|
||||
assignmentName: string;
|
||||
moduleName: string;
|
||||
toggleHelp: () => void;
|
||||
}) {
|
||||
const { courseName } = useCourseContext();
|
||||
const { data: settings } = useLocalCourseSettingsQuery();
|
||||
const {
|
||||
data: canvasAssignments,
|
||||
isPending: canvasIsPending,
|
||||
isRefetching: canvasIsRefetching,
|
||||
} = useCanvasAssignmentsQuery();
|
||||
const {
|
||||
data: assignment,
|
||||
isPending: assignmentIsPending,
|
||||
isRefetching,
|
||||
} = useAssignmentQuery(moduleName, assignmentName);
|
||||
const addToCanvas = useAddAssignmentToCanvasMutation();
|
||||
const deleteFromCanvas = useDeleteAssignmentFromCanvasMutation();
|
||||
const updateAssignment = useUpdateAssignmentInCanvasMutation();
|
||||
|
||||
const assignmentInCanvas = canvasAssignments.find(
|
||||
(a) => a.name === assignmentName
|
||||
);
|
||||
|
||||
const anythingIsLoading =
|
||||
addToCanvas.isPending ||
|
||||
canvasIsPending ||
|
||||
assignmentIsPending ||
|
||||
isRefetching ||
|
||||
canvasIsRefetching ||
|
||||
deleteFromCanvas.isPending ||
|
||||
updateAssignment.isPending;
|
||||
|
||||
return (
|
||||
<div className="p-5 flex flex-row justify-between gap-3">
|
||||
<div>
|
||||
<button onClick={toggleHelp}>Toggle Help</button>
|
||||
</div>
|
||||
<div className="flex flex-row gap-3 justify-end">
|
||||
{anythingIsLoading && <Spinner />}
|
||||
{assignmentInCanvas && !assignmentInCanvas.published && (
|
||||
<div className="text-rose-300 my-auto">Not Published</div>
|
||||
)}
|
||||
{!assignmentInCanvas && (
|
||||
<button
|
||||
disabled={addToCanvas.isPending}
|
||||
onClick={() => addToCanvas.mutate({ assignment, moduleName })}
|
||||
>
|
||||
Add to canvas
|
||||
</button>
|
||||
)}
|
||||
{assignmentInCanvas && (
|
||||
<a
|
||||
className="btn"
|
||||
target="_blank"
|
||||
href={`${baseCanvasUrl}/courses/${settings.canvasId}/assignments/${assignmentInCanvas.id}`}
|
||||
>
|
||||
View in Canvas
|
||||
</a>
|
||||
)}
|
||||
{assignmentInCanvas && (
|
||||
<button
|
||||
className=""
|
||||
disabled={deleteFromCanvas.isPending}
|
||||
onClick={() =>
|
||||
updateAssignment.mutate({
|
||||
canvasAssignmentId: assignmentInCanvas.id,
|
||||
assignment,
|
||||
})
|
||||
}
|
||||
>
|
||||
Update in Canvas
|
||||
</button>
|
||||
)}
|
||||
{assignmentInCanvas && (
|
||||
<button
|
||||
className="btn-danger"
|
||||
disabled={deleteFromCanvas.isPending}
|
||||
onClick={() =>
|
||||
deleteFromCanvas.mutate({
|
||||
canvasAssignmentId: assignmentInCanvas.id,
|
||||
assignmentName: assignment.name,
|
||||
})
|
||||
}
|
||||
>
|
||||
Delete from Canvas
|
||||
</button>
|
||||
)}
|
||||
<Link className="btn" href={getCourseUrl(courseName)} shallow={true}>
|
||||
Go Back
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user