Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/authentication #3

Open
wants to merge 21 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 6 commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
42bf83a
First commit for authentication, local TO BO FIXED code, migration fr…
Waysker Aug 13, 2020
545d7da
remote commit without husky. First authentication commit, TODO refact…
Waysker Aug 15, 2020
9f766c3
Fixed navigation, merged with existing views. Refactored naming and f…
Waysker Aug 17, 2020
c0c1e0b
Some fixes, migrated to SecureStore, used .env isntead of hardcoded A…
Waysker Aug 21, 2020
3135673
Fixed git not detecting auth.js->Auth.js name change
Waysker Aug 21, 2020
9add299
Reworked register form using formik + yup validation. Added global au…
Waysker Sep 6, 2020
df3ac7d
Changed register to polish, reworked auth flow
Waysker Sep 12, 2020
6b280a6
Merge branch 'master' into feature/authentication
Waysker Sep 13, 2020
1422b0f
Added bypass button for logging in during development, added temp log…
Waysker Sep 13, 2020
341d240
Refactored login with formik + yup, visual changes.
Waysker Oct 1, 2020
1eac964
Refactored spacing adn register view
Waysker Oct 1, 2020
c1ce3dd
Merge branch 'master' into feature/authentication, refactore forgotPa…
Waysker Oct 18, 2020
35d5d4c
commit fix
Waysker Oct 18, 2020
8fa265c
Remove package-lock.json
pectom Oct 19, 2020
6e384d3
Fix proptypes warning
pectom Oct 24, 2020
ce96ac1
Remove unused dependencies
pectom Oct 24, 2020
725d096
Fix default prop values in app button
pectom Oct 24, 2020
632f832
Fix error response validation
pectom Oct 24, 2020
765137d
Remove unused colors
pectom Oct 24, 2020
ef1ee4f
Remove strange naviagtion to username route in Authloading
pectom Oct 24, 2020
cabeceb
Standardise api error displaying in alerts, remove unused unused comp…
pectom Oct 24, 2020
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions App.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import PatientsContextProvider from "./src/modules/context/PatientsContext";

