Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature unsubscribe page, resizable video column and bubble menu improvements #44

Merged
merged 6 commits into from
Dec 7, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion app/assets/assets/locales/en/user.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,5 +23,9 @@
"emailConfirmed": "Email confirmed",
"linkedAccounts": "Linked accounts",
"linkAccount": "Link account",
"unlinkAccount": "Unlink account"
"unlinkAccount": "Unlink account",
"newsletter": {
"unsubscribe_success": "You've been unsubscribed from our newsletter",
"unsubscribe_error": "Given token seems invalid. If the problem persist, contact us"
}
}
7 changes: 4 additions & 3 deletions app/assets/assets/locales/en/videoDebate.json
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,10 @@
"textPlaceholder": "Type a raw transcript of what the speaker says",
"noSpeakerTextPlaceholder": "Describe what you see or select a speaker",
"text": "Text",
"add": "Add a statement",
"autoscroll_enable": "Enable autoscroll",
"autoscroll_disable": "Disable autoscroll",
"add": "Add a Statement",
"abortAdd": "Close Statement Form",
"autoscroll_enable": "Enable Autoscroll",
"autoscroll_disable": "Disable Autoscroll",
"reverseTimeLock_lock": "Unlock time marker",
"reverseTimeLock_unlock": "Lock time marker"
},
Expand Down
6 changes: 5 additions & 1 deletion app/assets/assets/locales/fr/user.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,5 +23,9 @@
"emailConfirmed": "Email confirmé",
"linkedAccounts": "Comptes liés",
"linkAccount": "Lier le compte",
"unlinkAccount": "Délier le compte"
"unlinkAccount": "Délier le compte",
"newsletter": {
"unsubscribe_success": "Désinscription de la newsletter enregistrée !",
"unsubscribe_error": "Erreur lors de la desinscription, le code est probablement invalide. Si le problème persiste, contactez nous"
}
}
1 change: 1 addition & 0 deletions app/assets/assets/locales/fr/videoDebate.json
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@
"noSpeakerTextPlaceholder": "Décrivez ce qui apparait à l'image ou ajoutez un intervenant",
"text": "Le texte",
"add": "Ajouter une citation",
"abortAdd": "Annuler l'ajout de citation",
"autoscroll_enable": "Activer le scroll automatique",
"autoscroll_disable": "Désactiver le scroll automatique",
"reverseTimeLock_lock": "Déverrouiller la position",
Expand Down
4 changes: 2 additions & 2 deletions app/components/Speakers/SpeakerPreview.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,8 @@ export class SpeakerPreview extends React.PureComponent {

renderSpeakerThumb(speaker) {
if (speaker.picture)
return (<img src={staticResource(speaker.picture)}/>)
return (<Icon name="user" size="large" style={{color: "grey"}}/>)
return (<img className="speaker-picture" src={staticResource(speaker.picture)}/>)
return (<Icon className="speaker-picture" name="user" size="large" style={{color: "grey"}}/>)
}

getTitle() {
Expand Down
6 changes: 3 additions & 3 deletions app/components/Statements/StatementForm.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,14 @@ const validate = ({text, time}, {t}) => {
return errors
}

const SpeakersSelect = ({input, speakers}) => {
const SpeakersSelect = ({input, speakers, label}) => {
return (
<Select className="speaker-select"
onChange={s => s && s.id ? input.onChange(s.id) : input.onChange(null)}
onBlur={() => input.onBlur(input.value.id)}
value={input.value}
name={input.name}
placeholder="Select Speaker..."
placeholder={label}
labelKey="full_name"
valueKey="id"
ignoreAccents={true}
Expand Down Expand Up @@ -113,7 +113,7 @@ export class StatementForm extends React.PureComponent {
<Icon size="small" name={toggleTimeLockAction}/>
</a>
{speaker && speaker.picture && <img className="speaker-mini" src={staticResource(speaker.picture)}/>}
<Field name="speaker_id" component={SpeakersSelect} speakers={speakers}/>
<Field name="speaker_id" component={SpeakersSelect} speakers={speakers} label={t('speaker.add')}/>
</div>
</header>
<div className="card-content">
Expand Down
35 changes: 35 additions & 0 deletions app/components/Users/NewsletterSubscription.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import React from 'react'
import { translate } from 'react-i18next'

import Notification from '../Utils/Notification'
import { HttpApi } from '../../API'
import { LoadingFrame } from '../Utils/LoadingFrame'


@translate('user')
export default class NewsletterSubscription extends React.PureComponent {
constructor(props) {
super(props)
this.state = {status: 'loading'}
}

componentDidMount() {
// Send request
HttpApi.get(`newsletter/unsubscribe/${this.props.params.token}`)
.then(() => this.setState({status: 'success'}))
.catch(() => this.setState({status: 'error'}))
}

render() {
if (this.state.status === 'loading')
return <LoadingFrame/>
const cssType = this.state.status === 'success' ? this.state.status : 'danger'
return (
<div className="container">
<Notification type={cssType} style={{maxWidth: 400, margin: '3em auto'}}>
{this.props.t('newsletter.unsubscribe', {context: this.state.status})}
</Notification>
</div>
)
}
}
4 changes: 2 additions & 2 deletions app/components/Users/SignupForm.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ export default withRouter(translate('user')(SignupForm))
@translate('user')
@reduxForm({form: 'signupForm', validate: validatePasswordRepeat})
@connect(
({CurrentUser: {data}}) => ({CurrentUser: data}),
({CurrentUser: {data}, UserPreferences: {locale}}) => ({CurrentUser: data, locale}),
{register, requestInvitation, errorToFlash}
)
class RealSignupForm extends React.PureComponent {
Expand All @@ -57,7 +57,7 @@ class RealSignupForm extends React.PureComponent {
}

submit({invitation_token, ...user}) {
return this.props.register({invitation_token, user})
return this.props.register({invitation_token, user: {...user, locale: this.props.locale}})
.then(handleFormEffectResponse({
onError: msg => typeof(msg) === 'string' ? this.props.errorToFlash(msg) : null
}))
Expand Down
4 changes: 2 additions & 2 deletions app/components/Utils/Notification.jsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React from 'react'

const Notification = ({children, type='info'}) =>
<div className={`notification is-${type}`}>
const Notification = ({children, type='info', ...otherProps}) =>
<div className={`notification is-${type}`} {...otherProps}>
{children}
</div>

Expand Down
31 changes: 25 additions & 6 deletions app/components/VideoDebate/ActionBubbleMenu.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,17 @@ import {isAuthenticated} from '../../state/users/current_user/selectors'
import { Icon } from '../Utils/Icon'
import ShareModal from '../Utils/ShareModal'
import EditVideoModal from '../Videos/EditVideoModal'
import { hasStatementForm } from '../../state/video_debate/statements/selectors'
import { destroyStatementForm } from '../../state/video_debate/statements/effects'


@connect(
state => ({hasAutoscroll: state.UserPreferences.enableAutoscroll, isAuthenticated: isAuthenticated(state)}),
{changeStatementFormSpeaker, toggleAutoscroll, addModal}
state => ({
hasAutoscroll: state.UserPreferences.enableAutoscroll,
isAuthenticated: isAuthenticated(state),
hasStatementForm: hasStatementForm(state)
}),
{changeStatementFormSpeaker, toggleAutoscroll, addModal, destroyStatementForm}
)
@translate(['videoDebate', 'main'])
@withRouter
Expand All @@ -39,15 +45,21 @@ export default class ActionBubbleMenu extends React.PureComponent {

render() {
return (
<div className={classNames("action-bubble-container", {active: this.state.active})}
<div className={classNames("action-bubble-container", {active: this.state.active, hasForm: this.props.hasStatementForm})}
onMouseEnter={this.activate}
onMouseLeave={() => this.setState({active: false})}
onTouchStart={this.activate}
>
{!this.props.isAuthenticated &&
<ActionBubble iconName="sign-in" label={this.props.t('main:menu.loginSignup')}
onClick={() => this.props.router.push('/login')}
/>
}
{this.props.isAuthenticated &&
<ActionBubble iconName="commenting-o"
label={this.props.t('statement.add')}
onClick={() => this.state.active ? this.addStatement() : null}
<ActionBubble iconName={this.props.hasStatementForm ? 'times' : "commenting-o"}
label={this.props.t(this.props.hasStatementForm ? 'statement.abortAdd' : 'statement.add')}
activated={!this.props.hasStatementForm}
onClick={() => this.onStatementBubbleClick()}
/>
}
<ActionBubble iconName="arrows-v"
Expand Down Expand Up @@ -77,6 +89,13 @@ export default class ActionBubbleMenu extends React.PureComponent {
</div>
)
}

onStatementBubbleClick() {
if (this.props.hasStatementForm)
this.props.destroyStatementForm()
else if (this.state.active)
this.addStatement()
}
}

const ActionBubble = ({iconName, label, activated=true, ...props}) => (
Expand Down
4 changes: 2 additions & 2 deletions app/i18n.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@ i18n
prefix: '_translations',
expirationTime: 48*60*60*1000, // 48h
versions: {
en: "0.7.2a",
fr: "0.7.2a"
en: "0.7.3",
fr: "0.7.3"
}
},
detection: {
Expand Down
2 changes: 2 additions & 0 deletions app/router.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import ResetPasswordRequestForm from './components/Users/ResetPasswordRequestFor
import ResetPasswordConfirmForm from './components/Users/ResetPasswordConfirmForm'
import ConfirmEmail from './components/Users/ConfirmEmail'
import { SpeakerPage } from './components/Speakers/SpeakerPage'
import NewsletterSubscription from './components/Users/NewsletterSubscription'


ReactDOM.render(
Expand All @@ -43,6 +44,7 @@ ReactDOM.render(
<Route path="/confirm_email/:token" component={ConfirmEmail}/>
<Route path="/reset_password" component={ResetPasswordRequestForm}/>
<Route path="/reset_password/confirm/:token" component={ResetPasswordConfirmForm}/>
<Route path="/newsletter/unsubscribe/:token" component={NewsletterSubscription}/>
<Route path="/u/:username" component={User}>
<IndexRoute component={UserProfile}/>
<Route path="/u/:username/activity" component={NotFound}/>
Expand Down
3 changes: 3 additions & 0 deletions app/state/video_debate/statements/effects.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { destroy } from 'redux-form'

import { SocketApi } from "../../../API"
import { STATEMENTS_CHANNEL } from "../../../constants"
import { add, fetchStatements, remove, setLoading, setSubmitting, update, updateAll } from './reducer'
Expand Down Expand Up @@ -45,3 +47,4 @@ export const shiftStatements = offset => createEffect(
{catch: errorToFlash}
)

export const destroyStatementForm = () => destroy('StatementForm')
2 changes: 1 addition & 1 deletion app/styles/_components/Speakers/speaker_preview.sass
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
.title
display: block

.media-left > img
.speaker-picture
border-radius: 25px
width: 50px
height: 50px
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,11 @@ $sub-bubble-icon-size: 24px
width: $main-bubble-height
background: $secondary
border-radius: 3em
box-shadow: 0px 3px 6px 0px transparentize($grey, 0.4)
box-shadow: 0 3px 6px 0 transparentize($grey, 0.4)
transition: box-shadow 0.3s, background 0.3s
&:hover
cursor: pointer
box-shadow: 0px 3px 6px 0px transparentize($grey, 0.2)
box-shadow: 0 3px 6px 0 transparentize($grey, 0.2)
.label
@include animate(fadeIn, 0.2s)
display: block
Expand Down Expand Up @@ -52,7 +52,7 @@ $sub-bubble-icon-size: 24px
.action-bubble:not(.activated)
background: $grey-light

.action-bubble-container:not(:hover):not(.active) .action-bubble:first-child
.action-bubble-container:not(:hover):not(.active):not(.hasForm) .action-bubble:first-child
i
transform: rotate(-360deg)
&:before
Expand Down
2 changes: 1 addition & 1 deletion app/styles/_components/VideoDebate/speaker_preview.sass
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ $speakingBoxShadowColor: transparentize($primary-darker, 0.4)
padding: 10px 15px
margin: 0
border-top: 1px solid rgba(219, 219, 219, 0.5)
&.isActive img
&.isActive .speaker-picture
animation: speakingPulse 2s infinite
.link-with-icon > i
font-size: 25px
4 changes: 3 additions & 1 deletion app/styles/_components/VideoDebate/video_debate.sass
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,10 @@
height: 100vh
overflow-y: auto
#col-video
resize: horizontal
padding-bottom: 25px
max-width: 600px
max-width: 60%
width: 36%

#col-debate
background: rgb(246, 247, 250)
Expand Down
4 changes: 2 additions & 2 deletions app/styles/_components/statements.sass
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ $statement-text-color: #e0e7f1
.statement-container
padding: 15px 0
&.is-focused .statement
box-shadow: 0px 0px 10px 5px rgba(197, 197, 197, 0.32)
box-shadow: 0px 0px 20px 0px rgb(148, 148, 148)
max-width: $statement-max-width
.statement
@include animate(fadeIn, 0.2s)
Expand Down Expand Up @@ -57,7 +57,7 @@ $statement-text-color: #e0e7f1
.button
margin-right: 10px
.speaker-select
min-width: 200px
min-width: 235px
.time-display
border: none
padding-right: 0
Expand Down
2 changes: 1 addition & 1 deletion app/styles/application.sass
Original file line number Diff line number Diff line change
Expand Up @@ -61,11 +61,11 @@
@import "_components/form"
@import "_components/invitation_request_form"
@import "_components/Utils/flash_messages"
@import "_components/action_bubble_menu"
@import "_components/Videos/card"
@import "_components/Videos/page"
@import "_components/Videos/player"
@import "_components/modal"
@import "_components/VideoDebate/action_bubble_menu"
@import "_components/VideoDebate/video_debate"
@import "_components/VideoDebate/history"
@import "_components/VideoDebate/speaker_preview"
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "captain-fact-frontend",
"version": "0.7.2",
"version": "0.7.3",
"private": true,
"scripts": {
"start": "brunch watch --server",
Expand Down