First attempt at getting a prototype up

This commit is contained in:
Kyle Corbelli committed 2017-09-02 15:07:05 -07:00
1 parent d0e63d5b9c
commit 10488ed6ba
40 files changed
+4673 -88

No files matched your search

+242
View File
@@ -0,0 +1,242 @@
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __generator = (this && this.__generator) || function (thisArg, body) {
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
function verb(n) { return function (v) { return step([n, v]); }; }
function step(op) {
if (f) throw new TypeError("Generator is already executing.");
while (_) try {
if (f = 1, y && (t = y[op[0] & 2 ? "return" : op[0] ? "throw" : "next"]) && !(t = t.call(y, op[1])).done) return t;
if (y = 0, t) op = [0, t.value];
switch (op[0]) {
case 0: case 1: t = op; break;
case 4: _.label++; return { value: op[1], done: false };
case 5: _.label++; y = op[1]; op = [0]; continue;
case 7: op = _.ops.pop(); _.trys.pop(); continue;
default:
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
if (t[2]) _.ops.pop();
_.trys.pop(); continue;
}
op = body.call(thisArg, _);
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
}
};
exports.__esModule = true;
var axios_1 = require("axios");
var types_1 = require("./types");
var auth_1 = require("./services/auth"); // <- maybe this is where you pass in the platform paramter, specifying if it is for a browser or for React Native
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Pure Redux actions:
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
exports.registrationRequestSent = function () { return ({
type: types_1.REGISTRATION_REQUEST_SENT
}); };
exports.registrationRequestSucceeded = function (userAttributes) { return ({
type: types_1.REGISTRATION_REQUEST_SUCCEEDED,
payload: {
userAttributes: userAttributes
}
}); };
exports.registrationRequestFailed = function () { return ({
type: types_1.REGISTRATION_REQUEST_FAILED
}); };
exports.verifyTokenRequestSent = function () { return ({
type: types_1.VERIFY_TOKEN_REQUEST_SENT
}); };
exports.verifyTokenRequestSucceeded = function (userAttributes) { return ({
type: types_1.VERIFY_TOKEN_REQUEST_SUCCEEDED,
payload: {
userAttributes: userAttributes
}
}); };
exports.verifyTokenRequestFailed = function () { return ({
type: types_1.VERIFY_TOKEN_REQUEST_FAILED
}); };
exports.signInRequestSent = function () { return ({
type: types_1.SIGNIN_REQUEST_SENT
}); };
exports.signInRequestSucceeded = function (userAttributes) { return ({
type: types_1.SIGNIN_REQUEST_SUCCEEDED,
payload: {
userAttributes: userAttributes
}
}); };
exports.signInRequestFailed = function () { return ({
type: types_1.SIGNIN_REQUEST_FAILED
}); };
exports.signOutRequestSent = function () { return ({
type: types_1.SIGNOUT_REQUEST_SENT
}); };
exports.signOutRequestSucceeded = function () { return ({
type: types_1.SIGNOUT_REQUEST_SUCCEEDED
}); };
exports.signOutRequestFailed = function () { return ({
type: types_1.SIGNOUT_REQUEST_FAILED
}); };
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Async Redux Thunk actions:
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Maybe type this even:
var theActionsExportThatShouldBeRenamed = function (authUrl) {
var registerUser = function (userRegistrationDetails) { return function (dispatch) {
return __awaiter(this, void 0, void 0, function () {
var firstName, email, password, passwordConfirmation, response, userAttributes, error_1;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
dispatch(exports.registrationRequestSent());
firstName = userRegistrationDetails.firstName, email = userRegistrationDetails.email, password = userRegistrationDetails.password, passwordConfirmation = userRegistrationDetails.passwordConfirmation;
_a.label = 1;
case 1:
_a.trys.push([1, 3, , 4]);
return [4 /*yield*/, axios_1["default"]({
method: 'POST',
url: authUrl,
data: {
email: email,
name: firstName,
password: password,
password_confirmation: passwordConfirmation
}
})];
case 2:
response = _a.sent();
auth_1.setAuthHeaders(response.headers);
auth_1.persistAuthHeadersInLocalStorage(response.headers);
userAttributes = {
firstName: firstName
};
dispatch(exports.registrationRequestSucceeded(userAttributes));
return [3 /*break*/, 4];
case 3:
error_1 = _a.sent();
dispatch(exports.registrationRequestFailed());
throw error_1;
case 4: return [2 /*return*/];
}
});
});
}; };
var verifyToken = function (verificationParams) { return function (dispatch) {
return __awaiter(this, void 0, void 0, function () {
var response, name, userAttributes, error_2;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
dispatch(exports.verifyTokenRequestSent());
_a.label = 1;
case 1:
_a.trys.push([1, 3, , 4]);
return [4 /*yield*/, axios_1["default"]({
method: 'GET',
url: authUrl + "/validate_token",
params: verificationParams
})];
case 2:
response = _a.sent();
name = response.data.data.name;
auth_1.setAuthHeaders(response.headers);
auth_1.persistAuthHeadersInLocalStorage(response.headers);
userAttributes = {
firstName: name
};
dispatch(exports.verifyTokenRequestSucceeded(userAttributes));
return [3 /*break*/, 4];
case 3:
error_2 = _a.sent();
dispatch(exports.verifyTokenRequestFailed());
return [3 /*break*/, 4];
case 4: return [2 /*return*/];
}
});
});
}; };
var signInUser = function (userSignInCredentials) { return function (dispatch) {
return __awaiter(this, void 0, void 0, function () {
var email, password, response, name, userAttributes, error_3;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
dispatch(exports.signInRequestSent());
email = userSignInCredentials.email, password = userSignInCredentials.password;
_a.label = 1;
case 1:
_a.trys.push([1, 3, , 4]);
return [4 /*yield*/, axios_1["default"]({
method: 'POST',
url: authUrl + "/sign_in",
data: {
email: email,
password: password
}
})];
case 2:
response = _a.sent();
auth_1.setAuthHeaders(response.headers);
auth_1.persistAuthHeadersInLocalStorage(response.headers);
name = response.data.data.name;
userAttributes = {
firstName: name
};
dispatch(exports.signInRequestSucceeded(userAttributes));
return [3 /*break*/, 4];
case 3:
error_3 = _a.sent();
dispatch(exports.signInRequestFailed());
throw error_3;
case 4: return [2 /*return*/];
}
});
});
}; };
var signOutUser = function (userSignOutCredentials) { return function (dispatch) {
return __awaiter(this, void 0, void 0, function () {
var error_4;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
dispatch(exports.signOutRequestSent());
_a.label = 1;
case 1:
_a.trys.push([1, 3, , 4]);
return [4 /*yield*/, axios_1["default"]({
method: 'DELETE',
url: authUrl + "/sign_out",
data: userSignOutCredentials
})];
case 2:
_a.sent();
auth_1.deleteAuthHeaders();
auth_1.deleteAuthHeadersFromLocalStorage();
dispatch(exports.signOutRequestSucceeded());
return [3 /*break*/, 4];
case 3:
error_4 = _a.sent();
dispatch(exports.signOutRequestFailed());
throw error_4;
case 4: return [2 /*return*/];
}
});
});
}; };
return {
registerUser: registerUser,
verifyToken: verifyToken,
signInUser: signInUser,
signOutUser: signOutUser
};
};
exports["default"] = theActionsExportThatShouldBeRenamed;
+225
View File
@@ -0,0 +1,225 @@
import axios from 'axios'
// import { authUrl } from '../../constants' // this has to be passed in by the package user
import { Dispatch } from 'redux'
import {
AuthResponse,
VerificationParams,
UserAttributes,
UserRegistrationDetails,
UserSignInCredentials,
UserSignOutCredentials,
REGISTRATION_REQUEST_SENT,
REGISTRATION_REQUEST_SUCCEEDED,
REGISTRATION_REQUEST_FAILED,
VERIFY_TOKEN_REQUEST_SENT,
VERIFY_TOKEN_REQUEST_SUCCEEDED,
VERIFY_TOKEN_REQUEST_FAILED,
SIGNIN_REQUEST_SENT,
SIGNIN_REQUEST_SUCCEEDED,
SIGNIN_REQUEST_FAILED,
SIGNOUT_REQUEST_SENT,
SIGNOUT_REQUEST_SUCCEEDED,
SIGNOUT_REQUEST_FAILED,
RegistrationRequestSentAction,
RegistrationRequestSucceededAction,
RegistrationRequestFailedAction,
VerifyTokenRequestSentAction,
VerifyTokenRequestSucceededAction,
VerifyTokenRequestFailedAction,
SignInRequestSentAction,
SignInRequestSucceededAction,
SignInRequestFailedAction,
SignOutRequestSentAction,
SignOutRequestSucceededAction,
SignOutRequestFailedAction,
} from './types'
import {
setAuthHeaders,
deleteAuthHeaders,
persistAuthHeadersInLocalStorage,
deleteAuthHeadersFromLocalStorage,
} from './services/auth' // <- maybe this is where you pass in the platform paramter, specifying if it is for a browser or for React Native
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Pure Redux actions:
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
export const registrationRequestSent = (): RegistrationRequestSentAction => ({
type: REGISTRATION_REQUEST_SENT,
})
export const registrationRequestSucceeded = (userAttributes: UserAttributes): RegistrationRequestSucceededAction => ({
type: REGISTRATION_REQUEST_SUCCEEDED,
payload: {
userAttributes,
},
})
export const registrationRequestFailed = (): RegistrationRequestFailedAction => ({
type: REGISTRATION_REQUEST_FAILED,
})
export const verifyTokenRequestSent = (): VerifyTokenRequestSentAction => ({
type: VERIFY_TOKEN_REQUEST_SENT,
})
export const verifyTokenRequestSucceeded = (userAttributes: UserAttributes): VerifyTokenRequestSucceededAction => ({
type: VERIFY_TOKEN_REQUEST_SUCCEEDED,
payload: {
userAttributes,
},
})
export const verifyTokenRequestFailed = (): VerifyTokenRequestFailedAction => ({
type: VERIFY_TOKEN_REQUEST_FAILED,
})
export const signInRequestSent = (): SignInRequestSentAction => ({
type: SIGNIN_REQUEST_SENT,
})
export const signInRequestSucceeded = (userAttributes: UserAttributes): SignInRequestSucceededAction => ({
type: SIGNIN_REQUEST_SUCCEEDED,
payload: {
userAttributes,
},
})
export const signInRequestFailed = (): SignInRequestFailedAction => ({
type: SIGNIN_REQUEST_FAILED,
})
export const signOutRequestSent = (): SignOutRequestSentAction => ({
type: SIGNOUT_REQUEST_SENT,
})
export const signOutRequestSucceeded = (): SignOutRequestSucceededAction => ({
type: SIGNOUT_REQUEST_SUCCEEDED,
})
export const signOutRequestFailed = (): SignOutRequestFailedAction => ({
type: SIGNOUT_REQUEST_FAILED,
})
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Async Redux Thunk actions:
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Maybe type this even:
const theActionsExportThatShouldBeRenamed = (authUrl: string) => {
const registerUser = (
userRegistrationDetails: UserRegistrationDetails,
) => async function (dispatch: Dispatch<{}>): Promise<void> {
dispatch(registrationRequestSent())
const {
firstName,
email,
password,
passwordConfirmation,
} = userRegistrationDetails
try {
const response: AuthResponse = await axios({
method: 'POST',
url: authUrl,
data: {
email,
name: firstName, // even this is tricky because it requires the user's devise configuration to allow the "name" attribute
password,
password_confirmation: passwordConfirmation,
},
})
setAuthHeaders(response.headers)
persistAuthHeadersInLocalStorage(response.headers)
// Gonna need to refer to the passed-in User model configuration from the package user
const userAttributes: UserAttributes = {
firstName,
}
dispatch(registrationRequestSucceeded(userAttributes))
} catch (error) {
dispatch(registrationRequestFailed())
throw error
}
}
const verifyToken = (
verificationParams: VerificationParams,
) => async function (dispatch: Dispatch<{}>): Promise<void> {
dispatch(verifyTokenRequestSent())
try {
const response = await axios({
method: 'GET',
url: `${authUrl}/validate_token`,
params: verificationParams,
})
const { name } = response.data.data
setAuthHeaders(response.headers)
persistAuthHeadersInLocalStorage(response.headers)
// Gonna need to refer to the passed-in User model configuration from the package user
const userAttributes: UserAttributes = {
firstName: name,
}
dispatch(verifyTokenRequestSucceeded(userAttributes))
} catch (error) {
dispatch(verifyTokenRequestFailed())
}
}
const signInUser = (
userSignInCredentials: UserSignInCredentials,
) => async function (dispatch: Dispatch<{}>): Promise<void> {
dispatch(signInRequestSent())
const {
email,
password,
} = userSignInCredentials
try {
const response = await axios({
method: 'POST',
url: `${authUrl}/sign_in`,
data: {
email,
password,
},
})
setAuthHeaders(response.headers)
persistAuthHeadersInLocalStorage(response.headers)
// Gonna need to refer to the passed-in User model configuration from the package user
const { name } = response.data.data
const userAttributes: UserAttributes = {
firstName: name,
}
dispatch(signInRequestSucceeded(userAttributes))
} catch (error) {
dispatch(signInRequestFailed())
throw error
}
}
const signOutUser = (
userSignOutCredentials: UserSignOutCredentials,
) => async function (dispatch: Dispatch<{}>): Promise<void> {
dispatch(signOutRequestSent())
try {
await axios({
method: 'DELETE',
url: `${authUrl}/sign_out`,
data: userSignOutCredentials,
})
deleteAuthHeaders()
deleteAuthHeadersFromLocalStorage()
dispatch(signOutRequestSucceeded())
} catch (error) {
dispatch(signOutRequestFailed())
throw error
}
}
return {
registerUser,
verifyToken,
signInUser,
signOutUser,
}
}
export default theActionsExportThatShouldBeRenamed
+24
View File
@@ -0,0 +1,24 @@
"use strict";
exports.__esModule = true;
var actions_1 = require("./actions");
exports.theActionsExportThatShouldBeRenamed = actions_1["default"];
var reducers_1 = require("./reducers");
exports.reduxTokenAuthReducer = reducers_1["default"];
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Example of how the end-user will import the actions
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// import {
// generateAuthFunctions,
// } from 'redux-token-auth'
//
// const authUrl: string = 'http://www.someapp.com/auth'
// const userAttributes = {
// firstName: 'name',
// imageUrl: 'image_url',
// }
// const {
// registerUser,
// verifyToken,
// signInUser,
// signOutUser,
// } = generateAuthFunctions(authUrl, userAttributes)
+27
View File
@@ -0,0 +1,27 @@
import theActionsExportThatShouldBeRenamed from './actions'
import reduxTokenAuthReducer from './reducers'
export {
theActionsExportThatShouldBeRenamed,
reduxTokenAuthReducer,
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Example of how the end-user will import the actions
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// import {
// generateAuthFunctions,
// } from 'redux-token-auth'
//
// const authUrl: string = 'http://www.someapp.com/auth'
// const userAttributes = {
// firstName: 'name',
// imageUrl: 'image_url',
// }
// const {
// registerUser,
// verifyToken,
// signInUser,
// signOutUser,
// } = generateAuthFunctions(authUrl, userAttributes)
+10
View File
@@ -0,0 +1,10 @@
"use strict";
exports.__esModule = true;
var initialState = {
currentUser: {
isLoggedIn: false,
isLoading: false,
attributes: {}
}
};
exports["default"] = initialState;
+13
View File
@@ -0,0 +1,13 @@
import {
ReduxState
} from './types'
const initialState: ReduxState = {
currentUser: {
isLoggedIn: false,
isLoading: false,
attributes: {},
},
}
export default initialState
+39
View File
@@ -0,0 +1,39 @@
"use strict";
var __assign = (this && this.__assign) || Object.assign || function(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
t[p] = s[p];
}
return t;
};
exports.__esModule = true;
var types_1 = require("../../types");
var initial_state_1 = require("../../initial-state");
var initialUser = initial_state_1["default"].currentUser;
var currentUser = function (state, action) {
if (state === void 0) { state = initialUser; }
switch (action.type) {
case types_1.REGISTRATION_REQUEST_SENT:
case types_1.VERIFY_TOKEN_REQUEST_SENT:
case types_1.SIGNIN_REQUEST_SENT:
case types_1.SIGNOUT_REQUEST_SENT:
return __assign({}, state, { isLoading: true });
case types_1.REGISTRATION_REQUEST_SUCCEEDED:
case types_1.VERIFY_TOKEN_REQUEST_SUCCEEDED:
case types_1.SIGNIN_REQUEST_SUCCEEDED:
var userAttributes = action.payload.userAttributes;
return __assign({}, state, { attributes: __assign({}, userAttributes), isLoading: false, isLoggedIn: true });
case types_1.REGISTRATION_REQUEST_FAILED:
case types_1.VERIFY_TOKEN_REQUEST_FAILED:
case types_1.SIGNIN_REQUEST_FAILED:
return __assign({}, state, { isLoading: false, isLoggedIn: false });
case types_1.SIGNOUT_REQUEST_SUCCEEDED:
return __assign({}, state, { attributes: __assign({}, state.attributes, { firstName: null }), isLoading: false, isLoggedIn: false });
case types_1.SIGNOUT_REQUEST_FAILED:
return __assign({}, state, { isLoading: false });
default:
return state;
}
};
exports["default"] = currentUser;
+191
View File
@@ -0,0 +1,191 @@
import currentUser from './index'
import {
RegistrationRequestSentAction,
RegistrationRequestSucceededAction,
RegistrationRequestFailedAction,
VerifyTokenRequestSentAction,
VerifyTokenRequestSucceededAction,
VerifyTokenRequestFailedAction,
SignInRequestSentAction,
SignInRequestSucceededAction,
SignInRequestFailedAction,
SignOutRequestSentAction,
SignOutRequestSucceededAction,
SignOutRequestFailedAction,
User,
UserAttributes,
} from '../../types'
import {
registrationRequestSent,
registrationRequestSucceeded,
registrationRequestFailed,
verifyTokenRequestSent,
verifyTokenRequestSucceeded,
verifyTokenRequestFailed,
signInRequestSent,
signInRequestSucceeded,
signInRequestFailed,
signOutRequestSent,
signOutRequestSucceeded,
signOutRequestFailed,
} from '../../actions'
describe('currentUser', () => {
const alreadyLoadingState: User = {
attributes: {
firstName: null,
},
isLoading: true,
isLoggedIn: false,
}
const loggedInUser: User = {
attributes: {
firstName: 'Snowball',
},
isLoading: false,
isLoggedIn: true,
}
const loggedInUserWithRequestAlreadySent: User = {
...loggedInUser,
isLoading: true,
}
describe('REGISTRATION_REQUEST_SENT', () => {
it('indicates that the current user is loading', () => {
const action: RegistrationRequestSentAction = registrationRequestSent()
const newState: User = currentUser(undefined, action)
expect(newState.isLoading).toBe(true)
})
})
describe('REGISTRATION_REQUEST_SUCCEEDED', () => {
it('sets the current user and indicates that it is no longer loading and is logged in', () => {
const newUserAttributes: UserAttributes = {
firstName: 'Rick',
}
const action: RegistrationRequestSucceededAction = registrationRequestSucceeded(newUserAttributes)
const newState: User = currentUser(alreadyLoadingState, action)
const expectedNewState: User = {
attributes: newUserAttributes,
isLoading: false,
isLoggedIn: true,
}
expect(newState).toEqual(expectedNewState)
})
})
describe('REGISTRATION_REQUEST_FAILED', () => {
it('indicates that the current user is no longer loading', () => {
const action: RegistrationRequestFailedAction = registrationRequestFailed()
const newState: User = currentUser(alreadyLoadingState, action)
expect(newState.isLoading).toBe(false)
})
})
describe('VERIFY_TOKEN_REQUEST_SENT', () => {
it('indicates that the current user is loading', () => {
const action: VerifyTokenRequestSentAction = verifyTokenRequestSent()
const newState: User = currentUser(undefined, action)
expect(newState.isLoading).toBe(true)
})
})
describe('VERIFY_TOKEN_REQUEST_SUCCEEDED', () => {
it('sets the current user and indicates that it is no longer loading and is logged in', () => {
const newUserAttributes: UserAttributes = {
firstName: 'Morty',
}
const action: VerifyTokenRequestSucceededAction = verifyTokenRequestSucceeded(newUserAttributes)
const newState: User = currentUser(alreadyLoadingState, action)
const expectedNewState: User = {
attributes: newUserAttributes,
isLoading: false,
isLoggedIn: true,
}
expect(newState).toEqual(expectedNewState)
})
})
describe('VERIFY_TOKEN_REQUEST_FAILED', () => {
it('indicates that the current user is no longer loading and is not logged in', () => {
const loggedInState: User = {
...alreadyLoadingState,
isLoggedIn: true,
}
const action: VerifyTokenRequestFailedAction = verifyTokenRequestFailed()
const newState: User = currentUser(loggedInState, action)
expect(newState.isLoading).toBe(false)
expect(newState.isLoggedIn).toBe(false)
})
})
describe('SIGNIN_REQUEST_SENT', () => {
it('indicates that the current user is loading', () => {
const action: SignInRequestSentAction = signInRequestSent()
const newState: User = currentUser(undefined, action)
expect(newState.isLoading).toBe(true)
})
})
describe('SIGNIN_REQUEST_SUCCEEDED', () => {
it('sets the current user and indicates that it is no longer loading and is logged in', () => {
const newUserAttributes: UserAttributes = {
firstName: 'Rick',
}
const action: SignInRequestSucceededAction = signInRequestSucceeded(newUserAttributes)
const newState: User = currentUser(alreadyLoadingState, action)
const expectedNewState: User = {
attributes: newUserAttributes,
isLoading: false,
isLoggedIn: true,
}
expect(newState).toEqual(expectedNewState)
})
})
describe('SIGNIN_REQUEST_FAILED', () => {
it('indicates that the current user is no longer loading and is not logged in', () => {
const action: SignInRequestFailedAction = signInRequestFailed()
const newState: User = currentUser(alreadyLoadingState, action)
expect(newState.isLoading).toBe(false)
expect(newState.isLoggedIn).toBe(false)
})
})
describe('SIGNOUT_REQUEST_SENT', () => {
it('indicates that the current user is loading', () => {
const action: SignOutRequestSentAction = signOutRequestSent()
const newState: User = currentUser(loggedInUser, action)
expect(newState.isLoading).toBe(true)
})
})
describe('SIGNOUT_REQUEST_SUCCEEDED', () => {
it('indicates that the current user is not loading, is logged out, and has empty attributes', () => {
const action: SignOutRequestSucceededAction = signOutRequestSucceeded()
const newState: User = currentUser(loggedInUserWithRequestAlreadySent, action)
const expectedNewState: User = {
attributes: {
firstName: null,
},
isLoading: false,
isLoggedIn: false,
}
expect(newState).toEqual(expectedNewState)
})
})
describe('SIGNOUT_REQUEST_FAILED', () => {
it('indicates that the user is not loading but is stilled logged in', () => {
const action: SignOutRequestFailedAction = signOutRequestFailed()
const newState: User = currentUser(loggedInUserWithRequestAlreadySent, action)
const expectedNewState: User = {
...loggedInUserWithRequestAlreadySent,
isLoading: false,
}
expect(newState).toEqual(expectedNewState)
})
})
})
+71
View File
@@ -0,0 +1,71 @@
import {
User,
ReduxAction,
REGISTRATION_REQUEST_SENT,
REGISTRATION_REQUEST_SUCCEEDED,
REGISTRATION_REQUEST_FAILED,
VERIFY_TOKEN_REQUEST_SENT,
VERIFY_TOKEN_REQUEST_SUCCEEDED,
VERIFY_TOKEN_REQUEST_FAILED,
SIGNIN_REQUEST_SENT,
SIGNIN_REQUEST_SUCCEEDED,
SIGNIN_REQUEST_FAILED,
SIGNOUT_REQUEST_SENT,
SIGNOUT_REQUEST_SUCCEEDED,
SIGNOUT_REQUEST_FAILED,
} from '../../types'
import initialState from '../../initial-state'
const {
currentUser: initialUser,
} = initialState
const currentUser = (state: User = initialUser, action: ReduxAction): User => {
switch (action.type) {
case REGISTRATION_REQUEST_SENT:
case VERIFY_TOKEN_REQUEST_SENT:
case SIGNIN_REQUEST_SENT:
case SIGNOUT_REQUEST_SENT:
return {
...state,
isLoading: true,
}
case REGISTRATION_REQUEST_SUCCEEDED:
case VERIFY_TOKEN_REQUEST_SUCCEEDED:
case SIGNIN_REQUEST_SUCCEEDED:
const { userAttributes } = action.payload
return {
...state,
attributes: { ...userAttributes },
isLoading: false,
isLoggedIn: true,
}
case REGISTRATION_REQUEST_FAILED:
case VERIFY_TOKEN_REQUEST_FAILED:
case SIGNIN_REQUEST_FAILED:
return {
...state,
isLoading: false,
isLoggedIn: false,
}
case SIGNOUT_REQUEST_SUCCEEDED:
return {
...state,
attributes: {
...state.attributes,
firstName: null,
},
isLoading: false,
isLoggedIn: false,
}
case SIGNOUT_REQUEST_FAILED:
return {
...state,
isLoading: false,
}
default:
return state
}
}
export default currentUser
+20
View File
@@ -0,0 +1,20 @@
"use strict";
exports.__esModule = true;
var redux_1 = require("redux");
var current_user_1 = require("./current-user");
var reduxTokenAuthReducer = redux_1.combineReducers({
currentUser: current_user_1["default"]
});
exports["default"] = reduxTokenAuthReducer;
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// An example of how the end-user will integrate this into their Redux store
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// import { combineReducers } from 'redux'
// import { reduxTokenAuthReducer } from 'redux-token-auth'
// import { myCustomReducer } from './my-custom-reducer'
//
// const rootReducer = combineReducers({
// reduxTokenAuth: reduxTokenAuthReducer,
// myCustomReducer,
// })
// Remember, they will have to user Redux Thunk when configuring their store
+23
View File
@@ -0,0 +1,23 @@
import { combineReducers } from 'redux'
import currentUser from './current-user'
const reduxTokenAuthReducer = combineReducers({
currentUser,
})
export default reduxTokenAuthReducer
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// An example of how the end-user will integrate this into their Redux store
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// import { combineReducers } from 'redux'
// import { reduxTokenAuthReducer } from 'redux-token-auth'
// import { myCustomReducer } from './my-custom-reducer'
//
// const rootReducer = combineReducers({
// reduxTokenAuth: reduxTokenAuthReducer,
// myCustomReducer,
// })
// Remember, they will have to user Redux Thunk when configuring their store
+32
View File
@@ -0,0 +1,32 @@
"use strict";
exports.__esModule = true;
var axios_1 = require("axios");
var authHeaderKeys = [
'access-token',
'token-type',
'client',
'expiry',
'uid',
];
exports.setAuthHeaders = function (headers) {
authHeaderKeys.forEach(function (key) {
axios_1["default"].defaults.headers.common[key] = headers[key];
});
};
// Will have to take a parameter from the package user to determine if this is for a browser or for React Native:
exports.persistAuthHeadersInLocalStorage = function (headers) {
authHeaderKeys.forEach(function (key) {
localStorage.setItem(key, headers[key]);
});
};
exports.deleteAuthHeaders = function () {
authHeaderKeys.forEach(function (key) {
delete axios_1["default"].defaults.headers.common[key];
});
};
// Will have to take a parameter from the package user to determine if this is for a browser or for React Native:
exports.deleteAuthHeadersFromLocalStorage = function () {
authHeaderKeys.forEach(function (key) {
localStorage.removeItem(key);
});
};
+34
View File
@@ -0,0 +1,34 @@
import axios from 'axios'
import { AuthHeaders } from '../types'
import {
setAuthHeaders,
deleteAuthHeaders,
} from './auth'
describe('auth service', () => {
const headers: AuthHeaders = {
'access-token': 'accessToken',
'token-type': 'tokenType',
client: 'client',
expiry: 'expiry',
uid: 'uid',
}
describe('setAuthHeaders', () => {
it('sets the appropriate auth headers on the global axios config', () => {
setAuthHeaders(headers)
Object.keys(headers).forEach((key: string) => {
expect(axios.defaults.headers.common[key]).toBe(headers[key])
})
})
})
describe('deleteAuthHeaders', () => {
it('deletes the appropriate auth headers from the global axios config', () => {
deleteAuthHeaders()
Object.keys(headers).forEach((key: string) => {
expect(axios.defaults.headers.common['access-token']).toBeUndefined()
})
})
})
})
+36
View File
@@ -0,0 +1,36 @@
import axios from 'axios'
import { AuthHeaders } from '../types'
const authHeaderKeys: Array<string> = [
'access-token',
'token-type',
'client',
'expiry',
'uid',
]
export const setAuthHeaders = (headers: AuthHeaders): void => {
authHeaderKeys.forEach((key: string) => {
axios.defaults.headers.common[key] = headers[key]
})
}
// Will have to take a parameter from the package user to determine if this is for a browser or for React Native:
export const persistAuthHeadersInLocalStorage = (headers: AuthHeaders): void => {
authHeaderKeys.forEach((key: string) => {
localStorage.setItem(key, headers[key])
})
}
export const deleteAuthHeaders = (): void => {
authHeaderKeys.forEach((key: string) => {
delete axios.defaults.headers.common[key]
})
}
// Will have to take a parameter from the package user to determine if this is for a browser or for React Native:
export const deleteAuthHeadersFromLocalStorage = (): void => {
authHeaderKeys.forEach((key: string) => {
localStorage.removeItem(key)
})
}
+15
View File
@@ -0,0 +1,15 @@
"use strict";
// Maybe make this the index.ts of a types directory so you can split things up
exports.__esModule = true;
exports.REGISTRATION_REQUEST_SENT = 'redux-token-auth/REGISTRATION_REQUEST_SENT';
exports.REGISTRATION_REQUEST_SUCCEEDED = 'redux-token-auth/REGISTRATION_REQUEST_SUCCEEDED';
exports.REGISTRATION_REQUEST_FAILED = 'redux-token-auth/REGISTRATION_REQUEST_FAILED';
exports.VERIFY_TOKEN_REQUEST_SENT = 'redux-token-auth/VERIFY_TOKEN_REQUEST_SENT';
exports.VERIFY_TOKEN_REQUEST_SUCCEEDED = 'redux-token-auth/VERIFY_TOKEN_REQUEST_SUCCEEDED';
exports.VERIFY_TOKEN_REQUEST_FAILED = 'redux-token-auth/VERIFY_TOKEN_REQUEST_FAILED';
exports.SIGNIN_REQUEST_SENT = 'redux-token-auth/SIGNIN_REQUEST_SENT';
exports.SIGNIN_REQUEST_SUCCEEDED = 'redux-token-auth/SIGNIN_REQUEST_SUCCEEDED';
exports.SIGNIN_REQUEST_FAILED = 'redux-token-auth/SIGNIN_REQUEST_FAILED';
exports.SIGNOUT_REQUEST_SENT = 'redux-token-auth/SIGNOUT_REQUEST_SENT';
exports.SIGNOUT_REQUEST_SUCCEEDED = 'redux-token-auth/SIGNOUT_REQUEST_SUCCEEDED';
exports.SIGNOUT_REQUEST_FAILED = 'redux-token-auth/SIGNOUT_REQUEST_FAILED';
+156
View File
@@ -0,0 +1,156 @@
// Maybe make this the index.ts of a types directory so you can split things up
// This one in particular will be a little tough because we don't know what the package user's "User" model looks like:
export interface UserAttributes {}
export interface User {
readonly isLoggedIn: boolean
readonly isLoading: boolean
readonly attributes: UserAttributes
}
export interface ReduxState {
readonly currentUser: User
}
export interface AuthHeaders {
readonly 'access-token': string
readonly 'token-type': string
readonly client: string
readonly expiry: string
readonly uid: string
}
export interface AuthResponse {
readonly headers: AuthHeaders
}
export interface VerificationParams {
readonly uid: string
readonly client: string
readonly 'access-token': string
}
export type REGISTRATION_REQUEST_SENT = 'redux-token-auth/REGISTRATION_REQUEST_SENT'
export const REGISTRATION_REQUEST_SENT: REGISTRATION_REQUEST_SENT = 'redux-token-auth/REGISTRATION_REQUEST_SENT'
export type REGISTRATION_REQUEST_SUCCEEDED = 'redux-token-auth/REGISTRATION_REQUEST_SUCCEEDED'
export const REGISTRATION_REQUEST_SUCCEEDED: REGISTRATION_REQUEST_SUCCEEDED = 'redux-token-auth/REGISTRATION_REQUEST_SUCCEEDED'
export type REGISTRATION_REQUEST_FAILED = 'redux-token-auth/REGISTRATION_REQUEST_FAILED'
export const REGISTRATION_REQUEST_FAILED: REGISTRATION_REQUEST_FAILED = 'redux-token-auth/REGISTRATION_REQUEST_FAILED'
export type VERIFY_TOKEN_REQUEST_SENT = 'redux-token-auth/VERIFY_TOKEN_REQUEST_SENT'
export const VERIFY_TOKEN_REQUEST_SENT: VERIFY_TOKEN_REQUEST_SENT = 'redux-token-auth/VERIFY_TOKEN_REQUEST_SENT'
export type VERIFY_TOKEN_REQUEST_SUCCEEDED = 'redux-token-auth/VERIFY_TOKEN_REQUEST_SUCCEEDED'
export const VERIFY_TOKEN_REQUEST_SUCCEEDED: VERIFY_TOKEN_REQUEST_SUCCEEDED = 'redux-token-auth/VERIFY_TOKEN_REQUEST_SUCCEEDED'
export type VERIFY_TOKEN_REQUEST_FAILED = 'redux-token-auth/VERIFY_TOKEN_REQUEST_FAILED'
export const VERIFY_TOKEN_REQUEST_FAILED: VERIFY_TOKEN_REQUEST_FAILED = 'redux-token-auth/VERIFY_TOKEN_REQUEST_FAILED'
export type SIGNIN_REQUEST_SENT = 'redux-token-auth/SIGNIN_REQUEST_SENT'
export const SIGNIN_REQUEST_SENT: SIGNIN_REQUEST_SENT = 'redux-token-auth/SIGNIN_REQUEST_SENT'
export type SIGNIN_REQUEST_SUCCEEDED = 'redux-token-auth/SIGNIN_REQUEST_SUCCEEDED'
export const SIGNIN_REQUEST_SUCCEEDED: SIGNIN_REQUEST_SUCCEEDED = 'redux-token-auth/SIGNIN_REQUEST_SUCCEEDED'
export type SIGNIN_REQUEST_FAILED = 'redux-token-auth/SIGNIN_REQUEST_FAILED'
export const SIGNIN_REQUEST_FAILED: SIGNIN_REQUEST_FAILED = 'redux-token-auth/SIGNIN_REQUEST_FAILED'
export type SIGNOUT_REQUEST_SENT = 'redux-token-auth/SIGNOUT_REQUEST_SENT'
export const SIGNOUT_REQUEST_SENT: SIGNOUT_REQUEST_SENT = 'redux-token-auth/SIGNOUT_REQUEST_SENT'
export type SIGNOUT_REQUEST_SUCCEEDED = 'redux-token-auth/SIGNOUT_REQUEST_SUCCEEDED'
export const SIGNOUT_REQUEST_SUCCEEDED: SIGNOUT_REQUEST_SUCCEEDED = 'redux-token-auth/SIGNOUT_REQUEST_SUCCEEDED'
export type SIGNOUT_REQUEST_FAILED = 'redux-token-auth/SIGNOUT_REQUEST_FAILED'
export const SIGNOUT_REQUEST_FAILED: SIGNOUT_REQUEST_FAILED = 'redux-token-auth/SIGNOUT_REQUEST_FAILED'
export interface UserRegistrationDetails {
readonly firstName: string
readonly email: string
readonly password: string
readonly passwordConfirmation: string
}
export interface UserSignInCredentials {
readonly email: string
readonly password: string
}
export interface UserSignOutCredentials {
readonly 'access-token': string
readonly client: string
readonly uid: string
}
export interface RegistrationRequestSentAction {
readonly type: REGISTRATION_REQUEST_SENT
}
export interface RegistrationRequestSucceededAction {
readonly type: REGISTRATION_REQUEST_SUCCEEDED
readonly payload: {
readonly userAttributes: UserAttributes
}
}
export interface RegistrationRequestFailedAction {
readonly type: REGISTRATION_REQUEST_FAILED
}
export interface VerifyTokenRequestSentAction {
readonly type: VERIFY_TOKEN_REQUEST_SENT
}
export interface VerifyTokenRequestSucceededAction {
readonly type: VERIFY_TOKEN_REQUEST_SUCCEEDED
readonly payload: {
readonly userAttributes: UserAttributes
}
}
export interface VerifyTokenRequestFailedAction {
readonly type: VERIFY_TOKEN_REQUEST_FAILED
}
export interface SignInRequestSentAction {
readonly type: SIGNIN_REQUEST_SENT
}
export interface SignInRequestSucceededAction {
readonly type: SIGNIN_REQUEST_SUCCEEDED
readonly payload: {
readonly userAttributes: UserAttributes
}
}
export interface SignInRequestFailedAction {
readonly type: SIGNIN_REQUEST_FAILED
}
export interface SignOutRequestSentAction {
readonly type: SIGNOUT_REQUEST_SENT
}
export interface SignOutRequestSucceededAction {
readonly type: SIGNOUT_REQUEST_SUCCEEDED
}
export interface SignOutRequestFailedAction {
readonly type: SIGNOUT_REQUEST_FAILED
}
export type ReduxAction = RegistrationRequestSentAction
| RegistrationRequestSucceededAction
| RegistrationRequestFailedAction
| VerifyTokenRequestSentAction
| VerifyTokenRequestSucceededAction
| VerifyTokenRequestFailedAction
| SignInRequestSentAction
| SignInRequestSucceededAction
| SignInRequestFailedAction
| SignOutRequestSentAction
| SignOutRequestSucceededAction
| SignOutRequestFailedAction