Skip to content

Commit

Permalink
Merge pull request #76 from NDLANO/NDLANO/Issue#474-Lydvelger-som-ege…
Browse files Browse the repository at this point in the history
…n-pakke

Ndlano/issue#474 lydvelger som egen pakke
  • Loading branch information
oyvinmar authored Aug 7, 2017
2 parents 39bdc84 + a7f5b15 commit 84fd204
Show file tree
Hide file tree
Showing 15 changed files with 809 additions and 12 deletions.
61 changes: 61 additions & 0 deletions packages/ndla-audio-search/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# ndla-audio-search

A simple library for selecting NDLA audio files.

## Installation

```sh
$ npm install ndla-audio-search
```

## Usage

### Get audio with the audio selector

To use the `AudioSearch` component, some functions for handling search and fetching audios are needed. In addition, some translations are needed.
```js
import AudioSearch from 'ndla-audio-search';

const searchAudios = queryObject => {
// Return new Promise of audio objects
};

const fetchAudio = id => {
// Return new Promise of a single audio object
};

const onError = err => {
// Handle error
};

const audioSelect = audio => {
// Handle audio selection
};

const translations = {
searchPlaceholder: /* Translated string */,
searchButtonTitle: /* Translated string */,
useAudio: /* Translated string */,
noResults: /* Translated string */,
};


<AudioSearch
translations={translations}
fetchAudio={fetchAudio}
searchAudios={searchAudios}
onAudioSelect={audioSelect}
onError={onError}
queryObject={defaultQueryObject}
/>
```

A `queryObject` must look like this:
```js
{
query: /* Query string */,
page: /* Page number */,
pageSize: /* Page size (elements per page) */,
locale: /* The search language; usually provided by the front-end */,
}
```
47 changes: 47 additions & 0 deletions packages/ndla-audio-search/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
{
"name": "ndla-audio-search",
"version": "0.1.1-0",
"description": "A simple library for searching for audio files from NDLA",
"license": "GPL-3.0",
"main": "lib/index.js",
"module": "es/index.js",
"jsnext:main": "es/index.js",
"scripts": {
"build": "npm run build:commonjs && npm run build:es",
"build:commonjs": "$(cd ..; npm bin)/cross-env BABEL_ENV=commonjs $(cd ..; npm bin)/babel src --out-dir lib --ignore __tests__",
"build:es": "$(cd ..; npm bin)/cross-env BABEL_ENV=es $(cd ..; npm bin)/babel src --out-dir es --ignore __tests__",
"clean": "$(cd ..; npm bin)/rimraf lib es",
"test": "$(cd ..; npm bin)/jest",
"prepublish": "npm run clean && npm run build"
},
"repository": {
"type": "git",
"url": "https://github.com/NDLANO/frontend-packages.git/ndla-ui/"
},
"keywords": [
"ndla"
],
"author": "[email protected]",
"files": [
],
"devDependencies": {
"ndla-article-scripts": "^0.0.3",
"ndla-licenses": "^0.0.7",
"ndla-ui": "^0.7.4",
"ndla-util": "^0.1.3",
"react-bem-helper": "^1.2.0"
},
"peerDependencies": {
"classnames": "^2.2.5",
"ndla-article-scripts": "^0.0.3",
"ndla-licenses": "^0.0.7",
"ndla-ui": "^0.7.4",
"ndla-util": "^0.1.3",
"react": "^15.0.0",
"react-bem-helper": "^1.2.0",
"react-dom": "^15.0.0"
},
"dependencies": {
"defined": "1.0.0"
}
}
67 changes: 67 additions & 0 deletions packages/ndla-audio-search/src/AudioBar.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/**
* Copyright (c) 2017-present, NDLA.
*
* This source code is licensed under the GPLv3 license found in the
* LICENSE file in the root directory of this source tree.
*
*/

/* eslint jsx-a11y/media-has-caption: 0 */

import React, { Component } from 'react';
import PropTypes from 'prop-types';
import BEMHelper from 'react-bem-helper';

const classes = new BEMHelper({
name: 'audio-bar',
prefix: 'c-',
});

class AudioBar extends Component {
constructor(props) {
super(props);
this.state = {
audioSource: undefined,
audioType: undefined,
};

this.loadAudio = this.loadAudio.bind(this);
}

loadAudio() {
this.props
.fetchAudio(this.props.audio.id)
.then(result => {
this.setState({
audioSource: result.audioFile.url,
audioType: result.audioFile.mimeType,
});
})
.catch(err => {
this.props.onError(err);
});
}

render() {
const { audioSource, audioType } = this.state;
return (
<div {...classes()}>
<audio controls autoPlay onPlay={!audioSource && this.loadAudio}>
{audioSource
? <source src={audioSource} type={audioType} />
: undefined}
</audio>
</div>
);
}
}

AudioBar.propTypes = {
audio: PropTypes.shape({
id: PropTypes.number.isRequired,
}),
fetchAudio: PropTypes.func.isRequired,
onError: PropTypes.func.isRequired,
};

export default AudioBar;
126 changes: 126 additions & 0 deletions packages/ndla-audio-search/src/AudioSearch.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
/**
* Copyright (c) 2017-present, NDLA.
*
* This source code is licensed under the GPLv3 license found in the
* LICENSE file in the root directory of this source tree.
*
*/

