Skip to content

Commit

Permalink
Merge pull request #44 from CaptainFact/feature/newsletter-unsubscribe
Browse files Browse the repository at this point in the history
Feature unsubscribe page, resizable video column and bubble menu improvements
  • Loading branch information
Betree committed Dec 7, 2017
2 parents 0ca757d + 3627118 commit 7b9c1fa
Show file tree
Hide file tree
Showing 20 changed files with 103 additions and 32 deletions.
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

0 comments on commit 7b9c1fa

Please sign in to comment.