ui phase 10

This commit is contained in:
hamid
2026-07-19 17:13:32 +03:30
parent b638e25a0e
commit b4b8c9ea79
48 changed files with 1643 additions and 290 deletions
@@ -1,9 +1,12 @@
'use client';
import { FunctionComponent } from 'react';
import { FunctionComponent, useState } from 'react';
import useMediaQuery from '@mui/material/useMediaQuery';
import { useTheme } from '@mui/material/styles';
import { useLocale, useTranslations } from 'next-intl';
import { useRouter } from 'next/navigation';
import { notificationsPath } from '@/constants';
import { useUnreadCount } from '@/services/notifications';
import NotificationBellPopover from './NotificationBellPopover';
import NotificationBellView from './NotificationBellView';
export interface NotificationBellProps {
@@ -13,9 +16,10 @@ export interface NotificationBellProps {
/**
* The notification bell **container** mounted in the app chrome. It subscribes to the polling
* `useUnreadCount` (stale-while-revalidate) and navigates to the role's notification center on click. Because
* only this small container reads the fast-changing count, a count change re-renders just the bell — not the
* whole shell.
* `useUnreadCount` (stale-while-revalidate) — the only thing in this component that re-renders on a count
* change, so the shell around it never does (§5 isolation). On the **nurse desktop** shell (§3.6) it opens
* a popover preview instead of navigating; every other case (customer — mobile-first, always navigates;
* nurse mobile; admin) keeps the direct full-page navigation.
* @component NotificationBell
*/
const NotificationBell: FunctionComponent<NotificationBellProps> = ({ role }) => {
@@ -23,13 +27,33 @@ const NotificationBell: FunctionComponent<NotificationBellProps> = ({ role }) =>
const router = useRouter();
const locale = useLocale();
const t = useTranslations('notifications');
const theme = useTheme();
const isDesktop = useMediaQuery(theme.breakpoints.up('md'));
const [anchorEl, setAnchorEl] = useState<HTMLButtonElement | null>(null);
const [popoverOpen, setPopoverOpen] = useState(false);
const usesPopover = role === 'nurse' && isDesktop;
const onClick = () => {
if (usesPopover) {
setPopoverOpen(true);
return;
}
router.push(`/${locale}${notificationsPath(role)}`);
};
return (
<NotificationBellView
count={count}
label={t('bell_aria', { count })}
onClick={() => router.push(`/${locale}${notificationsPath(role)}`)}
/>
<>
<NotificationBellView ref={setAnchorEl} count={count} label={t('bell_aria', { count })} onClick={onClick} />
{usesPopover ? (
<NotificationBellPopover
open={popoverOpen}
anchorEl={anchorEl}
onClose={() => setPopoverOpen(false)}
role="nurse"
/>
) : null}
</>
);
};