Skip to content

Commit

Permalink
EES-5589 edit and reorder related pages
Browse files Browse the repository at this point in the history
  • Loading branch information
amyb-hiveit committed Oct 24, 2024
1 parent 2cd67d1 commit a2e0007
Show file tree
Hide file tree
Showing 10 changed files with 646 additions and 212 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import Button from '@common/components/Button';
import FormFieldTextInput from '@common/components/form/FormFieldTextInput';
import FormProvider from '@common/components/form/FormProvider';
import Form from '@common/components/form/Form';
import { BasicLink } from '@common/services/publicationService';
import Yup from '@common/validation/yup';
import ButtonGroup from '@common/components/ButtonGroup';
import React from 'react';

export type RelatedPageFormValues = Omit<BasicLink, 'id'>;

interface Props {
initialValues?: RelatedPageFormValues;
onCancel: () => void;
onSubmit: (link: RelatedPageFormValues) => Promise<void>;
}

export default function RelatedPageForm({
initialValues,
onCancel,
onSubmit,
}: Props) {
return (
<FormProvider
initialValues={initialValues ?? { description: '', url: '' }}
validationSchema={Yup.object({
description: Yup.string().required('Enter a link title'),
url: Yup.string()
.url('Enter a valid link URL')
.required('Enter a link URL'),
})}
>
<Form id="relatedPageForm" onSubmit={onSubmit}>
<FormFieldTextInput<RelatedPageFormValues>
label="Title"
name="description"
/>
<FormFieldTextInput<RelatedPageFormValues>
label="Link URL"
name="url"
/>
<ButtonGroup>
<Button type="submit" className="govuk-button govuk-!-margin-right-1">
Save
</Button>
<Button
className="govuk-button govuk-button--secondary"
variant="secondary"
onClick={onCancel}
>
Cancel
</Button>
</ButtonGroup>
</Form>
</FormProvider>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import RelatedPageForm, {
RelatedPageFormValues,
} from '@admin/pages/release/content/components/RelatedPageForm';
import Button from '@common/components/Button';
import Modal from '@common/components/Modal';
import useToggle from '@common/hooks/useToggle';
import React from 'react';

interface Props {
onSubmit: (link: RelatedPageFormValues) => Promise<void>;
}

export default function RelatedPagesAddModal({ onSubmit }: Props) {
const [open, toggleOpen] = useToggle(false);

const handleSubmit = async (values: RelatedPageFormValues) => {
await onSubmit(values);
toggleOpen.off();
};

return (
<Modal
open={open}
title="Add related page link"
triggerButton={<Button onClick={toggleOpen.on}>Add related page</Button>}
onExit={toggleOpen.off}
>
<RelatedPageForm onCancel={toggleOpen.off} onSubmit={handleSubmit} />
</Modal>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
import Link from '@admin/components/Link';
import RelatedPageForm, {
RelatedPageFormValues,
} from '@admin/pages/release/content/components/RelatedPageForm';
import Button from '@common/components/Button';
import ButtonGroup from '@common/components/ButtonGroup';
import Modal from '@common/components/Modal';
import ReorderableList from '@common/components/ReorderableList';
import VisuallyHidden from '@common/components/VisuallyHidden';
import useToggle from '@common/hooks/useToggle';
import { BasicLink } from '@common/services/publicationService';
import reorder from '@common/utils/reorder';
import React, { useEffect, useState } from 'react';

interface Props {
relatedPages: BasicLink[];
onUpdate: (pages: BasicLink[]) => Promise<void>;
}

export default function RelatedPagesEditModal({
relatedPages: initialRelatedPages,
onUpdate,
}: Props) {
const [open, toggleOpen] = useToggle(false);
const [isReordering, toggleReordering] = useToggle(false);
const [editingPage, setEditingPage] = useState<BasicLink>();
const [relatedPages, setRelatedPages] =
useState<BasicLink[]>(initialRelatedPages);

useEffect(() => {
setRelatedPages(initialRelatedPages);
}, [initialRelatedPages]);

const handleRemove = async (id: string) => {
const updatedPages = relatedPages.filter(page => page.id !== id);
await onUpdate(updatedPages);
};

const handleSubmit = async (values: RelatedPageFormValues) => {
const updatedPages = relatedPages.map(page => {
if (page.id === editingPage?.id) {
return { id: editingPage.id, ...values };
}
return page;
});
await onUpdate(updatedPages);
setEditingPage(undefined);
};

return (
<Modal
className="govuk-!-width-one-half"
open={open}
title="Edit related pages"
triggerButton={
<Button variant="secondary" onClick={toggleOpen.on}>
Edit pages
</Button>
}
onExit={toggleOpen.off}
>
{editingPage ? (
<RelatedPageForm
initialValues={{
description: editingPage.description,
url: editingPage.url,
}}
onCancel={() => setEditingPage(undefined)}
onSubmit={handleSubmit}
/>
) : (
<>
{isReordering ? (
<ReorderableList
heading="Reorder pages"
id="reorder-related-pages"
list={relatedPages.map(page => ({
id: page.id,
label: page.description,
}))}
onCancel={() => {
toggleReordering.off();
setRelatedPages(initialRelatedPages);
}}
onConfirm={async () => {
await onUpdate(relatedPages);
toggleReordering.off();
}}
onMoveItem={({ prevIndex, nextIndex }) => {
const reordered = reorder(relatedPages, prevIndex, nextIndex);
setRelatedPages(reordered);
}}
onReverse={() => {
setRelatedPages(relatedPages.toReversed());
}}
/>
) : (
<>
<Button
className="govuk-!-margin-bottom-3"
variant="secondary"
onClick={toggleReordering}
>
Reorder pages
</Button>
<table>
<thead>
<tr>
<th>Title</th>
<th>Link URL</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
{relatedPages.map(page => (
<tr key={page.id}>
<td>{page.description}</td>
<td>
<Link to={page.url}>{page.url}</Link>
</td>
<td>
<ButtonGroup className="govuk-!-margin-bottom-0">
<Button onClick={() => setEditingPage(page)}>
Edit
<VisuallyHidden> {page.description}</VisuallyHidden>
</Button>
<Button
variant="warning"
onClick={() => handleRemove(page.id)}
>
Remove{' '}
<VisuallyHidden> {page.description}</VisuallyHidden>
</Button>
</ButtonGroup>
</td>
</tr>
))}
</tbody>
</table>
<Button onClick={toggleOpen.off}>
Close <VisuallyHidden> modal</VisuallyHidden>
</Button>
</>
)}
</>
)}
</Modal>
);
}
Original file line number Diff line number Diff line change
@@ -1,108 +1,69 @@
import EditableLink from '@admin/components/editable/EditableLink';
import Link from '@admin/components/Link';
import RelatedPagesEditModal from '@admin/pages/release/content/components/RelatedPagesEditModal';
import RelatedPagesAddModal from '@admin/pages/release/content/components/RelatedPagesAddModal';
import { RelatedPageFormValues } from '@admin/pages/release/content/components/RelatedPageForm';
import { useEditingContext } from '@admin/contexts/EditingContext';
import releaseContentRelatedInformationService from '@admin/services/releaseContentRelatedInformationService';
import { EditableRelease } from '@admin/services/releaseContentService';
import Button from '@common/components/Button';
import { FormFieldset } from '@common/components/form';
import FormFieldTextInput from '@common/components/form/FormFieldTextInput';
import FormProvider from '@common/components/form/FormProvider';
import Form from '@common/components/form/Form';
import useToggle from '@common/hooks/useToggle';
import ButtonGroup from '@common/components/ButtonGroup';
import { BasicLink } from '@common/services/publicationService';
import Yup from '@common/validation/yup';
import React, { useState } from 'react';

type FormValues = Omit<BasicLink, 'id'>;

interface Props {
release: EditableRelease;
}

export default function RelatedPagesSection({ release }: Props) {
const [links, setLinks] = useState<BasicLink[]>(release.relatedInformation);
const [formOpen, toggleFormOpen] = useToggle(false);
const [relatedPages, setRelatedPages] = useState<BasicLink[]>(
release.relatedInformation,
);

const { editingMode } = useEditingContext();

const removeLink = (linkId: string) => {
releaseContentRelatedInformationService
.delete(release.id, linkId)
.then(setLinks);
const handleSubmit = async (values: RelatedPageFormValues) => {
const updatedLinks = await releaseContentRelatedInformationService.update(
release.id,
[...relatedPages, values],
);
setRelatedPages(updatedLinks);
};

const handleSubmit = async (values: FormValues) => {
const newLinks = await releaseContentRelatedInformationService.create(
const handleUpdate = async (updatedPages: BasicLink[]) => {
const updatedLinks = await releaseContentRelatedInformationService.update(
release.id,
values,
updatedPages,
);
setLinks(newLinks);
toggleFormOpen.off();
setRelatedPages(updatedLinks);
};

return (
<>
{(editingMode === 'edit' || links.length > 0) && (
<>
<h2 className="govuk-heading-s" id="related-pages">
Related pages
</h2>
<ul className="govuk-list">
{links.map(({ id, description, url }) => (
<li key={id}>
<EditableLink removeOnClick={() => removeLink(id)} to={url}>
{description}
</EditableLink>
</li>
))}
</ul>
</>
{(editingMode === 'edit' || relatedPages.length > 0) && (
<h2 className="govuk-heading-s" id="related-pages">
Related pages
</h2>
)}

{relatedPages.length > 0 && (
<ul className="govuk-list">
{relatedPages.map(({ id, description, url }) => (
<li key={id}>
<Link to={url}>{description}</Link>
</li>
))}
</ul>
)}

{editingMode === 'edit' && (
<>
{formOpen ? (
<FormProvider
initialValues={{ description: '', url: '' }}
validationSchema={Yup.object({
description: Yup.string().required('Enter a link title'),
url: Yup.string()
.url('Enter a valid link URL')
.required('Enter a link URL'),
})}
>
<Form id="relatedPageForm" onSubmit={handleSubmit}>
<FormFieldset
id="relatedLink"
legend="Add related page link"
legendSize="m"
>
<FormFieldTextInput<FormValues>
label="Title"
name="description"
/>
<FormFieldTextInput<FormValues> label="Link URL" name="url" />
</FormFieldset>
<ButtonGroup>
<Button
type="submit"
className="govuk-button govuk-!-margin-right-1"
>
Create link
</Button>
<Button
className="govuk-button govuk-button--secondary"
variant="secondary"
onClick={toggleFormOpen.off}
>
Cancel
</Button>
</ButtonGroup>
</Form>
</FormProvider>
) : (
<Button onClick={toggleFormOpen.on}>Add related page link</Button>
<ButtonGroup>
<RelatedPagesAddModal onSubmit={handleSubmit} />
{relatedPages.length > 0 && (
<RelatedPagesEditModal
relatedPages={relatedPages}
onUpdate={handleUpdate}
/>
)}
</>
</ButtonGroup>
)}
</>
);
Expand Down
Loading

0 comments on commit a2e0007

Please sign in to comment.