import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { Pager } from 'ndla-ui';
import BEMHelper from 'react-bem-helper';

import AudioSearchForm from './AudioSearchForm';
import AudioSearchList from './AudioSearchList';

const classes = new BEMHelper({
name: 'audio-search',
prefix: 'c-',
});

class AudioSearch extends Component {
constructor(props) {
super(props);
this.state = {
queryObject: props.queryObject,
audios: [],
lastPage: 0,
totalCount: 0,
searching: false,
};

this.submitAudioSearchQuery = this.submitAudioSearchQuery.bind(this);
this.searchAudios = this.searchAudios.bind(this);
}

componentDidMount() {
this.searchAudios(this.state.queryObject);
}

submitAudioSearchQuery(queryObject) {
this.searchAudios({
query: queryObject.query,
page: 1,
pageSize: queryObject.pageSize,
locale: queryObject.locale,
});
}

searchAudios(queryObject) {
this.setState({ searching: true });
this.props
.searchAudios(queryObject)
.then(result => {
this.setState({
queryObject: {
query: queryObject.query,
page: queryObject.page,
pageSize: result.pageSize,
locale: queryObject.locale,
},
audios: result.results,
totalCount: result.totalCount,
lastPage: Math.ceil(result.totalCount / result.pageSize),
searching: false,
});
})
.catch(err => {
this.props.onError(err);
this.setState({ searching: false });
});
}

render() {
const { fetchAudio, onError, translations } = this.props;
const { queryObject, audios, lastPage, searching } = this.state;
const { page, locale } = queryObject;

return (
<div {...classes()}>
<AudioSearchForm
onSearchQuerySubmit={this.submitAudioSearchQuery}
queryObject={queryObject}
searching={searching}
translations={translations}
/>
<AudioSearchList
audios={audios}
searching={searching}
locale={locale}
translations={translations}
onError={onError}
fetchAudio={fetchAudio}
/>
<Pager
page={page ? parseInt(page, 10) : 1}
pathname=""
lastPage={lastPage}
query={queryObject}
onClick={this.searchAudios}
pageItemComponentClass="button"
/>
</div>
);
}
}

AudioSearch.propTypes = {
queryObject: PropTypes.shape({
query: PropTypes.string,
page: PropTypes.number.isRequired,
pageSize: PropTypes.number.isRequired,
locale: PropTypes.string.isRequired,
}),
fetchAudio: PropTypes.func.isRequired,
searchAudios: PropTypes.func.isRequired,
onError: PropTypes.func.isRequired,
translations: PropTypes.shape({
searchPlaceholder: PropTypes.string.isRequired,
searchButtonTitle: PropTypes.string.isRequired,
useAudio: PropTypes.string.isRequired,
noResults: PropTypes.string.isRequired,
}),
};

export default AudioSearch;
91 changes: 91 additions & 0 deletions packages/ndla-audio-search/src/AudioSearchForm.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
/**
* Copyright (c) 2017-present, NDLA.
*
* This source code is licensed under the GPLv3 license found in the
* LICENSE file in the root directory of this source tree.
*
*/

import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { Button } from 'ndla-ui';
import BEMHelper from 'react-bem-helper';

const classes = new BEMHelper({
name: 'audio-search',
prefix: 'c-',
});

class AudioSearchForm extends Component {
constructor(props) {
super(props);
this.state = {
queryObject: props.queryObject,
};
this.onKeyPress = this.onKeyPress.bind(this);
this.handleQueryChange = this.handleQueryChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}

onKeyPress(evt) {
if (evt.key === 'Enter') {
this.handleSubmit(evt);
}
}

handleQueryChange(evt) {
this.setState({
queryObject: {
query: evt.target.value,
page: this.state.queryObject.page,
pageSize: this.state.queryObject.pageSize,
locale: this.state.queryObject.locale,
},
});
}

handleSubmit(evt) {
evt.preventDefault();
this.props.onSearchQuerySubmit(this.state.queryObject);
}

render() {
const { searching, translations } = this.props;

return (
<div {...classes('form')}>
<input
{...classes('form-query')}
type="text"
onChange={this.handleQueryChange}
onKeyPress={this.onKeyPress}
value={this.state.queryObject.query}
placeholder={translations.searchPlaceholder}
/>
<Button
{...classes('form-button')}
onClick={this.handleSubmit}
loading={searching}>
{translations.searchButtonTitle}
</Button>
</div>
);
}
}

AudioSearchForm.propTypes = {
queryObject: PropTypes.shape({
query: PropTypes.string,
page: PropTypes.number.isRequired,
pageSize: PropTypes.number.isRequired,
locale: PropTypes.string.isRequired,
}),
translations: PropTypes.shape({
searchPlaceholder: PropTypes.string.isRequired,
searchButtonTitle: PropTypes.string.isRequired,
}),
searching: PropTypes.bool.isRequired,
onSearchQuerySubmit: PropTypes.func.isRequired,
};

export default AudioSearchForm;
Loading

0 comments on commit 84fd204

Please sign in to comment.