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

refactor(studio-root): seperated repeated html on ContactPage to React Component #14169

Merged
merged 4 commits into from
Nov 27, 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
1 change: 1 addition & 0 deletions .github/workflows/lint-pr.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ jobs:
resource-adm
resource-registry
settings
studio-root
subform
testing
text
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
.section {
background-color: var(--colors-grey-100);
border-radius: 4px;
display: flex;
gap: var(--fds-spacing-6);
padding: var(--fds-spacing-8);
max-width: 735px;
}

.iconContainer {
background-color: var(--primary-color-700);
border-radius: 100%;
color: var(--colors-white);
display: flex;
align-items: center;
justify-content: center;
height: 60px;
width: 60px;
box-sizing: border-box;
}

.icon {
font-size: var(--fds-sizing-7);
}

.textContainer {
flex: 1;
}

@media (min-width: 768px) {
.section {
padding: var(--fds-spacing-12);
}
}

@media (min-width: 960px) {
.section {
padding-right: var(--fds-spacing-22);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import React from 'react';
import { ContactSection, type ContactSectionProps } from './ContactSection';
import { render, screen } from '@testing-library/react';
import { SlackIcon } from '@studio/icons';

const defaultContactSectionProps: ContactSectionProps = {
title: '',
description: '',
link: {
name: '',
href: '',
},
Icon: SlackIcon,
};

describe('ContactSection', () => {
it('should render with provided props', () => {
const props: ContactSectionProps = {
...defaultContactSectionProps,
title: 'Get in touch',
description: 'We are helpfull',
Icon: SlackIcon,
link: {
name: 'Get in touch',
href: 'mailto:[email protected]',
},
additionalContent: 'additional content',
};
renderContactSection(props);

const icon = screen.getByTitle(props.title);
expect(icon).toBeInTheDocument();

const heading = screen.getByRole('heading', { name: props.title, level: 2 });
expect(heading).toBeInTheDocument();

const description = screen.getByText(props.description);
expect(description).toBeInTheDocument();

const additionalContent = screen.getByText(props.additionalContent as string);
expect(additionalContent).toBeInTheDocument();

const link = screen.getByRole('link', { name: props.link.name });
expect(link).toBeInTheDocument();
expect(link).toHaveAttribute('href', props.link.href);
});
});

function renderContactSection(props: ContactSectionProps = defaultContactSectionProps): void {
render(<ContactSection {...props} />);
}
38 changes: 38 additions & 0 deletions frontend/studio-root/components/ContactSection/ContactSection.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import React, { type ComponentType, type ReactElement, type ReactNode } from 'react';
import { StudioHeading, StudioLink, StudioParagraph } from '@studio/components';
import { type IconProps } from '@studio/icons';
import classes from './ContactSection.module.css';

export type ContactSectionProps = {
title: string;
description: string;
link: {
name: string;
href: string;
};
Icon: ComponentType<IconProps>;
additionalContent?: ReactNode;
};
export const ContactSection = ({
title,
description,
link,
Icon,
additionalContent,
}: ContactSectionProps): ReactElement => {
return (
<section className={classes.section}>
<div className={classes.iconContainer}>
<Icon className={classes.icon} title={title} aria-hidden />
</div>
<div className={classes.textContainer}>
<StudioHeading level={2} size='xs' spacing>
{title}
</StudioHeading>
<StudioParagraph spacing>{description}</StudioParagraph>
{additionalContent && <span>{additionalContent}</span>}
<StudioLink href={link.href}>{link.name}</StudioLink>
</div>
</section>
);
};
1 change: 1 addition & 0 deletions frontend/studio-root/components/ContactSection/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { ContactSection, type ContactSectionProps } from './ContactSection';
40 changes: 0 additions & 40 deletions frontend/studio-root/pages/Contact/ContactPage.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
flex-direction: column;
font-family: var(--studio-font-family);
position: relative;

margin: var(--fds-spacing-10) auto;
max-width: 1230px;
}
Expand All @@ -22,47 +21,8 @@
margin: var(--fds-spacing-12) var(--fds-spacing-8);
}

.section {
background-color: var(--colors-grey-100);
border-radius: 4px;
display: flex;
gap: var(--fds-spacing-6);
padding: var(--fds-spacing-8);
max-width: 735px;
}

.iconContainer {
background-color: var(--primary-color-700);
border-radius: 100%;
color: var(--colors-white);
display: flex;
align-items: center;
justify-content: center;
height: 60px;
width: 60px;
box-sizing: border-box;
}

.icon {
font-size: 2.3rem;
}

.textContainer {
flex: 1;
}

