Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
97 changes: 26 additions & 71 deletions src/pages/Notification.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,39 +6,39 @@ import { transitionEnter } from "../utils/motion";
import { useNotification } from "@/Zustand/Store";
import { MdOutlineSettingsInputComposite } from "react-icons/md";
import { Link } from "react-router-dom";
import { ConfirmationModal } from "@/components/ConfirmationModal";
import { X } from "lucide-react";
import { Pagination } from "@/components/Pagination";
import { paginate } from "@/utils/paginate";
import { usePrefersReducedMotion } from "../utils/usePrefersReducedMotion"; // <-- Import the hook

export default function Notification() {
const notifications = useNotification((state) => state.notification);
const setNotifications = useNotification((state) => state.setNotification);
const dismiss = useNotification((state) => state.dismiss);
const clearAll = useNotification((state) => state.clearAll);
const [currentNotification, setCurrentNotification] = useState(notifications);
const [currentFilterReadSeletion, setCurrentFilterReadSeletion] =
useState("all");
const [currentFilterTypeSeletion, setCurrentFilterTypeSeletion] =
useState("all");
const [currentFilterReadSeletion, setCurrentFilterReadSeletion] = useState("all");
const [currentFilterTypeSeletion, setCurrentFilterTypeSeletion] = useState("all");
const [currentPage, setCurrentPage] = useState(1);
const [isFilterOpen, setIsFilterOpen] = useState(false);
const [isPreferenceOpen, setIsPreferenceOpen] = useState(false);
const [showClearModal, setShowClearModal] = useState(false);
const itemsPerPage = 5;

const pagination = paginate(currentNotification, currentPage, itemsPerPage);
const currentData = pagination.items;
const prefersReducedMotion = usePrefersReducedMotion(); // <-- Consume the preference status

const containerRef = useRef<HTMLDivElement | null>(null); // 1. Create a reference to the container
const filterButtonRef = useRef<HTMLButtonElement | null>(null);
const filterPanelRef = useRef<HTMLDivElement | null>(null);
const [liveAnnouncement, setLiveAnnouncement] = useState("");
// Define a clean transition config that zero-durations motion elements when flag is on
const activeTransition = prefersReducedMotion
? { duration: 0 }
: transitionEnter;

const startIndex = (currentPage - 1) * itemsPerPage;
const currentData = currentNotification.slice(
startIndex,
startIndex + itemsPerPage,
);

const containerRef = useRef<HTMLDivElement | null>(null);

useEffect(() => {
// 2. Function to handle clicks
const handleClickOutside = (event: MouseEvent) => {
// If the clicked element is NOT inside our container, close it
if (
containerRef.current &&
!containerRef.current.contains(event.target as Node)
Expand Down Expand Up @@ -71,11 +71,7 @@ export default function Notification() {
}
};

// 3. Attach listener to the whole document
document.addEventListener("mousedown", handleClickOutside);
document.addEventListener("keydown", handleKeyDown);

// 4. Cleanup listener when component unmounts
return () => {
document.removeEventListener("mousedown", handleClickOutside);
document.removeEventListener("keydown", handleKeyDown);
Expand All @@ -84,7 +80,6 @@ export default function Notification() {

useEffect(() => {
let filtered = notifications;

if (!filtered) return;

if (currentFilterReadSeletion !== "all") {
Expand All @@ -100,65 +95,27 @@ export default function Notification() {
}
setCurrentNotification(filtered);
setCurrentPage(1);
}, [currentFilterReadSeletion, currentFilterTypeSeletion, notifications]);

// Reset to page 1 when the underlying notification list changes
useEffect(() => {
setCurrentPage(1);
}, [notifications.length]);

useEffect(() => {
const readLabel =
currentFilterReadSeletion === "all"
? "all"
: currentFilterReadSeletion === "0"
? "unread"
: "read";
const typeLabel =
currentFilterTypeSeletion === "all"
? "all categories"
: currentFilterTypeSeletion;

const count = currentNotification.length;
const countText = count === 1 ? "1 notification" : `${count} notifications`;

if (count === 0) {
setLiveAnnouncement(
`No notifications found. Active filters: status ${readLabel}, category ${typeLabel}.`
);
} else {
setLiveAnnouncement(
`Showing ${countText}. Active filters: status ${readLabel}, category ${typeLabel}.`
);
}
}, [currentFilterReadSeletion, currentFilterTypeSeletion, currentNotification.length]);

const handleDismiss = (id: string) => {
dismiss(id);
setCurrentNotification((prev) => prev.filter((n) => n.id !== id));
};

const handleClearAll = () => {
clearAll();
setCurrentNotification([]);
setShowClearModal(false);
setCurrentPage(1);
};
useEffect(() => {
filterNotification();
}, [currentFilterReadSeletion, currentFilterTypeSeletion, notifications]);

const totalPages = Math.ceil(currentNotification.length / itemsPerPage);

const setRead = (id: string) => {
setNotifications(
notifications.map((n) =>
// If this is the one we clicked, update isRead. Otherwise, return as is.
n.id === id ? { ...n, isRead: true } : n,
),
);
setCurrentNotification((prev) =>
prev.map((n) =>
// If this is the one we clicked, update isRead. Otherwise, return as is.
n.id === id ? { ...n, isRead: true } : n,
),
);
};

return (
<>
<div ref={containerRef} className="flex justify-between items-center">
Expand Down Expand Up @@ -199,12 +156,10 @@ export default function Notification() {
<AnimatePresence>
{isFilterOpen && (
<motion.div
ref={filterPanelRef}
id="notification-filter-panel"
initial={{ opacity: 0, y: -10, scale: 0.95 }}
initial={prefersReducedMotion ? { opacity: 1, y: 0, scale: 1 } : { opacity: 0, y: -10, scale: 0.95 }}
animate={{ opacity: 1, y: 0, scale: 1 }}
exit={{ opacity: 0, y: -10, scale: 0.95 }}
transition={transitionEnter}
exit={prefersReducedMotion ? { opacity: 1, y: 0, scale: 1 } : { opacity: 0, y: -10, scale: 0.95 }}
transition={activeTransition} // <-- Assign the guarded duration here
className="absolute w-[300px] h-[200px] translate-x-[-100%] bg-white text-black px-3 py-2 rounded-md"
style={{ zIndex: 'var(--z-index-drawer)' }}
>
Expand Down Expand Up @@ -323,4 +278,4 @@ export default function Notification() {
</div>
</>
);
}
}