Skip to content
This repository has been archived by the owner. It is now read-only.
Permalink
Browse files

Allow to remove account

  • Loading branch information...
brtjkzl committed Feb 3, 2019
1 parent bd77c61 commit 8e257d5340fb91042543bf1608e9af6483f6205a
@@ -1,7 +1,7 @@
// @flow
import * as React from "react";
import { Route, Switch } from "react-router-dom";
import { ROOT_PATH, PRiVACY_POLICY_PATH } from "routes/paths";
import { ROOT_PATH, PRIVACY_POLICY_PATH } from "routes/paths";
import HomePage from "ui/pages/HomePage";
import PrivacyPolicyPage from "ui/pages/PrivacyPolicyPage";
import Layout from "ui/components/Layout";
@@ -11,7 +11,7 @@ const App = () => (
<Layout>
<Switch>
<Route exact path={ROOT_PATH} component={HomePage} />
<Route path={PRiVACY_POLICY_PATH} component={PrivacyPolicyPage} />
<Route path={PRIVACY_POLICY_PATH} component={PrivacyPolicyPage} />
</Switch>
</Layout>
);
@@ -1,5 +1,6 @@
export const API_GAMES = "/api/games";
export const API_RATINGS = "/api/ratings";
export const API_STATIC_PAGES = "/api/static_pages/:id";
export const API_USER = "/api/user";
export const API_USER_GAMES = "/api/user/games";
export const API_USER_GAME = "/api/user/games/:id";
@@ -1,3 +1,3 @@
export const ROOT_PATH = "/";
export const FACEBOOK_AUTH_PATH = "/auth/facebook";
export const PRiVACY_POLICY_PATH = "/privacy-policy";
export const PRIVACY_POLICY_PATH = "/privacy-policy";
@@ -1,5 +1,7 @@
import cookies from "js-cookie";
import { signUserIn, signUserOut } from "./actionCreators";
import { closeModal } from "../ui/actionCreators";
import { deleteUser } from "./api";

export const setCurrentUser = () => dispatch => {
const currentUser =
@@ -10,6 +12,16 @@ export const setCurrentUser = () => dispatch => {
}
};

export const removeCurrentUser = () => (dispatch, getState) => {
const { token } = getState().Auth.currentUser;

deleteUser(token).then(() => {
cookies.remove("auth");
dispatch(closeModal());
dispatch(signUserOut());
});
};

export const signOut = () => dispatch => {
cookies.remove("auth");
dispatch(signUserOut());
@@ -0,0 +1,8 @@
import axios from "axios";
import { API_USER } from "../../routes/api";
import { setAuthToken } from "../utils";

export const deleteUser = token =>
axios.delete(API_USER, {
...setAuthToken(token)
});
@@ -1,6 +1,6 @@
import { get, put } from "axios";
import { API_RATINGS, API_USER_GAMES, API_USER_GAME } from "../../routes/api";
import { setAuthToken, filtersSerializer } from "./utils";
import { setAuthToken, filtersSerializer } from "../utils";

export const getRatings = params =>
get(API_RATINGS, { params, paramsSerializer: filtersSerializer });
@@ -0,0 +1,16 @@
// @flow
import * as React from "react";
import Button from "./Button";

type Props = {
onClick: () => void,
children: React.Node
};

const DestructiveButton = ({ onClick, children }: Props) => (
<Button className="button-destructive" onClick={onClick} testId="destructive">
{children}
</Button>
);

export default DestructiveButton;
@@ -43,6 +43,10 @@
border: 1px solid $color-primary;
}

.button-destructive {
background-color: $color-destructive;
}