@media (min-width: 768px) {
.content {
margin: var(--fds-spacing-18);
}

.section {
padding: var(--fds-spacing-12);
}
}

@media (min-width: 960px) {
.section {
padding-right: var(--fds-spacing-22);
}
}
104 changes: 50 additions & 54 deletions frontend/studio-root/pages/Contact/ContactPage.tsx
Original file line number Diff line number Diff line change
@@ -1,81 +1,77 @@
import React from 'react';
import classes from './ContactPage.module.css';
import { Heading, Link, Paragraph } from '@digdir/designsystemet-react';
import { Trans, useTranslation } from 'react-i18next';
import { EnvelopeClosedIcon, SlackIcon, GitHubIcon } from '@studio/icons';
import classNames from 'classnames';
import { GetInTouchWith } from 'app-shared/getInTouch';
import {
EmailContactProvider,
GitHubIssueContactProvider,
SlackContactProvider,
} from 'app-shared/getInTouch/providers';
import { StudioPageImageBackgroundContainer } from '@studio/components';
import {
StudioPageImageBackgroundContainer,
StudioHeading,
StudioParagraph,
} from '@studio/components';
import { ContactSection, type ContactSectionProps } from '../../components/ContactSection';

export const ContactPage = (): React.ReactElement => {
const { t } = useTranslation();
const contactByEmail = new GetInTouchWith(new EmailContactProvider());
const contactBySlack = new GetInTouchWith(new SlackContactProvider());
const contactByGitHubIssue = new GetInTouchWith(new GitHubIssueContactProvider());

const contactSections: Array<ContactSectionProps> = [
{
title: t('contact.email.heading'),
description: t('contact.email.content'),
link: {
name: t('general.service_desk.email'),
href: contactByEmail.url('serviceDesk'),
},
Icon: EnvelopeClosedIcon,
},
{
title: t('contact.slack.heading'),
description: t('contact.slack.content'),
additionalContent: (
<StudioParagraph spacing asChild>
<ul>
<Trans i18nKey='contact.slack.content_list'>
<li />
</Trans>
</ul>
</StudioParagraph>
),
link: {
name: t('contact.slack.link'),
href: contactBySlack.url('product-altinn-studio'),
},
Icon: SlackIcon,
},
{
title: t('contact.github_issue.heading'),
description: t('contact.github_issue.content'),
link: {
name: t('contact.github_issue.link_label'),
href: contactByGitHubIssue.url('choose'),
},
Icon: GitHubIcon,
},
];

return (
<StudioPageImageBackgroundContainer image='/designer/img/page-background.svg'>
<div className={classes.container}>
<div className={classes.content}>
<div>
<Heading size='medium' spacing>
<StudioHeading size='medium' spacing>
{t('general.contact')}
</Heading>
</StudioHeading>
</div>
<section className={classes.section}>
<div className={classes.iconContainer}>
<EnvelopeClosedIcon className={classes.icon} />
</div>
<div className={classes.textContainer}>
<Heading level={2} size='xsmall' spacing>
{t('contact.email.heading')}
</Heading>
<Paragraph spacing>{t('contact.email.content')}</Paragraph>
<Link href={contactByEmail.url('serviceDesk')}>
{t('general.service_desk.email')}
</Link>
</div>
</section>
<section className={classes.section}>
<div className={classes.iconContainer}>
<SlackIcon className={classes.icon} />
</div>
<div className={classes.textContainer}>
<Heading level={2} size='xsmall' spacing>
{t('contact.slack.heading')}
</Heading>
<Paragraph spacing>{t('contact.slack.content')}</Paragraph>
<Paragraph spacing asChild>
<ul>
<Trans i18nKey='contact.slack.content_list'>
<li />
</Trans>
</ul>
</Paragraph>
<Link href={contactBySlack.url('product-altinn-studio')}>
{t('contact.slack.link')}
</Link>
</div>
</section>
<section className={classes.section}>
<div className={classNames(classes.iconContainer)}>
<GitHubIcon className={classes.icon} />
</div>
<div className={classes.textContainer}>
<Heading level={2} size='xsmall' spacing>
{t('contact.github_issue.heading')}
</Heading>
<Paragraph spacing>{t('contact.github_issue.content')}</Paragraph>
<Link href={contactByGitHubIssue.url('choose')}>
{t('contact.github_issue.link_label')}
</Link>
</div>
</section>
{contactSections.map((contactSection) => (
<ContactSection {...contactSection} key={contactSection.title} />
))}
</div>
</div>
</StudioPageImageBackgroundContainer>
Expand Down