Skip to content

Commit

Permalink
feat: Create signup model
Browse files Browse the repository at this point in the history
see: #8
  • Loading branch information
sujinleeme committed Jul 10, 2018
1 parent 7175a7d commit 7c6384f
Show file tree
Hide file tree
Showing 5 changed files with 249 additions and 0 deletions.
12 changes: 12 additions & 0 deletions src/signup/actions.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { SIGNUP_REQUESTING } from "./constants"

const signupRequest = ({email, password}) => {
console.log("called")
return {
type: SIGNUP_REQUESTING,
email,
password
}
}

export default signupRequest
3 changes: 3 additions & 0 deletions src/signup/constants.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export const SIGNUP_REQUESTING = "SIGNUP_REQUESTING"
export const SIGNUP_SUCCESS = "SIGNUP_SUCCESS"
export const SIGNUP_ERROR = "SIGNUP_ERROR"
114 changes: 114 additions & 0 deletions src/signup/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
import React from "react"
import PropTypes from "prop-types"
import { withStyles } from "@material-ui/core/styles"
import MenuItem from "@material-ui/core/MenuItem"
import TextField from "@material-ui/core/TextField"
import Modal from "@material-ui/core/Modal"
import Button from "@material-ui/core/Button"

const styles = theme => ({
container: {
display: "flex",
flexWrap: "wrap"
},
textField: {
marginLeft: theme.spacing.unit,
marginRight: theme.spacing.unit,
width: 200
},
menu: {
width: 200
}
})

const currencies = [
{
value: "USD",
label: "$"
},
{
value: "EUR",
label: "€"
},
{
value: "BTC",
label: "฿"
},
{
value: "JPY",
label: "¥"
}
]

class Signup extends React.Component {
state = {
open: false,
name: "Cat in the Hat",
age: "",
multiline: "Controlled",
currency: "EUR"
}

handleOpen = () => {
this.setState({open: true})
}

handleClose = () => {
this.setState({open: false})
}

handleChange = name => event => {
this.setState({
[name]: event.target.value
})
}

render() {
const {classes} = this.props

return (
<Modal
aria-labelledby="simple-modal-title"
aria-describedby="simple-modal-description"

>
<form className={ classes.container } noValidate autoComplete="on">
<TextField
id="textarea"
label="With placeholder multiline"
placeholder="Placeholder"
multiline
className={ classes.textField }
margin="normal"
/>
<TextField
required
id="required"
label="Required"
defaultValue="Hello World"
className={ classes.textField }
margin="normal"
/>
<TextField
id="textarea"
label="With placeholder multiline"
placeholder="Placeholder"
multiline
className={ classes.textField }
margin="normal"
/>
</form>
</Modal>
)
}
}
/*
TextFields.propTypes = {
classes: PropTypes.object.isRequired
}
*/



export default withStyles(styles)(Signup)
58 changes: 58 additions & 0 deletions src/signup/reducer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import {
SIGNUP_REQUESTING,
SIGNUP_SUCCESS,
SIGNUP_ERROR
} from "./constants"

const initialState = {
requesting: false,
successful: false,
messages: [],
errors: []
}

const reducer = (state = initialState, action) => {
switch (action.type) {
case SIGNUP_REQUESTING:
return {
requesting: true,
successful: false,
messages: [{body: "Signing up...", time: new Date()}],
errors: []
}

// reset the state and add a body message of success!
// remember our successful returned payload will be:
// {"email": "of the new user", "id": "of the user"}
case SIGNUP_SUCCESS:
return {
errors: [],
messages: [{
body: `Successfully created account for ${action.response.email}`,
time: new Date()
}],
requesting: false,
successful: true
}

// reset the state but with errors!
// the error payload returned is actually far
// more detailed, but we'll just stick with
// the base message for now
case SIGNUP_ERROR:
return {
errors: state.errors.concat([{
body: action.error.toString(),
time: new Date()
}]),
messages: [],
requesting: false,
successful: false
}

default:
return state
}
}

export default reducer
62 changes: 62 additions & 0 deletions src/signup/sagas.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import { call, put, takeLatest } from "redux-saga/effects"
import { handleApiErrors } from "../lib/api-errors"
import {
SIGNUP_REQUESTING,
SIGNUP_SUCCESS,
SIGNUP_ERROR
} from "./constants"

// The url derived from our .env file
const signupUrl = `${process.env.REACT_APP_API_URL}/api/Clients`

function signupApi(email, password) {
// call to the "fetch". this is a "native" function for browsers
// that's conveniently polyfilled in create-react-app if not available
return fetch(signupUrl, {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({email, password})
})
.then(handleApiErrors) // we'll make this in a second
.then(response => response.json())
.then(json => json)
.catch((error) => {
throw error
})
}

// This will be run when the SIGNUP_REQUESTING
// Action is found by the watcher
function* signupFlow(action) {
try {
const {email, password} = action
// pulls "calls" to our signupApi with our email and password
// from our dispatched signup action, and will PAUSE
// here until the API async function, is complete!
const response = yield call(signupApi, email, password)

// when the above api call has completed it will "put",
// or dispatch, an action of type SIGNUP_SUCCESS with
// the successful response.
yield put({type: SIGNUP_SUCCESS, response})
} catch (error) {
// if the api call fails, it will "put" the SIGNUP_ERROR
// into the dispatch along with the error.
yield put({type: SIGNUP_ERROR, error})
}
}

// Watches for the SIGNUP_REQUESTING action type
// When it gets it, it will call signupFlow()
// WITH the action we dispatched
function* signupWatcher() {
// takeLatest() takes the LATEST call of that action and runs it
// if we we're to use takeEvery, it would take every single
// one of the actions and kick off a new task to handle it
// CONCURRENTLY!!!
yield takeLatest(SIGNUP_REQUESTING, signupFlow)
}

export default signupWatcher

0 comments on commit 7c6384f

Please sign in to comment.