Skip to content

Commit

Permalink
feat: add support for listing dialogs as archived or in bin and move …
Browse files Browse the repository at this point in the history
…dialogs to bin or archive
  • Loading branch information
seanes committed Oct 7, 2024
1 parent 72eabfa commit 5d4d667
Show file tree
Hide file tree
Showing 24 changed files with 308 additions and 65 deletions.
2 changes: 2 additions & 0 deletions packages/bff-types-generated/queries/dialog.fragment.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ fragment SearchDialogFields on SearchDialog {
...DialogContentFields
}
}
systemLabel
}

fragment DialogByIdFields on Dialog {
Expand All @@ -60,6 +61,7 @@ fragment DialogByIdFields on Dialog {
createdAt
updatedAt
extendedStatus
systemLabel
content {
title {
...DialogContentFields
Expand Down
5 changes: 5 additions & 0 deletions packages/bff-types-generated/queries/systemLabel.graphql
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
mutation updateSystemLabel($dialogId: UUID!, $label: SystemLabel!) {
setSystemLabel(input: { dialogId: $dialogId, label: $label }) {
success
}
}
2 changes: 1 addition & 1 deletion packages/bff/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
"@azure/keyvault-keys": "^4.7.2",
"@azure/monitor-opentelemetry": "1.7.0",
"@digdir/dialogporten-node-logger": "workspace:*",
"@digdir/dialogporten-schema": "1.19.0-651ca62",
"@digdir/dialogporten-schema": "1.21.0-3031d8d",
"@fastify/cookie": "^9.3.1",
"@fastify/cors": "^9.0.1",
"@fastify/formbody": "^7.4.0",
Expand Down
13 changes: 8 additions & 5 deletions packages/frontend/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Navigate, Route, Routes } from 'react-router-dom';
import { ProtectedPageLayout } from './components/PageLayout/PageLayout.tsx';
import { Inbox } from './pages/Inbox';
import { Routes as AppRoutes } from './pages/Inbox/Inbox.tsx';
import { InboxItemPage } from './pages/InboxItemPage';
import { Logout } from './pages/LogoutPage';
import { SavedSearchesPage } from './pages/SavedSearches';
Expand All @@ -12,11 +13,13 @@ function App() {
<div className="app">
<Routes>
<Route element={<ProtectedPageLayout />}>
<Route path="/" element={<Inbox key="inbox" viewType={'inbox'} />} />
<Route path="/drafts" element={<Inbox key="draft" viewType={'drafts'} />} />
<Route path="/sent" element={<Inbox key="sent" viewType={'sent'} />} />
<Route path="/saved-searches" element={<SavedSearchesPage />} />
<Route path="/inbox/:id" element={<InboxItemPage />} />
<Route path={AppRoutes.inbox} element={<Inbox key="inbox" viewType={'inbox'} />} />
<Route path={AppRoutes.drafts} element={<Inbox key="draft" viewType={'drafts'} />} />
<Route path={AppRoutes.sent} element={<Inbox key="sent" viewType={'sent'} />} />
<Route path={AppRoutes.archive} element={<Inbox key="archive" viewType={'archive'} />} />
<Route path={AppRoutes.bin} element={<Inbox key="bin" viewType={'bin'} />} />
<Route path={AppRoutes.savedSearches} element={<SavedSearchesPage />} />
<Route path={AppRoutes.inboxItem} element={<InboxItemPage />} />
<Route path="*" element={<Navigate to="/" />} />
</Route>
<Route path="/loggedout" element={<Logout />} />
Expand Down
7 changes: 7 additions & 0 deletions packages/frontend/src/api/queries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ import {
type OrganizationsQuery,
type SavedSearchInput,
type SavedSearchesQuery,
type SystemLabel,
type UpdateSavedSearchMutation,
type UpdateSystemLabelMutation,
getSdk,
} from 'bff-types-generated';
import { GraphQLClient } from 'graphql-request';
Expand All @@ -19,3 +21,8 @@ export const updateSavedSearch = (id: number, name: string): Promise<UpdateSaved
graphQLSDK.UpdateSavedSearch({ id, name });
export const createSavedSearch = (name: string, data: SavedSearchInput): Promise<CreateSavedSearchMutation> =>
graphQLSDK.CreateSavedSearch({ name, data });
export const updateSystemLabel = (dialogId: string, label: SystemLabel): Promise<UpdateSystemLabelMutation> =>
graphQLSDK.updateSystemLabel({
dialogId,
label,
});
3 changes: 3 additions & 0 deletions packages/frontend/src/api/useDialogById.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import type {
GetDialogByIdQuery,
OrganizationFieldsFragment,
PartyFieldsFragment,
SystemLabel,
} from 'bff-types-generated';
import type { GuiActionButtonProps, InboxItemMetaField } from '../components';
import { QUERY_KEYS } from '../constants/queryKeys.ts';
Expand Down Expand Up @@ -46,6 +47,7 @@ export interface DialogByIdDetails {
activities: DialogActivity[];
updatedAt: string;
createdAt: string;
label: SystemLabel;
}

interface UseDialogByIdOutput {
Expand Down Expand Up @@ -182,6 +184,7 @@ export function mapDialogDtoToInboxItem(
.reverse(),
createdAt: item.createdAt,
updatedAt: item.updatedAt,
label: item.systemLabel,
};
}
export const useDialogById = (parties: PartyFieldsFragment[], id?: string): UseDialogByIdOutput => {
Expand Down
48 changes: 33 additions & 15 deletions packages/frontend/src/api/useDialogs.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import { useQuery } from '@tanstack/react-query';
import type {
GetAllDialogsForPartiesQuery,
OrganizationFieldsFragment,
PartyFieldsFragment,
SearchDialogFieldsFragment,

import {
DialogStatus,
type GetAllDialogsForPartiesQuery,
type OrganizationFieldsFragment,
type PartyFieldsFragment,
type SearchDialogFieldsFragment,
SystemLabel,
} from 'bff-types-generated';
import { DialogStatus } from 'bff-types-generated';
import { useEffect, useState } from 'react';
import { useDebounce } from 'use-debounce';
import type { InboxItemMetaField, InboxItemMetaFieldType } from '../components';
Expand All @@ -16,7 +18,7 @@ import { useOrganizations } from '../pages/Inbox/useOrganizations.ts';
import { getOrganization } from './organizations.ts';
import { graphQLSDK } from './queries.ts';

export type InboxViewType = 'inbox' | 'drafts' | 'sent';
export type InboxViewType = 'inbox' | 'drafts' | 'sent' | 'archive' | 'bin';
interface UseDialogsOutput {
dialogs: InboxItemInput[];
dialogsByView: {
Expand Down Expand Up @@ -68,6 +70,7 @@ export function mapDialogDtoToInboxItem(
updatedAt: item.updatedAt,
status: item.status ?? 'UnknownStatus',
isSeenByEndUser,
label: item.systemLabel,
};
});
}
Expand Down Expand Up @@ -128,22 +131,35 @@ export const useSearchDialogs = ({ parties, searchString, org }: searchDialogsPr
};
};

export const isBinDialog = (dialog: InboxItemInput): boolean => dialog.label === SystemLabel.Bin;

export const isArchivedDialog = (dialog: InboxItemInput): boolean => dialog.label === SystemLabel.Archive;

export const isInboxDialog = (dialog: InboxItemInput): boolean =>
dialog.status === DialogStatus.New ||
dialog.status === DialogStatus.InProgress ||
dialog.status === DialogStatus.RequiresAttention ||
dialog.status === DialogStatus.Completed;
!isBinDialog(dialog) &&
!isArchivedDialog(dialog) &&
[DialogStatus.New, DialogStatus.InProgress, DialogStatus.RequiresAttention, DialogStatus.Completed].includes(
dialog.status,
);

export const isDraftDialog = (dialog: InboxItemInput): boolean => [DialogStatus.Draft].includes(dialog.status);
export const isDraftDialog = (dialog: InboxItemInput): boolean =>
!isBinDialog(dialog) && !isArchivedDialog(dialog) && dialog.status === DialogStatus.Draft;

export const isSentDialog = (dialog: InboxItemInput): boolean => dialog.status === DialogStatus.Sent;
export const isSentDialog = (dialog: InboxItemInput): boolean =>
!isBinDialog(dialog) && !isArchivedDialog(dialog) && dialog.status === DialogStatus.Sent;

export const getViewType = (dialog: InboxItemInput): InboxViewType => {
if (isDraftDialog(dialog)) {
return 'drafts';
}
if (isArchivedDialog(dialog)) {
return 'archive';
}
if (isSentDialog(dialog)) {
return 'sent';
}
if (isDraftDialog(dialog)) {
return 'drafts';
if (isBinDialog(dialog)) {
return 'bin';
}
return 'inbox';
};
Expand All @@ -167,6 +183,8 @@ export const useDialogs = (parties: PartyFieldsFragment[]): UseDialogsOutput =>
inbox: dialogs.filter(isInboxDialog),
drafts: dialogs.filter(isDraftDialog),
sent: dialogs.filter(isSentDialog),
archive: dialogs.filter(isArchivedDialog),
bin: dialogs.filter(isBinDialog),
},
};
};
Expand Down
53 changes: 53 additions & 0 deletions packages/frontend/src/components/DialogToolbar/DialogToolbar.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { ArchiveIcon, InboxFillIcon, TrashIcon } from '@navikt/aksel-icons';
import { SystemLabel } from 'bff-types-generated';
import { useTranslation } from 'react-i18next';
import { ProfileButton } from '../ProfileButton';
import styles from './dialogToolbar.module.css';

interface ToolbarActionProps {
onClick: () => void;
isLoading: boolean;
}

interface DialogToolbarProps {
archiveAction: ToolbarActionProps;
deleteAction: ToolbarActionProps;
undoAction: ToolbarActionProps;
currentLabel: SystemLabel;
}

export const DialogToolbar = ({ archiveAction, deleteAction, undoAction, currentLabel }: DialogToolbarProps) => {
const { t } = useTranslation();
return (
<section className={styles.dialogToolbar}>
{[SystemLabel.Archive, SystemLabel.Bin].includes(currentLabel) && (
<ProfileButton variant="tertiary" color="neutral" onClick={undoAction.onClick} isLoading={undoAction.isLoading}>
<InboxFillIcon fontSize="1.5rem" />
{t('dialog.toolbar.move_undo')}
</ProfileButton>
)}
{currentLabel !== SystemLabel.Archive && (
<ProfileButton
variant="tertiary"
color="neutral"
onClick={archiveAction.onClick}
isLoading={archiveAction.isLoading}
>
<ArchiveIcon fontSize="1.5rem" />
{t('dialog.toolbar.move_to_archive')}
</ProfileButton>
)}
{currentLabel !== SystemLabel.Bin && (
<ProfileButton
variant="tertiary"
color="neutral"
onClick={deleteAction.onClick}
isLoading={deleteAction.isLoading}
>
<TrashIcon fontSize="1.5rem" />
{t('dialog.toolbar.move_to_bin')}
</ProfileButton>
)}
</section>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
.dialogToolbar {
display: flex;
flex-direction: row;
flex-wrap: wrap;
gap: 0.5rem;
padding: 0.5rem;
}
Original file line number Diff line number Diff line change
Expand Up @@ -95,8 +95,8 @@ export const NavigationDropdownSubMenuInbox: React.FC<DropdownSubMenuProps> = ({
toolTipText={t('sidebar.deleted.label')}
leftIcon={<TrashIcon />}
count={0}
isActive={pathname === Routes.deleted}
path={Routes.deleted}
isActive={pathname === Routes.bin}
path={Routes.bin}
disabled
onClick={onClose}
/>
Expand Down
17 changes: 12 additions & 5 deletions packages/frontend/src/components/InboxItem/InboxItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,12 @@ import type { JSX } from 'react';
import { Link } from 'react-router-dom';
import { useSelectedDialogs } from '../PageLayout';

import cx from 'classnames';
import { useTranslation } from 'react-i18next';
import type { Participant } from '../../api/useDialogById.tsx';
import type { InboxViewType } from '../../api/useDialogs.tsx';
import { FeatureFlagKeys } from '../../featureFlags/FeatureFlags.ts';
import { useFeatureFlag } from '../../featureFlags/useFeatureFlag.ts';
import { FeatureFlagKeys } from '../../featureFlags';
import { useFeatureFlag } from '../../featureFlags';
import { Avatar } from '../Avatar';
import type { InboxItemMetaField } from '../MetaDataFields';
import { MetaDataFields } from '../MetaDataFields';
Expand Down Expand Up @@ -100,6 +101,8 @@ export const InboxItem = ({
const { t } = useTranslation();
const disableBulkActions = useFeatureFlag<boolean>(FeatureFlagKeys.DisableBulkActions);

const hideSummaryAndMeta = !summary || viewType === 'archive' || viewType === 'bin';

const onClick = () => {
if (inSelectionMode && onCheckedChange) {
onCheckedChange(!checkboxValue);
Expand Down Expand Up @@ -195,7 +198,7 @@ export const InboxItem = ({
/>
)}
</header>
<div className={styles.participants}>
<div className={cx(styles.participants, { [styles.bottomPadding]: hideSummaryAndMeta })}>
<div className={styles.sender}>
<Avatar
name={sender?.name ?? ''}
Expand All @@ -209,8 +212,12 @@ export const InboxItem = ({
<span className={styles.participantLabel}>{`${t('word.to')} ${receiver?.name}`}</span>
</div>
</div>
<p className={styles.summary}>{summary}</p>
<MetaDataFields metaFields={metaFields || []} viewType={viewType} />
{hideSummaryAndMeta ? null : (
<>
<p className={styles.summary}>{summary}</p>
<MetaDataFields metaFields={metaFields || []} viewType={viewType} />
</>
)}
</section>
</OptionalLinkContent>
</li>
Expand Down
14 changes: 8 additions & 6 deletions packages/frontend/src/components/InboxItem/InboxItemDetail.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -147,12 +147,14 @@ export const InboxItemDetail = ({ dialog }: InboxItemDetailProps): JSX.Element =
</section>
)}
</article>
<section data-id="dialog-activity-history" className={styles.activities}>
{activities.length > 0 && <h3 className={styles.activitiesTitle}>{t('word.activities')}</h3>}
{activities.map((activity) => (
<Activity key={activity.id} activity={activity} serviceOwner={sender} />
))}
</section>
{activities.length > 0 && (
<section data-id="dialog-activity-history" className={styles.activities}>
<h3 className={styles.activitiesTitle}>{t('word.activities')}</h3>
{activities.map((activity) => (
<Activity key={activity.id} activity={activity} serviceOwner={sender} />
))}
</section>
)}
</div>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,10 @@
margin-bottom: 0.125rem;
}

.bottomPadding {
padding-bottom: 0.5rem;
}

.receiver,
.sender {
display: flex;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
display: flex;
flex-direction: column;
background: #fff;
padding-bottom: 1.5rem;
}

@media (max-width: 1024px) {
Expand Down Expand Up @@ -57,7 +58,7 @@
}

.additionalInfo {
padding: 1.5rem 0;
padding: 1.5rem 0 0;
line-height: 1.5;
}

Expand Down
4 changes: 2 additions & 2 deletions packages/frontend/src/components/PageLayout/PageLayout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,8 @@ const PageLayoutContent: React.FC<PageLayoutContentProps> = memo(({ name, profil
drafts: dialogsByView.drafts.length,
sent: dialogsByView.sent.length,
'saved-searches': currentPartySavedSearches?.length ?? 0,
archive: 0,
deleted: 0,
archive: dialogsByView.archive.length,
bin: dialogsByView.bin.length,
} as ItemPerViewCount;

return (
Expand Down
Loading

0 comments on commit 5d4d667

Please sign in to comment.