• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

alkem-io / client-web / #6003

16 Oct 2023 06:46AM UTC coverage: 6.201%. First build
#6003

Pull #4952

travis-ci

Pull Request #4952: PageBanner and Breadcrumbs for global pages

173 of 8312 branches covered (0.0%)

Branch coverage included in aggregate %.

68 of 68 new or added lines in 21 files covered. (100.0%)

1297 of 15393 relevant lines covered (8.43%)

0.41 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/src/main/ui/platformNavigation/PlatformNavigationBar.tsx
1
import { cloneElement, ReactElement, Ref, useLayoutEffect, useRef, useState } from 'react';
2
import NavigationBar, { NAVIGATION_CONTENT_HEIGHT_GUTTERS } from '@/core/ui/navigation/NavigationBar';
3
import PlatformNavigationUserAvatar from './PlatformNavigationUserAvatar';
4
import PlatformSearch from '../platformSearch/PlatformSearch';
5
import PlatformNavigationMenuButton from './PlatformNavigationMenuButton';
6
import { Box, MenuItem, Slide } from '@mui/material';
7
import PlatformNavigationUserMenu, { UserMenuDivider } from './PlatformNavigationUserMenu';
8
import UserMenuPlatformNavigationSegment from './platformNavigationMenu/UserMenuPlatformNavigationSegment';
9
import NavigationBarSideContent from '@/core/ui/navigation/NavigationBarSideContent';
10
import { gutters } from '@/core/ui/grid/utils';
11
import { Collapsible } from '@/core/ui/navigation/Collapsible';
12
import { UncontrolledExpandable } from '@/core/ui/navigation/UncontrolledExpandable';
×
13
import { useResizeDetector } from 'react-resize-detector';
×
14
import { GUTTER_PX, useScreenSize } from '@/core/ui/grid/constants';
15
import PlatformNavigationUncollapse from './PlatformNavigationUncollapse';
16
import SkipLink from '@/core/ui/keyboardNavigation/SkipLink';
17
import { useTranslation } from 'react-i18next';
18
import PoweredBy from '../poweredBy/PoweredBy';
19
import { PlatformNotificationsButton } from './PlatformNotificationsButton';
20
import { UserMessagingButton } from '@/main/userMessaging/UserMessagingButton';
21

22
export interface PlatformNavigationBarProps {
23
  breadcrumbs?: ReactElement<UncontrolledExpandable & { ref: Ref<Collapsible> }>;
24
}
25

26
const DEFAULT_BOUNDING_CLIENT_RECT = {
27
  right: 0,
28
} as const;
29

30
const PlatformNavigationBar = ({ breadcrumbs }: PlatformNavigationBarProps) => {
31
  const { isSmallScreen } = useScreenSize();
32

33
  const [areBreadcrumbsHidden, setAreBreadcrumbsHidden] = useState(false);
34

35
  const breadcrumbsContainerRef = useRef<HTMLDivElement>(null);
36

37
  const buttonsContainerRef = useRef<HTMLDivElement>(null);
38

39
  const uncollapseButtonRef = useRef<HTMLButtonElement>(null);
40

41
  const [rightSideShift, setRightSideShift] = useState(0);
42

43
  const breadcrumbsRef = useRef<Collapsible>(null);
44
  const searchBoxRef = useRef<Collapsible>(null);
45

46
  const handleExpandSearch = (isExpanded: boolean) => {
47
    setAreBreadcrumbsHidden(isSmallScreen && isExpanded);
48
    if (isExpanded) {
49
      breadcrumbsRef.current?.collapse();
50
    }
51
  };
52

53
  const handleExpandBreadcrumbs = (areExpanded: boolean) => {
54
    if (areExpanded) {
55
      searchBoxRef.current?.collapse();
56
    }
57

58
    if (!isSmallScreen || !areExpanded) {
59
      setRightSideShift(0);
60
      return;
61
    }
62

63
    const { right: containerRight } =
64
      buttonsContainerRef.current?.getBoundingClientRect() ?? DEFAULT_BOUNDING_CLIENT_RECT;
65
    const { right: contentRight } =
66
      uncollapseButtonRef.current?.getBoundingClientRect() ?? DEFAULT_BOUNDING_CLIENT_RECT;
67

68
    setRightSideShift(prevShift => prevShift || containerRight - contentRight);
69
  };
70

71
  const { height: breadcrumbsHeight = 0, ref: breadcrumbsWrapperRef } = useResizeDetector();
72

73
  const breadcrumbsVerticalShift =
74
    breadcrumbsHeight > GUTTER_PX * 2 ? (NAVIGATION_CONTENT_HEIGHT_GUTTERS * GUTTER_PX - breadcrumbsHeight) / 2 : 0;
75

76
  useLayoutEffect(() => {
77
    breadcrumbsRef.current?.collapse();
78
    searchBoxRef.current?.collapse();
79
  }, [isSmallScreen]);
80

81
  const { t } = useTranslation();
82

83
  return (
84
    <NavigationBar>
85
      <SkipLink anchor={() => document.querySelector('main')}>{t('components.navigation.skipMenu')}</SkipLink>
86

87
      <NavigationBarSideContent ref={buttonsContainerRef}>
88
        <Box
89
          display="flex"
90
          gap={gutters(0.5)}
91
          padding={gutters(0.5)}
92
          justifyContent="end"
93
          position="relative"
94
          sx={{
95
            transform: `translateX(${rightSideShift}px)`,
96
            transition: theme =>
97
              `transform ${theme.transitions.duration.standard}ms ${theme.transitions.easing.easeInOut}`,
98
          }}
99
        >
100
          <PlatformSearch ref={searchBoxRef} onExpand={handleExpandSearch} compact={isSmallScreen}>
101
            <PlatformNavigationUncollapse ref={uncollapseButtonRef} visible={rightSideShift !== 0} />
102
          </PlatformSearch>
103
          <UserMessagingButton />
104
          <PlatformNotificationsButton />
105
          {!isSmallScreen && <PlatformNavigationMenuButton />}
106
          <PlatformNavigationUserAvatar drawer={isSmallScreen}>
107
            <PlatformNavigationUserMenu
108
              surface={!isSmallScreen}
109
              footer={
110
                isSmallScreen && [
111
                  <UserMenuDivider key="divider" />,
112
                  <Box component={MenuItem} paddingY={gutters(0.5)} key="menu-item">
113
                    <PoweredBy preview />
114
                  </Box>,
115
                ]
116
              }
117
            >
118
              {isSmallScreen && <UserMenuPlatformNavigationSegment />}
119
              {isSmallScreen && <UserMenuDivider />}
120
            </PlatformNavigationUserMenu>
121
          </PlatformNavigationUserAvatar>
122
        </Box>
123
      </NavigationBarSideContent>
124

125
      <NavigationBarSideContent
126
        ref={breadcrumbsContainerRef}
127
        sx={{
128
          pointerEvents: 'none',
129
          transform: `translateY(${breadcrumbsVerticalShift}px)`,
130
          transition: theme => `transform ${theme.transitions.duration.shortest}ms linear`,
131
        }}
132
      >
133
        <Slide in={!areBreadcrumbsHidden} container={breadcrumbsContainerRef.current} direction="right">
134
          <Box ref={breadcrumbsWrapperRef} display="flex">
135
            {breadcrumbs && cloneElement(breadcrumbs, { ref: breadcrumbsRef, onExpand: handleExpandBreadcrumbs })}
136
          </Box>
137
        </Slide>
138
      </NavigationBarSideContent>
139
    </NavigationBar>
140
  );
141
};
142

143
export default PlatformNavigationBar;
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc