index.jsx 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  1. import React, { Component } from "react";
  2. import async from "async";
  3. import PropTypes from "prop-types";
  4. import { connect } from "react-redux";
  5. import { NavLink } from "react-router-dom";
  6. import config from "config";
  7. import CustomInput from "components/CustomInput.jsx";
  8. import CustomMessages from "components/CustomMessages.jsx";
  9. import io from "io";
  10. @connect(state => ({
  11. user: {
  12. userId: state.user.get("userId"),
  13. },
  14. }))
  15. export default class Settings extends Component {
  16. static propTypes = {
  17. user: PropTypes.object,
  18. };
  19. static defaultProps = {
  20. user: {
  21. userId: "",
  22. },
  23. };
  24. constructor(props) {
  25. super(props);
  26. CustomInput.initialize(this);
  27. this.state = {
  28. passwordLinked: false,
  29. gitHubLinked: false,
  30. };
  31. io.getSocket(socket => {
  32. socket.emit("users.findBySession", res => {
  33. if (res.status === "success") {
  34. this.input.email.setValue(res.data.email.address, true);
  35. this.input.username.setValue(res.data.username, true);
  36. this.setState({
  37. passwordLinked: res.data.password,
  38. gitHubLinked: res.data.github,
  39. });
  40. } else {
  41. this.messages.addError("You are currently not logged in.");
  42. }
  43. });
  44. socket.on("event:user.username.changed", username => {
  45. this.input.username.setValue(username, true);
  46. });
  47. // TODO Email changed event?
  48. socket.on("event:user.linkPassword", () => {
  49. this.setState({
  50. passwordLinked: true,
  51. });
  52. });
  53. socket.on("event:user.linkGitHub", () => {
  54. this.setState({
  55. gitHubLinked: true,
  56. });
  57. });
  58. socket.on("event:user.unlinkPassword", () => {
  59. this.setState({
  60. passwordLinked: false,
  61. });
  62. });
  63. socket.on("event:user.unlinkGitHub", () => {
  64. this.setState({
  65. gitHubLinked: false,
  66. });
  67. });
  68. });
  69. }
  70. /* githubRedirect() {
  71. localStorage.setItem("github_redirect", window.location.pathname);
  72. } */
  73. saveChanges = () => {
  74. this.messages.clearErrorSuccess();
  75. async.waterfall([
  76. (next) => {
  77. if (this.input.username.isPristine()) this.input.username.validate(next);
  78. else next();
  79. },
  80. (next) => {
  81. if (this.input.email.isPristine()) this.input.email.validate(next);
  82. else next();
  83. },
  84. ], () => {
  85. if (CustomInput.hasInvalidInput(this.input, ["username", "email"])) {
  86. this.messages.clearAddError("Some fields are incorrect. Please fix them before continuing.");
  87. } else if (this.input.username.isOriginal() && this.input.email.isOriginal()) {
  88. this.messages.clearAddError("Username or email hasn't changed.");
  89. } else {
  90. const email = this.input.email.getValue();
  91. const username = this.input.username.getValue();
  92. io.getSocket(socket => {
  93. if (!this.input.email.isOriginal()) {
  94. socket.emit("users.updateEmail", this.props.user.userId, email, res => {
  95. if (res.status === "success") {
  96. this.messages.clearAddSuccess("Successfully updated email.");
  97. } else {
  98. this.messages.addError(res.message);
  99. }
  100. });
  101. }
  102. if (!this.input.username.isOriginal()) {
  103. socket.emit("users.updateUsername", this.props.user.userId, username, res => {
  104. if (res.status === "success") {
  105. this.messages.clearAddSuccess("Successfully updated username.");
  106. } else {
  107. this.messages.addError(res.message);
  108. }
  109. });
  110. }
  111. });
  112. }
  113. });
  114. };
  115. changePassword = () => {
  116. this.messages.clearErrorSuccess();
  117. if (CustomInput.hasInvalidInput(this.input, ["newPassword"])) {
  118. this.messages.clearAddError("Some fields are incorrect. Please fix them before continuing.");
  119. } else if (!this.state.passwordLinked) {
  120. this.messages.clearAddError("You don't have a password set.");
  121. } else {
  122. io.getSocket(socket => {
  123. socket.emit("users.updatePassword", this.input.newPassword.getValue(), res => {
  124. if (res.status === "success") {
  125. this.messages.clearAddSuccess("Successfully changed password.");
  126. } else {
  127. this.messages.addError(res.message);
  128. }
  129. });
  130. });
  131. }
  132. };
  133. logOutEverywhere = () => {
  134. this.messages.clearErrorSuccess();
  135. io.getSocket(socket => {
  136. socket.emit("users.removeSessions", this.props.user.userId, res => {
  137. if (res.status === "success") {
  138. this.messages.clearAddSuccess("Successfully logged out everywhere.");
  139. } else {
  140. this.messages.addError(res.message);
  141. }
  142. });
  143. });
  144. };
  145. unlinkGitHub = () => {
  146. this.messages.clearErrorSuccess();
  147. io.getSocket(socket => {
  148. socket.emit("users.unlinkGitHub", res => {
  149. if (res.status === "success") {
  150. this.messages.clearAddSuccess("Successfully unlinked GitHub.");
  151. } else {
  152. this.messages.addError(res.message);
  153. }
  154. });
  155. });
  156. };
  157. unlinkPassword = () => {
  158. this.messages.clearErrorSuccess();
  159. io.getSocket(socket => {
  160. socket.emit("users.unlinkPassword", res => {
  161. if (res.status === "success") {
  162. this.messages.clearAddSuccess("Successfully unlinked password.");
  163. } else {
  164. this.messages.addError(res.message);
  165. }
  166. });
  167. });
  168. };
  169. linkButtons = () => {
  170. const newPassword = <CustomInput key="newPassword" type="password" name="newPassword" label="New password" placeholder="New password" onRef={ ref => (this.input.newPassword = ref) } />;
  171. const changePasswordButton = <button key="changePassword" onClick={ this.changePassword }>Change password</button>;
  172. const linkPassword = <NavLink key="linkPassword" to="/settings/setpassword" >Add a password to account</NavLink>;
  173. const linkGitHub = <a key="linkGitHub" href={ config.serverDomain + "/auth/github/link" }>Link GitHub to account</a>;
  174. const unlinkGitHub = (<button key="unlinkGitHub" onClick={ this.unlinkGitHub }>
  175. Remove logging in with GitHub
  176. </button>);
  177. const unlinkPassword = (<button key="unlinkPassword" onClick={ this.unlinkPassword }>
  178. Remove logging in with password
  179. </button>);
  180. const toReturn = [];
  181. if (this.state.passwordLinked) {
  182. toReturn.push(newPassword);
  183. toReturn.push(changePasswordButton);
  184. }
  185. if (this.state.passwordLinked && this.state.gitHubLinked) {
  186. toReturn.push(unlinkGitHub);
  187. toReturn.push(unlinkPassword);
  188. } else if (!this.state.passwordLinked) {
  189. toReturn.push(linkPassword);
  190. } else toReturn.push(linkGitHub);
  191. return toReturn;
  192. };
  193. render() {
  194. return (
  195. <div>
  196. <CustomMessages onRef={ ref => (this.messages = ref) } />
  197. <div>
  198. <h2>General</h2>
  199. <CustomInput type="email" name="email" label="Email" placeholder="Email" onRef={ ref => (this.input.email = ref) } />
  200. <CustomInput type="username" name="username" label="Username" placeholder="Username" onRef={ ref => (this.input.username = ref) } />
  201. <button onClick={ this.saveChanges }>Save changes</button>
  202. </div>
  203. <div>
  204. <h2>Security</h2>
  205. { this.linkButtons() }
  206. <button onClick={ this.logOutEverywhere }>Log out everywhere</button>
  207. </div>
  208. </div>
  209. );
  210. }
  211. }