mirror of
https://github.com/scinote-eln/scinote-web.git
synced 2025-10-09 13:28:53 +08:00
adds getter and setters for user settings
This commit is contained in:
parent
66269d68ff
commit
26b526d61b
9 changed files with 130 additions and 120 deletions
|
@ -3,11 +3,15 @@ module ClientApi
|
||||||
class UsersController < ApplicationController
|
class UsersController < ApplicationController
|
||||||
|
|
||||||
def preferences_info
|
def preferences_info
|
||||||
|
settings = current_user.settings
|
||||||
respond_to do |format|
|
respond_to do |format|
|
||||||
format.json do
|
format.json do
|
||||||
render template: 'client_api/users/preferences',
|
render template: 'client_api/users/preferences',
|
||||||
status: :ok,
|
status: :ok,
|
||||||
locals: { user: current_user}
|
locals: {
|
||||||
|
timeZone: settings['time_zone'],
|
||||||
|
notifications: settings['notifications']
|
||||||
|
}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -67,7 +71,9 @@ module ClientApi
|
||||||
:full_name,
|
:full_name,
|
||||||
:password_confirmation,
|
:password_confirmation,
|
||||||
:current_password,
|
:current_password,
|
||||||
:avatar)
|
:avatar,
|
||||||
|
:assignments,
|
||||||
|
:time_zone)
|
||||||
end
|
end
|
||||||
|
|
||||||
def change_notification(dinamic_param, params)
|
def change_notification(dinamic_param, params)
|
||||||
|
|
|
@ -54,6 +54,7 @@ export default {
|
||||||
time_zone: "Time zone",
|
time_zone: "Time zone",
|
||||||
time_zone_warning:
|
time_zone_warning:
|
||||||
"Time zone setting affects all time & date fields throughout application.",
|
"Time zone setting affects all time & date fields throughout application.",
|
||||||
|
repeat_tutorial: "Repeat tutorial",
|
||||||
profile: "Profile",
|
profile: "Profile",
|
||||||
preferences: "Preferences",
|
preferences: "Preferences",
|
||||||
assignement: "Assignement",
|
assignement: "Assignement",
|
||||||
|
|
|
@ -1,11 +1,13 @@
|
||||||
import React, { Component } from "react";
|
import React, { Component } from "react";
|
||||||
import PropType from "prop-types";
|
import { string, func } from "prop-types";
|
||||||
import { Button } from "react-bootstrap";
|
import { Button } from "react-bootstrap";
|
||||||
import styled from "styled-components";
|
import styled from "styled-components";
|
||||||
import TimezonePicker from "react-bootstrap-timezone-picker";
|
import TimezonePicker from "react-bootstrap-timezone-picker";
|
||||||
import "react-bootstrap-timezone-picker/dist/react-bootstrap-timezone-picker.min.css";
|
import "react-bootstrap-timezone-picker/dist/react-bootstrap-timezone-picker.min.css";
|
||||||
import { FormattedMessage } from "react-intl";
|
import { FormattedMessage } from "react-intl";
|
||||||
|
|
||||||
|
import { updateUser } from "../../../../../services/api/users_api";
|
||||||
|
import InputDisabled from "../../../components/InputDisabled";
|
||||||
import { BORDER_LIGHT_COLOR } from "../../../../../config/constants/colors";
|
import { BORDER_LIGHT_COLOR } from "../../../../../config/constants/colors";
|
||||||
|
|
||||||
const Wrapper = styled.div`
|
const Wrapper = styled.div`
|
||||||
|
@ -22,16 +24,29 @@ const Wrapper = styled.div`
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
const WrapperInputDisabled = styled.div`
|
||||||
|
margin: 20px 0;
|
||||||
|
padding-bottom: 15px;
|
||||||
|
border-bottom: 1px solid ${BORDER_LIGHT_COLOR};
|
||||||
|
|
||||||
|
.settings-warning {
|
||||||
|
margin-top: -5px;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
class InputTimezone extends Component {
|
class InputTimezone extends Component {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
value: props.inputValue
|
value: "",
|
||||||
|
disabled: true
|
||||||
};
|
};
|
||||||
|
|
||||||
this.handleChange = this.handleChange.bind(this);
|
this.handleChange = this.handleChange.bind(this);
|
||||||
this.handleUpdate = this.handleUpdate.bind(this);
|
this.handleUpdate = this.handleUpdate.bind(this);
|
||||||
|
this.enableEdit = this.enableEdit.bind(this);
|
||||||
|
this.disableEdit = this.disableEdit.bind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
handleChange(timezone) {
|
handleChange(timezone) {
|
||||||
|
@ -40,20 +55,49 @@ class InputTimezone extends Component {
|
||||||
|
|
||||||
handleUpdate() {
|
handleUpdate() {
|
||||||
if (this.state.value !== "") {
|
if (this.state.value !== "") {
|
||||||
this.props.saveData(this.state.value);
|
updateUser({ time_zone: this.state.value }).then(() => {
|
||||||
|
this.disableEdit();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
this.props.disableEdit();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enableEdit() {
|
||||||
|
this.setState({ disabled: false, value: this.props.value });
|
||||||
|
}
|
||||||
|
|
||||||
|
disableEdit() {
|
||||||
|
this.setState({ disabled: true });
|
||||||
|
this.props.loadPreferences();
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
if (this.state.disabled) {
|
||||||
|
return (
|
||||||
|
<WrapperInputDisabled>
|
||||||
|
<InputDisabled
|
||||||
|
labelTitle="settings_page.time_zone"
|
||||||
|
inputValue={this.props.value}
|
||||||
|
inputType="text"
|
||||||
|
enableEdit={this.enableEdit}
|
||||||
|
/>
|
||||||
|
<div className="settings-warning">
|
||||||
|
<small>
|
||||||
|
<FormattedMessage id="settings_page.time_zone_warning" />
|
||||||
|
</small>
|
||||||
|
</div>
|
||||||
|
</WrapperInputDisabled>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Wrapper>
|
<Wrapper>
|
||||||
<h4>
|
<h4>
|
||||||
{this.props.labelValue}
|
<FormattedMessage id="settings_page.time_zone" />
|
||||||
</h4>
|
</h4>
|
||||||
<TimezonePicker
|
<TimezonePicker
|
||||||
absolute
|
absolute
|
||||||
defaultValue="Europe/London"
|
defaultValue="Europe/London"
|
||||||
value={this.props.inputValue}
|
value={this.state.value}
|
||||||
placeholder="Select timezone..."
|
placeholder="Select timezone..."
|
||||||
onChange={this.handleChange}
|
onChange={this.handleChange}
|
||||||
/>
|
/>
|
||||||
|
@ -62,11 +106,11 @@ class InputTimezone extends Component {
|
||||||
<FormattedMessage id="settings_page.time_zone_warning" />
|
<FormattedMessage id="settings_page.time_zone_warning" />
|
||||||
</small>
|
</small>
|
||||||
</div>
|
</div>
|
||||||
<Button bsStyle="primary" onClick={this.props.disableEdit}>
|
<Button bsStyle="primary" onClick={this.disableEdit}>
|
||||||
Cancel
|
<FormattedMessage id="general.cancel" />
|
||||||
</Button>
|
</Button>
|
||||||
<Button bsStyle="default" onClick={this.handleUpdate}>
|
<Button bsStyle="default" onClick={this.handleUpdate}>
|
||||||
Update
|
<FormattedMessage id="general.update" />
|
||||||
</Button>
|
</Button>
|
||||||
</Wrapper>
|
</Wrapper>
|
||||||
);
|
);
|
||||||
|
@ -74,10 +118,8 @@ class InputTimezone extends Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
InputTimezone.propTypes = {
|
InputTimezone.propTypes = {
|
||||||
labelValue: PropType.string.isRequired,
|
value: string.isRequired,
|
||||||
inputValue: PropType.string.isRequired,
|
loadPreferences: func.isRequired
|
||||||
disableEdit: PropType.func.isRequired,
|
|
||||||
saveData: PropType.func.isRequired
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default InputTimezone;
|
export default InputTimezone;
|
||||||
|
|
|
@ -1,10 +1,9 @@
|
||||||
import React, { Component } from "react";
|
import React, { Component } from "react";
|
||||||
import { connect } from "react-redux";
|
|
||||||
import PropTypes from "prop-types";
|
|
||||||
import styled from "styled-components";
|
|
||||||
import { FormattedMessage } from "react-intl";
|
import { FormattedMessage } from "react-intl";
|
||||||
|
import { Button } from "react-bootstrap";
|
||||||
|
import styled from "styled-components";
|
||||||
|
|
||||||
import InputDisabled from "../../components/InputDisabled";
|
import { getUserPreferencesInfo } from "../../../../services/api/users_api";
|
||||||
import SettingsAccountWrapper from "../../components/SettingsAccountWrapper";
|
import SettingsAccountWrapper from "../../components/SettingsAccountWrapper";
|
||||||
import InputTimezone from "./components/InputTimezone";
|
import InputTimezone from "./components/InputTimezone";
|
||||||
import NotificationsGroup from "./components/NotificationsGroup";
|
import NotificationsGroup from "./components/NotificationsGroup";
|
||||||
|
@ -21,106 +20,50 @@ import {
|
||||||
BORDER_LIGHT_COLOR
|
BORDER_LIGHT_COLOR
|
||||||
} from "../../../../config/constants/colors";
|
} from "../../../../config/constants/colors";
|
||||||
|
|
||||||
const WrapperInputDisabled = styled.div`
|
const TutorialWrapper = styled.div`
|
||||||
margin: 20px 0;
|
margin: 20px 0;
|
||||||
padding-bottom: 15px;
|
padding-bottom: 15px;
|
||||||
border-bottom: 1px solid ${BORDER_LIGHT_COLOR};
|
border-bottom: 1px solid ${BORDER_LIGHT_COLOR};
|
||||||
|
`
|
||||||
.settings-warning {
|
|
||||||
margin-top: -5px;
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
class SettingsPreferences extends Component {
|
class SettingsPreferences extends Component {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
isTimeZoneEditable: false,
|
timeZone: "",
|
||||||
email: "",
|
assignmentsNotification: false,
|
||||||
notifications: {
|
assignmentsEmailNotification: false,
|
||||||
assignmentsNotification: false,
|
recentNotification: false,
|
||||||
assignmentsNotificationEmail: false,
|
recentEmailNotification: false,
|
||||||
recentNotification: false,
|
systemMessageEmailNofification: false
|
||||||
recentNotificationEmail: false,
|
|
||||||
systemMessageNofificationEmail: false
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
this.setData = this.setData.bind(this);
|
this.getPreferencesInfo = this.getPreferencesInfo.bind(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
this.getPreferencesInfo();
|
this.getPreferencesInfo();
|
||||||
}
|
}
|
||||||
|
|
||||||
toggleIsEditable(fieldNameEnabled) {
|
|
||||||
const editableState = this.state[fieldNameEnabled];
|
|
||||||
this.setState({ [fieldNameEnabled]: !editableState });
|
|
||||||
}
|
|
||||||
|
|
||||||
setData({ data }) {
|
|
||||||
const user = data.user;
|
|
||||||
|
|
||||||
const newData = {
|
|
||||||
timeZone: user.timeZone,
|
|
||||||
notifications: {
|
|
||||||
assignmentsNotification: user.notifications.assignmentsNotification,
|
|
||||||
assignmentsNotificationEmail:
|
|
||||||
user.notifications.assignmentsNotificationEmail,
|
|
||||||
recentNotification: user.notifications.recentNotification,
|
|
||||||
recentNotificationEmail: user.notifications.recentNotificationEmail,
|
|
||||||
systemMessageNofificationEmail:
|
|
||||||
user.notifications.systemMessageNofificationEmail
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
this.setState(Object.assign({}, this.state, newData));
|
|
||||||
}
|
|
||||||
|
|
||||||
getPreferencesInfo() {
|
getPreferencesInfo() {
|
||||||
// axios
|
getUserPreferencesInfo().then(data => {
|
||||||
// .get("/client_api/users/preferences_info")
|
this.setState(data);
|
||||||
// .then(response => this.setData(response))
|
});
|
||||||
// .catch(error => console.log(error));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const isTimeZoneEditable = "isTimeZoneEditable";
|
|
||||||
let timezoneField;
|
|
||||||
|
|
||||||
if (this.state.isTimeZoneEditable) {
|
|
||||||
timezoneField = (
|
|
||||||
<InputTimezone
|
|
||||||
labelValue="Time zone"
|
|
||||||
inputValue={this.state.timeZone}
|
|
||||||
disableEdit={() => this.toggleIsEditable(isTimeZoneEditable)}
|
|
||||||
saveData={timeZone => this.props.changeTimezone(timeZone)}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
timezoneField = (
|
|
||||||
<WrapperInputDisabled>
|
|
||||||
<InputDisabled
|
|
||||||
labelTitle="settings_page.time_zone"
|
|
||||||
inputValue={this.state.timeZone}
|
|
||||||
inputType="text"
|
|
||||||
enableEdit={() => this.toggleIsEditable(isTimeZoneEditable)}
|
|
||||||
/>
|
|
||||||
<div className="settings-warning">
|
|
||||||
<small>
|
|
||||||
<FormattedMessage id="settings_page.time_zone_warning" />
|
|
||||||
</small>
|
|
||||||
</div>
|
|
||||||
</WrapperInputDisabled>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SettingsAccountWrapper>
|
<SettingsAccountWrapper>
|
||||||
<div className="col-xs-12 col-sm-9">
|
<div className="col-xs-12 col-sm-9">
|
||||||
{timezoneField}
|
<InputTimezone
|
||||||
|
value={this.state.timeZone}
|
||||||
|
loadPreferences={this.getPreferencesInfo}
|
||||||
|
/>
|
||||||
|
<TutorialWrapper>
|
||||||
|
<Button bsStyle="success">
|
||||||
|
<FormattedMessage id="settings_page.repeat_tutorial" />
|
||||||
|
</Button>
|
||||||
|
</TutorialWrapper>
|
||||||
<h3>Notifications</h3>
|
<h3>Notifications</h3>
|
||||||
<NotificationsGroup
|
<NotificationsGroup
|
||||||
type={ASSIGNMENT_NOTIFICATION}
|
type={ASSIGNMENT_NOTIFICATION}
|
||||||
|
@ -152,11 +95,4 @@ class SettingsPreferences extends Component {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SettingsPreferences.propTypes = {
|
export default SettingsPreferences;
|
||||||
changeTimezone: PropTypes.func.isRequired,
|
|
||||||
avatarPath: PropTypes.string.isRequired
|
|
||||||
};
|
|
||||||
|
|
||||||
const mapStateToProps = state => state.current_user;
|
|
||||||
|
|
||||||
export default connect(mapStateToProps)(SettingsPreferences);
|
|
||||||
|
|
|
@ -9,6 +9,7 @@ export const TEAMS_PATH = "/client_api/teams";
|
||||||
export const CHANGE_TEAM_PATH = "/client_api/teams/change_team";
|
export const CHANGE_TEAM_PATH = "/client_api/teams/change_team";
|
||||||
export const TEAM_DETAILS_PATH = "/client_api/teams/:team_id/details";
|
export const TEAM_DETAILS_PATH = "/client_api/teams/:team_id/details";
|
||||||
export const TEAM_UPDATE_PATH = "/client_api/teams/update";
|
export const TEAM_UPDATE_PATH = "/client_api/teams/update";
|
||||||
|
export const CURRENT_USER_PATH = "/client_api/current_user_info"
|
||||||
|
|
||||||
// search
|
// search
|
||||||
export const SEARCH_PATH = "/search";
|
export const SEARCH_PATH = "/search";
|
||||||
|
@ -19,6 +20,7 @@ export const RECENT_NOTIFICATIONS_PATH = "/client_api/recent_notifications";
|
||||||
// users
|
// users
|
||||||
export const USER_PROFILE_INFO = "/client_api/users/profile_info";
|
export const USER_PROFILE_INFO = "/client_api/users/profile_info";
|
||||||
export const UPDATE_USER_PATH = "/client_api/users/update";
|
export const UPDATE_USER_PATH = "/client_api/users/update";
|
||||||
|
export const PREFERENCES_INFO_PATH = "/client_api/users/preferences_info"
|
||||||
|
|
||||||
// info dropdown_title
|
// info dropdown_title
|
||||||
export const CUSTOMER_SUPPORT_LINK = "http://scinote.net/support";
|
export const CUSTOMER_SUPPORT_LINK = "http://scinote.net/support";
|
||||||
|
|
|
@ -2,12 +2,15 @@ import { axiosInstance } from "./config";
|
||||||
import {
|
import {
|
||||||
USER_PROFILE_INFO,
|
USER_PROFILE_INFO,
|
||||||
UPDATE_USER_PATH,
|
UPDATE_USER_PATH,
|
||||||
CURRENT_USER_PATH
|
CURRENT_USER_PATH,
|
||||||
|
PREFERENCES_INFO_PATH
|
||||||
} from "./endpoints";
|
} from "./endpoints";
|
||||||
|
|
||||||
export const getUserProfileInfo = () => {
|
export const getUserProfileInfo = () =>
|
||||||
return axiosInstance.get(USER_PROFILE_INFO).then(({ data }) => data.user);
|
axiosInstance.get(USER_PROFILE_INFO).then(({ data }) => data.user);
|
||||||
};
|
|
||||||
|
export const getUserPreferencesInfo = () =>
|
||||||
|
axiosInstance.get(PREFERENCES_INFO_PATH).then(({ data }) => data);
|
||||||
|
|
||||||
export const updateUser = (params, formObj = false) => {
|
export const updateUser = (params, formObj = false) => {
|
||||||
if (formObj) {
|
if (formObj) {
|
||||||
|
|
|
@ -36,7 +36,7 @@ class User < ApplicationRecord
|
||||||
size: { less_than: Constants::AVATAR_MAX_SIZE_MB.megabytes }
|
size: { less_than: Constants::AVATAR_MAX_SIZE_MB.megabytes }
|
||||||
validate :time_zone_check
|
validate :time_zone_check
|
||||||
|
|
||||||
store_accessor :settings, :time_zone
|
store_accessor :settings, :time_zone, :notifications
|
||||||
|
|
||||||
default_settings(
|
default_settings(
|
||||||
time_zone: 'UTC',
|
time_zone: 'UTC',
|
||||||
|
@ -48,7 +48,31 @@ class User < ApplicationRecord
|
||||||
system_message_email: false
|
system_message_email: false
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
# json.assignmentsNotification notifications['assignments']
|
||||||
|
# json.assignmentsEmailNotification notifications['assignments_email']
|
||||||
|
# json.recentNotification notifications['recent']
|
||||||
|
# json.recentEmailNotification notifications['recent_email']
|
||||||
|
# json.systemMessageEmailNofification notifications['system_message_email']
|
||||||
|
# joson friendly attributes
|
||||||
|
NOTIFICATIONS_TYPES = %w(assignmentsNotification assignmentsEmailNotification
|
||||||
|
recentNotification recentEmailNotification
|
||||||
|
systemMessageEmailNofification)
|
||||||
|
# declare notifications getters
|
||||||
|
NOTIFICATIONS_TYPES.each do |name|
|
||||||
|
define_method(name) do
|
||||||
|
attr_name = name.slice!('Notification').underscore
|
||||||
|
self.notifications.fetch(attr_name.to_sym)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# declare notifications setters
|
||||||
|
NOTIFICATIONS_TYPES.each do |name|
|
||||||
|
define_method("#{name}=") do |value|
|
||||||
|
attr_name = name.slice!('Notification').underscore
|
||||||
|
self.notifications[attr_name.to_sym] = value
|
||||||
|
save
|
||||||
|
end
|
||||||
|
end
|
||||||
# Relations
|
# Relations
|
||||||
has_many :user_teams, inverse_of: :user
|
has_many :user_teams, inverse_of: :user
|
||||||
has_many :teams, through: :user_teams
|
has_many :teams, through: :user_teams
|
||||||
|
|
|
@ -1,10 +1,6 @@
|
||||||
json.user do
|
json.timeZone timeZone
|
||||||
json.timeZone user.time_zone
|
json.assignmentsNotification notifications['assignments']
|
||||||
json.notifications do
|
json.assignmentsEmailNotification notifications['assignments_email']
|
||||||
json.assignmentsNotification user.assignments_notification
|
json.recentNotification notifications['recent']
|
||||||
json.assignmentsNotificationEmail user.assignments_notification_email
|
json.recentEmailNotification notifications['recent_email']
|
||||||
json.recentNotification user.recent_notification
|
json.systemMessageEmailNofification notifications['system_message_email']
|
||||||
json.recentNotificationEmail user.recent_notification_email
|
|
||||||
json.systemMessageNofificationEmail user.system_message_notification_email
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
json.user do
|
json.user do
|
||||||
json.id user.id
|
json.id user.id
|
||||||
json.fullName user.full_name
|
json.fullName user.full_name
|
||||||
json.avatarPath avatar_path(user, :icon_small)
|
json.avatarThumb avatar_path(user, :icon_small)
|
||||||
end
|
end
|
||||||
|
|
Loading…
Add table
Reference in a new issue