Skip to content

Commit

Permalink
feat: support brightcove element (#445)
Browse files Browse the repository at this point in the history
  • Loading branch information
ReenaSingh07 authored Jun 28, 2023
1 parent 99d226e commit 17cebc2
Show file tree
Hide file tree
Showing 15 changed files with 229 additions and 12 deletions.
1 change: 1 addition & 0 deletions docs-src/tutorials/opts.md
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,7 @@ Here too, `story` and `config` is same as what's mentioned <a href="#storyConfig
| ↳ | summaryElementRender | obj - {story, config, element} | - _same_ - |
| ↳ | textElementRender | obj - {story, config, element} | - _same_ - |
| ↳ | youtubeElementRender | obj - {story, config, element} | - _same_ - |
| ↳ | brightcoveElementRender | obj - {story, config, element} | - _same_ - |
| ↳ | vidibleElementRender | obj - {story, config, element} | - _same_ - |
| ↳ | twitterElementRender | obj - {story, config, element} | - _same_ - |
| ↳ | titleElementRender | obj - {story, config, element} | - _same_ - |
Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@quintype/amp",
"version": "2.15.2",
"version": "2.15.3-brightcove.3",
"description": "Quintype's AMP component library for publisher apps to create amp layouts",
"main": "dist/index.js",
"types": "dist/index.d.ts",
Expand Down
1 change: 1 addition & 0 deletions src/atoms/common-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ declare global {
"amp-video";
"amp-story-auto-ads";
"amp-story-page-outlink";
"amp-brightcove";
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`Brightcove should render default 1`] = `
<Fragment>
<HelmetWrapper
defer={true}
encodeSpecialCharacters={true}
>
<script
async={true}
custom-element="amp-brightcove"
src="https://cdn.ampproject.org/v0/amp-brightcove-0.1.js"
/>
</HelmetWrapper>
<amp-brightcove
data-account="1752604059001"
data-embed="default"
data-player="H1xW7NWcz"
data-video-id="6156696074001"
height="270"
layout="responsive"
width="480"
/>
</Fragment>
`;
41 changes: 41 additions & 0 deletions src/atoms/story-elements/brightcove/brightcove.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import React from "react";
import { storiesOf } from "@storybook/react";
import { Brightcove } from "./brightcove";
import { config, textStory } from "../../../__fixtures__";
import { Layout } from "../../layout";

const sampleBrightcoveElement = {
description: "",
"page-url": "/story/b7b6ecab-2b4f-4dc1-b04a-0b0ec76a50c4/element/2cfc6b4e-85fb-47b0-ae4e-580a650372f7",
type: "external-file",
"family-id": "0148ec01-3c7c-49ee-8a3f-db8ca4907dc8",
title: "",
"file-type": "video",
id: "2cfc6b4e-85fb-47b0-ae4e-580a650372f7",
url: null,
"content-type": "video/brightcove",
metadata: {
"account-id": "1752604059001",
"player-id": "default",
"player-media": "default",
"video-id": "6156696074001",
"embed-code":
"aHR0cHM6Ly9wbGF5ZXJzLmJyaWdodGNvdmUubmV0LzI3NjY2MjQ5MDUwMDEvZGVmYXVsdF9kZWZhdWx0L2luZGV4Lmh0bWw/dmlkZW9JZD02MzIzMDIxNjcxMTEy",
"player-url": "//players.brightcove.net/2766624905001/default_default/index.html?videoId=6323021671112"
},
subtype: "brightcove-video"
};

const { metadata, ...sampleBrightcoveElementWithoutMetadata } = sampleBrightcoveElement;

storiesOf("Brightcove Element", module)
.addDecorator((story) => (
<Layout story={textStory} config={config}>
{story()}
</Layout>
))
.add("Default", () => <Brightcove element={sampleBrightcoveElement} />)
.add("With a square different layout", () => (
<Brightcove element={sampleBrightcoveElement} layout="fixed" width="400" height="400" />
))
.add("Brightcove without metadata", () => <Brightcove element={sampleBrightcoveElementWithoutMetadata} />);
47 changes: 47 additions & 0 deletions src/atoms/story-elements/brightcove/brightcove.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import React from "react";
import { DefaultBrightcove, BrightcoveBase } from "./brightcove";
import { shallow } from "enzyme";
import { textStory, config } from "../../../__fixtures__";

const sampleBrightcoveElement = {
description: "",
"page-url": "/story/b7b6ecab-2b4f-4dc1-b04a-0b0ec76a50c4/element/2cfc6b4e-85fb-47b0-ae4e-580a650372f7",
type: "external-file",
"family-id": "0148ec01-3c7c-49ee-8a3f-db8ca4907dc8",
title: "",
"file-type": "video",
id: "2cfc6b4e-85fb-47b0-ae4e-580a650372f7",
url: null,
"content-type": "video/brightcove",
metadata: {
"account-id": "1752604059001",
"player-id": "H1xW7NWcz",
"player-media": "default",
"video-id": "6156696074001",
"embed-code":
"aHR0cHM6Ly9wbGF5ZXJzLmJyaWdodGNvdmUubmV0LzI3NjY2MjQ5MDUwMDEvZGVmYXVsdF9kZWZhdWx0L2luZGV4Lmh0bWw/dmlkZW9JZD02MzIzMDIxNjcxMTEy",
"player-url": "//players.brightcove.net/2766624905001/default_default/index.html?videoId=6323021671112"
},
subtype: "brightcove-video"
};
const { metadata, ...sampleBrightcoveElementWithoutMeta } = sampleBrightcoveElement;

describe("Brightcove", () => {
it("should render default", () => {
const wrapper = shallow(<DefaultBrightcove element={sampleBrightcoveElement} />);
expect(wrapper).toMatchSnapshot();
});
it("should call brightcoveElementRender when passed", () => {
const brightcoveElementRender = jest.fn();
const modifiedConfig = { ...config, opts: { render: { storyElementRender: { brightcoveElementRender } } } };
const wrapper = shallow(
<BrightcoveBase element={sampleBrightcoveElement} story={textStory} config={modifiedConfig} />
);
expect(brightcoveElementRender.mock.calls.length).toBe(1);
expect(wrapper.find(DefaultBrightcove).length).toBe(0);
});
it("shouldn't render brightcove", () => {
const wrapper = shallow(<DefaultBrightcove element={sampleBrightcoveElementWithoutMeta} />);
expect(wrapper.find("amp-brightcove").length).toBe(0);
});
});
79 changes: 79 additions & 0 deletions src/atoms/story-elements/brightcove/brightcove.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import React, { Fragment } from "react";
import Helmet from "react-helmet";
import { withStoryAndConfig } from "../../../context";
import get from "lodash.get";
import { BrightcoveElementTypes, DefaultBrightcoveElementTypes } from "./types";

export const DefaultBrightcove = ({
element,
layout = "responsive",
width = "480",
height = "270"
}: DefaultBrightcoveElementTypes) => {
const { "account-id": accountId, "player-id": playerId = "default", "video-id": videoId } = get(
element,
["metadata"],
{}
);
if (!accountId || !videoId || playerId === "default") {
return null;
}

return (
<Fragment>
<Helmet>
<script async custom-element="amp-brightcove" src="https://cdn.ampproject.org/v0/amp-brightcove-0.1.js" />
</Helmet>
<amp-brightcove
data-account={accountId}
data-player={playerId}
data-embed="default"
data-video-id={videoId}
layout={layout}
width={width}
height={height}
/>
</Fragment>
);
};

export const BrightcoveBase = ({ element, story, config }: BrightcoveElementTypes) => {
const brightcoveElementRender = get(
config,
["opts", "render", "storyElementRender", "brightcoveElementRender"],
null
);

return brightcoveElementRender ? (
brightcoveElementRender({ story, config, element })
) : (
<DefaultBrightcove element={element} />
);
};

/**
* Brightcove is a story element.
* The look of the Brightcove can be changed using the render prop BrightcoveElementRender. In case BrightcoveElementRender is passed in the config, it is rendered. Otherwise a default Brightcove is rendered.
*
* @param {Object} params object containing parameters passed to the render prop
* @param {Object} params.story story object
* @param {Object} params.config config object
* @param {Object} params.element the story element. This is same as the story element found in the story API response
*
* ```javascript
* ...
* ampRoutes(app, {
* render: {
* storyElementRender: {
* brightcoveElementRender: ({ story, config, element }) => <MyCustomBrightcove story={story} config={config} storyElement={element} />
* }
* }
* })
* ...
* ```
*
* @category StoryElements
* @module Brightcove
* @component
*/
export const Brightcove = withStoryAndConfig(BrightcoveBase);
2 changes: 2 additions & 0 deletions src/atoms/story-elements/brightcove/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
import { Brightcove } from "./brightcove";
export { Brightcove };
13 changes: 13 additions & 0 deletions src/atoms/story-elements/brightcove/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { Common } from "../../../atoms/common-types";
import { Config } from "../../../types/config";
import { Story, StoryElement } from "../../../types/story";

export interface BrightcoveElementTypes {
story: Story;
config: Config;
element: StoryElement;
}

export interface DefaultBrightcoveElementTypes extends Common {
element: StoryElement;
}
4 changes: 2 additions & 2 deletions src/atoms/story-elements/embed/embed.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ export const getIframeContent = (str, regex) => {

export const DefaultEmbed = ({ element }: StoryElementProps) => {
const embedData = element["embed-js"] ? atob(element["embed-js"]) : "";
const src = getIframeContent(embedData, /(?<=src=").*?(?=[*"])/);
const scrolling = getIframeContent(embedData, /(?<=scrolling=").*?(?=[*"])/);
const src = getIframeContent(embedData, /(?<=src=["']).*?(?=[*"'])/);
const scrolling = getIframeContent(embedData, /(?<=scrolling=["']).*?(?=[*"'])/);
const title = element.subtype || element.title || "";
return src ? <Iframe src={src} scrolling={scrolling} title={title} /> : null;
};
Expand Down
7 changes: 5 additions & 2 deletions src/atoms/story-elements/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { TwitterElement } from "./twitter-element";
import { FacebookElement } from "./facebook-element";
import { InstagramElement } from "./instagram-element";
import { VidibleElement } from "./vidible-element";
import { Brightcove } from "./brightcove";
import { Title } from "./title";
import { ImageGalleryElement } from "./image-gallery-element";
import { Attachment } from "./attachment";
Expand Down Expand Up @@ -45,7 +46,8 @@ const StoryElements = {
ImageGalleryElement,
Attachment,
TableElement,
Unsupported
Unsupported,
Brightcove
};
export {
Text,
Expand All @@ -70,6 +72,7 @@ export {
ImageGalleryElement,
Attachment,
TableElement,
Unsupported
Unsupported,
Brightcove
};
export { StoryElements };
5 changes: 3 additions & 2 deletions src/helpers/match-story-element/match-story-element.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ import {
ImageGalleryElement,
Attachment,
TableElement,
Unsupported
Unsupported,
Brightcove
} from "../../atoms/story-elements";

const anyType = "any";
Expand All @@ -34,7 +35,7 @@ const storyElementsTable = [
["composite", "references", Unsupported],
["data", "table", TableElement],
["external-file", "bitgravity-video", Unsupported],
["external-file", "brightcove-video", Unsupported],
["external-file", "brightcove-video", Brightcove],
["external-file", "jwplayer", Unsupported],
["external-file", "vod-video", Unsupported],
["external-file", anyType, Unsupported],
Expand Down
1 change: 1 addition & 0 deletions src/types/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,7 @@ export interface ConfigOpts {
blurbRender?: (props: CommonRenderPropTypes) => any;
alsoReadRender?: (props: CommonRenderPropTypes) => any;
tableElementRender?: (props: CommonRenderPropTypes) => any;
brightcoveElementRender?: (props: CommonRenderPropTypes) => any;
};
};
featureConfig?: FeatureConfigTypes;
Expand Down
9 changes: 6 additions & 3 deletions src/types/story.ts
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ export interface StoryElement {
description?: string;
"embed-js"?: string;
"page-url"?: string;
url?: string;
url?: string | null;
"image-metadata"?: object | null;
"image-attribution"?: string;
"image-s3-key"?: string;
Expand All @@ -151,8 +151,8 @@ export interface StoryElement {
text?: string;
"story-elements"?: StoryElement[];
data?: StoryElementData | null;
"file-type"?: string;
}

interface StoryElementData {
content: string;
"content-type": string;
Expand Down Expand Up @@ -186,8 +186,11 @@ export interface StoryElementMetadata {
"cta-url"?: string;
"open-in-new-tab"?: boolean;
"no-follow"?: boolean;
"account-id"?: string;
"player-id"?: string;
"player-media"?: string;
"embed-code"?: string;
}

export interface LinkedStory {
headline: string;
"story-content-id": string;
Expand Down

0 comments on commit 17cebc2

Please sign in to comment.