export default function App() {
console.log(`Initialize app in ${process.env.NODE_ENV}`);
console.log(`${process.env.AUTH_API_URL}/user/upload`);
return (
<PatientsContextProvider>
<MainNavigator />
Expand Down
9,401 changes: 9,401 additions & 0 deletions package-lock.json

Large diffs are not rendered by default.

9 changes: 8 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,20 +15,27 @@
"@react-native-community/masked-view": "0.1.10",
"@react-navigation/native": "^5.7.3",
"@react-navigation/stack": "^5.9.0",
"axios": "^0.19.2",
"babel-plugin-inline-dotenv": "^1.6.0",
"expo": "~38.0.8",
"expo-font": "~8.2.1",
"expo-secure-store": "~9.0.1",
"expo-status-bar": "^1.0.2",
"formik": "^2.1.5",
"native-base": "^2.13.13",
"prop-types": "^15.7.2",
"react": "~16.11.0",
"react-dom": "~16.11.0",
"react-native": "https://github.com/expo/react-native/archive/sdk-38.0.2.tar.gz",
"react-native-basic-form": "^1.1.11",
pectom marked this conversation as resolved.
Show resolved Hide resolved
"react-native-elements": "^2.2.1",
"react-native-gesture-handler": "~1.6.0",
"react-native-reanimated": "~1.9.0",
"react-native-safe-area-context": "~3.0.7",
"react-native-screens": "~2.9.0",
"react-native-web": "~0.11.7"
"react-native-web": "~0.11.7",
"yarn": "^1.22.4",
"yup": "^0.29.3"
},
"devDependencies": {
"@babel/core": "^7.8.6",
Expand Down
47 changes: 47 additions & 0 deletions src/api/Auth.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import axios from "axios";

import * as endpoints from "../constants/endpoints/auth";

export function handler(err) {
let error = err;

if (
err.response &&
Object.prototype.hasOwnProperty.call(err.response.data, "message")
pectom marked this conversation as resolved.
Show resolved Hide resolved
)
error = err.response.data;
else if (!Object.prototype.hasOwnProperty.call(err, "message"))
error = err.toJSON();

return new Error(error.message);
}

export async function register(data) {
try {
const response = await axios.post(endpoints.REGISTER, data);

return response.data;
} catch (e) {
throw handler(e);
}
}

export async function login(data) {
try {
const response = await axios.post(endpoints.LOGIN, data);

return response.data;
} catch (e) {
throw handler(e);
}
}

export async function forgotPassword(data) {
try {
const response = await axios.post(endpoints.FORGOT_PASSWORD, data);

return response.data;
} catch (e) {
throw handler(e);
}
}
75 changes: 75 additions & 0 deletions src/components/authentication/CTA.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import React from "react";
import {
View,
Text,
TouchableOpacity,
StyleSheet,
ViewPropTypes,
} from "react-native";
import PropTypes from "prop-types";
import { Typography, Colors } from "../../constants/styles";

export default function CTA({
pectom marked this conversation as resolved.
Show resolved Hide resolved
title,
ctaText,
onPress,
style,
titleStyle,
ctaStyle,
}) {
return (
<View style={[styles.footer, style]}>
{title && (
Waysker marked this conversation as resolved.
Show resolved Hide resolved
<Text
style={[styles.footerText, titleStyle, ctaText && { marginRight: 5 }]}
Waysker marked this conversation as resolved.
Show resolved Hide resolved
>
{title}
</Text>
)}

{ctaText && (
<TouchableOpacity onPress={onPress}>
<Text style={[styles.footerCTA, ctaStyle]}>{ctaText}</Text>
</TouchableOpacity>
)}
</View>
);
}

CTA.propTypes = {
title: PropTypes.string,
ctaText: PropTypes.string,
onPress: PropTypes.func,
style: ViewPropTypes.style,
titleStyle: ViewPropTypes.style,
ctaStyle: ViewPropTypes.style,
};
CTA.defaultProps = {
title: null,
ctaText: null,
onPress: {},
style: {},
titleStyle: {},
ctaStyle: {},
};

const styles = StyleSheet.create({
footer: {
flexDirection: "row",
justifyContent: "center",
alignItems: "center",
},

footerText: {
fontSize: Typography.FONT_SIZE_16,
fontFamily: Typography.FONT_AUTH.fontFamily,
color: Colors.AUTH_GRAY,
},

footerCTA: {
fontSize: Typography.FONT_SIZE_16,
color: Colors.AUTH_VIOLET,
fontWeight: Typography.FONT_AUTH.fontWeight,
fontFamily: Typography.FONT_AUTH.fontFamily,
},
});
54 changes: 54 additions & 0 deletions src/components/authentication/Shared.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import React from "react";
import { View, Text, StyleSheet, ViewPropTypes } from "react-native";
import PropTypes from "prop-types";
import { Typography, Colors } from "../../constants/styles";

// HEADER COMPONENT
export const Header = ({ title, style }) => {
pectom marked this conversation as resolved.
Show resolved Hide resolved
return (
<View style={[styles.header, style]}>
<Text style={styles.headerText}>{title}</Text>
</View>
);
};

Header.defaultProps = {
style: {},
};

// ERROR COMPONENT
export const ErrorText = ({ error }) => {
return <Text style={styles.errorText}>{error}</Text>;
};

ErrorText.defaultProps = {
error: "",
};

ErrorText.propTypes = {
error: PropTypes.string,
};

Header.propTypes = {
title: PropTypes.string.isRequired,
style: ViewPropTypes.style,
};

const styles = StyleSheet.create({
header: {
height: 50,
justifyContent: "center",
},

headerText: {
fontSize: Typography.FONT_SIZE_25,
color: Colors.AUTH_VIOLET_Dark,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A jest użycie tego koloru tylko, że z literówką

fontWeight: Typography.FONT_AUTH.fontWeight,
fontFamily: Typography.FONT_AUTH.fontFamily,
},

errorText: {
marginBottom: 8,
color: "red",
},
});
8 changes: 8 additions & 0 deletions src/constants/endpoints/auth.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// eslint-disable-next-line no-unused-vars
import React from "react";
// API End Points
export const REGISTER = `${process.env.AUTH_API_URL}/auth/register`;
export const LOGIN = `${process.env.AUTH_API_URL}/auth/login`;
export const UPDATE_PROFILE = `${process.env.AUTH_API_URL}/user`;
export const UPLOAD_IMAGE = `${process.env.AUTH_API_URL}/user/upload`;
export const FORGOT_PASSWORD = `${process.env.AUTH_API_URL}/auth/recover`;
2 changes: 2 additions & 0 deletions src/constants/keys/Auth.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export const TOKEN_KEY = "token";
export const USER_KEY = "user";
22 changes: 22 additions & 0 deletions src/constants/styles/auth.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { StyleSheet } from "react-native";
import { Colors, Typography } from "./index";

export const AUTH_STYLES = StyleSheet.create({
container: {
flex: 1,
paddingHorizontal: 16,
backgroundColor: Colors.WHITE,
},
login: {
marginTop: 50,
},
inputs: {
fontSize: Typography.FONT_SIZE_16,
borderColor: Colors.AUTH_VIOLET,
borderWidth: 1,
padding: 10,
borderRadius: 6,
},
});

export default AUTH_STYLES;
5 changes: 5 additions & 0 deletions src/constants/styles/colors.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,8 @@ export const ALERT = "#cc4b37";
export const GRAY_LIGHT = "#e6e6e6";
export const GRAY_MEDIUM = "#cacaca";
export const GRAY_DARK = "#8a8a8a";

// AUTH
export const AUTH_VIOLET = "#733AC2";
pectom marked this conversation as resolved.
Show resolved Hide resolved
export const AUTH_GRAY = "#636466";
export const AUTH_VIOLET_DARK = "362068";
8 changes: 8 additions & 0 deletions src/constants/styles/typography.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { Platform } from "react-native";
import { scaleFont } from "./mixins";

// FONT FAMILY
export const font = Platform.OS === "ios" ? "HelveticaNeue" : "Roboto"; // temp
export const FONT_FAMILY_REGULAR = "OpenSans-Regular";
export const FONT_FAMILY_BOLD = "OpenSans-Bold";

Expand All @@ -9,6 +11,7 @@ export const FONT_WEIGHT_REGULAR = "400";
export const FONT_WEIGHT_BOLD = "700";

// FONT SIZE
export const FONT_SIZE_25 = scaleFont(25);
export const FONT_SIZE_16 = scaleFont(16);
export const FONT_SIZE_14 = scaleFont(14);
export const FONT_SIZE_12 = scaleFont(12);
Expand All @@ -28,3 +31,8 @@ export const FONT_BOLD = {
fontFamily: FONT_FAMILY_BOLD,
fontWeight: FONT_WEIGHT_BOLD,
};

export const FONT_AUTH = {
fontFamily: Platform.OS === "ios" ? "HelveticaNeue" : "Roboto",
fontWeight: "500",
};
104 changes: 104 additions & 0 deletions src/modules/context/Auth.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
import React, { useMemo, useReducer, useContext } from "react";
import * as SecureStore from "expo-secure-store";
import axios from "axios";
import PropTypes from "prop-types";
import { TOKEN_KEY, USER_KEY } from "../../constants/keys/Auth";

// IMPORT REDUCER, INITIAL STATE AND ACTION TYPES
import reducer, { initialState, LOGGED_IN, LOGGED_OUT } from "./AuthReducer";

// CONFIG KEYS [Storage Keys]===================================
export const keys = [TOKEN_KEY, USER_KEY];

// CONTEXT ===================================
const AuthContext = React.createContext();

function AuthProvider(props) {
const [state, dispatch] = useReducer(reducer, initialState || {});

// Get Auth state
const getAuthState = async () => {
try {
// GET TOKEN && USER
const token = await SecureStore.getItemAsync(TOKEN_KEY);
let user = await SecureStore.getItemAsync(USER_KEY);
user = JSON.parse(user);

if (token !== null && user !== null) await handleLogin({ token, user });
else await handleLogout();

return { token, user };
} catch (error) {
throw new Error(error);
}
};

// Handle Login
const handleLogin = async (data) => {
try {
// STORE DATA
const { token, user } = data;

// TODO use Promise.all for multiple Key sets
await SecureStore.setItemAsync(USER_KEY, JSON.stringify(user));
await SecureStore.setItemAsync(TOKEN_KEY, token);

// AXIOS AUTHORIZATION HEADER
axios.defaults.headers.common.Authorization = `Bearer ${data.token}`;

// DISPATCH TO REDUCER
dispatch({ type: LOGGED_IN, user: data.user });
} catch (error) {
throw new Error(error);
}
};

// Handle Logout
const handleLogout = async () => {
try {
// REMOVE DATA

// TODO? use Promise.all for multiple Key sets
await SecureStore.deleteItemAsync(TOKEN_KEY);
await SecureStore.deleteItemAsync(USER_KEY);

// AXIOS AUTHORIZATION HEADER
delete axios.defaults.headers.common.Authorization;

// DISPATCH TO REDUCER
dispatch({ type: LOGGED_OUT });
} catch (error) {
throw new Error(error);
}
};

// UPDATE USER LOCAL STORAGE DATA AND DISPATCH TO REDUCER
const updateUser = async (user) => {
try {
await SecureStore.setItemAsync(USER_KEY, JSON.stringify(user));
dispatch({ type: LOGGED_IN, user }); // DISPATCH TO REDUCER
} catch (error) {
throw new Error(error);
}
};

const value = useMemo(() => {
return { state, getAuthState, handleLogin, handleLogout, updateUser };
}, [state]);

AuthProvider.propTypes = {
children: PropTypes.node,
};

AuthProvider.defaultProps = {
children: {},
};

const { children } = props;

return <AuthContext.Provider value={value}>{children}</AuthContext.Provider>;
}

const useAuth = () => useContext(AuthContext);
export { AuthContext, useAuth };
export default AuthProvider;
Loading