diff --git a/.storybook/addons.js b/.storybook/addons.js index 23ec40c..aa9c8cd 100644 --- a/.storybook/addons.js +++ b/.storybook/addons.js @@ -1,5 +1,5 @@ -import '@storybook/addon-knobs/register'; import '@storybook/addon-viewport/register'; import '@storybook/addon-actions/register'; import '@storybook/addon-links/register'; import '@storybook/addon-a11y/register'; + diff --git a/.storybook/config.js b/.storybook/config.js index f4a9aaa..41f6ddc 100644 --- a/.storybook/config.js +++ b/.storybook/config.js @@ -2,8 +2,6 @@ import { configure, addDecorator, addParameters } from '@storybook/react'; import { withA11y } from '@storybook/addon-a11y'; -// automatically import all files ending in *.stories.js -// https://webpack.js.org/guides/dependency-management/ const components = require.context('../packages/components/', true, /.stories.js$/); // const demo = require.context('../demo/', true, /.stories.js$/); const styles = require.context('./styles', true, /\.scss$/); diff --git a/package-lock.json b/package-lock.json index 25b56af..14ba103 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1624,16 +1624,16 @@ } }, "@storybook/addon-knobs": { - "version": "5.1.9", - "resolved": "https://registry.npmjs.org/@storybook/addon-knobs/-/addon-knobs-5.1.9.tgz", - "integrity": "sha512-7/bICMYtR9CaTqfZX1kT2pBOTLZo3HxeslyQKWWsWlNElV33Ym2d0PPL5eS36eFxG/ZOp6lQWIFhunNnlmP5xg==", + "version": "5.1.11", + "resolved": "https://registry.npmjs.org/@storybook/addon-knobs/-/addon-knobs-5.1.11.tgz", + "integrity": "sha512-16GY8IPxVBcmq5TqPtP6254Qw5FvdefDZjIQd+ByJJliQjXZMQKxEl6JhRq98iUfSxEB+6JCPnpKPa666jmCMA==", "dev": true, "requires": { - "@storybook/addons": "5.1.9", - "@storybook/client-api": "5.1.9", - "@storybook/components": "5.1.9", - "@storybook/core-events": "5.1.9", - "@storybook/theming": "5.1.9", + "@storybook/addons": "5.1.11", + "@storybook/client-api": "5.1.11", + "@storybook/components": "5.1.11", + "@storybook/core-events": "5.1.11", + "@storybook/theming": "5.1.11", "copy-to-clipboard": "^3.0.8", "core-js": "^3.0.1", "escape-html": "^1.0.3", @@ -1645,6 +1645,159 @@ "react-color": "^2.17.0", "react-lifecycles-compat": "^3.0.4", "react-select": "^2.2.0" + }, + "dependencies": { + "@storybook/addons": { + "version": "5.1.11", + "resolved": "https://registry.npmjs.org/@storybook/addons/-/addons-5.1.11.tgz", + "integrity": "sha512-714Xg6pX4rjDY1urL94w4oOxIiK6jCFSp4oKvqLj7dli5CG7d34Yt9joyTgOb2pkbrgmbMWAZJq0L0iOjHzpzw==", + "dev": true, + "requires": { + "@storybook/api": "5.1.11", + "@storybook/channels": "5.1.11", + "@storybook/client-logger": "5.1.11", + "core-js": "^3.0.1", + "global": "^4.3.2", + "util-deprecate": "^1.0.2" + } + }, + "@storybook/api": { + "version": "5.1.11", + "resolved": "https://registry.npmjs.org/@storybook/api/-/api-5.1.11.tgz", + "integrity": "sha512-zzPZM6W67D4YKCbUN4RhC/w+/CtnH/hFbSh/QUBdwXFB1aLh2qA1UTyB8i6m6OA6JgVHBqEkl10KhmeILLv/eA==", + "dev": true, + "requires": { + "@storybook/channels": "5.1.11", + "@storybook/client-logger": "5.1.11", + "@storybook/core-events": "5.1.11", + "@storybook/router": "5.1.11", + "@storybook/theming": "5.1.11", + "core-js": "^3.0.1", + "fast-deep-equal": "^2.0.1", + "global": "^4.3.2", + "lodash": "^4.17.11", + "memoizerific": "^1.11.3", + "prop-types": "^15.6.2", + "react": "^16.8.3", + "semver": "^6.0.0", + "shallow-equal": "^1.1.0", + "store2": "^2.7.1", + "telejson": "^2.2.1", + "util-deprecate": "^1.0.2" + } + }, + "@storybook/channels": { + "version": "5.1.11", + "resolved": "https://registry.npmjs.org/@storybook/channels/-/channels-5.1.11.tgz", + "integrity": "sha512-MlrjVGNvYOnDvv2JDRhr4wikbnZ8HCFCpVsFqKPFxj7I3OYBR417RvFkydX3Rtx4kwB9rmZEgLhfAfsSytkALg==", + "dev": true, + "requires": { + "core-js": "^3.0.1" + } + }, + "@storybook/client-api": { + "version": "5.1.11", + "resolved": "https://registry.npmjs.org/@storybook/client-api/-/client-api-5.1.11.tgz", + "integrity": "sha512-znzSxZ1ZCqtEKrFoW7xT8iBbdiAXaQ8RNxQFKHuYPqWX+RLol6S3duEOxu491X2SzUg0StUmrX5qL9Rnth8dRQ==", + "dev": true, + "requires": { + "@storybook/addons": "5.1.11", + "@storybook/client-logger": "5.1.11", + "@storybook/core-events": "5.1.11", + "@storybook/router": "5.1.11", + "common-tags": "^1.8.0", + "core-js": "^3.0.1", + "eventemitter3": "^3.1.0", + "global": "^4.3.2", + "is-plain-object": "^3.0.0", + "lodash": "^4.17.11", + "memoizerific": "^1.11.3", + "qs": "^6.6.0" + } + }, + "@storybook/client-logger": { + "version": "5.1.11", + "resolved": "https://registry.npmjs.org/@storybook/client-logger/-/client-logger-5.1.11.tgz", + "integrity": "sha512-je4To+9zD3SEJsKe9R4u15N4bdXFBR7pdBToaRIur+XSvvShLFehZGseQi+4uPAj8vyG34quGTCeUC/BKY0LwQ==", + "dev": true, + "requires": { + "core-js": "^3.0.1" + } + }, + "@storybook/components": { + "version": "5.1.11", + "resolved": "https://registry.npmjs.org/@storybook/components/-/components-5.1.11.tgz", + "integrity": "sha512-EQgD7HL2CWnnY968KrwUSU2dtKFGTGRJVc4vwphYEeZwAI0lX6qbTMuwEP22hDZ2OSRBxcvcXT8cvduDlZlFng==", + "dev": true, + "requires": { + "@storybook/client-logger": "5.1.11", + "@storybook/theming": "5.1.11", + "core-js": "^3.0.1", + "global": "^4.3.2", + "markdown-to-jsx": "^6.9.1", + "memoizerific": "^1.11.3", + "polished": "^3.3.1", + "popper.js": "^1.14.7", + "prop-types": "^15.7.2", + "react": "^16.8.3", + "react-dom": "^16.8.3", + "react-focus-lock": "^1.18.3", + "react-helmet-async": "^1.0.2", + "react-popper-tooltip": "^2.8.3", + "react-syntax-highlighter": "^8.0.1", + "react-textarea-autosize": "^7.1.0", + "recompose": "^0.30.0", + "simplebar-react": "^1.0.0-alpha.6" + } + }, + "@storybook/core-events": { + "version": "5.1.11", + "resolved": "https://registry.npmjs.org/@storybook/core-events/-/core-events-5.1.11.tgz", + "integrity": "sha512-m+yIFRdB47+IPBFBGS2OUXrSLkoz5iAXvb3c0lGAePf5wSR+o/Ni/9VD5l6xBf+InxHLSc9gcDEJehrT0fJAaQ==", + "dev": true, + "requires": { + "core-js": "^3.0.1" + } + }, + "@storybook/router": { + "version": "5.1.11", + "resolved": "https://registry.npmjs.org/@storybook/router/-/router-5.1.11.tgz", + "integrity": "sha512-Xt7R1IOWLlIxis6VKV9G8F+e/G4G8ng1zXCqoDq+/RlWzlQJ5ccO4bUm2/XGS1rEgY4agMzmzjum18HoATpLGA==", + "dev": true, + "requires": { + "@reach/router": "^1.2.1", + "core-js": "^3.0.1", + "global": "^4.3.2", + "memoizerific": "^1.11.3", + "qs": "^6.6.0" + } + }, + "@storybook/theming": { + "version": "5.1.11", + "resolved": "https://registry.npmjs.org/@storybook/theming/-/theming-5.1.11.tgz", + "integrity": "sha512-PtRPfiAWx5pQbTm45yyPB+CuW/vyDmcmNOt+xnDzK52omeWaSD7XK2RfadN3u4QXCgha7zs35Ppx1htJio2NRA==", + "dev": true, + "requires": { + "@emotion/core": "^10.0.9", + "@emotion/styled": "^10.0.7", + "@storybook/client-logger": "5.1.11", + "common-tags": "^1.8.0", + "core-js": "^3.0.1", + "deep-object-diff": "^1.1.0", + "emotion-theming": "^10.0.9", + "global": "^4.3.2", + "memoizerific": "^1.11.3", + "polished": "^3.3.1", + "prop-types": "^15.7.2", + "resolve-from": "^5.0.0" + } + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } } }, "@storybook/addon-links": { diff --git a/package.json b/package.json index 7ee9ebc..226391c 100644 --- a/package.json +++ b/package.json @@ -56,7 +56,6 @@ "@babel/core": "^7.5.5", "@storybook/addon-a11y": "^5.0.8", "@storybook/addon-actions": "^5.1.9", - "@storybook/addon-knobs": "^5.0.8", "@storybook/addon-links": "^5.1.9", "@storybook/addon-viewport": "^5.0.8", "@storybook/addons": "^5.1.9", diff --git a/packages/components/Breadcrumb/index.js b/packages/components/Breadcrumb/index.js index 448bc12..3b538a7 100644 --- a/packages/components/Breadcrumb/index.js +++ b/packages/components/Breadcrumb/index.js @@ -31,7 +31,7 @@ const CustomBreadcrumb = (props) => { }; CustomBreadcrumb.propTypes = { - items: PropTypes.list, + items: PropTypes.array, }; CustomBreadcrumb.defaultProps = { diff --git a/packages/components/CustomAlert/index.js b/packages/components/CustomAlert/index.js new file mode 100644 index 0000000..c865775 --- /dev/null +++ b/packages/components/CustomAlert/index.js @@ -0,0 +1,48 @@ +import React, { useState } from 'react'; +import PropTypes from 'prop-types'; +import Alert from 'react-bootstrap/Alert'; + +const CustomAlert = ({ ...props } ) => { + + const [ showAlert, toggleShowAlert ] = useState(props.show); + + const handleDismiss = () => { + toggleShowAlert(false); + }; + + const setAlertHeading = () => { + return props.heading ? {props.heading} : null; + }; + + const setAlert = () => { + if (showAlert) { + return ( + + {setAlertHeading()} + {props.message} + + ); + } else { + return null; + } + }; + + return setAlert(); +}; + +CustomAlert.propTypes = { + show: PropTypes.bool.isRequired, + heading: PropTypes.string, + message: PropTypes.string, + vatiant: PropTypes.string, +}; + +CustomAlert.defaultProps = { + show: true, +}; + +export default CustomAlert; \ No newline at end of file diff --git a/packages/components/CustomAlert/stories/index.stories.js b/packages/components/CustomAlert/stories/index.stories.js new file mode 100644 index 0000000..8522de1 --- /dev/null +++ b/packages/components/CustomAlert/stories/index.stories.js @@ -0,0 +1,21 @@ +import React from 'react'; +import { storiesOf } from '@storybook/react'; +import CustomAlert from '../index.js'; + +export const alertProps = { + variant: 'danger', + heading: 'Error could not contact the server', + message: 'There was an error trying to create this transcript on the server', + show: true +}; + +storiesOf('Custom Alert', module) + .add('Default', () => { + return ( +
+ +
+ ); + }); \ No newline at end of file diff --git a/packages/components/FormModal/index.js b/packages/components/FormModal/index.js index d8adb07..2dd4f91 100644 --- a/packages/components/FormModal/index.js +++ b/packages/components/FormModal/index.js @@ -1,22 +1,23 @@ import React, { useState } from 'react'; +import { withKnobs, text, boolean, number } from '@storybook/addon-knobs'; import PropTypes from 'prop-types'; import Modal from 'react-bootstrap/Modal'; -import ItemForm from './ItemForm/index.js'; +import ItemForm from '../ItemForm/index.js'; +import TranscriptForm from '../TranscriptForm/index.js'; const ItemFormModal = (props) => { - const [ showModal, toggleShowModal ] = useState(props.showModal); + const form = (props.type === 'transcript') ? : ; + return ( toggleShowModal(!showModal) }> {props.modalTitle} - + {form} ); diff --git a/packages/components/FormModal/stories/index.stories.js b/packages/components/FormModal/stories/index.stories.js index bde4f7b..3c7fe18 100644 --- a/packages/components/FormModal/stories/index.stories.js +++ b/packages/components/FormModal/stories/index.stories.js @@ -1,15 +1,14 @@ import React from 'react'; - import { storiesOf } from '@storybook/react'; import { actions } from '@storybook/addon-actions'; import StoryRouter from 'storybook-react-router'; import FormModal from '../index.js'; -import ItemForm from '../ItemForm'; export const modalItems = [ { id: 1, + itemType: 'project', showModal: true, - title: 'Example Transcript Title', + title: 'Example Project Title', description: 'This is a sample card description. This is fun!', url: '/projects/1/transcripts/1234', modalTitle: 'Edit Project', @@ -17,6 +16,15 @@ export const modalItems = [ { showModal: true, modalTitle: 'New Project', id: 2 +}, { + projectId: 123, + title: '', + description: '', + uploadCompleted: true, + showModal: true, + modalTitle: 'New Transcript', + id: 3, + type: 'transcript' } ]; export const modalActions = actions({ handleSaveForm: 'Form saved' }); @@ -42,16 +50,13 @@ storiesOf('Form Modal', module) /> ); - }); - -storiesOf('Form Modal / Item Form', module) - .addDecorator(StoryRouter()) - .add('Edit Project', () => { + }) + .add('New Transcript', () => { return (
-
); diff --git a/packages/components/FormModal/ItemForm/index.js b/packages/components/ItemForm/index.js similarity index 100% rename from packages/components/FormModal/ItemForm/index.js rename to packages/components/ItemForm/index.js diff --git a/packages/components/ItemForm/stories/index.stories.js b/packages/components/ItemForm/stories/index.stories.js new file mode 100644 index 0000000..dcb2b14 --- /dev/null +++ b/packages/components/ItemForm/stories/index.stories.js @@ -0,0 +1,18 @@ +import React from 'react'; +import { storiesOf } from '@storybook/react'; +import StoryRouter from 'storybook-react-router'; +import ItemForm from '../index.js'; +import { modalActions, modalItems } from '../../FormModal/stories/index.stories.js'; + +storiesOf('Item Form', module) + .addDecorator(StoryRouter()) + .add('Edit Project', () => { + return ( +
+ +
+ ); + }); \ No newline at end of file diff --git a/packages/components/SimpleCard/index.js b/packages/components/SimpleCard/index.js index 8e14fe2..e18f4f9 100644 --- a/packages/components/SimpleCard/index.js +++ b/packages/components/SimpleCard/index.js @@ -76,7 +76,7 @@ const SimpleCard = (props) => { }; SimpleCard.propTypes = { - key: PropTypes.string.isRequired, + key: PropTypes.string, id: PropTypes.string.isRequired, title: PropTypes.string.isRequired, url: PropTypes.string.isRequired, diff --git a/packages/components/TranscriptCard/index.js b/packages/components/TranscriptCard/index.js index 5cdcfe9..cf4ecab 100644 --- a/packages/components/TranscriptCard/index.js +++ b/packages/components/TranscriptCard/index.js @@ -141,7 +141,7 @@ const TranscriptCard = (props) => { }; TranscriptCard.propTypes = { - key: PropTypes.string.isRequired, + key: PropTypes.string, id: PropTypes.number.isRequired, title: PropTypes.string.isRequired, description: PropTypes.string, diff --git a/packages/components/TranscriptForm/index.js b/packages/components/TranscriptForm/index.js new file mode 100644 index 0000000..dee955a --- /dev/null +++ b/packages/components/TranscriptForm/index.js @@ -0,0 +1,138 @@ +import React, { useState, useEffect } from 'react'; +import PropTypes from 'prop-types'; +import Form from 'react-bootstrap/Form'; +import Button from 'react-bootstrap/Button'; +import Modal from 'react-bootstrap/Modal'; + +const TranscriptForm = ({ ...props }) => { + + const [ title, setTitle ] = useState(props.title); + const [ description, setDescription ] = useState(props.description); + const [ isValidated, setValidationStatus ] = useState(false); + const [ formData, setFormData ] = useState({}); + + const handleFileUpload = e => { + const file = e.target.files[0]; + + if (!title) { + setTitle(file.name); + } + + const fileObj = { + title: title, + description: description, + file: file, + type: file.type + }; + + setFormData(fileObj); + }; + + const sendRequest = () => { + const tmpObj = { + ...formData, + title: title, + description: description + }; + + setFormData(tmpObj); + + props.handleSaveForm(tmpObj); + }; + + const handleSubmit = (event) => { + const form = event.currentTarget; + event.preventDefault(); + event.stopPropagation(); + setValidationStatus(true); + + if (form.checkValidity()) { + sendRequest(); + } + }; + + return (<> +
handleSubmit(e) } + > + + Title + setTitle(e.target.value) } + /> + + Choose a title for your Transcript + + Looks good! + + Please choose a title for your transcript + + + + + Description + setDescription(e.target.value) } + /> + + Choose an optional description for your Transcript + + Looks good! + + Please choose a description for your transcript + + + + handleFileUpload(e) } + /> + + Select an audio or video file to upload + + Looks good! + + Please choose a audio or video file to upload + + + + + +
+ + ); +}; + +TranscriptForm.propTypes = { + id: PropTypes.number.isRequired, + projectId: PropTypes.number.isRequired, + title: PropTypes.string.isRequired, + description: PropTypes.string, + handleSaveForm: PropTypes.func.isRequired, +}; + +TranscriptForm.defaultProps = { + id: 456, + projectId: 123, + title: 'Sample Transcript Title', + description: 'Sample Transcript Description', + handleSaveForm: () => { + console.log('Form saved'); + }, +}; + +export default TranscriptForm; diff --git a/packages/components/TranscriptForm/stories/index.stories.js b/packages/components/TranscriptForm/stories/index.stories.js new file mode 100644 index 0000000..0b07247 --- /dev/null +++ b/packages/components/TranscriptForm/stories/index.stories.js @@ -0,0 +1,27 @@ +import React from 'react'; +import { storiesOf } from '@storybook/react'; +import StoryRouter from 'storybook-react-router'; +import TranscriptForm from '../index.js'; + +import { modalActions } from '../../FormModal/stories/index.stories.js'; + +const transcriptFormProps = { + projectId: 123, + title: 'Sample Transcript Title', + description: 'Sample Transcript Description', + id: 456, + uploadCompleted: true +}; + +storiesOf('Transcript Form', module) + .addDecorator(StoryRouter()) + .add('Default', () => { + return ( +
+ +
+ ); + });