Fakultas Ilmu Komputer UI

Commit 62fc9c8f authored by Nandhika Prayoga's avatar Nandhika Prayoga
Browse files
parents e588c76b 49ca0e5c
Pipeline #39357 canceled with stages
in 46 minutes and 54 seconds
import React, {useState, useEffect} from 'react';
import React, {useState, useEffect, useRef} from 'react';
import styled, {ThemeProvider} from 'styled-components/native';
import {NavigationContainer} from '@react-navigation/native';
import {createStackNavigator} from '@react-navigation/stack';
......@@ -14,6 +14,7 @@ import {
ContactInvestigationFormStep2,
ContactInvestigationFormStep3,
ContactInvestigationFormStep4,
Splash
} from 'scenes';
import {Dimensions} from 'react-native';
import initialCacheState, {
......@@ -83,8 +84,10 @@ const theme: ThemeProps = {
const App = () => {
const [cache, setCache] = useState<CacheType>(initialCacheState);
const [token, setToken] = useState('');
const [token, setToken] = useState();
const [user, setUser] = useState();
const [isFirstTimeHandleToken, setIsFirstTimeHandleToken] = useState(true);
const navigatorRef = useRef()
const mainService = useMainService(token);
const global: GlobalProps = {
......@@ -103,32 +106,39 @@ const App = () => {
cache,
setCache,
};
useEffect(() => {
LocalStorage.setSecretKey("sssttt")
const setSessionIfExist = async () => {
const token = await LocalStorage.getItem("token")
if (token) {
setToken(token)
if (token) {
const getUser = async () => {
const response = await mainService.me()
if (response.status === 200) {
setUser(response.data)
navigatorRef.current?.reset({
index: 0,
routes: [{name: 'home'}]
})
}
}
getUser()
} else if (token === '') {
navigatorRef.current?.reset({
index: 0,
routes: [{name: 'login'}]
})
}
setSessionIfExist()
}, [])
}, [token])
return (
<AppContext.Provider value={global}>
<ThemeProvider theme={theme}>
<StyledApp>
<NavigationContainer>
<NavigationContainer ref={navigatorRef}>
<Stack.Navigator
screenOptions={{
// Empty header
header: () => <></>,
}}>
<Stack.Screen name="splash" component={Splash} />
<Stack.Screen name="login" component={LoginPage} />
<Stack.Screen name="home" component={Home} />
<Stack.Screen
......
......@@ -33,7 +33,7 @@ const Header = ({
<FlexControl>
<Image
style={{borderRadius: 100, width: imageSize, height: imageSize}}
source={require('./img/pl_img.jpg')}
source={require('../../../assets/icons/user-placeholder.png')}
/>
<TextView>
<Text fontSize={greetingFont}>Halo, {greetingName} !</Text>
......
......@@ -2,8 +2,9 @@ import React, {useContext, useState, useEffect} from 'react';
import { useNavigation } from '@react-navigation/native';
import styled from 'styled-components/native';
import {Header, Text, Button} from 'components';
import {Header, Text, Button, Box, Gap} from 'components';
import {AppContext} from 'contexts';
import {LocalStorage} from 'services';
interface User {
username: string;
......@@ -15,16 +16,25 @@ const Home = () => {
const headerFont = global.vh * 0.033;
const subHeaderFont = global.vh * 0.026;
const subContentFont = global.vh * 0.022;
const [user, setUser] = useState<User | null>(null);
useEffect(() => {
setUser({username: 'Dep'});
}, []);
return (
<Container>
<Header isHome={true} greetingName={(user && user.username) || 'Jojo'} />
<Header isHome={true} greetingName={(global.user && global.user.name.split(" ")[0]) || ''} />
<Content>
<Box
width="150px"
>
<Button
type={Button.Type.Outline}
onPress={async () => {
global.setToken("")
await LocalStorage.setItem("token", "")
}}
>
LOGOUT
</Button>
</Box>
<Gap gap={16} axis={Gap.Axis.Vertical} />
<Text isBold={true} fontSize={headerFont}>
Hari ini saya akan
</Text>
......
......@@ -444,7 +444,7 @@ exports[`renders correctly 1`] = `
]
}
>
Nama tidak boleh kosong
</Text>
</View>
</View>
......@@ -578,7 +578,7 @@ exports[`renders correctly 1`] = `
onChangeText={[Function]}
placeholder="Password"
rejectResponderTermination={true}
secureTextEntry={false}
secureTextEntry={true}
style={
Array [
Object {
......@@ -689,7 +689,7 @@ exports[`renders correctly 1`] = `
]
}
>
Nama tidak boleh kosong
</Text>
</View>
</View>
......
import React, {useContext, useState} from 'react';
import {AppContext} from 'contexts';
import React, {useContext} from 'react';
import styled from 'styled-components/native';
import {Button, Text, Field} from '../../components';
import {Button, Text, Field} from 'components';
import {useFormState} from 'helpers';
import {LocalStorage} from 'services';
import {useNavigation} from '@react-navigation/native';
const LoginPage = () => {
const navigation = useNavigation();
const global = useContext(AppContext);
const headingSize = 0.06 * global.vh;
const [isLoading, setIsLoading] = useState(false)
const [isFirstTime, setIsFirstTime] = useState(true)
const { vh, setToken, services } = useContext(AppContext);
const headingSize = 0.06 * vh;
const [form, setField] = useFormState({
username: {type: 'any'},
password: {type: 'any'},
username: {
type: 'text',
pattern: /^[a-zA-Z0-9]+$/
},
password: {
type: 'password'
},
});
return (
......@@ -27,7 +33,7 @@ const LoginPage = () => {
name="Username"
placeholder="Username"
information={
form.fields.username.isValid ? '' : 'Nama tidak boleh kosong'
isFirstTime || form.fields.username.isValid ? '' : 'Username tidak boleh kosong atau hanya mengandung karakter alphanumerik'
}
updateValue={val => setField('username', val)}
/>
......@@ -35,20 +41,44 @@ const LoginPage = () => {
<FieldControl>
<Field
name="Password"
shouldSecure={true}
placeholder="Password"
information={
form.fields.password.isValid ? '' : 'Nama tidak boleh kosong'
isFirstTime || form.fields.password.isValid ? '' : 'Password tidak boleh kosong atau harus mengandung setidaknya 1 huruf kecil, 1 huruf besar, 1 angka dengan panjang minimal 8 karakter'
}
updateValue={val => setField('password', val)}
/>
</FieldControl>
</Container>
<Action>
<Button type={1} onPress={() => navigation.navigate('home')}>Masuk Aplikasi</Button>
<Button
type={Button.Type.Filled}
clickable={!isLoading}
onPress={async () => {
setIsFirstTime(false)
setIsLoading(true)
if (form.isValid) {
const loginResponse = await services.main.login({
username: form.fields.username.value,
password: form.fields.password.value,
})
if (loginResponse.status === 200) {
LocalStorage.setItem("token", loginResponse.data.token)
setToken(loginResponse.data.token)
}
}
setIsLoading(false)
}}
>
Masuk Aplikasi
</Button>
<Line />
<Button
type={1}
onPress={() => navigation.navigate('officer-signup-form')}>
clickable={!isLoading}
type={Button.Type.Filled}
onPress={() => navigation.navigate('officer-signup-form')}
>
Ajukan Akun Kader
</Button>
</Action>
......
/**
* @format
*/
import 'react-native';
import React from 'react';
import {LocalStorage} from 'services';
import {NavigationContainer} from '@react-navigation/native';
import {createStackNavigator} from '@react-navigation/stack';
import Splash from '.';
// Note: test renderer must be required after react-native.
import renderer, { act } from 'react-test-renderer';
const Stack = createStackNavigator();
LocalStorage.setSecretKey("sssttt")
LocalStorage.setItem("token", "token listrik")
it('renders correctly', () => {
const instance = renderer.create(
<NavigationContainer>
<Stack.Navigator
screenOptions={{
// Empty header
header: () => <></>,
}}>
<Stack.Screen name="splash" component={Splash} />
</Stack.Navigator>
</NavigationContainer>,
);
expect(instance).toBeTruthy()
});
import React, { useEffect, useContext } from 'react'
import splashIcon from '../../../assets/illustrations/doctor-team.png'
import { Image } from 'react-native'
import { Box } from 'components'
import { LocalStorage } from 'services'
import { AppContext } from 'contexts'
export default function Splash() {
const { setToken } = useContext(AppContext)
useEffect(() => {
LocalStorage.setSecretKey("sssttt")
const setTokenIfExist = async () => {
const token = await LocalStorage.getItem("token")
if (token) {
setToken(token)
} else {
setToken('')
}
}
setTokenIfExist()
}, [])
return (
<Box
height="100%"
width="100%"
background="white"
mainAxis="center"
crossAxis="center"
>
<Image
resizeMode="contain"
style={{
height: "70%",
width: "70%",
}}
source={splashIcon}
/>
</Box>
)
}
\ No newline at end of file
......@@ -9,8 +9,10 @@ import {
OfficerSignupFormFinishPage,
ContactInvestigationFormFinishPage,
} from './FinishPage';
import Splash from './Splash'
export {
Splash,
Home,
LoginPage,
OfficerSignupForm,
......
......@@ -8,6 +8,30 @@ describe('Test API that needs token', () => {
const withAuth = useMainServices('my-secret-token');
describe('Authentication and User', () => {
test('Login', async () => {
const auth = {
"username": "admin",
"password": "password"
}
const token = "random-token"
mockedAxios.request.mockImplementationOnce(
() => new Promise(resolve => {
resolve({
status: 200,
data: {
token,
},
});
})
);
const result = await withAuth.login(auth)
expect(result.status).toBe(200);
expect(result.data).toMatchObject({token});
})
test('Get current user profile', async () => {
const userProfile = {
"id": "d207657e-f0e6-4f9b-828e-af94fc654ca3",
......
......@@ -3,9 +3,8 @@ import axios from 'axios';
import { API_MAIN_URL } from 'react-native-dotenv';
const END_POINTS = {
LOGIN: '/login',
LOGIN: '/auth/token/',
ACCOUNT: createEndpoint(["accounts"]),
ME: '/accounts/me',
CREATE_CASE_SUBJECT: createEndpoint(["cases", "case-subjects"]),
CREATE_INVESTIGATION_CASE: createEndpoint(["cases", "investigation-cases"])
};
......@@ -71,7 +70,10 @@ export default function useMainService(token: string) {
}
async function me() {
return fetchWithAuthentication(END_POINTS.ME, Method.GET)
const endpoint = END_POINTS.ACCOUNT([
"me"
])
return fetchWithAuthentication(endpoint, Method.GET)
}
interface UserFormType {
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment