Skip to content
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
1,916 changes: 958 additions & 958 deletions package-lock.json

Large diffs are not rendered by default.

4 changes: 3 additions & 1 deletion src/components/BtnGroup/BtnGroup.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,9 @@ class BtnGroup extends React.Component {
<button
key={item.value}
className={cn('tc-btn tc-btn-sm tc-btn-default', { active: item.value === this.state.value })}
onClick={() => {
onClick={(evt) => {
// prevent parent form to be submitted
evt.preventDefault()
if (item.value !== this.state.value) {
this.setState({ value: item.value })
if (this.props.onChange) {
Expand Down
18 changes: 14 additions & 4 deletions src/components/BtnGroup/BtnGroup.scss
Original file line number Diff line number Diff line change
Expand Up @@ -6,24 +6,34 @@
> .tc-btn {
border-radius: 0;
border-left-width: 0;
margin: 0;
}

> .tc-btn:first-child {
border-radius: 2 * $corner-radius 0 0 2 * $corner-radius;
border-left-width: 1px;
}

> .tc-btn:last-child {
border-radius: 0 2 * $corner-radius 2 * $corner-radius 0;
}

> .tc-btn.active,
> .tc-btn.active:hover,
> .tc-btn.active:active {
background: $tc-gray-20;
box-shadow: inset 0 1px 3px 0 rgba($tc-gray-80, 0.38);
cursor: default;
}

@media screen and (max-width: $screen-md - 1px) {
> .tc-btn,
> .tc-btn:first-child,
> .tc-btn:last-child {
border-radius: 2 * $corner-radius;
border-width: 1px;
margin: 5px;
}
}
}
}

8 changes: 8 additions & 0 deletions src/config/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -399,3 +399,11 @@ export const SCREEN_BREAKPOINT_RG = 992
export const SCREEN_BREAKPOINT_MD = 768
export const SCREEN_BREAKPOINT_SM = 640
export const SCREEN_BREAKPOINT_XS = 320

export const NOTIFICATION_SETTINGS_PERIODS = [
{ text: 'Send as they happen', value: 'immediately' },
{ text: 'Every 10m.', value: 'every10minutes' },
{ text: 'Hourly', value: 'hourly' },
{ text: 'Daily', value: 'daily' },
{ text: 'Weekly', value: 'weekly' },
]
2 changes: 0 additions & 2 deletions src/routes/settings/components/SettingsPanel.scss
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,9 @@
.settings-panel {
margin: 20px auto 0;
padding: 0 20px;
min-width: 960px;

@media screen and (max-width: $screen-md - 1px) {
margin: 0;
min-width: 0;
padding: 0;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,11 @@ import React from 'react'
import PropTypes from 'prop-types'
import FormsyForm from 'appirio-tech-react-components/components/Formsy'
const Formsy = FormsyForm.Formsy
import { NOTIFICATION_SETTINGS_PERIODS } from '../../../../../config/constants'
import SwitchButton from 'appirio-tech-react-components/components/SwitchButton/SwitchButton'
import BtnGroup from '../../../../../components/BtnGroup/BtnGroup'
import IconSettingsWeb from '../../../../../assets/icons/settings-icon-web.svg'
import IconSettingsEmail from '../../../../../assets/icons/settings-icon-mail.svg'
import './NotificationSettingsForm.scss'
import _ from 'lodash'

Expand Down Expand Up @@ -78,22 +80,28 @@ const topics = [
*/
const initSettings = (notInitedSettings) => {
const settings = {...notInitedSettings}
const notifications = {...settings.notifications}
const allTypes = _.flatten(_.map(topics, 'types'))

allTypes.forEach((type) => {
if (!settings[type]) {
settings[type] = {}
if (!notifications[type]) {
notifications[type] = {}
}

// check each of deliveryMethod method separately as some can have
// check each of serviceId method separately as some can have
// values and some don't have
['web', 'email'].forEach((deliveryMethod) => {
if (_.isUndefined(settings[type][deliveryMethod])) {
settings[type][deliveryMethod] = 'yes'
['web', 'email'].forEach((serviceId) => {
if (!notifications[type][serviceId]) {
notifications[type][serviceId] = {}
}
if (_.isUndefined(notifications[type][serviceId].enabled)) {
notifications[type][serviceId].enabled = 'yes'
}
})
})

settings.notifications = notifications

return settings
}

Expand All @@ -107,26 +115,45 @@ class NotificationSettingsForm extends React.Component {
}

this.handleChange = this.handleChange.bind(this)
this.handleBundleEmailChange = this.handleBundleEmailChange.bind(this)
}

handleChange(topicIndex, deliveryMethod) {
const s = {
settings: {
...this.state.settings
}
}
handleChange(topicIndex, serviceId) {
const notifications = {...this.state.settings.notifications}

// update values for all types of the topic
topics[topicIndex].types.forEach((type) => {
s.settings[type][deliveryMethod] = s.settings[type][deliveryMethod] === 'yes' ? 'no' : 'yes'
notifications[type][serviceId].enabled = notifications[type][serviceId].enabled === 'yes' ? 'no' : 'yes'
})

this.setState({
settings: {
...this.state.settings,
notifications,
}
})
}

this.setState(s)
handleBundleEmailChange(bundlePeriod) {
this.setState({
settings: {
...this.state.settings,
services: {
...this.state.settings.services,
email: {
...this.state.settings.services.email,
// this will be send to backend which uses null instead of 'immediately'
bundlePeriod: bundlePeriod === 'immediately' ? null : bundlePeriod,
}
}
}
})
}

render() {
const areSettingsProvided = !!this.props.values.settings
const settings = this.state.settings
const notifications = settings.notifications

// if settings weren't provided (not loaded) don't render anything
if (!areSettingsProvided) {
Expand All @@ -145,8 +172,9 @@ class NotificationSettingsForm extends React.Component {
<th><span className="th-with-icon">
<IconSettingsWeb className="icon-settings-web"/>
<span>Web</span></span></th>
{/* as email notification currently not supported, hide them for now */}
{/*<th><span className="th-with-icon"><img src={iconMail} /><span>Email</span></span></th>*/}
<th><span className="th-with-icon">
<IconSettingsEmail />
<span>Email</span></span></th>
</tr>
</thead>
<tbody>
Expand All @@ -157,37 +185,26 @@ class NotificationSettingsForm extends React.Component {
return (
<tr key={index}>
<th>{topic.title}</th>
<td><SwitchButton onChange={() => this.handleChange(index, 'web')} defaultChecked={settings[topicFirstType] && settings[topicFirstType].web === 'yes'} /></td>
{/* as email notification currently not supported, hide them for now */}
{/*<td><SwitchButton onChange={() => this.handleChange(topic, 'email')} defaultChecked={settings[topic] && settings[topic].email === 'yes'} /></td>*/}
<td><SwitchButton onChange={() => this.handleChange(index, 'web')} defaultChecked={notifications[topicFirstType].web.enabled === 'yes'} /></td>
<td><SwitchButton onChange={() => this.handleChange(index, 'email')} defaultChecked={notifications[topicFirstType].email.enabled === 'yes'} /></td>
</tr>
)
})}

{ false && <tr>
<tr>
<td colSpan="3">
<div className="bundle-emails">
<div className="th">Bundle emails:</div>
<BtnGroup
items={[
{ text: 'Send as they happen', value: 'immediately' },
{ text: 'Every hour', value: 'hourly' },
{ text: 'Every 12h.', value: '12h' },
{ text: 'Every 24h.', value: '24h' }
]}
defaultValue={this.props.values.bundleEmail}
items={NOTIFICATION_SETTINGS_PERIODS}
onChange={this.handleBundleEmailChange}
defaultValue={_.get(this.props.values, 'settings.services.email.bundlePeriod') || 'immediately'}
/>
</div>
</td>
</tr>
}
</tbody>
</table>

<div className="email-settings">
<a href="https://www.topcoder.com/settings/email/">Manage email settings</a>
</div>

<div className="controls">
<button type="submit" className="tc-btn tc-btn-primary" disabled={this.props.values.pending}>Save settings</button>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,14 @@
margin-left: 10px;
margin-bottom: 10px;
}

@media screen and (max-width: 430px - 1px) {
> span {
display: block;
margin-left: $base-unit;
margin-right: $base-unit;
}
}
}

.none {
Expand Down Expand Up @@ -135,21 +143,5 @@
margin-top: 6 * $base-unit;
text-align: center;
}

> .email-settings {
@include roboto;
margin: 20px 0;

// Link colors
a:link,
a:visited {
color: $tc-dark-blue;
}

a:hover,
a:active {
color: $tc-dark-blue-70;
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,6 @@ class NotificationSettingsContainer extends React.Component {
return (
<SettingsPanel
title="Notifications"
// link={{
// to: 'https://www.topcoder.com/settings/email/',
// text: 'email settings here'
// }}
text="Notifications are a great way to get back to what matters. Sometimes things can be a bit overwhelming, we get it, so here you can turn off the things that bug you. Once off, you won’t get any notifications of that category until you turn it back on. To manage your email notifications, follow the link at the bottom of the page."
isWide
>
Expand Down
37 changes: 1 addition & 36 deletions src/routes/settings/services/settings.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
*
* TODO has to be replaced with the real service
*/
import _ from 'lodash'
import { axiosInstance as axios } from '../../../api/requestInterceptor'
import { TC_NOTIFICATION_URL } from '../../../config/constants'

Expand Down Expand Up @@ -66,42 +65,8 @@ const getNotificationSettings = () => {
.then(resp => resp.data)
}

// TODO move this list to constants together with the same list in NotificationSettingsForm.jsx
const topics = [
'notifications.connect.project.created',
'notifications.connect.project.updated',
'notifications.connect.project.canceled',
'notifications.connect.project.approved',
'notifications.connect.project.paused',
'notifications.connect.project.completed',
'notifications.connect.project.submittedForReview',
'notifications.connect.project.active',

'notifications.connect.project.fileUploaded',
'notifications.connect.project.specificationModified',
'notifications.connect.project.linkCreated',

'notifications.connect.project.member.joined',
'notifications.connect.project.member.left',
'notifications.connect.project.member.removed',
'notifications.connect.project.member.managerJoined',
'notifications.connect.project.member.copilotJoined',
'notifications.connect.project.member.assignedAsOwner',

'notifications.connect.project.topic.created',
'notifications.connect.project.topic.deleted',
'notifications.connect.project.post.created',
'notifications.connect.project.post.edited',
'notifications.connect.project.post.deleted'
]

const saveNotificationSettings = (data) => {
const body = []
_.each(topics, (topic) => {
body.push({ topic, deliveryMethod: 'email', value: data[topic] && data[topic].email === 'yes' ? 'yes' : 'no' })
body.push({ topic, deliveryMethod: 'web', value: data[topic] && data[topic].web === 'yes' ? 'yes' : 'no' })
})
return axios.put(`${TC_NOTIFICATION_URL}/settings`, body)
return axios.put(`${TC_NOTIFICATION_URL}/settings`, data)
}

export default {
Expand Down