@financial-times/n-myft-ui 25.0.0-beta.1 → 25.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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-beta.1",
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
- }