.button-facebook {
color: $color-light;
background-color: $color-facebook;
@@ -1,6 +1,7 @@
// @flow
import "./button.scss";

export { default as DestructiveButton } from "./DestructiveButton";
export { default as FacebookButton } from "./FacebookButton";
export { default as SmallButton } from "./SmallButton";
export { default as SmallInactiveButton } from "./SmallInactiveButton";
@@ -1,16 +1,51 @@
// @flow
import * as React from "react";
import { connect } from "react-redux";
import { Link } from "react-router-dom";
import { PRiVACY_POLICY_PATH } from "routes/paths";
import { PRIVACY_POLICY_PATH } from "routes/paths";
import { openModal } from "state/ui/actionCreators";
import { removeAccount } from "ui/components/Modal";
import "./footer.scss";

const Footer = () => (
<ul className="footer" data-cy="footer">
<li>Games Tracker API is powered by IGDB</li>
<li>
<Link to={PRiVACY_POLICY_PATH}>Privacy Policy</Link>
</li>
</ul>
);
type Props = {
userSignedIn: boolean,
openModal: () => void
};

export default Footer;
const mapStateToProps = ({ Auth }) => ({
userSignedIn: Auth.userSignedIn
});

const mapDispatchToProps = {
openModal
};

const Footer = ({ userSignedIn, openModal }: Props) => {
const openRemoveAccountModal = (
event: SyntheticMouseEvent<HTMLLinkElement>
) => {
event.preventDefault();
openModal(removeAccount);
};

return (
<ul className="footer" data-cy="footer">
<li>Games Tracker API is powered by IGDB</li>
<li>
<Link to={PRIVACY_POLICY_PATH}>Privacy policy</Link>
</li>
{userSignedIn ? (
<li>
<a href="" onClick={openRemoveAccountModal}>
Remove my account
</a>
</li>
) : null}
</ul>
);
};

export default connect(
mapStateToProps,
mapDispatchToProps
)(Footer);
@@ -2,7 +2,9 @@
import * as React from "react";
import { connect } from "react-redux";
import { closeModal } from "state/ui/actionCreators";
import { FacebookButton } from "../Button";
import { removeCurrentUser } from "state/auth/actions";
import { DestructiveButton, FacebookButton } from "../Button";
import store from "state/store";
import "./modal.scss";

type Props = {
@@ -27,6 +29,18 @@ export const notAuthorized = (
</div>
);

export const removeAccount = (
<div>
<p>
You are about to delete your account. Once you do this, there is no going
back.
</p>
<DestructiveButton onClick={() => store.dispatch(removeCurrentUser())}>
Destroy my account
</DestructiveButton>
</div>
);

const Modal = ({ isModalOpen, content, closeModal }: Props) => {
// $FlowFixMe
const modalEl = React.useRef(null);
@@ -1,3 +1,7 @@
class Api::UserController < ApiController
before_action :authorize

def destroy
current_user.destroy
end
end
@@ -1,7 +1,7 @@
class User < ApplicationRecord
validates :email, uniqueness: true, presence: true

has_many :user_games
has_many :user_games, dependent: :destroy
has_many :games, through: :user_games

def self.authenticate(token)
@@ -1,4 +1,4 @@
<h1>Privacy Policy</h1>
<h1>Privacy policy</h1>

<ol>
<li>
@@ -4,6 +4,8 @@
resources :games, only: [:index, :update]
end

delete :user, to: "user#destroy"

resources :games, only: [:index]
resources :ratings, only: [:index, :show]
resources :static_pages, only: [:show], defaults: { format: :html }
@@ -14,4 +14,28 @@ describe("Authentication", () => {
.getId("button-facebook")
.should("exist");
});

it("allows to remove account", () => {
const user = "user@example.com";
cy.signIn(user)
.getId("search-bar-input")
.type("witcher{enter}")
.getId("card-the-witcher-3-wild-hunt")
.findId("dropdown-collection")
.click()
.getId("dropdown-item-playing")
.click()
.visit("/")
.getId("card-the-witcher-3-wild-hunt")
.should("exist")
.getId("footer")
.contains("Remove my account")
.click()
.getId("button-destructive")
.click()
.signIn(user)
.getId("card-the-witcher-3-wild-hunt")
.should("not.exist")
.signOut();
});
});
@@ -9,7 +9,7 @@ describe("Authorization", () => {
.findId("dropdown-collection")
.click()
.getId("modal")
.contains("Please sign in to use this feature.")
.contains("You have to be signed in to use this feature.")
.getId("modal-close")
.click();
});
@@ -19,7 +19,7 @@ describe("Authorization", () => {
.findId("dropdown-rating")
.click()
.getId("modal")
.contains("Please sign in to use this feature.")
.contains("You have to be signed in to use this feature.")
.getId("modal-close")
.click();
});
@@ -29,7 +29,7 @@ describe("Authorization", () => {
.findId("button-small-inactive-pc")
.click()
.getId("modal")
.contains("Please sign in to use this feature.")
.contains("You have to be signed in to use this feature.")
.getId("modal-close")
.click();
});
@@ -2,10 +2,10 @@ describe("Static pages", () => {
it("allows to visit privacy policy", () => {
cy.visit("/")
.getId("footer")
.contains("Privacy Policy")
.contains("Privacy policy")
.click()
.get("h1")
.contains("Privacy Policy")
.contains("Privacy policy")
.should("exist");
});
});
@@ -12,5 +12,8 @@ Cypress.Commands.add("signIn", (email = `user-${Date.now()}@example.com`) => {
});

Cypress.Commands.add("signOut", () => {
cy.clearCookie("auth");
cy.getId("dropdown-user")
.click()
.getId("dropdown-item-sign-out")
.click();
});

0 comments on commit 8e257d5

Please sign in to comment.
You can’t perform that action at this time.