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/get user api integration #190

18 changes: 15 additions & 3 deletions App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,25 @@ import React from 'react';
import { AuthProvider } from './src/context/AuthContext';
import Toast from 'react-native-toast-message';
import Index from './src/Index';
import { applyMiddleware, compose, createStore } from 'redux';
import reducers from './src/reducers';
import { Provider } from 'react-redux';
import createSagaMiddleware from '@redux-saga/core';
import rootSaga from './src/sagas/rootSaga';

const sagaMiddleware = createSagaMiddleware();
const middleware = [sagaMiddleware];
const store = compose(applyMiddleware(...middleware))(createStore)(reducers);
sagaMiddleware.run(rootSaga);

const App = () => {
return (
<>
<AuthProvider>
<Index />
</AuthProvider>
<Provider store={store}>
<AuthProvider>
<Index />
</AuthProvider>
</Provider>
<Toast />
</>
);
Expand Down
40 changes: 40 additions & 0 deletions __tests__/Util-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ import {
updateStatus,
} from '../src/screens/AuthScreen/Util';
import { urls } from '../src/constants/appConstant/url';
import { fetchUserRequest } from '../src/sagas/handlers/user';
import { fetchUserData } from '../src/sagas/requests/fetchUser';
import { call, put } from 'redux-saga/effects';
import Strings from '../src/i18n/en';
import axios from 'axios';

Expand Down Expand Up @@ -133,3 +136,40 @@ test('check is otpcode of valid format', () => {
expect(isValidTextInput('AB12')).toBeFalsy();
expect(isValidTextInput('1%2B')).toBeFalsy();
});

describe('fetchUserRequest', () => {
const action = { type: 'GET_USER', payload: 'lDaUIVTP4sXRwPWh3Gn4' };
const generator = fetchUserRequest(action);

test('should call fetchUserData', () => {
expect(generator.next().value).toEqual(call(fetchUserData, action.payload));
});

test('should dispatch FETCH_USER action', () => {
const user = {
company: 'Deloitte',
designation: 'Frontend Developer',
githubUrl: 'https://twitter.combharati-21',
linkedInUrl: 'https://www.linkedin.com/in/bharati-subramanian-29734b152',
name: 'Bharati Subramanian',
profileUrl:
'https://res.cloudinary.com/realdevsquad/image/upload/v1687759892/profile/lDaUIVTP4sXRwPWh3Gn4/sqaq4clqiprmdwu2lyjk.jpg',
twitterUrl: 'https://github.com/_bhaaratii',
userName: 'bharati',
};
expect(generator.next(user).value).toEqual(
put({ type: 'FETCH_USER', user }),
);
});

test('should dispatch FETCH_USER_ERROR action on error', () => {
const error = new Error('Something went wrong');
expect(generator.throw(error).value).toEqual(
put({ type: 'FETCH_USER_ERROR', message: error.message }),
);
});

test('should be done', () => {
expect(generator.next().done).toBe(true);
});
});
6 changes: 5 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,11 @@
"react-native-safe-area-context": "^3.2.0",
"react-native-screens": "^3.9.0",
"react-native-toast-message": "^2.1.5",
"react-native-webview": "^11.13.0"
"react-native-webview": "^11.13.0",
"react-redux": "^8.1.1",
"redux": "^4.2.1",
"redux-saga": "^1.2.3",
"react-native-vision-camera": "^2.15.4"
},
"devDependencies": {
"@babel/core": "^7.12.9",
Expand Down
6 changes: 6 additions & 0 deletions src/actions/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export const getUser = (userId: string) => {
return {
type: 'GET_USER',
payload: userId,
};
};
5 changes: 5 additions & 0 deletions src/constants/appConstant/url.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,9 @@ export const urls = {
API_ENDPOINT: 'https://api.realdevsquad.com/',
REDIRECT_URL: 'https://www.realdevsquad.com/goto',
GET_USERS_DATA: 'https://api.realdevsquad.com/users/self',
GET_USER_DATA: 'https://api.realdevsquad.com/users?id=',
GET_CONTRIBUTIONS: 'https://api.realdevsquad.com/contributions/',
GITHUB: 'https://github.com/',
TWITTER: 'https://twitter.com',
LINKEDIN: 'https://www.linkedin.com/in/',
};
11 changes: 11 additions & 0 deletions src/context/type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,14 @@ export type loggedInUserType = {
profileUrl: string;
status: string;
};

export interface User {
name: string;
profileUrl: string;
userName: string;
designation: string;
company: string;
linkedInUrl: string;
twitterUrl: string;
githubUrl: string;
}
6 changes: 6 additions & 0 deletions src/reducers/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { combineReducers } from 'redux';
import user from './user.reducer';

const reducers = combineReducers({ user });

export default reducers;
20 changes: 20 additions & 0 deletions src/reducers/user.reducer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
export const intialState = {
data: {},
loading: false,
error: '',
};

const user = (state = intialState, action) => {
switch (action.type) {
case 'FETCH_USER':
return { ...state, loading: false, data: action.user };
case 'GET_USER':
return { ...state, loading: true };
case 'FETCH_USER_ERROR':
return { ...state, loading: false, error: action.message };
default:
return state;
}
};

export default user;
18 changes: 18 additions & 0 deletions src/sagas/handlers/user.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { call, put, takeEvery } from 'redux-saga/effects';
import { User } from '../../context/type';
import { fetchUserData } from '../requests/fetchUser';

export function* fetchUserRequest(action) {
try {
const user: User = yield call(fetchUserData, action.payload);
yield put({ type: 'FETCH_USER', user: user });
} catch (error: any) {
yield put({ type: 'FETCH_USER_ERROR', message: error.message });
}
}

function* watchUserRequestSaga() {
yield takeEvery('GET_USER', fetchUserRequest);
}

export default watchUserRequestSaga;
26 changes: 26 additions & 0 deletions src/sagas/requests/fetchUser.ts
shreya-mishra marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import axios from 'axios';
import { urls } from '../../constants/appConstant/url';
import { User } from '../../context/type';

export const fetchUserData = async (userId: string): Promise<User | null> => {
try {
const response = await axios.get(urls.GET_USER_DATA + userId, {
headers: {
cookie: '',
},
});
const user = response.data.user;
return {
name: user.github_display_name,
profileUrl: user.picture?.url,
userName: user.username,
designation: user.designation,
company: user.company,
linkedInUrl: urls.LINKEDIN + user.linkedin_id,
twitterUrl: urls.GITHUB + user.twitter_id,
githubUrl: urls.TWITTER + user.github_id,
};
} catch (error) {
throw error;
}
};
8 changes: 8 additions & 0 deletions src/sagas/rootSaga.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { all } from 'redux-saga/effects';
import watchUserRequestSaga from './handlers/user';

function* rootSaga() {
yield all([watchUserRequestSaga()]);
}

export default rootSaga;
13 changes: 13 additions & 0 deletions src/screens/AuthScreen/Util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,19 @@ export const getUserData = async (url: string) => {
}
};

