Skip to content

Commit

Permalink
feat: add all organizations option to party selection
Browse files Browse the repository at this point in the history
  • Loading branch information
seanes committed Sep 9, 2024
1 parent 151876c commit 6717148
Show file tree
Hide file tree
Showing 27 changed files with 491 additions and 200 deletions.
2 changes: 1 addition & 1 deletion packages/frontend/src/api/useDialogs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {
import { useEffect, useState } from 'react';
import { useQuery } from 'react-query';
import { useDebounce } from 'use-debounce';
import type { InboxItemMetaField } from '../components/index.ts';
import type { InboxItemMetaField } from '../components';
import { i18n } from '../i18n/config.ts';
import { type FormatFunction, useFormat } from '../i18n/useDateFnsLocale.tsx';
import type { InboxItemInput } from '../pages/Inbox/Inbox.tsx';
Expand Down
40 changes: 27 additions & 13 deletions packages/frontend/src/api/useParties.ts
Original file line number Diff line number Diff line change
@@ -1,47 +1,58 @@
import type { PartiesQuery, PartyFieldsFragment } from 'bff-types-generated';
import { useQuery, useQueryClient } from 'react-query';
import { toTitleCase } from '../profile/name.ts';
import { toTitleCase } from '../profile';
import { graphQLSDK } from './queries.ts';

interface UsePartiesOutput {
parties: PartyFieldsFragment[];
deletedParties: PartyFieldsFragment[];
isSuccess: boolean;
isLoading: boolean;
selectedParties: PartyFieldsFragment[];
selectedPartyIds: string[];
setSelectedParties: (parties: PartyFieldsFragment[]) => void;
setSelectedPartyIds: (parties: string[]) => void;
currentEndUser: PartyFieldsFragment | undefined;
allOrganizationsSelected: boolean;
}

interface PartiesResult {
parties: PartyFieldsFragment[];
deletedParties: PartyFieldsFragment[];
}

const fetchParties = (): Promise<PartiesQuery> => graphQLSDK.parties();

export const useParties = (): UsePartiesOutput => {
const queryClient = useQueryClient();
const { data, isLoading, isSuccess } = useQuery<PartiesQuery>(
const { data, isLoading, isSuccess } = useQuery<PartiesResult>(
'parties',
async () => {
const response = await fetchParties();
const partiesWithNormalizedNames =
response.parties.map((party) => ({
...party,
name: toTitleCase(party.name),
})) ?? [];
return {
parties: (
response.parties.map((party) => ({
...party,
name: toTitleCase(party.name),
})) ?? []
).filter((party) => !party.isDeleted),
parties: partiesWithNormalizedNames.filter((party) => !party.isDeleted),
deletedParties: partiesWithNormalizedNames.filter((party) => party.isDeleted),
};
},
{
onSuccess: (data) => {
if (!getSelectedParties() && data.parties && data.parties.length > 0) {
onSuccess: (data: PartiesResult) => {
if (!getSelectedParties().length && data?.parties?.length > 0) {
const currentEndUser = data.parties.find((party) => party.isCurrentEndUser);
if (currentEndUser) {
setSelectedParties([currentEndUser]);
} else {
console.warn('No current end user found, unable to select default parties.');
}
}
},
},
);
const getSelectedParties = () => queryClient.getQueryData<PartyFieldsFragment[]>('selectedParties');
const getSelectedParties = () => queryClient.getQueryData<PartyFieldsFragment[]>('selectedParties') ?? [];
const setSelectedParties = (parties: PartyFieldsFragment[] | null) => {
queryClient.setQueryData('selectedParties', parties);
};
Expand All @@ -53,10 +64,13 @@ export const useParties = (): UsePartiesOutput => {
return {
isLoading,
isSuccess,
parties: data?.parties ?? ([] as PartyFieldsFragment[]),
selectedParties: getSelectedParties() ?? ([] as PartyFieldsFragment[]),
selectedParties: getSelectedParties(),
selectedPartyIds: getSelectedParties().map((party) => party.party) ?? [],
setSelectedParties,
setSelectedPartyIds,
parties: data?.parties ?? [],
currentEndUser: data?.parties.find((party) => party.isCurrentEndUser),
deletedParties: data?.deletedParties ?? [],
allOrganizationsSelected: getSelectedParties().every((party) => party.partyType === 'Organization'),
};
};
Original file line number Diff line number Diff line change
@@ -1,18 +1,15 @@
import { Search } from '@digdir/designsystemet-react';
import { ArrowLeftIcon } from '@navikt/aksel-icons';
import { useState } from 'react';
import { useTranslation } from 'react-i18next';
import { useParties } from '../../api/useParties.ts';
import { HorizontalLine } from '../HorizontalLine';
import { MenuItem } from '../MenuBar';
import { PartyList } from '../PartyDropdown/PartyList.tsx';
import { PartyListContainer } from '../PartyDropdown/PartyListContainer.tsx';
import { MenuLogoutButton } from './MenuLogoutButton.tsx';
import type { DropdownSubMenuProps } from './NavigationDropdownSubMenu.tsx';
import styles from './navigationDropdownMenu.module.css';

export const NavigationDropdownSubMenuProfile: React.FC<DropdownSubMenuProps> = ({ onClose, onBack }) => {
const { t } = useTranslation();
const [searchValue, setSearchValue] = useState('');
const { parties } = useParties();
if (!parties.length) {
return null;
Expand All @@ -39,22 +36,7 @@ export const NavigationDropdownSubMenuProfile: React.FC<DropdownSubMenuProps> =
isWhiteBackground
/>
<HorizontalLine />
<MenuItem
leftContent={
<Search
autoComplete="off"
size="sm"
aria-label={t('word.search')}
placeholder={t('word.search')}
onChange={(e) => {
setSearchValue(e.target.value);
}}
value={searchValue}
onClear={() => setSearchValue('')}
/>
}
/>
<PartyList onOpenMenu={onClose} />
<PartyListContainer onSelect={onClose} />
<HorizontalLine />
<MenuLogoutButton />
</ul>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,13 @@

.menuList {
background: #fff;
overflow: visible;
list-style-type: none;
padding: 0;
margin: 0;
border-radius: 0.5rem;
z-index: 1001;
max-height: 600px;
overflow: auto;
}

@media screen and (max-width: 1024px) {
Expand All @@ -37,6 +38,8 @@
top: 10rem;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
z-index: 1002;
overflow: auto;
height: calc(100% - 12rem);
}

.menuList {
Expand Down
2 changes: 1 addition & 1 deletion packages/frontend/src/components/Header/SearchBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ export const SearchBar: React.FC = () => {
}}
aria-label={t('header.searchPlaceholder')}
placeholder={t('header.searchPlaceholder')}
className={cx(styles.searchInput)}
className={styles.searchInput}
onChange={(e) => {
setSearchValue(e.target.value);
}}
Expand Down
6 changes: 1 addition & 5 deletions packages/frontend/src/components/Header/SearchDropdown.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -93,11 +93,7 @@ export const SearchDropdown: React.FC<SearchDropdownProps> = ({ showDropdownMenu
...(filters?.length && { filters: JSON.stringify(filters) }),
});
return (
<a
href={`${fromView}?${queryParams.toString()}`}
className={styles.goToSavedSearchLink}
key={search.id}
>
<a href={`${fromView}?${queryParams.toString()}`} key={search.id}>
<SearchDropdownItem>
{search.name ? (
<div className={styles.savedSearchItem}>
Expand Down
5 changes: 2 additions & 3 deletions packages/frontend/src/components/Header/search.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
border-radius: 6px 6px 0 0;
}

input {
.searchInput {
color: black;
font-size: 1.125rem;
font-style: normal;
Expand All @@ -40,7 +40,7 @@ input {
align-self: flex-start;
}

input:focus-visible {
.searchInput:focus-visible {
outline: none;
}

Expand Down Expand Up @@ -237,7 +237,6 @@ input:focus-visible {
display: flex;
flex-direction: row;
justify-content: space-between;
/* margin: 0 1rem; */
}

.rightContent {
Expand Down
8 changes: 4 additions & 4 deletions packages/frontend/src/components/MenuBar/MenuItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,25 +21,25 @@ interface MenuItem {
rightContent?: React.ReactNode;
useProfiledHover?: boolean;
largeText?: boolean;
classNames?: string;
className?: string;
disabled?: boolean;
}

const MenuItem = (props: MenuItem) => {
const { path, onClick, isExternalLink, leftContent, rightContent, classNames } = props;
const { path, onClick, isExternalLink, leftContent, rightContent, className } = props;
const content = <MenuItemContent {...props} />;

if (path) {
return (
<Link className={styles.isLink} to={path} onClick={onClick} target={isExternalLink ? '_blank' : '_self'}>
<li className={cx(styles.liItem, classNames)}>{content}</li>
<li className={cx(styles.liItem, className)}>{content}</li>
</Link>
);
}

if (onClick) {
return (
<li className={cx(styles.isLink, styles.liItem, classNames)} onClick={onClick} onKeyUp={onClick}>
<li className={cx(styles.isLink, styles.liItem, className)} onClick={onClick} onKeyUp={onClick}>
{content}
</li>
);
Expand Down
7 changes: 7 additions & 0 deletions packages/frontend/src/components/MenuBar/menuItem.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@

.liItem {
margin-bottom: 0.5rem;
list-style: none;
}

.isLink {
Expand All @@ -39,6 +40,12 @@
width: 100%;
}

.rightContent {
display: flex;
align-items: center;
grid-area: right;
}

.displayText {
margin-left: 10px;
color: var(--black-100, #000);
Expand Down
10 changes: 7 additions & 3 deletions packages/frontend/src/components/PageLayout/PageLayout.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import cx from 'classnames';
import type React from 'react';
import { memo, useEffect } from 'react';
import { useTranslation } from 'react-i18next';
import { useQueryClient } from 'react-query';
import { Outlet, useLocation, useSearchParams } from 'react-router-dom';
import { Footer, Header, type ItemPerViewCount, Sidebar } from '..';
Expand Down Expand Up @@ -33,11 +34,12 @@ interface PageLayoutContentProps {

const PageLayoutContent: React.FC<PageLayoutContentProps> = memo(
({ name, companyName, isCompany, notificationCount }) => {
const { t } = useTranslation();
const { inSelectionMode } = useSelectedDialogs();
const { isTabletOrSmaller } = useWindowSize();
const showSidebar = !isTabletOrSmaller && !inSelectionMode;
const { selectedParties } = useParties();
const { currentPartySavedSearches } = useSavedSearches(selectedParties);
const { selectedPartyIds, selectedParties, allOrganizationsSelected } = useParties();
const { currentPartySavedSearches } = useSavedSearches(selectedPartyIds);
const { dialogsByView } = useDialogs(selectedParties);
const itemsPerViewCount = {
inbox: dialogsByView.inbox.length,
Expand All @@ -48,9 +50,11 @@ const PageLayoutContent: React.FC<PageLayoutContentProps> = memo(
deleted: 0,
} as ItemPerViewCount;

const usedCompanyName = allOrganizationsSelected ? t('parties.labels.all_organizations') : companyName;

return (
<>
<Header name={name} companyName={companyName} notificationCount={notificationCount} />
<Header name={name} companyName={usedCompanyName} notificationCount={notificationCount} />
<div className={styles.pageLayout}>
{showSidebar && <Sidebar itemsPerViewCount={itemsPerViewCount} isCompany={isCompany} />}
<Outlet />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,9 @@
}

.background {
background: var(--background-color);
min-height: 100vh;
background: var(--background-color);
overflow: auto;
}

.inSelectionMode.background {
Expand All @@ -25,7 +26,6 @@

.pageLayout > main {
grid-area: main;
overflow: auto;
padding: 0;
width: 100%;
margin-right: auto;
Expand Down
13 changes: 7 additions & 6 deletions packages/frontend/src/components/PartyDropdown/PartyDropdown.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { Backdrop } from '../Backdrop';
import { DropdownList, DropdownMobileHeader } from '../DropdownMenu';
import { ProfileButton } from '../ProfileButton';
import type { SideBarView } from '../Sidebar';
import { PartyList } from './PartyList.tsx';
import { PartyListContainer } from './PartyListContainer.tsx';

interface PartyDropdownRef {
openPartyDropdown: () => void;
Expand All @@ -20,7 +20,7 @@ export const PartyDropdown = forwardRef((props: PartyDropdownProps, ref: Ref<Par
const { counterContext } = props;
const [isMenuOpen, setIsMenuOpen] = useState<boolean>(false);
const { t } = useTranslation();
const { selectedParties } = useParties();
const { selectedParties, allOrganizationsSelected, parties } = useParties();

useImperativeHandle(ref, () => ({
openPartyDropdown: () => {
Expand All @@ -30,8 +30,10 @@ export const PartyDropdown = forwardRef((props: PartyDropdownProps, ref: Ref<Par

return (
<div>
<ProfileButton size="xs" onClick={() => setIsMenuOpen(!isMenuOpen)} color="neutral">
{selectedParties?.[0]?.name ?? t('partyDropdown.selectParty')}
<ProfileButton size="xs" onClick={() => setIsMenuOpen(!isMenuOpen)} color="neutral" disabled={!parties.length}>
{allOrganizationsSelected
? t('parties.labels.all_organizations')
: selectedParties?.[0]?.name ?? t('partyDropdown.selectParty')}
<ChevronUpDownIcon fontSize="1.25rem" />
</ProfileButton>
<DropdownList variant="long" isExpanded={isMenuOpen}>
Expand All @@ -40,9 +42,8 @@ export const PartyDropdown = forwardRef((props: PartyDropdownProps, ref: Ref<Par
buttonText={t('word.back')}
buttonIcon={null}
/>
<PartyList onOpenMenu={setIsMenuOpen} counterContext={counterContext} />
<PartyListContainer onSelect={() => setIsMenuOpen(false)} counterContext={counterContext} />
</DropdownList>

<Backdrop show={isMenuOpen} onClick={() => setIsMenuOpen(false)} />
</div>
);
Expand Down
Loading

0 comments on commit 6717148

Please sign in to comment.