Skip to content

Commit

Permalink
Adds account signup functionality
Browse files Browse the repository at this point in the history
  • Loading branch information
Kyle Andrews committed Aug 9, 2019
1 parent 84eadde commit 3045a3b
Show file tree
Hide file tree
Showing 5 changed files with 224 additions and 15 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ class V1Controller extends Controller
* The actions must be in 'kebab-case'
* @access protected
*/
protected $allowAnonymous = ['login'];
protected $allowAnonymous = true;

// Public Methods
// =========================================================================
Expand All @@ -44,4 +44,13 @@ public function actionLogin()
$response = PrototypeModule::$instance->userService->loginUser($request->getBodyParams());
return json_encode($response);
}

public function actionSignup()
{
$this->requirePostRequest();
$this->requireAcceptsJson();
$request = Craft::$app->getRequest();
$response = PrototypeModule::$instance->userService->signupUser($request->getBodyParams());
return json_encode($response);
}
}
76 changes: 76 additions & 0 deletions craftcms/modules/prototypemodule/src/services/UserService.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

use Craft;
use craft\base\Component;
use craft\elements\User;

/**
* @author Kyle Andrews
Expand Down Expand Up @@ -98,4 +99,79 @@ public function loginUser(Array $params)

return $response;
}

public function signupUser(Array $params)
{
$response['success'] = true;
$response['errors'] = [];

if (!isset($params['name']))
{
$response['success'] = false;
$response['errors'][] = [
'id' => 'name',
'message' => 'This field is required.'
];
}

if (!isset($params['email']))
{
$response['success'] = false;
$response['errors'][] = [
'id' => 'email',
'message' => 'This field is required.'
];
}

if (!isset($params['password']))
{
$response['success'] = false;
$response['errors'][] = [
'id' => 'password',
'message' => 'This field is required.'
];
}

if (!$response['success'])
{
return $response;
}

$name = $params['name'];
$email = $params['email'];
$password = $params['password'];

$existingUser = Craft::$app->getUsers()->getUserByUsernameOrEmail($email);
if(!empty($existingUser))
{
$response['success'] = false;
$response['errors'][] = [
'id' => 'email',
'message' => 'Email address already exists. Try signing in.'
];
return $response;
}

$user = new User();
$user->newPassword = $password;
$user->email = $email;
$user->username = $user->email;
$user->firstName = $name;
$token = Craft::$app->request->getCsrfToken();
$response['token'] = $token;
$user->setFieldValue('sessionToken', $token);

if (!Craft::$app->getElements()->saveElement($user, true))
{
$response['success'] = false;
$response['errors'][] = [
'message' => 'Failed to create account, please try again later.'
];
return $response;
}

Craft::$app->getUsers()->activateUser($user);

return $response;
}
}
30 changes: 26 additions & 4 deletions src/LoginForm.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import React, { Component } from "react";
import { render } from "react-dom";

import { SignupForm } from './SignupForm';

export class LoginForm extends React.Component
{
private _loginForm : HTMLFormElement|null;
Expand All @@ -15,6 +17,18 @@ export class LoginForm extends React.Component
}

private submitFormEvent:EventListener = this.submitLoginForm.bind(this);
private handleSignupClick:EventListener = this.showSignupForm.bind(this);

private showSignupForm()
{

if (this._loginForm && this._loginForm.parentElement)
{
this._loginForm.parentElement.style.display = 'none';
}

new SignupForm();
}

private submitLoginForm(e:Event)
{
Expand Down Expand Up @@ -47,23 +61,31 @@ export class LoginForm extends React.Component

componentDidMount()
{
this._loginForm = document.body.querySelector('form');
this._loginForm = document.body.querySelector('.t-login form');

if (this._loginForm)
{
this._loginForm.addEventListener('submit', this.submitFormEvent);
}

const signupButton:HTMLButtonElement|null = document.body.querySelector('.t-login p button');

if (signupButton)
{
signupButton.addEventListener('click', this.handleSignupClick);
}
}

render()
{
return (
<div className="t-login">
<form className="is-hidden">
<input type="email" name="email" placeholder="Email" />
<input type="password" name="password" placeholder="Password" />
<form>
<input type="email" name="email" placeholder="Email" required />
<input type="password" name="password" placeholder="Password" required />
<button type="submit">Log In</button>
</form>
<p>Don't have an account? <button>Sign up.</button></p>
</div>
);
}
Expand Down
87 changes: 87 additions & 0 deletions src/SignupForm.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import React, { Component } from "react";
import { render } from "react-dom";

export class SignupForm extends React.Component
{

private _root : HTMLElement;

private _form : HTMLFormElement|null;

constructor(props:any = null)
{
super(props);

this._form = null;

this._root = (document.body.querySelector('main') || document.body);
render(<SignupForm />, this._root);
}

private handleFormSubmit:EventListener = this.submitSignupForm.bind(this);

private submitSignupForm(e:Event)
{
e.preventDefault();

if (!this._form)
{
return;
}

const data = new FormData(this._form);

fetch('http://react-craft.local/actions/prototype/v1/signup',
{
method: 'POST',
headers: new Headers({
'Accept': 'application/json',
'X-Requested-With': 'XMLHttpRequest'
}),
body: data
})
.then(request => request.json())
.then(response => {
if (response.success)
{
sessionStorage.setItem('token', response.token);
}
else if(response.errors.length)
{
for (let i = 0; i < response.errors.length; i++)
{
console.error(response.errors[i]);
}
}
})
.catch(error => {
console.error('Failed to sign up user', error);
});
}

componentDidMount()
{
this._form = this._root.querySelector('.t-signup form');

if (this._form)
{

this._form.addEventListener('submit', this.handleFormSubmit);
}
}

render()
{
return(
<div className="t-signup">
<form>
<input type="text" name="name" placeholder="Full Name" required />
<input type="email" name="email" placeholder="Email" required />
<input type="password" name="password" placeholder="Password" required />
<button type="submit">Sign Up</button>
</form>
<p>Already have an account? <button>Log in.</button></p>
</div>
);
}
}
35 changes: 25 additions & 10 deletions src/base.css
Original file line number Diff line number Diff line change
Expand Up @@ -34,30 +34,29 @@ main
flex-flow: column wrap;
}

.t-login
.t-login form,
.t-signup form
{
display: grid;
grid-template-rows: 1fr;
gap: 2rem;
background-color: var(--off-white);
border-radius: 1rem;
width: 420px;
padding: 2rem;
}

.t-login form
{
display: grid;
grid-template-rows: 1fr;
gap: 2rem;
}

.t-login form input
.t-login form input,
.t-signup form input
{
border: 2px solid rgba(23, 41, 81, 0.3);
height: 48px;
line-height: 48px;
padding: 14px 16px 12px 16px;
}

.t-login form button
.t-login form button,
.t-signup form button
{
height: 36px;
line-height: 32px;
Expand All @@ -71,3 +70,19 @@ main
text-transform: uppercase;
font-size: 14px;
}

.t-login p,
.t-signup p
{
color: var(--off-white);
margin-top: 2rem;
text-align: center;
display: block;
}

.t-login p button,
.t-signup p button
{
color: var(--primary);
cursor: pointer;
}

0 comments on commit 3045a3b

Please sign in to comment.