Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Notifications #688

Merged
merged 3 commits into from
Jun 28, 2024
Merged
Show file tree
Hide file tree
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
2 changes: 1 addition & 1 deletion apps/researcher/e2e/object-list.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ test.describe('Object list page logged in', () => {
await gotoSignedIn(objectUrl);
await page.getByTestId('popover-menu-button').hover();
await page.getByTestId(`object-list-${listId}`).click();
await expect(page.getByTestId('notification')).toHaveCount(3);
await expect(page.getByTestId('notification')).toHaveCount(1);
await page.goto(`/en/communities/${community.slug}/${listId}`);
await expect(page.getByTestId('object-card')).toHaveCount(1);
});
Expand Down
2 changes: 1 addition & 1 deletion apps/researcher/e2e/object.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ test.describe('Object details page logged in', () => {
.getByTestId('enrichment-form')
.locator('button[type="submit"]')
.click();
await expect(page.getByTestId('notification')).toHaveCount(3, {
await expect(page.getByTestId('notification')).toHaveCount(1, {
timeout: 30000,
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,7 @@ export default function AddProvenanceForm({
});

addNotification({
id: 'add-user-enrichment-success',
id: 'provenance.added.success',
message: t('successfullyAdded'),
type: 'success',
});
Expand Down Expand Up @@ -411,7 +411,6 @@ export default function AddProvenanceForm({
<InputLabel
title={t('qualifier')}
description={t('qualifierDescription')}
required
/>
<QualifierSelector name="qualifier" />
</Field>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ async function AddProvenanceSlideOut({objectId}: {objectId: string}) {

return (
<>
<Notifications />
<Notifications prefixFilters={['provenance.']} />
<SignedInWithCommunitySideOut
slideOutId={slideOutId}
needAccountTitle={t('needAccountToAddProvenanceTitle')}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ export function LocalContextsNoticeForm({
});

addNotification({
id: 'add-user-notice-success',
id: 'notice.added.success',
message: t('successfullyAdded'),
type: 'success',
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ export default async function LocalContextsNotices() {
})}
</p>
<AddLocalContextsNotice />
<Notifications />
<Notifications prefixFilters={['notice.']} />
<div className="w-full mt-4">
{noticesToDisplay.map(notice => (
<div
Expand Down
96 changes: 53 additions & 43 deletions apps/researcher/src/app/[locale]/objects/[id]/metadata.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
import {useTranslations} from 'next-intl';
import {PropsWithChildren, ReactNode} from 'react';
import useObject from './use-object';
import {SlideOutButton, LocalizedMarkdown} from '@colonial-collections/ui';
import {
SlideOutButton,
LocalizedMarkdown,
Notifications,
} from '@colonial-collections/ui';
import {UserEnrichmentForm} from './user-enrichment-form';
import {ChatBubbleBottomCenterTextIcon} from '@heroicons/react/24/outline';
import type {
Expand Down Expand Up @@ -31,53 +35,59 @@ export function Metadata({
: [];

return (
<div className="flex flex-col gap-4">
<div className="flex flex-col xl:flex-row gap-2 xl:gap-10">
<div className="w-full xl:w-1/5 border-t border-neutral-400 pt-4">
<div className="sticky top-6 py-1">
<h3 className="text-lg w-full my-1 flex items-center" tabIndex={0}>
{t(translationKey)}
</h3>
<div className="text-neutral-600 text-sm">
{t(`${translationKey}SubTitle`)}
<>
<div className="flex flex-col gap-4">
<div className="flex flex-col xl:flex-row gap-2 xl:gap-10">
<div className="w-full xl:w-1/5 border-t border-neutral-400 pt-4">
<div className="sticky top-6 py-1">
<h3
className="text-lg w-full my-1 flex items-center"
tabIndex={0}
>
{t(translationKey)}
</h3>
<div className="text-neutral-600 text-sm">
{t(`${translationKey}SubTitle`)}
</div>
</div>
</div>
</div>
{!children && metadataEnrichments.length === 0 ? (
<div className="text-neutral-600 italic w-full py-6 text-sm xl:w-4/5 border-t border-neutral-400">
{t.rich('noData', {
subject: () => (
<span className="lowercase">{t(translationKey)}</span>
),
})}
</div>
) : (
<div className="w-full xl:w-4/5 flex flex-col gap-2 border-t border-neutral-400">
<MetadataEntry translationKey={translationKey} isCurrentPublisher>
{children}
</MetadataEntry>
{metadataEnrichments?.map(enrichment => (
<MetadataEntry
key={enrichment.id}
translationKey={translationKey}
dateCreated={enrichment.pubInfo.dateCreated}
citation={enrichment.citation}
creator={enrichment.pubInfo.creator}
languageCode={enrichment.inLanguage}
>
<ReadMoreText text={enrichment.description} />
{!children && metadataEnrichments.length === 0 ? (
<div className="text-neutral-600 italic w-full py-6 text-sm xl:w-4/5 border-t border-neutral-400">
{t.rich('noData', {
subject: () => (
<span className="lowercase">{t(translationKey)}</span>
),
})}
</div>
) : (
<div className="w-full xl:w-4/5 flex flex-col gap-2 border-t border-neutral-400">
<MetadataEntry translationKey={translationKey} isCurrentPublisher>
{children}
</MetadataEntry>
))}
</div>
{metadataEnrichments?.map(enrichment => (
<MetadataEntry
key={enrichment.id}
translationKey={translationKey}
dateCreated={enrichment.pubInfo.dateCreated}
citation={enrichment.citation}
creator={enrichment.pubInfo.creator}
languageCode={enrichment.inLanguage}
>
<ReadMoreText text={enrichment.description} />
</MetadataEntry>
))}
</div>
)}
</div>
{enrichmentType && (
<AddMetadataEnrichment
translationKey={translationKey}
enrichmentType={enrichmentType}
/>
)}
</div>
{enrichmentType && (
<AddMetadataEnrichment
translationKey={translationKey}
enrichmentType={enrichmentType}
/>
)}
</div>
<Notifications prefixFilters={[`userEnrichment.${enrichmentType}`]} />
</>
);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,15 +58,15 @@ function CommunityMenuItems({
});

addNotification({
id: 'objectAddedToList',
id: 'objectList.added.success',
message: t.rich('objectAddedToList', {
name: () => <em>{objectList.name}</em>,
}),
type: 'success',
});
} catch (err) {
addNotification({
id: 'errorObjectAddedToList',
id: 'objectList.added.error',
message: t('errorObjectAddedToList'),
type: 'error',
});
Expand All @@ -76,15 +76,15 @@ function CommunityMenuItems({
await deleteObjectFromList(objectList.objects![0].id, communityId);

addNotification({
id: 'objectRemovedFromList',
id: 'objectList.removed.success',
message: t.rich('objectRemovedFromList', {
name: () => <em>{objectList.name}</em>,
}),
type: 'success',
});
} catch (err) {
addNotification({
id: 'errorObjectRemovedFromList',
id: 'objectList.removed.error',
message: t('errorObjectRemovedFromList'),
type: 'error',
});
Expand Down
2 changes: 1 addition & 1 deletion apps/researcher/src/app/[locale]/objects/[id]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ export default async function Details({params}: Props) {

<div className="max-w-[1800px] mx-auto flex flex-col md:flex-row h-full items-stretch grow content-stretch self-stretch gap-4 md:gap-16 w-full px-4 sm:px-10">
<main className="w-full md:w-2/3 order-2 md:order-1">
<Notifications />
<Notifications prefixFilters={['objectList']} />
<div className="mb-4 mt-10 flex justify-between">
<h2 className="text-2xl scroll-mt-20" tabIndex={0} id="metadata">
{t('metadata')}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ export function UserEnrichmentForm({
});

addNotification({
id: 'add-user-enrichment-success',
id: `userEnrichment.${enrichmentType}.added.success`,
message: t('successfullyAdded'),
type: 'success',
});
Expand Down
2 changes: 1 addition & 1 deletion apps/researcher/src/components/object-list-form/form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ function Form({
try {
await saveAction({list, pathName, id: listId});
addNotification({
id: 'add-object-list-success',
id: 'objectList.created.success',
message: t.rich(successfulSaveMessageKey, {
name: () => <em>{list.name}</em>,
}),
Expand Down
66 changes: 42 additions & 24 deletions packages/ui/notifications.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,7 @@ import {create} from 'zustand';
import {XMarkIcon} from '@heroicons/react/24/outline';
import {ReactNode, useEffect} from 'react';
import {usePathname} from 'next/navigation';

const typeColors = {
success: 'green-grey',
warning: 'yellow',
error: 'red',
};
import classNames from 'classnames';

type Notification = {
id: string;
Expand Down Expand Up @@ -40,7 +35,11 @@ export const useNotifications = create<State>(set => ({
})),
}));

export function Notifications() {
interface NotificationsProps {
prefixFilters?: string[];
}

export function Notifications({prefixFilters = []}: NotificationsProps) {
const {notifications, removeNotification, reset} = useNotifications();
const pathname = usePathname();

Expand All @@ -55,24 +54,43 @@ export function Notifications() {

return (
<div className="my-6">
{notifications.map(notification => {
const typeColor = typeColors[notification.type];
return (
<div
data-testid="notification"
key={notification.id}
className={`justify-between items-center bg-${typeColor}-50 border-${typeColor}-100 text-${typeColor}-800 border p-4 rounded-xl flex my-2`}
>
<div>{notification.message}</div>
<button
onClick={() => removeNotification(notification)}
className={`hover:bg-${typeColor}-200 p-1 rounded`}
{notifications
.filter(
notification =>
prefixFilters.length === 0 ||
prefixFilters.some(prefix => notification.id.startsWith(prefix))
)
.map(notification => {
return (
<div
data-testid="notification"
key={notification.id}
className={classNames(
'justify-between items-center border p-4 rounded-xl flex my-2',
{
'bg-green-grey-50 border-green-grey-100 text-green-grey-800':
notification.type === 'success',
'bg-yellow-50 border-yellow-100 text-yellow-800':
notification.type === 'warning',
'bg-red-50 border-red-100 text-red-800':
notification.type === 'error',
}
)}
>
<XMarkIcon className="w-4 h-4" />
</button>
</div>
);
})}
<div>{notification.message}</div>
<button
onClick={() => removeNotification(notification)}
className={classNames('hover:bg-gray-200 p-1 rounded', {
'text-green-grey-800': notification.type === 'success',
'text-yellow-800': notification.type === 'warning',
'text-red-800': notification.type === 'error',
})}
>
<XMarkIcon className="w-4 h-4" />
</button>
</div>
);
})}
</div>
);
}