@financial-times/n-myft-ui 25.0.0 → 25.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,77 @@
1
+ <section
2
+ class="collection {{#if liteStyle}}collection--lite{{else}}collection--regular{{/if}}"
3
+ data-trackable="{{#if trackable}}{{trackable}}{{else}}collection{{/if}}">
4
+ <header class="collection__header {{#if liteStyle}}collection__header--lite{{else}}collection__header--regular{{/if}}">
5
+ <h2 class="collection__title {{#if liteStyle}}collection__title--lite{{else}}collection__title--regular{{/if}}">
6
+ {{title}}
7
+ </h2>
8
+ </header>
9
+ <ul class="collection__concepts">
10
+ {{#concepts}}
11
+ <li class="collection__concept">
12
+ {{#if ../liteStyle}}
13
+ {{{renderReactComponent localPath="components/follow-button/follow-button" variant="primary" buttonText=name flags=@root.flags collectionName=../collectionName}}}
14
+ {{else}}
15
+ {{{renderReactComponent localPath="components/follow-button/follow-button" variant="inverse" buttonText=name flags=@root.flags collectionName=../collectionName}}}
16
+ {{/if}}
17
+ </li>
18
+ {{/concepts}}
19
+ </ul>
20
+ <div class="collection__meta">
21
+ <form
22
+ method="POST"
23
+ action="#"
24
+ data-myft-ui="follow"
25
+ {{#if collectionName}}data-myft-tracking="collectionName={{collectionName}}"{{/if}}
26
+ data-concept-id="
27
+ {{~#concepts~}}
28
+ {{conceptId}}
29
+ {{~#unless @last~}}
30
+ ,
31
+ {{~/unless~}}
32
+ {{~/concepts~}}"
33
+ class="n-myft-ui n-myft-ui--follow n-ui-hide-core collection-follow-all">
34
+ <input
35
+ type="hidden"
36
+ name="directType"
37
+ value="
38
+ {{~#concepts~}}
39
+ {{directType}}
40
+ {{~#unless @last~}}
41
+ ,
42
+ {{~/unless~}}
43
+ {{~/concepts~}}"
44
+ />
45
+ {{{renderReactComponent localPath="components/csrf-token/input"}}}
46
+ <input
47
+ type="hidden"
48
+ name="name"
49
+ value="
50
+ {{~#concepts~}}
51
+ {{name}}
52
+ {{~#unless @last~}}
53
+ ,
54
+ {{~/unless~}}
55
+ {{~/concepts~}}"
56
+ />
57
+ <button
58
+ type="submit"
59
+ aria-pressed="false"
60
+ class="collection-follow-all__button {{#if liteStyle}}collection-follow-all__button--lite{{else}}collection-follow-all__button--regular{{/if}}"
61
+ data-trackable="follow all"
62
+ data-concept-id="
63
+ {{~#concepts~}}
64
+ {{conceptId}}
65
+ {{~#unless @last~}}
66
+ ,
67
+ {{~/unless~}}
68
+ {{~/concepts~}}"
69
+ aria-label="Add all topics in the {{title}} collection to my F T"
70
+ data-alternate-label="Remove all topics in the {{title}} collection from my F T"
71
+ data-alternate-text="Added"
72
+ title="Add all topics in the {{title}} collection to my F T">
73
+ Add all to myFT
74
+ </button>
75
+ </form>
76
+ </div>
77
+ </section>
@@ -0,0 +1,28 @@
1
+ {{#ifAll @root.flags.myFtApi @root.flags.myFtApiWrite concepts concepts.length}}
2
+ <div
3
+ class="concept-list"
4
+ data-trackable="{{#if trackable}}{{trackable}}{{else}}concept-list{{/if}}">
5
+ {{#ifSome contentType conceptListTitle}}
6
+ <h2 class="concept-list__title">
7
+ {{#if conceptListTitle}}
8
+ {{conceptListTitle}}
9
+ {{else}}
10
+ Follow the topics in this {{contentType}}
11
+ {{/if}}
12
+ </h2>
13
+ {{/ifSome}}
14
+ <ul class="concept-list__list">
15
+ {{#each concepts}}
16
+ <li class="concept-list__list-item">
17
+ <a
18
+ href="{{relativeUrl}}"
19
+ data-trackable="{{#if conceptTrackable}}{{conceptTrackable}}{{else}}concept{{/if}}"
20
+ class="concept-list__concept">
21
+ {{prefLabel}}
22
+ </a>
23
+ {{{renderReactComponent localPath="components/follow-button/follow-button" conceptId=id name=prefLabel flags=@root.flags}}}
24
+ </li>
25
+ {{/each}}
26
+ </ul>
27
+ </div>
28
+ {{/ifAll}}
@@ -16,7 +16,7 @@ describe('Follow button', () => {
16
16
 
17
17
  test('It renders default button', async () => {
18
18
  render(<FollowButton {...props} />);
19
- expect(await screen.findByText('Add to myFT')).toBeTruthy();
19
+ expect(screen.findByText('Add to myFT')).toBeTruthy();
20
20
  });
21
21
 
22
22
  test('It renders a variant', async () => {
@@ -29,12 +29,12 @@ describe('Follow button', () => {
29
29
  expect(container.querySelector(`form[action='/myft/add/${props.conceptId}']`)).toBeTruthy();
30
30
  });
31
31
 
32
- test('Button state changes when attributes change', async () => {
32
+ test('Button state changes when attributes change', () => {
33
33
  render(<FollowButton {...props}
34
34
  variant={'standard'}
35
35
  setFollowButtonStateToSelected={true}
36
36
  cacheablePersonalisedUrl={true} />);
37
- expect(await screen.findByText('Added')).toBeTruthy();
37
+ expect(screen.findByText('Added')).toBeTruthy();
38
38
  });
39
39
 
40
40
  });
@@ -1,4 +1,4 @@
1
- import React, {Fragment} from 'react';
1
+ import React from 'react';
2
2
  import CsrfToken from '../csrf-token/input';
3
3
 
4
4
  function generateFormProps (props) {
@@ -148,7 +148,7 @@ export default function FollowButton (props) {
148
148
  const getVariantClass = (variant) => variant ? `n-myft-follow-button--${variant}` : '';
149
149
 
150
150
  return (
151
- <Fragment>
151
+ <>
152
152
  {flags.myFtApiWrite && <form
153
153
  className={`n-myft-ui n-myft-ui--follow ${extraClasses || ''}`}
154
154
  method="GET"
@@ -168,7 +168,7 @@ export default function FollowButton (props) {
168
168
  {getButtonText(props)}
169
169
  </button>
170
170
  </form>}
171
- </Fragment>
171
+ </>
172
172
  );
173
173
 
174
174
  }
@@ -0,0 +1,20 @@
1
+ {{#if showPrioritiseButton}}
2
+ <span class="myft-pin-divider"></span>
3
+ <div class="myft-pin-button-wrapper">
4
+ <form method="post" action="/__myft/api/core/prioritised/concept/{{id}}?method={{#if prioritised}}delete{{else}}put{{/if}}" data-myft-prioritise>
5
+ {{{renderReactComponent localPath="components/csrf-token/input"}}}
6
+ <input type="hidden" value="{{name}}" name="name"> {{#if directType}}
7
+ <input type="hidden" value="{{directType}}" name="directType"> {{else}}
8
+ <input type="hidden" value="http://www.ft.com/ontology/concept/Concept" name="directType"> {{/if}}
9
+ <div
10
+ class="n-myft-ui__announcement o-normalise-visually-hidden"
11
+ aria-live="assertive"
12
+ data-pressed-text="{{name}} pinned in myFT."
13
+ data-unpressed-text="Unpinned {{name}} from myFT."
14
+ ></div>
15
+ <button id="myft-pin-button__{{id}}" class="myft-pin-button" data-prioritise-button data-trackable="prioritised" data-concept-id="{{id}}" data-prioritised="{{#if prioritised}}true{{else}}false{{/if}}"
16
+ aria-label="{{#if prioritised}}Unpin{{else}}Pin{{/if}} {{name}} {{#if prioritised}}from{{else}}in{{/if}} myFT" aria-pressed="{{#if prioritised}}true{{else}}false{{/if}}" title="{{#if prioritised}}Unpin{{else}}Pin{{/if}} {{name}}">
17
+ </button>
18
+ </form>
19
+ </div>
20
+ {{/if}}
@@ -0,0 +1,67 @@
1
+ {{#if @root.flags.myFtApiWrite}}
2
+ <form class="n-myft-ui n-myft-ui--save" method="GET"
3
+ data-content-id="{{contentId}}"
4
+ data-myft-ui="saved"
5
+ action="/myft/save/{{contentId}}"
6
+ data-js-action="/__myft/api/core/saved/content/{{contentId}}?method=put">
7
+ {{{renderReactComponent localPath="components/csrf-token/input"}}}
8
+ <div
9
+ class="n-myft-ui__announcement o-normalise-visually-hidden"
10
+ aria-live="assertive"
11
+ data-pressed-text="Article saved in My FT."
12
+ data-unpressed-text="Removed article from My FT."
13
+ ></div>
14
+ <button
15
+ type="submit"
16
+ class="{{#if saveButtonWithIcon}}n-myft-ui__save-button-with-icon{{else}}n-myft-ui__button{{#variant}} n-myft-ui__button--{{this}}{{/variant}}{{/if}}"
17
+ data-trackable="{{#if trackableId}}{{trackableId}}{{else}}save-for-later{{/if}}"
18
+ {{#if isSaved}}
19
+ {{!-- The value of alternate label needs to be the opposite of label / the current saved state. This allows the client side JS to toggle the labels on state changes --}}
20
+ title="{{#if title}}{{title}} is{{/if}} Saved to myFT"
21
+ aria-label="{{#if title}}{{title}} is{{/if}} Saved to myFT"
22
+ data-alternate-label="{{#if title}}Save {{title}} to myFT for later{{else}}Save this article to myFT for later{{/if}}"
23
+ aria-pressed="true"
24
+ {{else}}
25
+ title="{{#if title}}Save {{title}} to myFT for later{{else}}Save this article to myFT for later{{/if}}"
26
+ aria-label="{{#if title}}Save {{title}} to myFT for later{{else}}Save this article to myFT for later{{/if}}"
27
+ data-alternate-label="{{#if title}}{{title}} is{{/if}} Saved to myFT"
28
+ aria-pressed="false"
29
+ {{/if}}
30
+ {{#unlessEquals appIsStreamPage true}}
31
+ {{#if saveButtonWithIcon}}
32
+ data-text-variant="save-button-with-icon-copy"
33
+ {{else}}
34
+ data-text-variant="save-button-longer-copy"
35
+ {{/if}}
36
+ {{/unlessEquals}}
37
+ {{#if alternateText}}
38
+ data-alternate-text="{{alternateText}}"
39
+ {{else}}
40
+ {{#if isSaved}}
41
+ data-alternate-text="Save&nbsp;"
42
+ {{else}}
43
+ data-alternate-text="Saved&nbsp;"
44
+ {{/if}}
45
+ {{/if}}
46
+ data-content-id="{{contentId}}" {{! duplicated here for tracking}}
47
+ >
48
+ {{#if saveButtonWithIcon}}
49
+ <span class="save-button-with-icon-copy" data-variant-label>{{#if buttonText~}}
50
+ {{buttonText}}
51
+ {{~else~}}
52
+ {{#if isSaved}}Saved{{else}}Save{{/if}}
53
+ {{~/if}}</span>
54
+ {{else}}
55
+ {{#if buttonText}}{{buttonText}}{{else}}
56
+ {{#unlessEquals appIsStreamPage true}}
57
+ <span class="save-button-longer-copy" data-variant-label>{{#if isSaved}}Saved&nbsp;{{else}}Save&nbsp;{{/if}}</span><span class="n-myft-ui__button--viewport-large" aria-hidden="true">to myFT</span>
58
+ {{else}}
59
+ <span>{{#if isSaved}}Saved{{else}}Save{{/if}}</span>
60
+ {{/unlessEquals}}
61
+ {{/if}}
62
+ {{/if}}
63
+ </button>
64
+ </form>
65
+ {{else}}
66
+ <!-- Save button hidden due to myFtApiWrite being off -->
67
+ {{/if }}
package/demos/app.js CHANGED
@@ -41,7 +41,9 @@ app.set('view engine', '.html');
41
41
  app.engine('.html', new PageKitHandlebars({
42
42
  cache: false,
43
43
  handlebars,
44
- helpers
44
+ helpers: {
45
+ ...helpers
46
+ }
45
47
  }).engine);
46
48
 
47
49
  app.use('/public', nExpress.static(path.join(__dirname, '../public'), { redirect: false }));
@@ -54,7 +56,7 @@ app.get('/', (req, res) => {
54
56
  flags: {
55
57
  myFtApi: true,
56
58
  myFtApiWrite: true
57
- },
59
+ }
58
60
  }, fixtures));
59
61
  });
60
62
 
@@ -48,35 +48,35 @@
48
48
  <h2 class="demo-section__title">
49
49
  Save button
50
50
  </h2>
51
- {{{renderReactComponent localPath="components/save-for-later/save-for-later" flags=@root.flags title=title contentId=contentId }}}
51
+ {{> n-myft-ui/components/save-for-later/save-for-later }}
52
52
  {{/saveButton}}
53
53
 
54
54
  {{#saveButton}}
55
55
  <h2 class="demo-section__title">
56
56
  Unsave button
57
57
  </h2>
58
- {{{renderReactComponent localPath="components/save-for-later/save-for-later" flags=@root.flags title=title contentId=contentId isSaved=true }}}
58
+ {{> n-myft-ui/components/save-for-later/save-for-later isSaved=true }}
59
59
  {{/saveButton}}
60
60
 
61
61
  {{#saveButton}}
62
62
  <h2 class="demo-section__title">
63
63
  Save button with icon
64
64
  </h2>
65
- {{{renderReactComponent localPath="components/save-for-later/save-for-later" flags=@root.flags title=title contentId=contentId saveButtonWithIcon=true }}}
65
+ {{> n-myft-ui/components/save-for-later/save-for-later saveButtonWithIcon=true }}
66
66
  {{/saveButton}}
67
67
 
68
68
  {{#saveButton}}
69
69
  <h2 class="demo-section__title">
70
70
  Unsave button with icon
71
71
  </h2>
72
- {{{renderReactComponent localPath="components/save-for-later/save-for-later" flags=@root.flags title=title contentId=contentId saveButtonWithIcon=true isSaved=true }}}
72
+ {{> n-myft-ui/components/save-for-later/save-for-later isSaved=true saveButtonWithIcon=true }}
73
73
  {{/saveButton}}
74
74
 
75
75
  <h2 class="demo-section__title">
76
76
  Pin button
77
77
  </h2>
78
78
  {{#each pinButton}}
79
- {{{renderReactComponent localPath="components/pin-button/pin-button" flags=@root.flags title=title id=id name=name directType=directType showPrioritiseButton=showPrioritiseButton }}}
79
+ {{> n-myft-ui/components/pin-button/pin-button }}
80
80
  {{/each}}
81
81
 
82
82
  {{#instantAlert}}
@@ -449,7 +449,7 @@
449
449
 
450
450
  {{#collections}}
451
451
  <div data-o-grid-colspan="3">
452
- {{{renderReactComponent localPath="components/collections/collections" flags=@root.flags concepts=this.concepts title=this.title liteStyle=this.liteStyle collectionName=this.collectionName trackable=this.trackable}}}
452
+ {{> n-myft-ui/components/collections/collections }}
453
453
  </div>
454
454
  {{/collections}}
455
455
  </div>
@@ -471,7 +471,7 @@
471
471
 
472
472
  {{#each conceptList}}
473
473
  <div data-o-grid-colspan="3">
474
- {{{renderReactComponent localPath="components/concept-list/concept-list" flags=@root.flags concepts=this.concepts contentType=this.contentType conceptListTitle=this.conceptListTitle trackable=this.trackable}}}
474
+ {{> n-myft-ui/components/concept-list/concept-list }}
475
475
  </div>
476
476
  {{/each}}
477
477
  </div>
@@ -1,9 +1,5 @@
1
1
  import React from 'react';
2
2
  import FollowButton from '../../components/follow-button/follow-button';
3
- import ConceptList from '../../components/concept-list/concept-list';
4
- import Collections from '../../components/collections/collections';
5
- import { SaveForLater } from '../../components';
6
- import { PinButton } from '../../components';
7
3
 
8
4
  export default function Demo (props) {
9
5
 
@@ -11,13 +7,9 @@ export default function Demo (props) {
11
7
  title,
12
8
  flags,
13
9
  followButton,
14
- conceptList,
15
- collections,
16
- saveButton,
17
- pinButton
18
10
  } = props;
19
11
 
20
- const followButtonProps = { ...followButton, flags };
12
+ const followButtonProps = {...followButton, flags};
21
13
 
22
14
  return (
23
15
  <div className="o-grid-container o-grid-container--snappy demo-container">
@@ -33,93 +25,9 @@ export default function Demo (props) {
33
25
  Follow button
34
26
  </h2>
35
27
  <FollowButton {...followButtonProps} />
36
-
37
-
38
- <h2
39
- className="demo-section__title">
40
- x-dash follow button
41
- </h2>
42
-
43
- <FollowButton {...followButtonProps} buttonText={followButton.name} />
44
-
45
-
46
- <h2 className="demo-section__title">
47
- Save button
48
- </h2>
49
- <SaveForLater flags={flags} {...saveButton} />
50
-
51
- <h2 className="demo-section__title">
52
- Unsave button
53
- </h2>
54
- <SaveForLater flags={flags} {...saveButton} isSaved={true} />
55
-
56
- <h2 className="demo-section__title">
57
- Unsave button with icon
58
- </h2>
59
- <SaveForLater flags={flags} {...saveButton} saveButtonWithIcon={true} />
60
-
61
- <h2 className="demo-section__title">
62
- Save button with icon
63
- </h2>
64
- <SaveForLater flags={flags} {...saveButton} isSaved={true} saveButtonWithIcon={true} />
65
-
66
- <h2 className="demo-section__title">
67
- Pin button
68
- </h2>
69
-
70
- {pinButton.map((item, index) => <PinButton key={index} {...item}/>)}
71
-
72
- </div>
73
- </div>
74
- </section>
75
-
76
- <section
77
- id="topic-list"
78
- className="demo-section">
79
- <div className="o-grid-row">
80
- <div data-o-grid-colspan="12">
81
- <h2 className="demo-section__title">
82
- Topic list
83
- </h2>
84
-
85
- <p className="demo-section__description">
86
- A list of topics to follow
87
- </p>
88
- </div>
89
-
90
- {
91
- conceptList && conceptList.map((list, index) =>
92
- <div key={index} data-o-grid-colspan="3">
93
- <ConceptList {...list} flags={flags} />
94
- </div>)
95
- }
96
-
97
- </div>
98
- </section>
99
-
100
- <section
101
- id="collections"
102
- className="demo-section">
103
- <div className="o-grid-row">
104
- <div data-o-grid-colspan="12">
105
- <h2 className="demo-section__title">
106
- Collections
107
- </h2>
108
-
109
- <p className="demo-section__description">
110
- Curated collections of topics to follow.
111
- </p>
112
28
  </div>
113
-
114
- {collections.map((collection, index) => (
115
- <div key={index} data-o-grid-colspan="3">
116
- <Collections {...collection} flags={flags} />
117
- </div>
118
- ))}
119
-
120
29
  </div>
121
30
  </section>
122
-
123
31
  </div>
124
32
  )
125
33
  }
package/package.json CHANGED
@@ -1,15 +1,13 @@
1
1
  {
2
2
  "name": "@financial-times/n-myft-ui",
3
- "version": "25.0.0",
3
+ "version": "25.0.1",
4
4
  "description": "Client side component for interaction with myft",
5
- "main": "dist/bundles/bundle.js",
6
- "module": "dist/bundles/bundle.js",
5
+ "main": "server.js",
7
6
  "scripts": {
8
7
  "test": "echo \"Error: no test specified\" && exit 1",
9
8
  "commit": "commit-wizard",
10
9
  "prepare": "npx snyk protect || npx snyk protect -d || true",
11
- "preinstall": "npm_config_yes=true npx check-engine",
12
- "build-package": "webpack"
10
+ "preinstall": "[ \"$INIT_CWD\" != \"$PWD\" ] || npm_config_yes=true npx check-engine"
13
11
  },
14
12
  "repository": {
15
13
  "type": "git",
@@ -46,8 +44,6 @@
46
44
  "babel-plugin-transform-runtime": "^6.9.0",
47
45
  "babel-preset-env": "^1.7.0",
48
46
  "babel-preset-es2015": "^6.6.0",
49
- "babel-preset-react": "^6.24.1",
50
- "babel-preset-stage-2": "^6.24.1",
51
47
  "babel-runtime": "^6.9.2",
52
48
  "bower": "^1.8.8",
53
49
  "bower-resolve-webpack-plugin": "^1.0.5",
@@ -1,68 +0,0 @@
1
- import React from 'react';
2
- import CsrfToken from '../csrf-token/input';
3
- import FollowButton from '../follow-button/follow-button';
4
-
5
- export default function Collections ({ title, liteStyle, flags, collectionName, trackable, concepts = [] }) {
6
- const getLiteStyleModifier = () => liteStyle ? 'lite' : 'regular';
7
- let formProps = {
8
- method: 'POST',
9
- action: '#',
10
- 'data-myft-ui': 'follow',
11
- 'data-concept-id': concepts.map(concept => concept.id).join(',')
12
- };
13
-
14
- if (collectionName) {
15
- formProps['data-myft-tracking'] = collectionName;
16
- }
17
-
18
- return (
19
- <section
20
- className={`collection collection--${getLiteStyleModifier()}`}
21
- data-trackable={trackable ? trackable : 'collection'}>
22
- <header className={`collection__header collection__header--${getLiteStyleModifier()}`}>
23
- <h2 className={`collection__title collection__title--${getLiteStyleModifier()}`}>
24
- {title}
25
- </h2>
26
- </header>
27
- <ul className="collection__concepts">
28
- {concepts && concepts.map((concept, index) =>
29
- <li className="collection__concept" key={index}>
30
- <FollowButton variant={liteStyle ? 'primary' : 'inverse'} buttonText={concept.name} flags={flags} collectionName={collectionName} />
31
- </li>)
32
- }
33
- </ul>
34
-
35
- <div className="collection__meta">
36
- <form
37
- {...formProps}
38
- className="n-myft-ui n-myft-ui--follow n-ui-hide-core collection-follow-all">
39
- <input
40
- type="hidden"
41
- name="directType"
42
- value={concepts.map(concept => concept.directType).join(',')}
43
- />
44
- <CsrfToken />
45
- <input
46
- type="hidden"
47
- name="name"
48
- value={concepts.map(concept => concept.name).join(',')}
49
- />
50
- <button
51
- type="submit"
52
- aria-pressed="false"
53
- className={`collection-follow-all__button collection-follow-all__button--${getLiteStyleModifier()}`}
54
- data-trackable="follow all"
55
- data-concept-id={concepts.map(concept => concept.id).join(',')}
56
- aria-label={`Add all topics in the ${title} collection to my F T`}
57
- data-alternate-label={`Remove all topics in the ${title} collection from my F T`}
58
- data-alternate-text="Added"
59
- title={`Add all topics in the ${title} collection to my F T`}>
60
- Add all to myFT
61
- </button>
62
- </form>
63
- </div>
64
- </section>
65
-
66
- )
67
-
68
- }
@@ -1,83 +0,0 @@
1
- import React from 'react';
2
- import Collections from './collections';
3
- import { render, screen } from '@testing-library/react';
4
- import '@testing-library/jest-dom';
5
-
6
- const fixtures = {
7
- 'title': 'European Union',
8
- 'concepts': [
9
- {
10
- 'id': '00000000-0000-0000-0000-000000000000',
11
- 'prefLabel': 'EU immigration',
12
- 'directType': 'http://www.ft.com/ontology/Topic',
13
- 'url': 'https://www.ft.com/stream/00000000-0000-0000-0000-000000000000',
14
- 'name': 'EU immigration'
15
- },
16
- {
17
- 'id': '00000000-0000-0000-0000-000000000001',
18
- 'prefLabel': 'Europe Quantitative Easing',
19
- 'directType': 'http://www.ft.com/ontology/Topic',
20
- 'url': 'https://www.ft.com/stream/00000000-0000-0000-0000-000000000000',
21
- 'name': 'Europe Quantitative Easing'
22
- },
23
- {
24
- 'id': '00000000-0000-0000-0000-000000000002',
25
- 'prefLabel': 'EU financial regulation',
26
- 'directType': 'http://www.ft.com/ontology/Topic',
27
- 'url': 'https://www.ft.com/stream/00000000-0000-0000-0000-000000000000',
28
- 'name': 'EU financial regulation'
29
- },
30
- {
31
- 'id': '00000000-0000-0000-0000-000000000003',
32
- 'prefLabel': 'EU nothing',
33
- 'directType': 'http://www.ft.com/ontology/Topic',
34
- 'url': 'https://www.ft.com/stream/00000000-0000-0000-0000-000000000000',
35
- 'name': 'EU nothing'
36
- },
37
- {
38
- 'id': '00000000-0000-0000-0000-000000000004',
39
- 'prefLabel': 'EU trade',
40
- 'directType': 'http://www.ft.com/ontology/Topic',
41
- 'url': 'https://www.ft.com/stream/00000000-0000-0000-0000-000000000000',
42
- 'name': 'EU trade'
43
- }
44
- ]
45
- };
46
- const joinedDirectTypes = 'http://www.ft.com/ontology/Topic,http://www.ft.com/ontology/Topic,http://www.ft.com/ontology/Topic,http://www.ft.com/ontology/Topic,http://www.ft.com/ontology/Topic';
47
-
48
- const flags = {
49
- myFtApi: true,
50
- myFtApiWrite: true
51
- };
52
-
53
- describe('Concept List', () => {
54
-
55
- test('It renders the title of the collection', async () => {
56
- render(<Collections {...fixtures} flags={flags} />);
57
- expect(await screen.findByText('European Union')).toBeTruthy();
58
- });
59
-
60
- test('It renders label for the concept button', async () => {
61
- render(<Collections {...fixtures} flags={flags} />);
62
- expect(await screen.findByText('EU immigration')).toBeTruthy();
63
- expect(await screen.findByText('Europe Quantitative Easing')).toBeTruthy();
64
- expect(await screen.findByText('EU financial regulation')).toBeTruthy();
65
- expect(await screen.findByText('EU nothing')).toBeTruthy();
66
- expect(await screen.findByText('EU trade')).toBeTruthy();
67
- });
68
-
69
- test('It renders form "Add all to my FT" from', () => {
70
- const { container} = render(<Collections {...fixtures} flags={flags} />);
71
- const formElement = container.querySelector('form[action="#"]');
72
- expect(formElement).toBeTruthy();
73
- expect(formElement.method).toEqual('post');
74
- });
75
-
76
- test('It renders directType input with value of types joined', () => {
77
- const { container} = render(<Collections {...fixtures} flags={flags} />);
78
- const directTypeElement = container.querySelector('input[name="directType"]');
79
- expect(directTypeElement).toBeTruthy();
80
- expect(directTypeElement.value).toEqual(joinedDirectTypes);
81
- });
82
-
83
- });
@@ -1,55 +0,0 @@
1
- import React, { Fragment } from 'react';
2
- import FollowButton from '../follow-button/follow-button';
3
-
4
- export default function ConceptList ({ flags, concepts, contentType, conceptListTitle, trackable }) {
5
-
6
- const {
7
- myFtApi,
8
- myFtApiWrite
9
- } = flags;
10
-
11
- const generateTrackableProps = (primary, seconday) => {
12
- return {
13
- 'data-trackable': primary ? primary : seconday
14
- }
15
- }
16
-
17
-
18
- return (
19
-
20
- <Fragment>
21
- {(myFtApi && myFtApiWrite && concepts && concepts.length) &&
22
- <div
23
- className='concept-list'
24
- {...generateTrackableProps(trackable, 'concept-list')}>
25
- {
26
- (contentType || conceptListTitle) &&
27
- <h2 className='concept-list__title'>
28
- {conceptListTitle ? conceptListTitle : `Follow the topics in this ${contentType}`}
29
- </h2>
30
- }
31
- <ul className='concept-list__list'>
32
- {concepts.map((concept, index) => {
33
- const {
34
- relativeUrl,
35
- url,
36
- conceptTrackable,
37
- prefLabel,
38
- id
39
- } = concept;
40
- return (
41
- <li key={index} className='concept-list__list-item'>
42
- <a
43
- href={relativeUrl || url}
44
- {...generateTrackableProps(conceptTrackable, 'concept')}
45
- className='concept-list__concept'>
46
- {prefLabel}
47
- </a>
48
- <FollowButton conceptId={id} name={prefLabel} flags={flags} />
49
- </li>
50
- )
51
- })}
52
- </ul>
53
- </div>}
54
- </Fragment>)
55
- }