diff --git a/src/app/components/book-tile/book-tile-display.tsx b/src/app/components/book-tile/book-tile-display.tsx
new file mode 100644
index 000000000..344799135
--- /dev/null
+++ b/src/app/components/book-tile/book-tile-display.tsx
@@ -0,0 +1,55 @@
+import React from 'react';
+import PromoteBadge from '~/components/promote-badge/promote-badge';
+import type {Item} from '~/models/book-titles';
+import {Book as BookInfo} from '~/pages/subjects/new/specific/context';
+import GetTheBookDropdown from './dropdown-menu';
+import cn from 'classnames';
+import './book-tile.scss';
+
+type AdditionalFields = Partial<{
+ promoteSnippet: Item['promote_snippet'];
+ bookState: string;
+}>
+
+export default function BookTile({book}: {book: BookInfo & AdditionalFields}) {
+ const {coverUrl, title, slug} = book;
+ const comingSoon = book.bookState === 'coming_soon';
+ const snippets = book.promoteSnippet?.filter((s) => s.value.image);
+ const promoteSnippet = snippets?.find((s) => s.value.image);
+ const classes = cn({
+ 'book-tile': true,
+ 'coming-soon': comingSoon,
+ promote: Boolean(promoteSnippet)
+ });
+
+ return (
+
+ );
+}
diff --git a/src/app/components/book-tile/book-tile.tsx b/src/app/components/book-tile/book-tile.tsx
index b471f2515..0dca94486 100644
--- a/src/app/components/book-tile/book-tile.tsx
+++ b/src/app/components/book-tile/book-tile.tsx
@@ -1,54 +1,19 @@
import React from 'react';
-import PromoteBadge from '~/components/promote-badge/promote-badge';
import bookPromise, {Item} from '~/models/book-titles';
import {Book as BookInfo} from '~/pages/subjects/new/specific/context';
-import GetTheBookDropdown from './dropdown-menu';
-import cn from 'classnames';
import './book-tile.scss';
+import BookTileDisplay from './book-tile-display';
-// eslint-disable-next-line complexity
export default function BookTile({book: [book]}: {book: [BookInfo]}) {
- const {coverUrl, title, slug} = book;
const info = useBookInfo(book.id);
- const comingSoon = info?.book_state === 'coming_soon';
- const snippets = info?.promote_snippet.filter((s) => s.value.image);
- const promoteSnippet = snippets?.find((s) => s.value.image);
- const classes = cn({
- 'book-tile': true,
- 'coming-soon': comingSoon,
- promote: Boolean(promoteSnippet)
- });
- return (
-
- );
+ return ;
}
function useBookInfo(id: number) {
diff --git a/src/app/pages/flex-page/blocks/BookListBlock.scss b/src/app/pages/flex-page/blocks/BookListBlock.scss
new file mode 100644
index 000000000..6cb6e2b22
--- /dev/null
+++ b/src/app/pages/flex-page/blocks/BookListBlock.scss
@@ -0,0 +1,16 @@
+@import 'pattern-library/core/pattern-library/headers';
+
+.flex-page.page div.content-block-book-list {
+ display: grid;
+ grid-template-columns: repeat(auto-fill, minmax(16rem, 1fr));
+ margin: $normal-margin 0;
+ width: 100%;
+
+ @include width-up-to($phone-max) {
+ grid-gap: 1rem;
+ }
+
+ @include wider-than($phone-max) {
+ grid-gap: 4rem 2rem;
+ }
+}
diff --git a/src/app/pages/flex-page/blocks/BookListBlock.tsx b/src/app/pages/flex-page/blocks/BookListBlock.tsx
new file mode 100644
index 000000000..5dfb531ed
--- /dev/null
+++ b/src/app/pages/flex-page/blocks/BookListBlock.tsx
@@ -0,0 +1,44 @@
+import React from 'react';
+import cn from 'classnames';
+import './BookListBlock.scss';
+import BookTile from '~/components/book-tile/book-tile-display';
+
+/*
+ * the book data formatting in the CMS is currently fragemented,
+ * when it gets centralized we can centralize the types as well
+ */
+export type BookInfo = {
+ id: number;
+ slug: string;
+ title: string;
+ webviewRexLink: string;
+ webviewLink: string;
+ highResolutionPdfUrl: string;
+ lowResolutionPdfUrl: string;
+ coverUrl: string;
+ bookState: string;
+ promoteSnippet: {
+ value: {
+ id: number;
+ description: string;
+ image: string;
+ name: string;
+ };
+ }[];
+};
+
+export type BookListBlockConfig = {
+ id: string;
+ type: 'book_list';
+ value: {
+ books: BookInfo[];
+ };
+};
+
+export function BookListBlock({data}: {data: BookListBlockConfig}) {
+ return (
+
+ {data.value.books.map((book) => )}
+
+ );
+}
diff --git a/src/app/pages/flex-page/blocks/ContentBlock.tsx b/src/app/pages/flex-page/blocks/ContentBlock.tsx
index d1a6907a4..780f3f17f 100644
--- a/src/app/pages/flex-page/blocks/ContentBlock.tsx
+++ b/src/app/pages/flex-page/blocks/ContentBlock.tsx
@@ -9,6 +9,7 @@ import { HTMLBlockConfig, HTMLBlock } from './HTMLBlock';
import { LinksBlockConfig, LinksBlock } from './LinksBlock';
import { QuoteBlock, QuoteBlockConfig } from './QuoteBlock';
import { FAQBlockConfig, FAQBlock } from './FAQBlock';
+import { BookListBlockConfig, BookListBlock } from './BookListBlock';
export type ContentBlockConfig =
LinksBlockConfig |
@@ -20,6 +21,7 @@ export type ContentBlockConfig =
RichTextBlockConfig |
QuoteBlockConfig |
FAQBlockConfig |
+ BookListBlockConfig |
CardsBlockConfig;
export function ContentBlocks({data}: {data: ContentBlockConfig[]}) {
@@ -51,6 +53,8 @@ export function ContentBlock({data}: {data: ContentBlockConfig}) {
return ;
case 'faq':
return ;
+ case 'book_list':
+ return ;
default:
return {JSON.stringify(data, null, 2)}
;
}
diff --git a/src/app/pages/flex-page/blocks/RichTextBlock.scss b/src/app/pages/flex-page/blocks/RichTextBlock.scss
index df0810030..891972590 100644
--- a/src/app/pages/flex-page/blocks/RichTextBlock.scss
+++ b/src/app/pages/flex-page/blocks/RichTextBlock.scss
@@ -9,12 +9,12 @@
width: 100%;
height: auto;
}
-
+
img.richtext-image.left {
float: left;
margin-right: $normal-margin;
}
-
+
img.richtext-image.right {
float: right;
margin-left: $normal-margin;
@@ -23,7 +23,7 @@
> *:first-child {
margin-top: 0;
}
- > *:last-child {
+ > *:not(h1, h2, h3, h4, h5, h6):last-child {
margin-bottom: 0;
}
diff --git a/src/app/pages/flex-page/flex-page.scss b/src/app/pages/flex-page/flex-page.scss
new file mode 100644
index 000000000..936bf92dd
--- /dev/null
+++ b/src/app/pages/flex-page/flex-page.scss
@@ -0,0 +1,4 @@
+
+.page.flex-page {
+ overflow: visible;
+}
diff --git a/src/app/pages/flex-page/flex-page.tsx b/src/app/pages/flex-page/flex-page.tsx
index 765809fba..737cb5579 100644
--- a/src/app/pages/flex-page/flex-page.tsx
+++ b/src/app/pages/flex-page/flex-page.tsx
@@ -1,6 +1,7 @@
import React from 'react';
import { LoadedPage } from '~/components/jsx-helpers/loader-page';
import { ContentBlocks, ContentBlockConfig } from './blocks/ContentBlock';
+import './flex-page.scss';
type Data = {
body: ContentBlockConfig[];
diff --git a/test/src/pages/flex-page.test.tsx b/test/src/pages/flex-page.test.tsx
index 131ac72c3..e838c2973 100644
--- a/test/src/pages/flex-page.test.tsx
+++ b/test/src/pages/flex-page.test.tsx
@@ -1,4 +1,5 @@
import React from 'react';
+import ShellContextProvider from '~/../../test/helpers/shell-context';
import {render, screen} from '@testing-library/preact';
import {describe, it} from '@jest/globals';
import userEvent from '@testing-library/user-event';
@@ -38,9 +39,11 @@ let body: Data['body'];
function Component() {
return (
-
-
-
+
+
+
+
+
);
}
@@ -156,6 +159,11 @@ describe('flex-page', () => {
expect(screen.getAllByText('Some text with')).toHaveLength(1);
expect(screen.getAllByText('formatting')).toHaveLength(1);
});
+ it('renders bookListBlock', () => {
+ body = [bookListBlock()];
+ render();
+ expect(screen.getAllByText('book title')).toHaveLength(1);
+ });
});
function imageBlock(name: string) {
@@ -338,3 +346,26 @@ function sectionBlock(): ContentBlockConfig {
}
};
}
+
+function bookListBlock(): ContentBlockConfig {
+ return {
+ id: 'book-list-id',
+ type: 'book_list',
+ value: {
+ books: [
+ {
+ id: 1,
+ slug: 'book-slug',
+ title: 'book title',
+ webviewRexLink: 'webview-rex-link',
+ webviewLink: 'webview-link',
+ highResolutionPdfUrl: 'high-res-url',
+ lowResolutionPdfUrl: 'low-res-url',
+ coverUrl: 'cover-url',
+ bookState: 'book-state',
+ promoteSnippet: [],
+ }
+ ]
+ }
+ };
+}