export const fetchContribution = async (userName: string): Promise<any> => {
try {
const response = await axios.get(urls.GET_CONTRIBUTIONS + userName, {
headers: {
cookie: '',
},
});
return response.data;
} catch (error) {
return null;
}
};

export const updateStatus = async (status: string) => {
const res = await axios.patch(
urls.GET_USERS_DATA,
Expand Down
11 changes: 10 additions & 1 deletion src/screens/HomeScreen/HomeScreen.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useContext, useState } from 'react';
import React, { useContext, useEffect, useState } from 'react';
import { Text, View, TouchableOpacity } from 'react-native';
import { AuthContext } from '../../context/AuthContext';
import withHeader from '../../helpers/withHeader';
Expand All @@ -7,9 +7,12 @@ import Strings from '../../i18n/en';
import { updateStatus } from '../AuthScreen/Util';
import { HomeViewStyle } from './styles';
import Toast from 'react-native-toast-message';
import { useDispatch } from 'react-redux';
import { getUser } from '../../actions';

const HomeScreen = () => {
const [loader, setLoader] = useState<boolean>(false);
const dispatch = useDispatch();

const { loggedInUserData, setLoggedInUserData } = useContext(AuthContext);

Expand Down Expand Up @@ -75,6 +78,12 @@ const HomeScreen = () => {
</View>
);
};

useEffect(() => {
// TODO: get the userId from global store
dispatch(getUser('lDaUIVTP4sXRwPWh3Gn4'));
}, [dispatch]);

return <View style={HomeViewStyle.container}>{renderScreen()}</View>;
};

Expand Down
21 changes: 21 additions & 0 deletions src/screens/ProfileScreen/ProfileScreen.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
// TODO: we wil remove this once we start using userData and contributionData
/* eslint-disable @typescript-eslint/no-unused-vars */
import React, { useState, useCallback, useContext } from 'react';
import { View, Text, Pressable } from 'react-native';
import { ScreenViewContainer } from '../../styles/GlobalStyle';
Expand All @@ -9,10 +11,19 @@ import UploadImageModalView from '../../components/GalleryModal';
import { AuthContext } from '../../context/AuthContext';
import { ImagePickerResponse } from 'react-native-image-picker';
import Strings from '../../i18n/en';
import { fetchContribution } from '../AuthScreen/Util';
import { useFocusEffect } from '@react-navigation/native';

import { useSelector } from 'react-redux';

const ProfileScreen = () => {
const { data: userData } = useSelector((store) => store.user);
const [response, setResponse] = useState<ImagePickerResponse>({});
const [modalVisible, setModalVisible] = useState(false);
const [contributionData, setContributionData] = useState({
allData: [],
noteworthy: [],
});
const { loggedInUserData, setLoggedInUserData } = useContext(AuthContext);
console.log('loggedIn', loggedInUserData);

Expand All @@ -36,6 +47,16 @@ const ProfileScreen = () => {
return true;
};

useFocusEffect(
useCallback(() => {
(async () => {
const userName = 'ankush';
const contributionResponse = await fetchContribution(userName);
setContributionData(contributionResponse);
})();
}, []),
);

return (
<View style={ScreenViewContainer.container}>
<Pressable
Expand Down
Loading
Loading