From 6babd570b569681cd32b1898e6217b52fe6fe855 Mon Sep 17 00:00:00 2001 From: Benjamin Piouffle Date: Wed, 14 Mar 2018 17:56:33 +1100 Subject: [PATCH 01/11] Add react-helmet to put video titlte in title tag when watching it --- app/components/App/index.jsx | 4 ++++ app/components/VideoDebate/index.jsx | 6 ++++++ package.json | 1 + 3 files changed, 11 insertions(+) diff --git a/app/components/App/index.jsx b/app/components/App/index.jsx index aeed21c62..6e7c18b2b 100644 --- a/app/components/App/index.jsx +++ b/app/components/App/index.jsx @@ -1,6 +1,7 @@ import React from "react" import { connect } from "react-redux" import { I18nextProvider } from 'react-i18next' +import { Helmet } from 'react-helmet' import i18n from '../../i18n/i18n' import { FlashMessages } from "../Utils" @@ -20,6 +21,9 @@ export default class App extends React.PureComponent { return (
+ + CaptainFact +
diff --git a/app/components/VideoDebate/index.jsx b/app/components/VideoDebate/index.jsx index fb44af9c0..c46c26a2f 100644 --- a/app/components/VideoDebate/index.jsx +++ b/app/components/VideoDebate/index.jsx @@ -1,6 +1,7 @@ import React from "react" import { connect } from "react-redux" import { translate } from 'react-i18next' +import { Helmet } from 'react-helmet' import { ErrorView } from "../Utils" import { isAuthenticated } from "../../state/users/current_user/selectors" @@ -14,6 +15,8 @@ import { ColumnDebate } from './ColumnDebate' @connect(state => ({ videoErrors: state.VideoDebate.video.errors, + isLoading: state.VideoDebate.video.isLoading, + videoTitle: state.VideoDebate.video.data.title, authenticated: isAuthenticated(state), }), { joinVideoDebateChannel, joinCommentsChannel, joinStatementsChannel, @@ -44,6 +47,9 @@ export class VideoDebate extends React.PureComponent { return return (
+ + {!this.props.isLoading && {this.props.videoTitle}} +
diff --git a/package.json b/package.json index 18bdb05d9..3f02fe4f3 100644 --- a/package.json +++ b/package.json @@ -43,6 +43,7 @@ "react": "^16.2.0", "react-dom": "^16.2.0", "react-flip-move": "^3.0.1", + "react-helmet": "^5.2.0", "react-i18next": "^7.4.0", "react-markdown": "^3.2.2", "react-player": "0.25.3", From 3ee62b2c82c748f888b723566d4c3c0d6f9973a1 Mon Sep 17 00:00:00 2001 From: Benjamin Piouffle Date: Thu, 15 Mar 2018 14:53:37 +1100 Subject: [PATCH 02/11] Fix player position. Still need to be tested on live and to fix https://github.com/CookPete/react-player/issues/357 --- app/components/VideoDebate/ColumnVideo.jsx | 4 +- .../VideoDebate/VideoDebatePlayer.jsx | 43 ++++++++++++++ app/components/Videos/AddVideoForm.jsx | 57 +++++++++++-------- app/components/Videos/DummyVideoPlayer.jsx | 48 ---------------- app/components/Videos/VideoPlayer.jsx | 27 --------- app/components/Videos/index.js | 2 - package.json | 2 +- 7 files changed, 78 insertions(+), 105 deletions(-) create mode 100644 app/components/VideoDebate/VideoDebatePlayer.jsx delete mode 100644 app/components/Videos/DummyVideoPlayer.jsx delete mode 100644 app/components/Videos/VideoPlayer.jsx diff --git a/app/components/VideoDebate/ColumnVideo.jsx b/app/components/VideoDebate/ColumnVideo.jsx index e8049836b..61dcf011b 100644 --- a/app/components/VideoDebate/ColumnVideo.jsx +++ b/app/components/VideoDebate/ColumnVideo.jsx @@ -7,9 +7,9 @@ import { Link } from 'react-router' import { MIN_REPUTATION_ADD_SPEAKER } from '../../constants' import { videoDebateOnlineUsersCount, videoDebateOnlineViewersCount } from '../../state/video_debate/presence/selectors' import { AddSpeakerForm, SpeakerPreview } from "../Speakers" -import { VideoPlayer } from "../Videos" import { LoadingFrame, Icon } from "../Utils" import ReputationGuard from '../Utils/ReputationGuard' +import VideoDebatePlayer from './VideoDebatePlayer' import Presence from './Presence' @@ -29,7 +29,7 @@ export class ColumnVideo extends React.PureComponent { const { url, title, speakers } = video return (
- +

{title}

diff --git a/app/components/VideoDebate/VideoDebatePlayer.jsx b/app/components/VideoDebate/VideoDebatePlayer.jsx new file mode 100644 index 000000000..ac3744172 --- /dev/null +++ b/app/components/VideoDebate/VideoDebatePlayer.jsx @@ -0,0 +1,43 @@ +import React from "react" +import { connect } from "react-redux" +import ReactPlayer from 'react-player' + +import { setPosition } from '../../state/video_debate/video/reducer' + + +/** + * A player connected to VideoDebate state. Update position in it when playing + * and seekTo position when requested in state. + */ +@connect(state => ({ + position: state.VideoDebate.video.playback.position, + forcedPosition: state.VideoDebate.video.playback.forcedPosition +}), {setPosition}) +export default class VideoDebatePlayer extends React.Component { + shouldComponentUpdate(newProps) { + return this.props.url !== newProps.url + } + + componentWillReceiveProps(newProps) { + const { forcedPosition } = newProps + if (forcedPosition.requestId !== null && + forcedPosition.requestId !== this.props.forcedPosition.requestId) { + this.refs.player.seekTo(forcedPosition.time) + } + } + + render() { + const { setPosition, url } = this.props + + return ( + setPosition(playedSeconds)} + width="" + height="" + controls + /> + ) + } +} diff --git a/app/components/Videos/AddVideoForm.jsx b/app/components/Videos/AddVideoForm.jsx index 26ff04d7e..fc9cfa8b7 100644 --- a/app/components/Videos/AddVideoForm.jsx +++ b/app/components/Videos/AddVideoForm.jsx @@ -3,9 +3,9 @@ import { withRouter } from "react-router" import { Field, reduxForm } from 'redux-form' import { connect } from 'react-redux' import trim from 'voca/trim' +import ReactPlayer from 'react-player' import { youtubeRegex } from '../../lib/url_utils' -import { DummyVideoPlayer } from "../Videos" import { FieldWithButton } from "../FormUtils" import { LoadingFrame } from '../Utils/LoadingFrame' import { postVideo, searchVideo } from '../../state/videos/effects' @@ -18,19 +18,6 @@ const validate = ({ url }) => { return {} } -const renderVideoField = (field) => { - const { meta: {error}, input: {value} } = field - const urlInput = FieldWithButton(field) - - return ( -
- {!error && } - {error &&
} - {urlInput} -
- ) -} - @withRouter @connect((state, props) => ({ initialValues: {url: props.params.videoUrl}, @@ -48,22 +35,13 @@ export class AddVideoForm extends React.PureComponent { } } - handleSubmit(video) { - const promise = this.props.postVideo(video) - return promise.then(action => { - if (!action.error) - this.props.router.push(`/videos/${action.payload.id}`) - else if (action.payload === 'unauthorized' && !this.props.isAuthenticated) - this.props.router.push('/login') - }) - } - render() { return (
- trim(s)} /> @@ -74,4 +52,33 @@ export class AddVideoForm extends React.PureComponent {
) } + + renderVideoField = (field) => { + const { meta: {error}, input: {value} } = field + const urlInput = FieldWithButton(field) + + return ( +
+ {!error && + + } + {error &&
} + {urlInput} +
+ ) + } + + handleSubmit(video) { + const promise = this.props.postVideo(video) + return promise.then(action => { + if (!action.error) + this.props.router.push(`/videos/${action.payload.id}`) + else if (action.payload === 'unauthorized' && !this.props.isAuthenticated) + this.props.router.push('/login') + }) + } } diff --git a/app/components/Videos/DummyVideoPlayer.jsx b/app/components/Videos/DummyVideoPlayer.jsx deleted file mode 100644 index 35b343b94..000000000 --- a/app/components/Videos/DummyVideoPlayer.jsx +++ /dev/null @@ -1,48 +0,0 @@ -import React from "react" - -import ReactPlayer from 'react-player' - - -export class DummyVideoPlayer extends React.PureComponent { - constructor(props) { - super(props) - this.duration = 0 - } - - handleDuration(duration) { - this.duration = duration - } - - // Override props handleprogress to return time elapsed instead of rate played - handleProgress({played}) { - if (this.props.onProgress) - this.props.onProgress({played: played * this.duration}) - } - - seekTo(time) { - if (this.duration) - this.refs.player.seekTo(time / this.duration) - } - - render() { - const { url } = this.props - const {playback, dispatch, onProgress, position, forcedPosition, ...iframeProps} = this.props - if (!url) - return (
) - return ( - - ) - } -} - -DummyVideoPlayer.defaultProps = { - frameBorder: 0, - allowFullScreen: true, - width: '', - height: '', - controls: true -} diff --git a/app/components/Videos/VideoPlayer.jsx b/app/components/Videos/VideoPlayer.jsx deleted file mode 100644 index c27b47154..000000000 --- a/app/components/Videos/VideoPlayer.jsx +++ /dev/null @@ -1,27 +0,0 @@ -import React from "react" -import { connect } from "react-redux" - -import { DummyVideoPlayer } from "./DummyVideoPlayer" -import { setPosition } from '../../state/video_debate/video/reducer' - - -@connect(state => ({ - position: state.VideoDebate.video.playback.position, - forcedPosition: state.VideoDebate.video.playback.forcedPosition -}), {setPosition}) -export class VideoPlayer extends React.PureComponent { - componentDidUpdate(oldProps) { - const { forcedPosition } = this.props - if (forcedPosition.requestId !== null && forcedPosition.requestId !== oldProps.forcedPosition.requestId) - this.refs.player.seekTo(forcedPosition.time) - } - - render() { - const {setPosition, ...playerProps} = this.props - return ( - setPosition(played)} - {...playerProps}/> - ) - } -} diff --git a/app/components/Videos/index.js b/app/components/Videos/index.js index 1d8b80c79..c36131e7d 100644 --- a/app/components/Videos/index.js +++ b/app/components/Videos/index.js @@ -1,6 +1,4 @@ export * from './AddVideoForm' export * from './PublicVideos' export * from './VideoCard' -export * from './DummyVideoPlayer' -export * from './VideoPlayer' export * from './VideosGrid' diff --git a/package.json b/package.json index 18bdb05d9..c71285c24 100644 --- a/package.json +++ b/package.json @@ -45,7 +45,7 @@ "react-flip-move": "^3.0.1", "react-i18next": "^7.4.0", "react-markdown": "^3.2.2", - "react-player": "0.25.3", + "react-player": "^1.2.1", "react-redux": "^5.0.7", "react-router": "^3.0.1", "react-select": "^1.2.1", From f6a9e246d296f74a67e09deb833ef1a6760e5c0b Mon Sep 17 00:00:00 2001 From: Benjamin Piouffle Date: Thu, 15 Mar 2018 22:13:59 +1100 Subject: [PATCH 03/11] Fix typos and translations (#99) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Update tasks.md Update english subtitle from "Traductions" to "Translation" * Update User.js Change from "Registered since {{value}}" to "Registered for {{value}}" * Update tasks.md Change from "oeuil" to "œil" * Correct bug_report.md Correct "divulation" to "divulgation". * Update ambassadors.md Correction * Update ambassadors.md Correction + "garantir votre indépendance" --- app/assets/assets/help/en/contribute/tasks.md | 4 ++-- app/assets/assets/help/fr/ambassadors.md | 13 ++++++------- app/assets/assets/help/fr/bug_report.md | 2 +- app/assets/assets/help/fr/contribute/tasks.md | 2 +- app/i18n/en/user.js | 2 +- 5 files changed, 11 insertions(+), 12 deletions(-) diff --git a/app/assets/assets/help/en/contribute/tasks.md b/app/assets/assets/help/en/contribute/tasks.md index 14f24d459..6f1abb45a 100644 --- a/app/assets/assets/help/en/contribute/tasks.md +++ b/app/assets/assets/help/en/contribute/tasks.md @@ -15,7 +15,7 @@ can [contact us](/help/contact) directly. If you have experience with legal structures issues and particularly with non-profit / common good companies your help could be extremely valuable. -# Traductions +# Translation Helping to translate CaptainFact doesn't require any technical skills, it's just a matter of replacing strings in files. @@ -31,4 +31,4 @@ of replacing strings in files. #### If you don't know what the heck git is about -[Contact us](/help/contact) and we'll send you the files along with instructions. \ No newline at end of file +[Contact us](/help/contact) and we'll send you the files along with instructions. diff --git a/app/assets/assets/help/fr/ambassadors.md b/app/assets/assets/help/fr/ambassadors.md index 6c3688205..2968f0c84 100644 --- a/app/assets/assets/help/fr/ambassadors.md +++ b/app/assets/assets/help/fr/ambassadors.md @@ -37,7 +37,7 @@ vous êtes là pour nous rappeler à l'ordre. Que ça soit sur la plateforme ou le [Discord](https://discord.gg/2Qd7hMz), vous pouvez prendre la température des utilisateurs, modérer les échanges et garantir -une utilisation seine de la plateforme. +une utilisation saine de la plateforme. ### 👁‍ Vous êtes en **auto-gestion** ! @@ -47,17 +47,16 @@ nous souhaitons construire une relation de confiance avec vous. ### ⏲‍ Vous êtes **mandatés** ! Afin de garantir un minimum d'investissement et -un renouvellement régulier, votre mandat sera limité à une durée de 6 mois -et renouvelable. - +un renouvellement régulier des ambassadeurs, votre mandat est de 6 mois +et il est renouvelable. ### 😃‍ Vous êtes **réels** ! Nous allons travailler avec vous pour définir votre -statut juridique au sein de notre structure pour garantir +statut juridique au sein de notre structure pour garantir votre indépendance. ### 🔗‍ Vous êtes **un lien** ! -Nous souhaitons casser cette dimension virtuelle de +Nous souhaitons casser la dimension virtuelle de notre communauté et vous avez un rôle à jouer, que ca soit à travers la promotion ou l'organisation d'événements nous serons là pour vous soutenir. @@ -72,4 +71,4 @@ des règles qui vous sembleraient importantes. De quitter vos fonctions d'ambassadeur à tout moment. ### 😃‍ Vous êtes **géniaux** ! -Merci pour votre implication et votre travail. \ No newline at end of file +Merci pour votre implication et votre travail. diff --git a/app/assets/assets/help/fr/bug_report.md b/app/assets/assets/help/fr/bug_report.md index dad333966..87cf5f2fb 100644 --- a/app/assets/assets/help/fr/bug_report.md +++ b/app/assets/assets/help/fr/bug_report.md @@ -14,7 +14,7 @@ pour l'extension. # Pire ! Une faille de sécurité ? -Nous croyons en la divulation responsable et l'encourageons. +Nous croyons en la divulgation responsable et l'encourageons. Si votre signalement est relatif à une faille de sécurité critique, vous pouvez chiffrer votre message avec la clef PGP ci-dessous : diff --git a/app/assets/assets/help/fr/contribute/tasks.md b/app/assets/assets/help/fr/contribute/tasks.md index 9c70e67b6..07f5ff294 100644 --- a/app/assets/assets/help/fr/contribute/tasks.md +++ b/app/assets/assets/help/fr/contribute/tasks.md @@ -6,7 +6,7 @@ Pour toutes les tâches liées au développement, # Design Pour les tâches liées à la ludification (gamification) vous pouvez jeter un -coup d'oeuil [par ici](https://github.com/CaptainFact/captain-fact-frontend/issues/6) +coup d'œuil [par ici](https://github.com/CaptainFact/captain-fact-frontend/issues/6) Pour tout le reste ou si vous n'êtes pas à l'aise avec Github vous pouvez [nous contacter](/help/contact) directement. diff --git a/app/i18n/en/user.js b/app/i18n/en/user.js index 10697b37a..54a1c78a7 100644 --- a/app/i18n/en/user.js +++ b/app/i18n/en/user.js @@ -13,7 +13,7 @@ export default { "actionWithThirdParty": "Or login using a third party service", "deleteAccount": "Delete Account", "dangerZone": "Danger Zone", - "registeredSince": "Registered since {{value}}", + "registeredSince": "Registered for {{value}}", "forgottenPassword": "Forgotten password", "resetPassword": "Reset password", "resetPasswordRequestSuccess": "If an account is associated with this address, an email with a link to reset password has been sent", From 054f0b16fffca364253122c667b926b3538d16a3 Mon Sep 17 00:00:00 2001 From: Benjamin Piouffle Date: Fri, 16 Mar 2018 19:21:31 +1100 Subject: [PATCH 04/11] Small optimizations and code clean (#100) * Small optimizations and remove useless comments --- app/components/Comments/CommentDisplay.jsx | 67 +++++++++---------- app/components/Comments/CommentForm.jsx | 38 +++++------ app/components/Comments/CommentsContainer.jsx | 15 ++--- app/components/Comments/FlagForm.jsx | 2 +- app/components/Comments/ModalFlag.jsx | 2 +- app/components/Help/Help.jsx | 2 +- app/components/Moderation/ModerationEntry.jsx | 2 +- app/components/Pages/Home.jsx | 2 +- app/components/Speakers/SpeakerPreview.jsx | 2 +- app/components/Statements/Statement.jsx | 35 ++++------ app/components/Statements/StatementForm.jsx | 4 +- app/components/Statements/StatementsList.jsx | 7 +- app/components/Users/DeleteUserModal.jsx | 2 +- app/components/Users/EditUserForm.jsx | 2 +- .../Users/InvitationRequestForm.jsx | 2 +- app/components/Users/LoginForm.jsx | 2 +- app/components/Users/User.jsx | 5 +- app/components/Users/UserProfile.jsx | 8 --- app/components/UsersActions/ActionsTable.jsx | 2 +- app/components/UsersActions/Entity.jsx | 2 +- app/components/UsersActions/History.jsx | 2 +- app/components/UsersActions/UserAction.jsx | 2 +- app/components/Utils/ErrorView.jsx | 2 +- app/components/Utils/FlashMessages.jsx | 2 +- app/components/Utils/LoadingFrame.jsx | 8 +-- .../VideoDebate/ActionBubbleMenu.jsx | 2 +- app/components/VideoDebate/ColumnDebate.jsx | 3 +- app/components/VideoDebate/ModalHistory.jsx | 4 +- app/components/Videos/PublicVideos.jsx | 2 +- app/components/Videos/VideoCard.jsx | 2 +- app/lib/__tests__/seconds_formatter.js | 18 ++--- app/state/video_debate/comments/selectors.js | 6 +- app/state/video_debate/selectors.js | 6 +- .../video_debate/statements/selectors.js | 18 +++-- 34 files changed, 129 insertions(+), 151 deletions(-) diff --git a/app/components/Comments/CommentDisplay.jsx b/app/components/Comments/CommentDisplay.jsx index 0c7f599cc..8237d9d69 100644 --- a/app/components/Comments/CommentDisplay.jsx +++ b/app/components/Comments/CommentDisplay.jsx @@ -22,33 +22,25 @@ import MediaLayout from '../Utils/MediaLayout' import Vote from './Vote' -// TODO Use ReputationGuard to protect actions -// Add the following possibilities to reputationGuard : -// onUnauthorized = "hide" | "showMessage" | "flash" - @connect(({CurrentUser, VideoDebate}, props) => ({ currentUser: CurrentUser.data, myVote: VideoDebate.comments.voted.get(props.comment.id, 0), isVoting: VideoDebate.comments.voting.has(props.comment.id), replies: VideoDebate.comments.replies.get(props.comment.id), - isFlagged: VideoDebate.comments.myFlags.has(props.comment.id) // TODO Selector + isFlagged: VideoDebate.comments.myFlags.has(props.comment.id) }), {addModal, deleteComment, flagComment, commentVote, change, flashErrorUnauthenticated}) -@translate(['main', 'videoDebate']) +@translate('main') export class CommentDisplay extends React.PureComponent { constructor(props) { super(props) this.state = {isBlurred: false, showReplies: props.nesting !== 4} - this.showRepliesToggle = this.showRepliesToggle.bind(this) - - // Authenticated actions - this.actionReply = this.actionAuthenticated(this.actionReply.bind(this)) - this.handleFlag = this.actionAuthenticated(this.handleFlag.bind(this)) } render() { const { user, text, source, score, inserted_at, approve } = this.props.comment const { t, withoutActions, withoutHeader, replyingTo, nesting, replies, myVote, isVoting, hideThread, className, richMedias=true } = this.props const approveClass = approve !== null && (approve ? 'approve' : 'refute') + const showReplies = this.state.showReplies const isOwnComment = this.props.comment.user.id === this.props.currentUser.id return ( @@ -58,7 +50,9 @@ export class CommentDisplay extends React.PureComponent { ContainerType="article" left={!withoutActions && this.props.commentVote({comment: this.props.comment, value})}/> + onVote={value => this.ensureAuthenticated() && + this.props.commentVote({comment: this.props.comment, value}) + }/> } content={
@@ -83,11 +77,11 @@ export class CommentDisplay extends React.PureComponent {
) } + + static getNbDisplayedRange(nesting) { + if (nesting > 3) + return [3, 5] + return [4 - nesting, 6 - nesting] + } } CommentsContainer.defaultProps = { diff --git a/app/components/Comments/FlagForm.jsx b/app/components/Comments/FlagForm.jsx index be54dc9a8..5b971d9ea 100644 --- a/app/components/Comments/FlagForm.jsx +++ b/app/components/Comments/FlagForm.jsx @@ -26,7 +26,7 @@ export default class FlagForm extends React.PureComponent { render() { const { handleSubmit } = this.props - // TODO see https://stackoverflow.com/help/privileges/flag-posts + return ( diff --git a/app/components/Comments/ModalFlag.jsx b/app/components/Comments/ModalFlag.jsx index 14e683d0b..9c7049c53 100644 --- a/app/components/Comments/ModalFlag.jsx +++ b/app/components/Comments/ModalFlag.jsx @@ -11,7 +11,7 @@ import HttpApi from '../../API/http_api' const flagFormValueSelector = formValueSelector('flagForm') @connect(state => ({selectedReason: flagFormValueSelector(state, 'reason')})) -@translate(['videoDebate', 'main']) +@translate('videoDebate') export default class ModalFlag extends React.PureComponent { constructor(props) { super(props) diff --git a/app/components/Help/Help.jsx b/app/components/Help/Help.jsx index d6a2324c6..68b8398c7 100644 --- a/app/components/Help/Help.jsx +++ b/app/components/Help/Help.jsx @@ -7,7 +7,7 @@ import HelpPageContent from './HelpPageContent' import PublicAchievementUnlocker from '../Users/PublicAchievementUnlocker' -@translate(['help', 'main']) +@translate('help') @withRouter export default class Help extends React.PureComponent { render() { diff --git a/app/components/Moderation/ModerationEntry.jsx b/app/components/Moderation/ModerationEntry.jsx index b6e366ee9..820e3b299 100644 --- a/app/components/Moderation/ModerationEntry.jsx +++ b/app/components/Moderation/ModerationEntry.jsx @@ -17,7 +17,7 @@ import format from 'date-fns/format' import { locales } from '../../i18n/i18n' @connect(state => ({ locale: state.UserPreferences.locale })) -@translate('moderation', 'main') +@translate('moderation') export default class ModerationEntry extends React.PureComponent { render() { const { entry, locale, t, onAction } = this.props diff --git a/app/components/Pages/Home.jsx b/app/components/Pages/Home.jsx index 4dc48f8d6..fcce21c22 100644 --- a/app/components/Pages/Home.jsx +++ b/app/components/Pages/Home.jsx @@ -10,7 +10,7 @@ import Logo from '../App/Logo' @connect(state => ({authenticated: isAuthenticated(state)})) -@translate(['home', 'main']) +@translate('home') export class Home extends React.PureComponent { render() { return ( diff --git a/app/components/Speakers/SpeakerPreview.jsx b/app/components/Speakers/SpeakerPreview.jsx index e705110a5..b961e67f5 100644 --- a/app/components/Speakers/SpeakerPreview.jsx +++ b/app/components/Speakers/SpeakerPreview.jsx @@ -23,7 +23,7 @@ import {getFocusedStatementSpeakerId} from '../../state/video_debate/statements/ @withRouter -@translate(['videoDebate', 'main']) +@translate('videoDebate') @connect((state, props) => ( {isAuthenticated: isAuthenticated(state), isFocused: getFocusedStatementSpeakerId(state) === props.speaker.id}), {addModal, changeStatementFormSpeaker, removeSpeaker, updateSpeaker} diff --git a/app/components/Statements/Statement.jsx b/app/components/Statements/Statement.jsx index 7c552f1e4..89d50eab1 100644 --- a/app/components/Statements/Statement.jsx +++ b/app/components/Statements/Statement.jsx @@ -33,7 +33,6 @@ import { setScrollTo } from '../../state/video_debate/statements/reducer' refutingFacts : commentsSelectors.getStatementRefutingFacts(state, props), approveScore: statementSelectors.getStatementApproveScore(state, props), refuteScore: statementSelectors.getStatementRefuteScore(state, props), - commentsLoading: commentsSelectors.areCommentsLoading(state), isFocused: statementSelectors.isStatementFocused(state, props), currentUser: state.CurrentUser.data, scrollTo: state.VideoDebate.statements.scrollTo, @@ -42,11 +41,7 @@ import { setScrollTo } from '../../state/video_debate/statements/reducer' }), {addModal, updateStatement, deleteStatement, forcePosition, setScrollTo}) @translate('videoDebate') export class Statement extends React.PureComponent { - constructor(props) { - super(props) - this.state = { isDeleting: false, isEditing: false } - this.showHistory = this.showHistory.bind(this) - } + state = { isDeleting: false, isEditing: false } componentDidUpdate(prevProps) { if (this.shouldScroll(this.props, prevProps)) @@ -78,16 +73,6 @@ export class Statement extends React.PureComponent { ) } - showHistory() { - this.props.addModal({ - Modal: ModalHistory, - props: { - entity: ENTITY_STATEMENT, - entityId: this.props.statement.id - } - }) - } - renderCardHeaderAndContent(speaker, statement) { const {t, forcePosition, setScrollTo, addModal} = this.props @@ -122,7 +107,7 @@ export class Statement extends React.PureComponent {

- + this.showHistory() }/> ) const { statement, comments, approvingFacts, refutingFacts } = this.props return ( @@ -173,13 +156,23 @@ export class Statement extends React.PureComponent { }
{comments.size > 0 && } - {/* TODO This can be optimized as initialValues will always change upon rendering */} - +
) } + showHistory() { + this.props.addModal({ + Modal: ModalHistory, + props: { + entity: ENTITY_STATEMENT, + entityId: this.props.statement.id + } + }) + } + // ---- Autoscroll ---- shouldScroll = (props, prevProps) => { diff --git a/app/components/Statements/StatementForm.jsx b/app/components/Statements/StatementForm.jsx index 77a14bc0c..721aed5fb 100644 --- a/app/components/Statements/StatementForm.jsx +++ b/app/components/Statements/StatementForm.jsx @@ -14,13 +14,13 @@ import { decrementFormCount, incrementFormCount, setScrollTo, STATEMENT_FORM_NAM import { handleFormEffectResponse } from '../../lib/handle_effect_response' -@translate(['videoDebate', 'main']) -@reduxForm({form: STATEMENT_FORM_NAME}) @connect(({VideoDebate: {video, statements}}) => ({ position: video.playback.position, speakers: video.data.speakers, submitting: statements.isSubmitting }), {forcePosition, setScrollTo, incrementFormCount, decrementFormCount}) +@reduxForm({form: STATEMENT_FORM_NAME}) +@translate('videoDebate') export class StatementForm extends React.PureComponent { constructor(props) { super(props) diff --git a/app/components/Statements/StatementsList.jsx b/app/components/Statements/StatementsList.jsx index 219a93e55..284856635 100644 --- a/app/components/Statements/StatementsList.jsx +++ b/app/components/Statements/StatementsList.jsx @@ -2,6 +2,7 @@ import React from 'react' import { connect } from "react-redux" import { translate } from 'react-i18next' import { withRouter } from 'react-router' +import FlipMove from 'react-flip-move' import { StatementForm } from './StatementForm' import { Statement } from './Statement' @@ -38,7 +39,11 @@ export default class StatementsList extends React.PureComponent { e => {if (!e.error) this.props.closeStatementForm(); return e;} )}/> } - {statements.map(statement => )} + + {statements.map(statement => + + )} +
) } diff --git a/app/components/Users/DeleteUserModal.jsx b/app/components/Users/DeleteUserModal.jsx index 25ef5a019..d0965aae0 100644 --- a/app/components/Users/DeleteUserModal.jsx +++ b/app/components/Users/DeleteUserModal.jsx @@ -41,7 +41,7 @@ const valueSelector = formValueSelector(DELETE_FORM) @connect(state => ({ isValid: valueSelector(state, 'usernameConfirm') === state.CurrentUser.data.username })) -@translate(['main', 'user']) +@translate('main') export default class DeleteUserModal extends React.PureComponent { render() { const { t, isValid, ...otherProps } = this.props diff --git a/app/components/Users/EditUserForm.jsx b/app/components/Users/EditUserForm.jsx index 61f986118..3830e2c0f 100644 --- a/app/components/Users/EditUserForm.jsx +++ b/app/components/Users/EditUserForm.jsx @@ -18,7 +18,7 @@ import { handleFormEffectResponse } from '../../lib/handle_effect_response' }), {updateInfo}) @reduxForm({ form: 'editUserForm', validate: validatePasswordRepeat }) @withRouter -@translate(['user', 'main']) +@translate('user') export default class EditUserForm extends React.PureComponent { componentDidUpdate() { // Redirect to user profile when logged in diff --git a/app/components/Users/InvitationRequestForm.jsx b/app/components/Users/InvitationRequestForm.jsx index 42a30bc6c..876a6a26d 100644 --- a/app/components/Users/InvitationRequestForm.jsx +++ b/app/components/Users/InvitationRequestForm.jsx @@ -20,7 +20,7 @@ const validate = ({email}) => { } @reduxForm({form: 'newsletterSubscribeForm', validate}) -@translate(['home', 'user']) +@translate('home') @connect(null, {addFlash, errorToFlash, requestInvitation}) export default class InvitationRequestForm extends React.PureComponent { constructor(props) { diff --git a/app/components/Users/LoginForm.jsx b/app/components/Users/LoginForm.jsx index 31ab532c4..20888d02b 100644 --- a/app/components/Users/LoginForm.jsx +++ b/app/components/Users/LoginForm.jsx @@ -13,7 +13,7 @@ import { tError } from '../../lib/errors' @reduxForm({form: 'loginForm'}) @connect(({CurrentUser: {data, error}}) => ({CurrentUser: data, error}), {login}) @withRouter -@translate(['user', 'main', 'errors']) +@translate('user') export default class LoginForm extends React.PureComponent { componentWillReceiveProps(props) { // Redirect when logged in diff --git a/app/components/Users/User.jsx b/app/components/Users/User.jsx index 751524e35..eed1054c6 100644 --- a/app/components/Users/User.jsx +++ b/app/components/Users/User.jsx @@ -20,7 +20,7 @@ import { resetUser } from '../../state/users/displayed_user/reducer' isLoading, errors, user: data }), {fetchUser, resetUser}) -@translate(['main', 'user']) +@translate('main') export default class User extends React.PureComponent { componentDidMount() { this.props.fetchUser(this.props.params.username) @@ -30,8 +30,7 @@ export default class User extends React.PureComponent { // If user's username was updated if (this.props.user.id === oldProps.user.id && this.props.user.username !== oldProps.user.username) - // Remove old user profile from history - // TODO + // TODO Remove old user profile from history // Redirect this.props.router.replace(`/u/${this.props.user.username}`) diff --git a/app/components/Users/UserProfile.jsx b/app/components/Users/UserProfile.jsx index 005fa02f3..ba8c25fd1 100644 --- a/app/components/Users/UserProfile.jsx +++ b/app/components/Users/UserProfile.jsx @@ -15,14 +15,6 @@ class UserProfile extends PureComponent { const {user: {achievements}, t} = this.props return (
- {/*
*/} - {/*

*/} - {/* Statistics*/} - {/*

*/} - {/*

Posted x comments

*/} - {/*

Posted x sourced comments

*/} - {/*TODO: Top comments*/} - {/*
*/}

{t('title')} diff --git a/app/components/UsersActions/ActionsTable.jsx b/app/components/UsersActions/ActionsTable.jsx index 5876b79b1..dba318853 100644 --- a/app/components/UsersActions/ActionsTable.jsx +++ b/app/components/UsersActions/ActionsTable.jsx @@ -17,7 +17,7 @@ import { ACTION_DELETE, ACTION_REMOVE, MIN_REPUTATION_RESTORE_ENTITY } from '../ import { LoadingFrame } from '../Utils/LoadingFrame' -@translate(['history', 'main']) +@translate('history') @connect( (state, props) => ({ lastActionsIds: state.UsersActions.lastActionsIds, diff --git a/app/components/UsersActions/Entity.jsx b/app/components/UsersActions/Entity.jsx index 6cb204fc1..1ac069115 100644 --- a/app/components/UsersActions/Entity.jsx +++ b/app/components/UsersActions/Entity.jsx @@ -16,7 +16,7 @@ import { SpeakerPreview } from '../Speakers/SpeakerPreview' reference: state.UsersActions.referenceEntities.get(props.entityKey), speakers: state.VideoDebate.video.data.speakers }), {forcePosition}) -@translate(['main', 'videoDebate']) +@translate('main') export default class Entity extends React.PureComponent { render() { return ( diff --git a/app/components/UsersActions/History.jsx b/app/components/UsersActions/History.jsx index cd8e7cb31..ea0e5adbe 100644 --- a/app/components/UsersActions/History.jsx +++ b/app/components/UsersActions/History.jsx @@ -10,7 +10,7 @@ import { UserAction } from './UserAction' /** * Display a list of `UserAction` record as an history */ -@translate(['main', 'videoDebate']) +@translate('main') export class History extends React.PureComponent { constructor(props) { super(props) diff --git a/app/components/UsersActions/UserAction.jsx b/app/components/UsersActions/UserAction.jsx index 6d047fdbd..05e7b43eb 100644 --- a/app/components/UsersActions/UserAction.jsx +++ b/app/components/UsersActions/UserAction.jsx @@ -9,7 +9,7 @@ import ActionDiff from './ActionDiff' import ActionIcon from './ActionIcon' -@translate(['history', 'main']) +@translate('history') export class UserAction extends React.PureComponent { render() { const { action, className, t } = this.props diff --git a/app/components/Utils/ErrorView.jsx b/app/components/Utils/ErrorView.jsx index 59beea419..d79c460d0 100644 --- a/app/components/Utils/ErrorView.jsx +++ b/app/components/Utils/ErrorView.jsx @@ -11,7 +11,7 @@ const refreshableErrors = ['join_crashed'] @withRouter -@translate(['errors', 'main']) +@translate('errors') export class ErrorView extends React.PureComponent { getMoreInfo() { const errorInfo = getErrorInfo(this.props.error) diff --git a/app/components/Utils/FlashMessages.jsx b/app/components/Utils/FlashMessages.jsx index 210e45588..9b4c9bc03 100644 --- a/app/components/Utils/FlashMessages.jsx +++ b/app/components/Utils/FlashMessages.jsx @@ -65,7 +65,7 @@ export class FlashMessages extends React.PureComponent { } -@translate(['main', 'errors', 'achievements']) +@translate('main') @connect(null, {popModal, removeFlash}) class FlashContent extends React.Component { shouldComponentUpdate(nextProps) { diff --git a/app/components/Utils/LoadingFrame.jsx b/app/components/Utils/LoadingFrame.jsx index 3fad62083..fcec2d618 100644 --- a/app/components/Utils/LoadingFrame.jsx +++ b/app/components/Utils/LoadingFrame.jsx @@ -1,23 +1,17 @@ import React from "react" import { translate } from 'react-i18next' -import capitalize from 'voca/capitalize' import classNames from 'classnames' @translate('main') export class LoadingFrame extends React.PureComponent { - defaultTitle() { - // If translation is not available, we'll show "Loading..." - return capitalize(this.props.t('actions.loading').replace('actions.', '')) - } - render() { const {title, size="large"} = this.props return (
-

{title || this.defaultTitle()}...

+

{title || this.props.t('actions.loading')}...

) } diff --git a/app/components/VideoDebate/ActionBubbleMenu.jsx b/app/components/VideoDebate/ActionBubbleMenu.jsx index 455a2b555..717c9d945 100644 --- a/app/components/VideoDebate/ActionBubbleMenu.jsx +++ b/app/components/VideoDebate/ActionBubbleMenu.jsx @@ -26,7 +26,7 @@ import { destroyStatementForm } from '../../state/video_debate/statements/effect }), {changeStatementFormSpeaker, toggleAutoscroll, addModal, destroyStatementForm} ) -@translate(['videoDebate', 'main']) +@translate('videoDebate') @withRouter export default class ActionBubbleMenu extends React.PureComponent { render() { diff --git a/app/components/VideoDebate/ColumnDebate.jsx b/app/components/VideoDebate/ColumnDebate.jsx index 658453fb2..e4a76a8df 100644 --- a/app/components/VideoDebate/ColumnDebate.jsx +++ b/app/components/VideoDebate/ColumnDebate.jsx @@ -1,6 +1,7 @@ import React from "react" import { connect } from "react-redux" import { Trans, translate } from 'react-i18next' +import { isLoadingVideoDebate } from '../../state/video_debate/selectors' import VideoDebateHistory from "./VideoDebateHistory" import ActionBubbleMenu from './ActionBubbleMenu' @@ -12,7 +13,7 @@ import { isAuthenticated } from '../../state/users/current_user/selectors' @connect(state => ({ - isLoading: state.VideoDebate.video.isLoading || state.VideoDebate.statements.isLoading, + isLoading: isLoadingVideoDebate(state), hasStatements: state.VideoDebate.statements.data.size !== 0, hasSpeakers: state.VideoDebate.video.data.speakers.size !== 0, hasStatementForm: hasStatementForm(state), diff --git a/app/components/VideoDebate/ModalHistory.jsx b/app/components/VideoDebate/ModalHistory.jsx index 71a1e54d5..0d63a6261 100644 --- a/app/components/VideoDebate/ModalHistory.jsx +++ b/app/components/VideoDebate/ModalHistory.jsx @@ -11,11 +11,11 @@ import ActionsTable from '../UsersActions/ActionsTable' import { reset } from '../../state/user_actions/reducer' -@connect((state, props) => ({ +@connect(state => ({ actions: state.UsersActions.actions, isLoading: state.UsersActions.isLoading }), {joinStatementHistoryChannel, leaveStatementHistoryChannel, popModal, reset}) -@translate(['history']) +@translate('history') export class ModalHistory extends React.PureComponent { componentDidMount() { if (this.props.entity === ENTITY_STATEMENT) diff --git a/app/components/Videos/PublicVideos.jsx b/app/components/Videos/PublicVideos.jsx index c51189be2..66de0e341 100644 --- a/app/components/Videos/PublicVideos.jsx +++ b/app/components/Videos/PublicVideos.jsx @@ -23,7 +23,7 @@ import capitalize from 'voca/capitalize' error: state.Videos.error, languageFilter: state.UserPreferences.videosLanguageFilter }), {fetchPublicVideos, reset, changeVideosLanguageFilter}) -@translate(['main', 'errors']) +@translate('main') export class PublicVideos extends React.PureComponent { componentDidMount() { this.props.fetchPublicVideos(this.props.languageFilter && {language: this.props.languageFilter}) diff --git a/app/components/Videos/VideoCard.jsx b/app/components/Videos/VideoCard.jsx index 5743c054c..d9b50c646 100644 --- a/app/components/Videos/VideoCard.jsx +++ b/app/components/Videos/VideoCard.jsx @@ -7,7 +7,7 @@ import { translate } from 'react-i18next' import CardLayout from '../Utils/CardLayout' -@translate(['main', 'videoDebate']) +@translate('main') export class VideoCard extends React.PureComponent { static videoThumb(provider, provider_id) { if (provider === "youtube") diff --git a/app/lib/__tests__/seconds_formatter.js b/app/lib/__tests__/seconds_formatter.js index f9c3d127f..321c24db1 100644 --- a/app/lib/__tests__/seconds_formatter.js +++ b/app/lib/__tests__/seconds_formatter.js @@ -2,16 +2,16 @@ import formatter from '../seconds_formatter' it('should correctly convert seconds', () => { - expect(formatter((0))).toBe('0:00:00') - expect(formatter((4))).toBe('0:00:04') - expect(formatter((42))).toBe('0:00:42') - expect(formatter((60))).toBe('0:01:00') - expect(formatter((100))).toBe('0:01:40') - expect(formatter((3600))).toBe('1:00:00') - expect(formatter((4000))).toBe('1:06:40') - expect(formatter((1527273762))).toBe('424242:42:42') + expect(formatter(0)).toBe('0:00:00') + expect(formatter(4)).toBe('0:00:04') + expect(formatter(42)).toBe('0:00:42') + expect(formatter(60)).toBe('0:01:00') + expect(formatter(100)).toBe('0:01:40') + expect(formatter(3600)).toBe('1:00:00') + expect(formatter(4000)).toBe('1:06:40') + expect(formatter(1527273762)).toBe('424242:42:42') }) it('should display a negative sign for negative times', () => { - expect(formatter((-42))).toBe('-0:00:42') + expect(formatter(-42)).toBe('-0:00:42') }) \ No newline at end of file diff --git a/app/state/video_debate/comments/selectors.js b/app/state/video_debate/comments/selectors.js index 551174ef4..d597c0770 100644 --- a/app/state/video_debate/comments/selectors.js +++ b/app/state/video_debate/comments/selectors.js @@ -2,12 +2,12 @@ import { List } from "immutable" import createCachedSelector from 're-reselect' -export const getAllComments = (state) => state.VideoDebate.comments.comments +const EMPTY_COMMENTS_LIST = new List() -export const areCommentsLoading = (state) => state.VideoDebate.comments.isLoading +export const getAllComments = (state) => state.VideoDebate.comments.comments export const getStatementAllComments = (state, props) => - getAllComments(state).get(props.statement.id, new List()) + getAllComments(state).get(props.statement.id, EMPTY_COMMENTS_LIST) export const getStatementComments = createCachedSelector( getStatementAllComments, diff --git a/app/state/video_debate/selectors.js b/app/state/video_debate/selectors.js index 480c0ee9a..2e60ce280 100644 --- a/app/state/video_debate/selectors.js +++ b/app/state/video_debate/selectors.js @@ -1,2 +1,6 @@ -export const getVideoDebateSpeakers = state => state.VideoDebate.video.data.speakers +export const getVideoDebateSpeakers = state => + state.VideoDebate.video.data.speakers +export const isLoadingVideoDebate = state => + state.VideoDebate.video.isLoading || state.VideoDebate.statements.isLoading || + state.VideoDebate.comments.isLoading \ No newline at end of file diff --git a/app/state/video_debate/statements/selectors.js b/app/state/video_debate/statements/selectors.js index 457a0b7fe..31ae48345 100644 --- a/app/state/video_debate/statements/selectors.js +++ b/app/state/video_debate/statements/selectors.js @@ -10,7 +10,8 @@ import { STATEMENT_FOCUS_TIME } from "../../../constants" export const getStatementSpeakerId = (state, props) => props.statement.speaker_id export const getStatementSpeaker = createCachedSelector( - [getStatementSpeakerId, getVideoDebateSpeakers], + getStatementSpeakerId, + getVideoDebateSpeakers, (speakerId, speakers) => speakers.find(s => s.id === speakerId) )((state, props) => props.statement.id) @@ -26,10 +27,8 @@ export const getStatementRefuteScore = createCachedSelector( export const getFocusedStatementId = createSelector( - [ - state => state.VideoDebate.statements.data, - state => state.VideoDebate.video.playback.position - ], + state => state.VideoDebate.statements.data, + state => state.VideoDebate.video.playback.position, (statements, position) => { if (!position) return -1 @@ -39,10 +38,8 @@ export const getFocusedStatementId = createSelector( ) export const getFocusedStatementSpeakerId = createSelector( - [ - state => state.VideoDebate.statements.data, - getFocusedStatementId - ], + state => state.VideoDebate.statements.data, + getFocusedStatementId, (statements, focusId) => { if (focusId === -1) return null @@ -52,7 +49,8 @@ export const getFocusedStatementSpeakerId = createSelector( ) export const isStatementFocused = createSelector( - [getFocusedStatementId, (state, props) => props.statement.id], + getFocusedStatementId, + (state, props) => props.statement.id, (focusedStatementId, statementId) => focusedStatementId === statementId ) From db98f5a430c0f1e4bd5fd2b0bb8a7bc30e8e35b3 Mon Sep 17 00:00:00 2001 From: Benjamin Piouffle Date: Sat, 17 Mar 2018 16:16:57 +1100 Subject: [PATCH 05/11] Update react-player to 1.3.0 Fix #88 and #91 Tested with regular videos and live stream --- app/components/Statements/StatementsList.jsx | 2 +- app/styles/_components/statements.sass | 1 - package.json | 2 +- 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/app/components/Statements/StatementsList.jsx b/app/components/Statements/StatementsList.jsx index 284856635..b65b1489a 100644 --- a/app/components/Statements/StatementsList.jsx +++ b/app/components/Statements/StatementsList.jsx @@ -39,7 +39,7 @@ export default class StatementsList extends React.PureComponent { e => {if (!e.error) this.props.closeStatementForm(); return e;} )}/> } - + {statements.map(statement => )} diff --git a/app/styles/_components/statements.sass b/app/styles/_components/statements.sass index ae1588e1c..f29c0c489 100644 --- a/app/styles/_components/statements.sass +++ b/app/styles/_components/statements.sass @@ -21,7 +21,6 @@ $statement-text-color: #e0e7f1 box-shadow: 0px 0px 20px 0px rgb(148, 148, 148) max-width: $statement-max-width .statement - @include animate(fadeIn, 0.2s) margin: 0 auto max-width: $statement-max-width - $statement-focus-size transition: box-shadow 0.5s, max-width 0.5s diff --git a/package.json b/package.json index 991ab067d..6e18e5dca 100644 --- a/package.json +++ b/package.json @@ -46,7 +46,7 @@ "react-helmet": "^5.2.0", "react-i18next": "^7.4.0", "react-markdown": "^3.2.2", - "react-player": "^1.2.1", + "react-player": "^1.3.0", "react-redux": "^5.0.7", "react-router": "^3.0.1", "react-select": "^1.2.1", From 7f6925a0fffb22a725a1cdaabdf4ff1091699747 Mon Sep 17 00:00:00 2001 From: Benjamin Piouffle Date: Sat, 17 Mar 2018 16:27:14 +1100 Subject: [PATCH 06/11] Fix woff2 content-type for prod --- config/mime.types | 1 + 1 file changed, 1 insertion(+) diff --git a/config/mime.types b/config/mime.types index d2b946e30..b65db8bd4 100644 --- a/config/mime.types +++ b/config/mime.types @@ -25,6 +25,7 @@ types { image/webp webp; application/font-woff woff; + application/font-woff2 woff2; application/x-font-ttf ttf; application/json json; application/pdf pdf; From 739d7ee0ece06979dc03de9a190ec9dc0f98cd07 Mon Sep 17 00:00:00 2001 From: Benjamin Piouffle Date: Sat, 17 Mar 2018 17:23:56 +1100 Subject: [PATCH 07/11] Various improvements * Show error on user's profile when not found * Made "Show answers" link more visible * Reduce required reputation for moderation (200) * Improve "Add first statement" tooltip message --- app/components/Comments/CommentDisplay.jsx | 3 ++- app/constants.js | 27 ++++++++++--------- app/i18n/en/videoDebate.js | 2 +- app/i18n/fr/videoDebate.js | 2 +- .../users/displayed_user/__tests__/effects.js | 14 +++------- app/state/users/displayed_user/effects.js | 6 ++--- app/state/users/displayed_user/reducer.js | 2 ++ app/styles/_components/comments.sass | 2 ++ 8 files changed, 28 insertions(+), 30 deletions(-) diff --git a/app/components/Comments/CommentDisplay.jsx b/app/components/Comments/CommentDisplay.jsx index 8237d9d69..56c07042a 100644 --- a/app/components/Comments/CommentDisplay.jsx +++ b/app/components/Comments/CommentDisplay.jsx @@ -77,7 +77,8 @@ export class CommentDisplay extends React.PureComponent {
    - + { t('menu.myBookmarks') } - + { t('menu.myActivity') }
@@ -153,7 +153,7 @@ export default class Sidebar extends React.PureComponent { { capitalize(t('entities.video_plural')) } - + { capitalize(t('entities.speaker_plural')) } @@ -166,6 +166,6 @@ export default class Sidebar extends React.PureComponent { } usernameFontSize() { - return `${1.5 - this.props.CurrentUser.username.length / 38}em` + return `${1.4 - this.props.CurrentUser.username.length / 40}em` } } diff --git a/app/components/Comments/CommentForm.jsx b/app/components/Comments/CommentForm.jsx index 25923f95b..a3d2aa729 100644 --- a/app/components/Comments/CommentForm.jsx +++ b/app/components/Comments/CommentForm.jsx @@ -76,8 +76,8 @@ export class CommentForm extends React.Component { if (!this.props.currentUser.id || this.state.isCollapsed && !replyTo) return (
@@ -93,17 +93,16 @@ export class CommentForm extends React.Component {
{replyTo &&
- + this.props.change('reply_to', null)}/> - {t('comment.replyingTo')}  - + {t('comment.replyingTo')} - -
} + if (!sourceUrl) return ( + - ]) + ) else return ([ - , - , - diff --git a/app/components/Comments/ModalFlag.jsx b/app/components/Comments/ModalFlag.jsx index 9c7049c53..5478f8dd2 100644 --- a/app/components/Comments/ModalFlag.jsx +++ b/app/components/Comments/ModalFlag.jsx @@ -13,10 +13,7 @@ const flagFormValueSelector = formValueSelector('flagForm') @connect(state => ({selectedReason: flagFormValueSelector(state, 'reason')})) @translate('videoDebate') export default class ModalFlag extends React.PureComponent { - constructor(props) { - super(props) - this.state = {isLoading: true, flagsAvailable: 0, error: null} - } + state = {isLoading: true, flagsAvailable: 0, error: null} componentDidMount() { HttpApi.get('users/me/available_flags') @@ -29,7 +26,6 @@ export default class ModalFlag extends React.PureComponent { render() { const { isLoading, flagsAvailable } = this.state const { t, handleAbort, selectedReason, comment, ...otherProps } = this.props - const availableStr = t('flagForm.xAvailable', {count: flagsAvailable}) return ( ) } + + renderConfirmText(t, flagsAvailable) { + return ( + + {t('main:actions.flag')} ({t('flagForm.xAvailable', {count: flagsAvailable})}) + + ) + } } diff --git a/app/components/Comments/Source.jsx b/app/components/Comments/Source.jsx index 7f8eef68c..3fe12f35b 100644 --- a/app/components/Comments/Source.jsx +++ b/app/components/Comments/Source.jsx @@ -25,14 +25,20 @@ const isPlayer = url => { return false } +const PLAYER_CONFIG = {youtube: {playerVars: { showinfo: 1 }}} + export const Source = ({ source: { url, title, site_name }, withoutPlayer }) => { if (!withoutPlayer && isPlayer(url)) { - return + return } else { return (
- + {upperCase(site_name) || getDisplayableHostname(url)} diff --git a/app/components/Comments/Vote.jsx b/app/components/Comments/Vote.jsx index 11be7adac..290a7db6e 100644 --- a/app/components/Comments/Vote.jsx +++ b/app/components/Comments/Vote.jsx @@ -1,21 +1,23 @@ import React from 'react' import classNames from 'classnames' -import { Icon } from '../Utils' +import ClickableIcon from '../Utils/ClickableIcon' const Vote = ({isVoting, score, myVote, onVote}) => (
- 0 })} - onClick={() => myVote <= 0 ? onVote(1) : onVote(0)}/> + onClick={() => myVote <= 0 ? onVote(1) : onVote(0)} + />
{isVoting ? : score}
- myVote >= 0 ? onVote(-1) : onVote(0)}/> + onClick={() => myVote >= 0 ? onVote(-1) : onVote(0)} + />
) diff --git a/app/components/FormUtils/index.jsx b/app/components/FormUtils/index.jsx index f2c9b7d2e..0c58155c6 100644 --- a/app/components/FormUtils/index.jsx +++ b/app/components/FormUtils/index.jsx @@ -71,18 +71,20 @@ export const renderFieldWithLabel = (params) => ( export const FieldWithButton = (params) => { const { submitting, invalid } = params.meta || {} - const { buttonClassName, buttonLabel, buttonClickHandler, ...inputProps } = params + const { buttonClassName, buttonLabel, buttonClickHandler, expandInput, ...inputProps } = params return ( -
-

+

+
{ renderInput(inputProps) } +
+
-

+
) } diff --git a/app/components/Modal/Modal.jsx b/app/components/Modal/Modal.jsx index 2a1c7ff21..c5afa9411 100644 --- a/app/components/Modal/Modal.jsx +++ b/app/components/Modal/Modal.jsx @@ -21,7 +21,7 @@ const Modal = ({
{helpLink && - + }
- +
) } diff --git a/app/components/Modal/ModalFormContainer.jsx b/app/components/Modal/ModalFormContainer.jsx index e3fc61954..ed63ed076 100644 --- a/app/components/Modal/ModalFormContainer.jsx +++ b/app/components/Modal/ModalFormContainer.jsx @@ -43,21 +43,22 @@ export class ModalFormContainer extends React.PureComponent { const isSubmitting = this.props.isSubmitting || this.state.isSubmitting return ( )} diff --git a/app/components/Pages/BrowserExtensionsPage.jsx b/app/components/Pages/BrowserExtensionsPage.jsx index 73ef16baa..3995cb925 100644 --- a/app/components/Pages/BrowserExtensionsPage.jsx +++ b/app/components/Pages/BrowserExtensionsPage.jsx @@ -44,11 +44,11 @@ export const BrowserExtensionsPage = translate('extension')(({t}) => ( const BrowserExtension = ({browser, image, buttonLabel, url, onClick, disabled=false}) => (
- +
{browser}/
- + {buttonLabel} diff --git a/app/components/Pages/Home.jsx b/app/components/Pages/Home.jsx index fcce21c22..a7fe34eb2 100644 --- a/app/components/Pages/Home.jsx +++ b/app/components/Pages/Home.jsx @@ -19,36 +19,27 @@ export class Home extends React.PureComponent {
-

+

Let's check the Internet

-
-
-

- {this.props.t('presentation1')} -

- CaptainFact {this.props.t('presentation2')} -

-
-

-
-

- {this.props.t('main:entities.video_plural')} - }/> - {this.props.authenticated ? '.' : - {this.props.t('creatingAnAccount')} - }/> - } -
-
-

-
+
+

+ {this.props.t('presentation1')} +

+ CaptainFact {this.props.t('presentation2')} +

+
+

+ {this.props.t('main:entities.video_plural')} + }/> +
+
+

@@ -62,14 +53,12 @@ export class Home extends React.PureComponent {
diff --git a/app/components/Speakers/SpeakerPage.jsx b/app/components/Speakers/SpeakerPage.jsx index da632fb48..c4b4d7e13 100644 --- a/app/components/Speakers/SpeakerPage.jsx +++ b/app/components/Speakers/SpeakerPage.jsx @@ -1,5 +1,6 @@ import React from "react" import { connect } from "react-redux" +import Helmet from 'react-helmet' import { SpeakerPreview } from './SpeakerPreview' import { fetchSpeaker, fetchWikiDataInfo } from '../../state/speakers/effects' @@ -54,6 +55,9 @@ export class SpeakerPage extends React.PureComponent { return return (
+ + {this.props.speaker.full_name} +
diff --git a/app/components/Speakers/SpeakerPreview.jsx b/app/components/Speakers/SpeakerPreview.jsx index b961e67f5..b085ba1a2 100644 --- a/app/components/Speakers/SpeakerPreview.jsx +++ b/app/components/Speakers/SpeakerPreview.jsx @@ -12,6 +12,7 @@ import { isAuthenticated } from "../../state/users/current_user/selectors" import { staticResource } from "../../API" import { ModalFormContainer } from "../Modal" import { Icon, LinkWithIcon } from "../Utils" +import ClickableIcon from '../Utils/ClickableIcon' import ReputationGuard from '../Utils/ReputationGuard' import { EditSpeakerForm } from "./SpeakerForm" import ModalRemoveSpeaker from './ModalRemoveSpeaker' @@ -29,67 +30,6 @@ import {getFocusedStatementSpeakerId} from '../../state/video_debate/statements/ {addModal, changeStatementFormSpeaker, removeSpeaker, updateSpeaker} ) export class SpeakerPreview extends React.PureComponent { - handleRemove() { - this.props.addModal({ - Modal: ModalRemoveSpeaker, - props: { - speaker: this.props.speaker, - handleConfirm: () => this.props.removeSpeaker(this.props.speaker) - } - }) - } - - handleEdit() { - this.props.addModal({ - Modal: ModalFormContainer, - props: { - title: `Edit ${this.props.speaker.full_name} information`, - FormComponent: EditSpeakerForm, - handleConfirm: (s) => this.props.updateSpeaker(s), - formProps: {initialValues: this.props.speaker.toJS()} - } - }) - } - - handleAddStatement() { - const historyRegex = new RegExp("/history/?$") - const currentPath = this.props.location.pathname - if (currentPath.match(historyRegex)) - this.props.router.push(currentPath.replace(historyRegex, "")) - this.props.changeStatementFormSpeaker({id: this.props.speaker.id}) - } - - renderSpeakerThumb(speaker) { - if (speaker.picture) - return () - return () - } - - getTitle() { - const { title, is_user_defined, country } = this.props.speaker - // Only translate if title exists and is not user defined - if (!title) - return '...' - else if (is_user_defined) - return title - - let i18nTitle = '' - if (this.props.i18n.language === 'en') // No need to translate title for english - i18nTitle = title - else { - // If unknown title, return raw title - const i18nTitleKey = `speaker.titles.${title}` - i18nTitle = this.props.t(i18nTitleKey) - if (i18nTitle === i18nTitleKey) - return title - } - // Try to return title + nationality, otherwise fallback on translated title - return this.props.t('speaker.titleFormat', { - title: i18nTitle, - context: country - }) - } - render() { const { speaker, isAuthenticated, withoutActions , className} = this.props @@ -100,7 +40,7 @@ export class SpeakerPreview extends React.PureComponent { content={
{this.renderName(speaker)} -

{this.getTitle()}

+

{this.getTitle()}

} right={isAuthenticated && !withoutActions && this.renderActions()} @@ -108,25 +48,31 @@ export class SpeakerPreview extends React.PureComponent { ) } + renderSpeakerThumb(speaker) { + if (speaker.picture) + return + return + } + renderActions() { return (
{this.props.speaker.is_user_defined && - this.handleEdit()}/> + this.handleEdit()}/> } - this.handleRemove()}/> + this.handleRemove()}/> - this.handleAddStatement()}/> + this.handleAddStatement()}/>
) @@ -134,11 +80,66 @@ export class SpeakerPreview extends React.PureComponent { renderName(speaker) { if (speaker.is_user_defined) - return
{speaker.full_name}
+ return
{speaker.full_name}
return ( - + {speaker.full_name} ) } + + getTitle() { + const { title, is_user_defined, country } = this.props.speaker + // Only translate if title exists and is not user defined + if (!title) + return '...' + else if (is_user_defined) + return title + + let i18nTitle = '' + if (this.props.i18n.language === 'en') // No need to translate title for english + i18nTitle = title + else { + // If unknown title, return raw title + const i18nTitleKey = `speaker.titles.${title}` + i18nTitle = this.props.t(i18nTitleKey) + if (i18nTitle === i18nTitleKey) + return title + } + // Try to return title + nationality, otherwise fallback on translated title + return this.props.t('speaker.titleFormat', { + title: i18nTitle, + context: country + }) + } + + handleRemove() { + this.props.addModal({ + Modal: ModalRemoveSpeaker, + props: { + speaker: this.props.speaker, + handleConfirm: () => this.props.removeSpeaker(this.props.speaker) + } + }) + } + + handleEdit() { + this.props.addModal({ + Modal: ModalFormContainer, + props: { + title: `Edit ${this.props.speaker.full_name} information`, + FormComponent: EditSpeakerForm, + handleConfirm: (s) => this.props.updateSpeaker(s), + formProps: {initialValues: this.props.speaker.toJS()} + } + }) + } + + handleAddStatement() { + const historyRegex = new RegExp("/history/?$") + const currentPath = this.props.location.pathname + if (currentPath.match(historyRegex)) + this.props.router.push(currentPath.replace(historyRegex, "")) + this.props.changeStatementFormSpeaker({id: this.props.speaker.id}) + } } diff --git a/app/components/Statements/Statement.jsx b/app/components/Statements/Statement.jsx index 89d50eab1..b753a6714 100644 --- a/app/components/Statements/Statement.jsx +++ b/app/components/Statements/Statement.jsx @@ -132,7 +132,12 @@ export class Statement extends React.PureComponent { } renderCommentsContainerHeader(label, tagType, score) { - return {this.props.t(label)} { score } + return ( +
+ {this.props.t(label)} + { score } +
+ ) } renderFactsAndComments() { @@ -141,7 +146,7 @@ export class Statement extends React.PureComponent { return (
{(approvingFacts.size > 0 || refutingFacts.size > 0) && -
+
{refutingFacts.size > 0 && {t('main:actions.save')} {t('main:actions.cancel')} diff --git a/app/components/Users/DeleteUserModal.jsx b/app/components/Users/DeleteUserModal.jsx index d0965aae0..df5a7c73b 100644 --- a/app/components/Users/DeleteUserModal.jsx +++ b/app/components/Users/DeleteUserModal.jsx @@ -16,7 +16,7 @@ class DeleteForm extends React.PureComponent {

- This action is irreversible. + This action is irreversible


Deleting your account will...

@@ -28,7 +28,7 @@ class DeleteForm extends React.PureComponent {
  • Anonymize your actions history

  • -
    Type your username below to confirm the deletion :
    +

    Type your username below to confirm the deletion :

    ) diff --git a/app/components/Users/InvitationRequestForm.jsx b/app/components/Users/InvitationRequestForm.jsx index 876a6a26d..1e8f76eea 100644 --- a/app/components/Users/InvitationRequestForm.jsx +++ b/app/components/Users/InvitationRequestForm.jsx @@ -23,10 +23,7 @@ const validate = ({email}) => { @translate('home') @connect(null, {addFlash, errorToFlash, requestInvitation}) export default class InvitationRequestForm extends React.PureComponent { - constructor(props) { - super(props) - this.state = {confirmed: false} - } + state = { confirmed: false } submit(user) { return this.props.requestInvitation(user) @@ -41,9 +38,12 @@ export default class InvitationRequestForm extends React.PureComponent { getContent() { if (!this.state.confirmed) - return + buttonLabel={this.props.t('main:actions.send')}/> else return ( diff --git a/app/components/Users/ScoreTag.jsx b/app/components/Users/ScoreTag.jsx index 25ebf1670..e49756bf9 100644 --- a/app/components/Users/ScoreTag.jsx +++ b/app/components/Users/ScoreTag.jsx @@ -13,7 +13,7 @@ function getTagType(reputation) { } const ScoreTag = ({reputation, size="small", withIcon=false}) => - + { withIcon && } { reputation } diff --git a/app/components/Users/ThirdPartyAuthList.jsx b/app/components/Users/ThirdPartyAuthList.jsx index ab8a3249e..35b34d938 100644 --- a/app/components/Users/ThirdPartyAuthList.jsx +++ b/app/components/Users/ThirdPartyAuthList.jsx @@ -11,9 +11,9 @@ const ThirdPartyAuthList = ({t, location: {query: {invitation_token}}}) => (

    {t('actionWithThirdParty')}

    - - - + + +
    ) diff --git a/app/components/Users/ThirdPartyServiceButton.jsx b/app/components/Users/ThirdPartyServiceButton.jsx index f43468d14..3df489594 100644 --- a/app/components/Users/ThirdPartyServiceButton.jsx +++ b/app/components/Users/ThirdPartyServiceButton.jsx @@ -4,9 +4,10 @@ import classNames from 'classnames' import { Icon } from "../Utils" -const ThirdPartyServiceButton = ({url, icon, className, newTab=false}) => ( +const ThirdPartyServiceButton = ({url, icon, className, newTab=false, ...props}) => ( + className={classNames("icon is-large third-party-service-button", className)} + {...props}> ) diff --git a/app/components/Users/User.jsx b/app/components/Users/User.jsx index eed1054c6..8b4564c26 100644 --- a/app/components/Users/User.jsx +++ b/app/components/Users/User.jsx @@ -51,7 +51,7 @@ export default class User extends React.PureComponent { return (
  • - + {this.props.t(menuTKey)} diff --git a/app/components/Users/UserFormFields.jsx b/app/components/Users/UserFormFields.jsx index ce579730a..3c4373c02 100644 --- a/app/components/Users/UserFormFields.jsx +++ b/app/components/Users/UserFormFields.jsx @@ -40,9 +40,8 @@ export const passwordRepeatField = (t) => export const submitButton = (text, valid) =>

    -

    diff --git a/app/components/Users/UserSettings.jsx b/app/components/Users/UserSettings.jsx index 37c345478..7ad80ea90 100644 --- a/app/components/Users/UserSettings.jsx +++ b/app/components/Users/UserSettings.jsx @@ -15,9 +15,15 @@ import { LoadingFrame } from '../Utils/LoadingFrame' class ThirdPartyAccountLinker extends React.PureComponent { render() { return ( -

    - - {this.props.isLinked ? this.renderUnlinkAccount() : this.renderLinkAccount()} +

    +

    +
    + {this.props.title} +
    +
    +
    + {this.props.isLinked ? this.renderUnlinkAccount() : this.renderLinkAccount()} +

    ) } @@ -55,7 +61,9 @@ export default class UserSettings extends React.PureComponent {

    {this.props.t('linkedAccounts')}

    -
    diff --git a/app/components/UsersActions/ActionsTable.jsx b/app/components/UsersActions/ActionsTable.jsx index dba318853..dddb10a62 100644 --- a/app/components/UsersActions/ActionsTable.jsx +++ b/app/components/UsersActions/ActionsTable.jsx @@ -54,7 +54,7 @@ class ActionsTable extends React.PureComponent { {showEntity && {t('entity')}} {this.renderCompareAllButton(isMostlyComparing)} {canRestore && {t('revert')}} - {t('moderation')} + {/*{t('moderation')}*/} ) } @@ -115,16 +115,16 @@ class ActionsTable extends React.PureComponent { } } - - - - {t('main:actions.approve')} -    - - - {t('main:actions.flag')} - - + {/**/} + {/**/} + {/**/} + {/*{t('main:actions.approve')}*/} + {/*  */} + {/**/} + {/**/} + {/*{t('main:actions.flag')}*/} + {/**/} + {/**/} ) } diff --git a/app/components/Utils/ClickableIcon.jsx b/app/components/Utils/ClickableIcon.jsx new file mode 100644 index 000000000..1302ce9c1 --- /dev/null +++ b/app/components/Utils/ClickableIcon.jsx @@ -0,0 +1,15 @@ +import React from "react" +import classNames from 'classnames' + + +export const ClickableIcon = ({name, size, className, ...otherProps}) => { + const sizeClass = size && `is-${size}` + + return ( + + + + ) +} + +export default ClickableIcon \ No newline at end of file diff --git a/app/components/Utils/LoadingFrame.jsx b/app/components/Utils/LoadingFrame.jsx index fcec2d618..03682ba7b 100644 --- a/app/components/Utils/LoadingFrame.jsx +++ b/app/components/Utils/LoadingFrame.jsx @@ -11,7 +11,9 @@ export class LoadingFrame extends React.PureComponent { return (
    -

    {title || this.props.t('actions.loading')}...

    +
    + {title || this.props.t('actions.loading')}... +
    ) } diff --git a/app/components/Utils/ShareModal.jsx b/app/components/Utils/ShareModal.jsx index 095c42455..79b139e10 100644 --- a/app/components/Utils/ShareModal.jsx +++ b/app/components/Utils/ShareModal.jsx @@ -27,12 +27,11 @@ export default class ShareModal extends React.PureComponent { buttonClassName="is-medium" buttonLabel={} buttonClickHandler={this.copyUrlToClipboard.bind(this)} - /> + expandInput/>
    - diff --git a/app/components/Utils/TimeSince.jsx b/app/components/Utils/TimeSince.jsx index b97db2be3..8a14e53c1 100644 --- a/app/components/Utils/TimeSince.jsx +++ b/app/components/Utils/TimeSince.jsx @@ -19,6 +19,21 @@ export class TimeSince extends React.PureComponent { this.timeoutUpdate() } + componentWillUnmount() { + this.clearTimeout() + } + + render() { + const { time, locale, dispatch, addSuffix=true, isDateTime=true, ...props } = this.props + const localeObj = locales[locale] + const dateFormat = isDateTime ? localeObj.defaultDateTimeFormat : localeObj.defaultDateFormat + return ( + + { distanceInWordsToNow(time, {addSuffix: addSuffix, locale: localeObj}) } + + ) + } + timeoutUpdate() { const secondsSince = !this.props.time ? 0 : differenceInSeconds(Date.now(), this.props.time) const minutesSince = Math.trunc(secondsSince / 60) @@ -35,10 +50,6 @@ export class TimeSince extends React.PureComponent { this.timeout = setTimeout(this.timeoutUpdate, (60 - (minutesSince % 60)) * 60 * 1000) } - componentWillUnmount() { - this.clearTimeout() - } - clearTimeout() { if (this.timeout) clearTimeout(this.timeout) @@ -48,15 +59,4 @@ export class TimeSince extends React.PureComponent { static getMinutesSince(time) { return !time ? 0 : Math.trunc(differenceInSeconds(Date.now(), time) / 60) } - - render() { - const { time, locale, dispatch, addSuffix=true, isDateTime=true, ...props } = this.props - const localeObj = locales[locale] - const dateFormat = isDateTime ? localeObj.defaultDateTimeFormat : localeObj.defaultDateFormat - return ( - - { distanceInWordsToNow(time, {addSuffix: addSuffix, locale: localeObj}) } - - ) - } } \ No newline at end of file diff --git a/app/components/VideoDebate/ActionBubbleMenu.jsx b/app/components/VideoDebate/ActionBubbleMenu.jsx index 717c9d945..3f4c16076 100644 --- a/app/components/VideoDebate/ActionBubbleMenu.jsx +++ b/app/components/VideoDebate/ActionBubbleMenu.jsx @@ -3,7 +3,6 @@ import classNames from 'classnames' import { connect } from 'react-redux' import { withRouter } from 'react-router' import { translate } from 'react-i18next' -import debounce from 'debounce' import { MIN_REPUTATION_UPDATE_VIDEO } from '../../constants' import { changeStatementFormSpeaker } from '../../state/video_debate/statements/reducer' diff --git a/app/components/VideoDebate/ColumnVideo.jsx b/app/components/VideoDebate/ColumnVideo.jsx index 61dcf011b..581733388 100644 --- a/app/components/VideoDebate/ColumnVideo.jsx +++ b/app/components/VideoDebate/ColumnVideo.jsx @@ -27,22 +27,24 @@ export class ColumnVideo extends React.PureComponent { const { video, view, t } = this.props const { url, title, speakers } = video + const isDebate = view === "debate" + return (
    -

    {title}

    +

    {title}

      -
    • +
    • { t('debate') }
    • -
    • +
    • { t('history') } @@ -50,16 +52,20 @@ export class ColumnVideo extends React.PureComponent {
    - -
    - + {isDebate && +
    + +
    + +
    +
    +
    + {speakers.map(speaker => + + )} +
    - -
    - {speakers.map(speaker => - - )} -
    + }
    ) } diff --git a/app/components/VideoDebate/Presence.jsx b/app/components/VideoDebate/Presence.jsx index c0bca5cbf..84fb9cabb 100644 --- a/app/components/VideoDebate/Presence.jsx +++ b/app/components/VideoDebate/Presence.jsx @@ -8,11 +8,11 @@ import Tag from '../Utils/Tag' const Presence = ({t, nbUsers, nbViewers}) =>
    - + {t('presence.user', {count: nbUsers})} - + {t('presence.viewer', {count: nbViewers})} diff --git a/app/components/VideoDebate/VideoDebateHistory.jsx b/app/components/VideoDebate/VideoDebateHistory.jsx index 14c32a0a8..e52be211a 100644 --- a/app/components/VideoDebate/VideoDebateHistory.jsx +++ b/app/components/VideoDebate/VideoDebateHistory.jsx @@ -26,10 +26,8 @@ export default class VideoDebateHistory extends React.PureComponent { return (
    -
    - { error && error } - -
    + { error && error } +
    ) } diff --git a/app/components/Videos/AddVideoForm.jsx b/app/components/Videos/AddVideoForm.jsx index fc9cfa8b7..0fe873547 100644 --- a/app/components/Videos/AddVideoForm.jsx +++ b/app/components/Videos/AddVideoForm.jsx @@ -44,6 +44,7 @@ export class AddVideoForm extends React.PureComponent { buttonLabel="Add Video" placeholder="Video URL" buttonClassName="is-primary" normalize={s => trim(s)} + expandInput />
    diff --git a/app/components/Videos/EditVideoModal.jsx b/app/components/Videos/EditVideoModal.jsx index a7ff8b7c3..a240b82a4 100644 --- a/app/components/Videos/EditVideoModal.jsx +++ b/app/components/Videos/EditVideoModal.jsx @@ -13,8 +13,11 @@ import {shiftStatements} from '../../state/video_debate/statements/effects' const TimeShiftForm = reduxForm({form: 'shiftStatements', initialValues: {offset: 0}})(translate('main')( ({handleSubmit, t}) => -
    - + !offset}/> @@ -25,7 +28,8 @@ const TimeShiftForm = reduxForm({form: 'shiftStatements', initialValues: {offset export default class EditVideoModal extends React.PureComponent { render() { return ( - {this.props.t('video.edit')}}>

    {this.props.t('video.shiftStatements')}

    diff --git a/app/components/Videos/PublicVideos.jsx b/app/components/Videos/PublicVideos.jsx index 66de0e341..53fdce78a 100644 --- a/app/components/Videos/PublicVideos.jsx +++ b/app/components/Videos/PublicVideos.jsx @@ -38,8 +38,8 @@ export class PublicVideos extends React.PureComponent {

    - - {capitalize(this.props.t('entities.video_plural'))} + + {capitalize(this.props.t('entities.video_plural'))}

    hasReputation || user.is_publisher}> @@ -49,17 +49,15 @@ export class PublicVideos extends React.PureComponent {
    -
    - {this.renderFilterBar()} - {this.renderContent()} -
    + {this.renderFilterBar()} + {this.renderContent()}
    ) } renderFilterBar() { return ( -
    diff --git a/app/components/Utils/Icon.jsx b/app/components/Utils/Icon.jsx index 02cddc7e7..869f20257 100644 --- a/app/components/Utils/Icon.jsx +++ b/app/components/Utils/Icon.jsx @@ -1,19 +1,15 @@ import React from "react" import classNames from 'classnames' +import RawIcon from './RawIcon' -export const Icon = ({name, size, withContainer=true, className, isClickable, ...otherProps}) => { +export const Icon = ({name, size, className, ...otherProps}) => { const sizeClass = size && `is-${size}` - const icon = - if (!withContainer) - return icon - - const Container = isClickable ? 'a' : 'span' return ( - - {icon} - + + + ) } diff --git a/app/components/Utils/LinkWithIcon.jsx b/app/components/Utils/LinkWithIcon.jsx index 1aa0d860e..c49f226f6 100644 --- a/app/components/Utils/LinkWithIcon.jsx +++ b/app/components/Utils/LinkWithIcon.jsx @@ -3,11 +3,12 @@ import { Link } from 'react-router' import classNames from 'classnames' import { Icon } from './Icon' +import RawIcon from './RawIcon' export const LinkWithIcon = ({to, iconName, children, className, ...props}) => ( - + {children} ) diff --git a/app/components/Utils/RawIcon.jsx b/app/components/Utils/RawIcon.jsx new file mode 100644 index 000000000..dbcfcc7f9 --- /dev/null +++ b/app/components/Utils/RawIcon.jsx @@ -0,0 +1,7 @@ +import React from 'react' + + +export const RawIcon = ({name}) => + + +export default RawIcon \ No newline at end of file diff --git a/app/components/Utils/__tests__/Icon.spec.jsx b/app/components/Utils/__tests__/Icon.spec.jsx index 57e6107e8..3c81d448d 100644 --- a/app/components/Utils/__tests__/Icon.spec.jsx +++ b/app/components/Utils/__tests__/Icon.spec.jsx @@ -8,14 +8,6 @@ test("set size", () => { snapshot() }) -test("render without container", () => { - snapshot() -}) - -test("use 'a' if is link", () => { - snapshot() -}) - test("other props get passed to container", () => { snapshot() }) \ No newline at end of file diff --git a/app/components/Utils/__tests__/RawIcon.spec.jsx b/app/components/Utils/__tests__/RawIcon.spec.jsx new file mode 100644 index 000000000..a4816ea75 --- /dev/null +++ b/app/components/Utils/__tests__/RawIcon.spec.jsx @@ -0,0 +1,5 @@ +import RawIcon from '../RawIcon' + +test("render icon", () => { + snapshot() +}) diff --git a/app/components/Utils/__tests__/__snapshots__/Icon.spec.jsx.snap b/app/components/Utils/__tests__/__snapshots__/Icon.spec.jsx.snap index 542c89b21..63203b6b5 100644 --- a/app/components/Utils/__tests__/__snapshots__/Icon.spec.jsx.snap +++ b/app/components/Utils/__tests__/__snapshots__/Icon.spec.jsx.snap @@ -5,8 +5,8 @@ exports[`other props get passed to container 1`] = ` className="icon" title="Add some stuff" > - `; @@ -15,34 +15,18 @@ exports[`render icon 1`] = ` - `; -exports[`render without container 1`] = ` - -`; - exports[`set size 1`] = ` - `; - -exports[`use 'a' if is link 1`] = ` - - - -`; diff --git a/app/components/Utils/__tests__/__snapshots__/RawIcon.spec.jsx.snap b/app/components/Utils/__tests__/__snapshots__/RawIcon.spec.jsx.snap new file mode 100644 index 000000000..61f234c09 --- /dev/null +++ b/app/components/Utils/__tests__/__snapshots__/RawIcon.spec.jsx.snap @@ -0,0 +1,7 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`render icon 1`] = ` + +`; diff --git a/app/components/Videos/VideoCard.jsx b/app/components/Videos/VideoCard.jsx index a5985bc21..a6c4adfb1 100644 --- a/app/components/Videos/VideoCard.jsx +++ b/app/components/Videos/VideoCard.jsx @@ -5,6 +5,7 @@ import { Icon, TimeSince } from "../Utils" import iterateWithSeparators from '../../lib/iterate_with_separators' import { translate } from 'react-i18next' import CardLayout from '../Utils/CardLayout' +import RawIcon from '../Utils/RawIcon' @translate('main') @@ -47,7 +48,7 @@ export class VideoCard extends React.PureComponent { image={
    - +
    diff --git a/app/styles/_components/Speakers/speaker_preview.sass b/app/styles/_components/Speakers/speaker_preview.sass index a35d9a39a..86ab21ba1 100644 --- a/app/styles/_components/Speakers/speaker_preview.sass +++ b/app/styles/_components/Speakers/speaker_preview.sass @@ -14,7 +14,3 @@ border-radius: 25px width: 50px height: 50px - - .quick-actions .icon - font-size: 1.60em - margin: 0 0.15em \ No newline at end of file diff --git a/app/styles/_components/Utils/icons.sass b/app/styles/_components/Utils/icons.sass index 2cdf2be6e..81f0bbc9b 100644 --- a/app/styles/_components/Utils/icons.sass +++ b/app/styles/_components/Utils/icons.sass @@ -29,6 +29,11 @@ .icon.is-medium i font-size: 1.5rem +.icon.is-action-size + font-size: 1.5em + width: 1.25em + height: 1.25em + .icon.is-large i font-size: 3rem diff --git a/app/styles/_components/modal.sass b/app/styles/_components/modal.sass index 923d41288..bf75ea4b5 100644 --- a/app/styles/_components/modal.sass +++ b/app/styles/_components/modal.sass @@ -22,6 +22,9 @@ $modal-background: rgba(10, 10, 10, 0.50) &:hover color: #aeaeae +.modal-card + @include animate(fadeInDown, 0.4s) + .modal.is-small font-size: 0.8em .modal-card-head diff --git a/app/styles/_components/statements.sass b/app/styles/_components/statements.sass index 7f5f9506c..e0047dc66 100644 --- a/app/styles/_components/statements.sass +++ b/app/styles/_components/statements.sass @@ -31,10 +31,8 @@ $statement-text-color: #e0e7f1 height: 25px margin-right: 5px border-radius: 15px - .link-with-icon - font-size: 15px - &:not(:last-child) - margin-right: 0.3em + .card-header-icon + font-size: .9em .time-display min-width: 60px color: grey From 27df8dbfeafd5bcc9f4dcd2b84ab3938901d1f39 Mon Sep 17 00:00:00 2001 From: Benjamin Piouffle Date: Sun, 25 Mar 2018 20:02:28 +1100 Subject: [PATCH 11/11] Bump version to 0.8.6 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 0a5df9c8c..39534cbe4 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "captain-fact-frontend", - "version": "0.8.5", + "version": "0.8.6", "private": true, "scripts": { "start": "brunch watch --server",