mirror of
https://github.com/scinote-eln/scinote-web.git
synced 2025-10-06 11:57:16 +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
|
||||
|
||||
def preferences_info
|
||||
settings = current_user.settings
|
||||
respond_to do |format|
|
||||
format.json do
|
||||
render template: 'client_api/users/preferences',
|
||||
status: :ok,
|
||||
locals: { user: current_user}
|
||||
locals: {
|
||||
timeZone: settings['time_zone'],
|
||||
notifications: settings['notifications']
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -67,7 +71,9 @@ module ClientApi
|
|||
:full_name,
|
||||
:password_confirmation,
|
||||
:current_password,
|
||||
:avatar)
|
||||
:avatar,
|
||||
:assignments,
|
||||
:time_zone)
|
||||
end
|
||||
|
||||
def change_notification(dinamic_param, params)
|
||||
|
|
|
@ -54,6 +54,7 @@ export default {
|
|||
time_zone: "Time zone",
|
||||
time_zone_warning:
|
||||
"Time zone setting affects all time & date fields throughout application.",
|
||||
repeat_tutorial: "Repeat tutorial",
|
||||
profile: "Profile",
|
||||
preferences: "Preferences",
|
||||
assignement: "Assignement",
|
||||
|
|
|
@ -1,11 +1,13 @@
|
|||
import React, { Component } from "react";
|
||||
import PropType from "prop-types";
|
||||
import { string, func } from "prop-types";
|
||||
import { Button } from "react-bootstrap";
|
||||
import styled from "styled-components";
|
||||
import TimezonePicker from "react-bootstrap-timezone-picker";
|
||||
import "react-bootstrap-timezone-picker/dist/react-bootstrap-timezone-picker.min.css";
|
||||
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";
|
||||
|
||||
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 {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
value: props.inputValue
|
||||
value: "",
|
||||
disabled: true
|
||||
};
|
||||
|
||||
this.handleChange = this.handleChange.bind(this);
|
||||
this.handleUpdate = this.handleUpdate.bind(this);
|
||||
this.enableEdit = this.enableEdit.bind(this);
|
||||
this.disableEdit = this.disableEdit.bind(this);
|
||||
}
|
||||
|
||||
handleChange(timezone) {
|
||||
|
@ -40,20 +55,49 @@ class InputTimezone extends Component {
|
|||
|
||||
handleUpdate() {
|
||||
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() {
|
||||
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 (
|
||||
<Wrapper>
|
||||
<h4>
|
||||
{this.props.labelValue}
|
||||
<FormattedMessage id="settings_page.time_zone" />
|
||||
</h4>
|
||||
<TimezonePicker
|
||||
absolute
|
||||
defaultValue="Europe/London"
|
||||
value={this.props.inputValue}
|
||||
value={this.state.value}
|
||||
placeholder="Select timezone..."
|
||||
onChange={this.handleChange}
|
||||
/>
|
||||
|
@ -62,11 +106,11 @@ class InputTimezone extends Component {
|
|||
<FormattedMessage id="settings_page.time_zone_warning" />
|
||||
</small>
|
||||
</div>
|
||||
<Button bsStyle="primary" onClick={this.props.disableEdit}>
|
||||
Cancel
|
||||
<Button bsStyle="primary" onClick={this.disableEdit}>
|
||||
<FormattedMessage id="general.cancel" />
|
||||
</Button>
|
||||
<Button bsStyle="default" onClick={this.handleUpdate}>
|
||||
Update
|
||||
<FormattedMessage id="general.update" />
|
||||
</Button>
|
||||
</Wrapper>
|
||||
);
|
||||
|
@ -74,10 +118,8 @@ class InputTimezone extends Component {
|
|||
}
|
||||
|
||||
InputTimezone.propTypes = {
|
||||
labelValue: PropType.string.isRequired,
|
||||
inputValue: PropType.string.isRequired,
|
||||
disableEdit: PropType.func.isRequired,
|
||||
saveData: PropType.func.isRequired
|
||||
value: string.isRequired,
|
||||
loadPreferences: func.isRequired
|
||||
};
|
||||
|
||||
export default InputTimezone;
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
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 { 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 InputTimezone from "./components/InputTimezone";
|
||||
import NotificationsGroup from "./components/NotificationsGroup";
|
||||
|
@ -21,106 +20,50 @@ import {
|
|||
BORDER_LIGHT_COLOR
|
||||
} from "../../../../config/constants/colors";
|
||||
|
||||
const WrapperInputDisabled = styled.div`
|
||||
const TutorialWrapper = styled.div`
|
||||
margin: 20px 0;
|
||||
padding-bottom: 15px;
|
||||
border-bottom: 1px solid ${BORDER_LIGHT_COLOR};
|
||||
|
||||
.settings-warning {
|
||||
margin-top: -5px;
|
||||
}
|
||||
`;
|
||||
|
||||
`
|
||||
class SettingsPreferences extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
isTimeZoneEditable: false,
|
||||
email: "",
|
||||
notifications: {
|
||||
assignmentsNotification: false,
|
||||
assignmentsNotificationEmail: false,
|
||||
recentNotification: false,
|
||||
recentNotificationEmail: false,
|
||||
systemMessageNofificationEmail: false
|
||||
}
|
||||
timeZone: "",
|
||||
assignmentsNotification: false,
|
||||
assignmentsEmailNotification: false,
|
||||
recentNotification: false,
|
||||
recentEmailNotification: false,
|
||||
systemMessageEmailNofification: false
|
||||
};
|
||||
|
||||
this.setData = this.setData.bind(this);
|
||||
this.getPreferencesInfo = this.getPreferencesInfo.bind(this)
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
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() {
|
||||
// axios
|
||||
// .get("/client_api/users/preferences_info")
|
||||
// .then(response => this.setData(response))
|
||||
// .catch(error => console.log(error));
|
||||
getUserPreferencesInfo().then(data => {
|
||||
this.setState(data);
|
||||
});
|
||||
}
|
||||
|
||||
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 (
|
||||
<SettingsAccountWrapper>
|
||||
<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>
|
||||
<NotificationsGroup
|
||||
type={ASSIGNMENT_NOTIFICATION}
|
||||
|
@ -152,11 +95,4 @@ class SettingsPreferences extends Component {
|
|||
}
|
||||
}
|
||||
|
||||
SettingsPreferences.propTypes = {
|
||||
changeTimezone: PropTypes.func.isRequired,
|
||||
avatarPath: PropTypes.string.isRequired
|
||||
};
|
||||
|
||||
const mapStateToProps = state => state.current_user;
|
||||
|
||||
export default connect(mapStateToProps)(SettingsPreferences);
|
||||
export default SettingsPreferences;
|
||||
|
|
|
@ -9,6 +9,7 @@ export const TEAMS_PATH = "/client_api/teams";
|
|||
export const CHANGE_TEAM_PATH = "/client_api/teams/change_team";
|
||||
export const TEAM_DETAILS_PATH = "/client_api/teams/:team_id/details";
|
||||
export const TEAM_UPDATE_PATH = "/client_api/teams/update";
|
||||
export const CURRENT_USER_PATH = "/client_api/current_user_info"
|
||||
|
||||
// search
|
||||
export const SEARCH_PATH = "/search";
|
||||
|
@ -19,6 +20,7 @@ export const RECENT_NOTIFICATIONS_PATH = "/client_api/recent_notifications";
|
|||
// users
|
||||
export const USER_PROFILE_INFO = "/client_api/users/profile_info";
|
||||
export const UPDATE_USER_PATH = "/client_api/users/update";
|
||||
export const PREFERENCES_INFO_PATH = "/client_api/users/preferences_info"
|
||||
|
||||
// info dropdown_title
|
||||
export const CUSTOMER_SUPPORT_LINK = "http://scinote.net/support";
|
||||
|
|
|
@ -2,12 +2,15 @@ import { axiosInstance } from "./config";
|
|||
import {
|
||||
USER_PROFILE_INFO,
|
||||
UPDATE_USER_PATH,
|
||||
CURRENT_USER_PATH
|
||||
CURRENT_USER_PATH,
|
||||
PREFERENCES_INFO_PATH
|
||||
} from "./endpoints";
|
||||
|
||||
export const getUserProfileInfo = () => {
|
||||
return axiosInstance.get(USER_PROFILE_INFO).then(({ data }) => data.user);
|
||||
};
|
||||
export const getUserProfileInfo = () =>
|
||||
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) => {
|
||||
if (formObj) {
|
||||
|
|
|
@ -36,7 +36,7 @@ class User < ApplicationRecord
|
|||
size: { less_than: Constants::AVATAR_MAX_SIZE_MB.megabytes }
|
||||
validate :time_zone_check
|
||||
|
||||
store_accessor :settings, :time_zone
|
||||
store_accessor :settings, :time_zone, :notifications
|
||||
|
||||
default_settings(
|
||||
time_zone: 'UTC',
|
||||
|
@ -48,7 +48,31 @@ class User < ApplicationRecord
|
|||
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
|
||||
has_many :user_teams, inverse_of: :user
|
||||
has_many :teams, through: :user_teams
|
||||
|
|
|
@ -1,10 +1,6 @@
|
|||
json.user do
|
||||
json.timeZone user.time_zone
|
||||
json.notifications do
|
||||
json.assignmentsNotification user.assignments_notification
|
||||
json.assignmentsNotificationEmail user.assignments_notification_email
|
||||
json.recentNotification user.recent_notification
|
||||
json.recentNotificationEmail user.recent_notification_email
|
||||
json.systemMessageNofificationEmail user.system_message_notification_email
|
||||
end
|
||||
end
|
||||
json.timeZone timeZone
|
||||
json.assignmentsNotification notifications['assignments']
|
||||
json.assignmentsEmailNotification notifications['assignments_email']
|
||||
json.recentNotification notifications['recent']
|
||||
json.recentEmailNotification notifications['recent_email']
|
||||
json.systemMessageEmailNofification notifications['system_message_email']
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
json.user do
|
||||
json.id user.id
|
||||
json.fullName user.full_name
|
||||
json.avatarPath avatar_path(user, :icon_small)
|
||||
json.avatarThumb avatar_path(user, :icon_small)
|
||||
end
|
||||
|
|
Loading…
Add table
Reference in a new issue