From 69d00c986c36677f93e643d9a3e286a02a2403e4 Mon Sep 17 00:00:00 2001 From: William Thorenfeldt <48119543+wrt95@users.noreply.github.com> Date: Tue, 19 Nov 2024 14:06:54 +0100 Subject: [PATCH] refactor: Refactor Dashboard resources to use studio/components and icons (#13962) --- .../ResourceItem/ResourceItem.test.tsx | 35 +++ .../components/ResourceItem/ResourceItem.tsx | 20 +- .../components/Resources/Resources.tsx | 209 ++---------------- frontend/dashboard/types/Resource.ts | 8 + .../src/react/icons/ContactResourceIcon.tsx | 43 ++++ .../src/react/icons/DesignResourceIcon.tsx | 35 +++ .../src/react/icons/DocsResourceIcon.tsx | 19 ++ .../icons/OperationStatusResourceIcon.tsx | 34 +++ .../src/react/icons/OrgResourceIcon.tsx | 23 ++ .../src/react/icons/RoadmapResourceIcon.tsx | 15 ++ .../src/react/icons/SlackIcon.tsx | 30 --- .../studio-icons/src/react/icons/index.ts | 6 + 12 files changed, 249 insertions(+), 228 deletions(-) create mode 100644 frontend/dashboard/components/ResourceItem/ResourceItem.test.tsx create mode 100644 frontend/dashboard/types/Resource.ts create mode 100644 frontend/libs/studio-icons/src/react/icons/ContactResourceIcon.tsx create mode 100644 frontend/libs/studio-icons/src/react/icons/DesignResourceIcon.tsx create mode 100644 frontend/libs/studio-icons/src/react/icons/DocsResourceIcon.tsx create mode 100644 frontend/libs/studio-icons/src/react/icons/OperationStatusResourceIcon.tsx create mode 100644 frontend/libs/studio-icons/src/react/icons/OrgResourceIcon.tsx create mode 100644 frontend/libs/studio-icons/src/react/icons/RoadmapResourceIcon.tsx diff --git a/frontend/dashboard/components/ResourceItem/ResourceItem.test.tsx b/frontend/dashboard/components/ResourceItem/ResourceItem.test.tsx new file mode 100644 index 00000000000..c6924ae2080 --- /dev/null +++ b/frontend/dashboard/components/ResourceItem/ResourceItem.test.tsx @@ -0,0 +1,35 @@ +import React from 'react'; +import { render, screen } from '@testing-library/react'; +import { ResourceItem, type ResourceItemProps } from './ResourceItem'; +import { textMock } from '@studio/testing/mocks/i18nMock'; +import '@testing-library/jest-dom'; +import { type Resource } from 'dashboard/types/Resource'; + +const resourceMock: Resource = { + url: 'https://example.com', + label: 'test_label', + description: 'test_description', + icon: 🔗, +}; + +describe('ResourceItem', () => { + it('should render the icon, label, and description', () => { + renderResourceItem(); + expect(screen.getByTestId('icon')).toBeInTheDocument(); + const linkElement = screen.getByRole('link', { name: textMock(resourceMock.label) }); + expect(linkElement).toBeInTheDocument(); + expect(screen.getByText(textMock(resourceMock.description))).toBeInTheDocument(); + }); + + it('should set the correct href and attributes on the link', () => { + renderResourceItem(); + + const linkElement = screen.getByRole('link', { name: textMock(resourceMock.label) }); + expect(linkElement).toHaveAttribute('href', resourceMock.url); + expect(linkElement).toHaveAttribute('target', '_blank'); + expect(linkElement).toHaveAttribute('rel', 'noopener noreferrer'); + }); +}); + +const renderResourceItem = (props: Partial = {}) => + render(); diff --git a/frontend/dashboard/components/ResourceItem/ResourceItem.tsx b/frontend/dashboard/components/ResourceItem/ResourceItem.tsx index ffb19745057..5de084b185e 100644 --- a/frontend/dashboard/components/ResourceItem/ResourceItem.tsx +++ b/frontend/dashboard/components/ResourceItem/ResourceItem.tsx @@ -1,24 +1,24 @@ -import type { ReactNode } from 'react'; +import type { ReactElement } from 'react'; import React from 'react'; import classes from './ResourceItem.module.css'; import { useTranslation } from 'react-i18next'; +import { StudioLink } from '@studio/components'; +import { type Resource } from 'dashboard/types/Resource'; -export interface ResourceItemProps { - link: string; - label: string; - description: string; - icon: ReactNode; -} +export type ResourceItemProps = { + resource: Resource; +}; -export function ResourceItem({ link, label, description, icon }: ResourceItemProps) { +export function ResourceItem({ resource }: ResourceItemProps): ReactElement { const { t } = useTranslation(); + const { url, label, description, icon } = resource; return (
{icon}
- + {t(label)} - +

{t(description)}

diff --git a/frontend/dashboard/components/Resources/Resources.tsx b/frontend/dashboard/components/Resources/Resources.tsx index c06e39bd549..238ebebe6ca 100644 --- a/frontend/dashboard/components/Resources/Resources.tsx +++ b/frontend/dashboard/components/Resources/Resources.tsx @@ -1,220 +1,59 @@ -import React from 'react'; +import React, { type ReactElement } from 'react'; import { ResourceItem } from '../ResourceItem'; import classes from './Resources.module.css'; import { useTranslation } from 'react-i18next'; -import { StudioHeading } from '@studio/components'; +import { + OrgResourceIcon, + DocsResourceIcon, + ContactResourceIcon, + DesignResourceIcon, + RoadmapResourceIcon, + OperationStatusResourceIcon, +} from '@studio/icons'; import { altinnDocsUrl } from 'app-shared/ext-urls'; - -interface Resource { - label: string; - description: string; - url: string; - icon: React.ReactNode; -} +import { StudioHeading } from '@studio/components'; +import { type Resource } from 'dashboard/types/Resource'; const resources: Resource[] = [ { label: 'dashboard.resource_docs_label', description: 'dashboard.resource_docs_description', - url: 'https://docs.altinn.studio', - icon: ( - - - - - - ), + url: altinnDocsUrl(), + icon: , }, { label: 'dashboard.resource_organisations_label', description: 'dashboard.resource_organisations_description', url: `${window.location.origin}/repos/explore/organizations`, - icon: ( - - - - - - - ), + icon: , }, { label: 'dashboard.resource_contact_label', description: 'dashboard.resource_contact_description', url: 'https://altinn.studio/contact', - icon: ( - - - - - - - - - - - - ), + icon: , }, { label: 'dashboard.resource_design_label', description: 'dashboard.resource_design_description', url: 'https://www.figma.com/file/wnBveAG2ikUspFsQwM3GNE/Prototyping-av-skjematjenester?node-id=47%3A4068', - icon: ( - - - - - - - - - - ), + icon: , }, { label: 'dashboard.resource_roadmap_label', description: 'dashboard.resource_roadmap_description', url: altinnDocsUrl({ relativeUrl: 'community/roadmap/' }), - icon: ( - - - - - ), + icon: , }, { label: 'dashboard.resource_status_label', description: 'dashboard.resource_status_description', url: 'https://status.digdir.no/', - icon: ( - - - - - - - - - - - - ), + icon: , }, ]; -export function Resources() { +export function Resources(): ReactElement { const { t } = useTranslation(); return (
@@ -222,14 +61,8 @@ export function Resources() { {t('dashboard.resources')}
- {resources.map((resource, index) => ( - + {resources.map((resource: Resource, index: number) => ( + ))}
diff --git a/frontend/dashboard/types/Resource.ts b/frontend/dashboard/types/Resource.ts new file mode 100644 index 00000000000..ca5615bee2f --- /dev/null +++ b/frontend/dashboard/types/Resource.ts @@ -0,0 +1,8 @@ +import { type ReactNode } from 'react'; + +export type Resource = { + label: string; + description: string; + url: string; + icon: ReactNode; +}; diff --git a/frontend/libs/studio-icons/src/react/icons/ContactResourceIcon.tsx b/frontend/libs/studio-icons/src/react/icons/ContactResourceIcon.tsx new file mode 100644 index 00000000000..27e66572790 --- /dev/null +++ b/frontend/libs/studio-icons/src/react/icons/ContactResourceIcon.tsx @@ -0,0 +1,43 @@ +import React from 'react'; +import type { IconProps } from '../types'; +import { SvgTemplate } from './SvgTemplate'; + +export const ContactResourceIcon = (props: IconProps): React.ReactElement => { + return ( + + + + + + + + + + + + ); +}; diff --git a/frontend/libs/studio-icons/src/react/icons/DesignResourceIcon.tsx b/frontend/libs/studio-icons/src/react/icons/DesignResourceIcon.tsx new file mode 100644 index 00000000000..a66fead81a5 --- /dev/null +++ b/frontend/libs/studio-icons/src/react/icons/DesignResourceIcon.tsx @@ -0,0 +1,35 @@ +import React from 'react'; +import type { IconProps } from '../types'; +import { SvgTemplate } from './SvgTemplate'; + +export const DesignResourceIcon = (props: IconProps): React.ReactElement => { + return ( + + + + + + + + + + ); +}; diff --git a/frontend/libs/studio-icons/src/react/icons/DocsResourceIcon.tsx b/frontend/libs/studio-icons/src/react/icons/DocsResourceIcon.tsx new file mode 100644 index 00000000000..7c1f2b8370e --- /dev/null +++ b/frontend/libs/studio-icons/src/react/icons/DocsResourceIcon.tsx @@ -0,0 +1,19 @@ +import React from 'react'; +import type { IconProps } from '../types'; +import { SvgTemplate } from './SvgTemplate'; + +export const DocsResourceIcon = (props: IconProps): React.ReactElement => { + return ( + + + + + + ); +}; diff --git a/frontend/libs/studio-icons/src/react/icons/OperationStatusResourceIcon.tsx b/frontend/libs/studio-icons/src/react/icons/OperationStatusResourceIcon.tsx new file mode 100644 index 00000000000..258f2d62d27 --- /dev/null +++ b/frontend/libs/studio-icons/src/react/icons/OperationStatusResourceIcon.tsx @@ -0,0 +1,34 @@ +import React from 'react'; +import type { IconProps } from '../types'; +import { SvgTemplate } from './SvgTemplate'; + +export const OperationStatusResourceIcon = (props: IconProps): React.ReactElement => { + return ( + + + + + + + + + + + + ); +}; diff --git a/frontend/libs/studio-icons/src/react/icons/OrgResourceIcon.tsx b/frontend/libs/studio-icons/src/react/icons/OrgResourceIcon.tsx new file mode 100644 index 00000000000..97f60785490 --- /dev/null +++ b/frontend/libs/studio-icons/src/react/icons/OrgResourceIcon.tsx @@ -0,0 +1,23 @@ +import React from 'react'; +import type { IconProps } from '../types'; +import { SvgTemplate } from './SvgTemplate'; + +export const OrgResourceIcon = (props: IconProps): React.ReactElement => { + return ( + + + + + + + ); +}; diff --git a/frontend/libs/studio-icons/src/react/icons/RoadmapResourceIcon.tsx b/frontend/libs/studio-icons/src/react/icons/RoadmapResourceIcon.tsx new file mode 100644 index 00000000000..ddb3a30aa23 --- /dev/null +++ b/frontend/libs/studio-icons/src/react/icons/RoadmapResourceIcon.tsx @@ -0,0 +1,15 @@ +import React from 'react'; +import type { IconProps } from '../types'; +import { SvgTemplate } from './SvgTemplate'; + +export const RoadmapResourceIcon = (props: IconProps): React.ReactElement => { + return ( + + + + + ); +}; diff --git a/frontend/libs/studio-icons/src/react/icons/SlackIcon.tsx b/frontend/libs/studio-icons/src/react/icons/SlackIcon.tsx index c7e3238c3b2..384b9a554eb 100644 --- a/frontend/libs/studio-icons/src/react/icons/SlackIcon.tsx +++ b/frontend/libs/studio-icons/src/react/icons/SlackIcon.tsx @@ -40,33 +40,3 @@ export const SlackIcon = (props: IconProps): React.ReactElement => { ); }; - -/* - - - - - - - - - - - -*/ diff --git a/frontend/libs/studio-icons/src/react/icons/index.ts b/frontend/libs/studio-icons/src/react/icons/index.ts index 76234f2d6bb..80042250b29 100644 --- a/frontend/libs/studio-icons/src/react/icons/index.ts +++ b/frontend/libs/studio-icons/src/react/icons/index.ts @@ -5,8 +5,11 @@ export { CheckboxIcon } from './CheckboxIcon'; export { CodeListsIcon } from './CodeListsIcon'; export { CombinationIcon } from './CombinationIcon'; export { ConfirmationTaskIcon } from './ConfirmationTaskIcon'; +export { ContactResourceIcon } from './ContactResourceIcon'; export { DataTaskIcon } from './DataTaskIcon'; export { DefinitionIcon } from './DefinitionIcon'; +export { DesignResourceIcon } from './DesignResourceIcon'; +export { DocsResourceIcon } from './DocsResourceIcon'; export { ElementIcon } from './ElementIcon'; export { EndEventIcon } from './EndEventIcon'; export { FeedbackTaskIcon } from './FeedbackTaskIcon'; @@ -18,6 +21,9 @@ export { LongTextIcon } from './LongTextIcon'; export { NavBarIcon } from './NavBarIcon'; export { NumberIcon } from './NumberIcon'; export { ObjectIcon } from './ObjectIcon'; +export { OrgResourceIcon } from './OrgResourceIcon'; +export { OperationStatusResourceIcon } from './OperationStatusResourceIcon'; +export { RoadmapResourceIcon } from './RoadmapResourceIcon'; export { TextIcon } from './TextIcon'; export { PaymentDetailsIcon } from './PaymentDetailsIcon'; export { PaymentTaskIcon } from './PaymentTaskIcon';