Implemented base vote screen and updated ConnectionManager.js to match new protocol

This commit is contained in:
Arnaud Vergnet 2020-04-06 18:32:10 +02:00
parent 7b332e11fc
commit e1a57487a2
9 changed files with 358 additions and 182 deletions

View file

@ -65,84 +65,64 @@ test('recoverLogin success saved', () => {
test('isRequestResponseValid', () => { test('isRequestResponseValid', () => {
let json = { let json = {
state: true, error: 0,
data: {} data: {}
}; };
expect(c.isRequestResponseValid(json)).toBeTrue(); expect(c.isResponseValid(json)).toBeTrue();
json = { json = {
state: false, error: 1,
data: {} data: {}
}; };
expect(c.isRequestResponseValid(json)).toBeTrue(); expect(c.isResponseValid(json)).toBeTrue();
json = { json = {
state: false, error: 50,
message: 'coucou', data: {}
};
expect(c.isResponseValid(json)).toBeTrue();
json = {
error: 50,
data: {truc: 'machin'} data: {truc: 'machin'}
}; };
expect(c.isRequestResponseValid(json)).toBeTrue(); expect(c.isResponseValid(json)).toBeTrue();
json = { json = {
message: 'coucou' message: 'coucou'
}; };
expect(c.isRequestResponseValid(json)).toBeFalse(); expect(c.isResponseValid(json)).toBeFalse();
json = { json = {
state: 'coucou' error: 'coucou',
data: {truc: 'machin'}
}; };
expect(c.isRequestResponseValid(json)).toBeFalse(); expect(c.isResponseValid(json)).toBeFalse();
json = { json = {
state: true, error: 0,
data: 'coucou'
}; };
expect(c.isRequestResponseValid(json)).toBeFalse(); expect(c.isResponseValid(json)).toBeFalse();
json = {
error: 0,
};
expect(c.isResponseValid(json)).toBeFalse();
}); });
test("isConnectionResponseValid", () => { test("isConnectionResponseValid", () => {
let json = { let json = {
state: true, error: 0,
message: 'Connexion confirmée', data: {token: 'token'}
token: 'token'
}; };
expect(c.isConnectionResponseValid(json)).toBeTrue(); expect(c.isConnectionResponseValid(json)).toBeTrue();
json = { json = {
state: true, error: 2,
token: 'token' data: {}
}; };
expect(c.isConnectionResponseValid(json)).toBeTrue(); expect(c.isConnectionResponseValid(json)).toBeTrue();
json = { json = {
state: false, error: 0,
}; data: {token: ''}
expect(c.isConnectionResponseValid(json)).toBeTrue();
json = {
state: false,
message: 'Adresse mail ou mot de passe incorrect',
token: ''
};
expect(c.isConnectionResponseValid(json)).toBeTrue();
json = {
state: true,
message: 'Connexion confirmée',
token: ''
}; };
expect(c.isConnectionResponseValid(json)).toBeFalse(); expect(c.isConnectionResponseValid(json)).toBeFalse();
json = { json = {
state: true, error: 'prout',
message: 'Connexion confirmée', data: {token: ''}
};
expect(c.isConnectionResponseValid(json)).toBeFalse();
json = {
state: 'coucou',
message: 'Connexion confirmée',
token: 'token'
};
expect(c.isConnectionResponseValid(json)).toBeFalse();
json = {
state: true,
message: 'Connexion confirmée',
token: 2
};
expect(c.isConnectionResponseValid(json)).toBeFalse();
json = {
coucou: 'coucou',
message: 'Connexion confirmée',
token: 'token'
}; };
expect(c.isConnectionResponseValid(json)).toBeFalse(); expect(c.isConnectionResponseValid(json)).toBeFalse();
}); });
@ -152,10 +132,9 @@ test("connect bad credentials", () => {
return Promise.resolve({ return Promise.resolve({
json: () => { json: () => {
return { return {
state: false, error: ERROR_TYPE.BAD_CREDENTIALS,
message: 'Adresse mail ou mot de passe incorrect', data: {}
token: '' };
}
}, },
}) })
}); });
@ -168,10 +147,9 @@ test("connect good credentials", () => {
return Promise.resolve({ return Promise.resolve({
json: () => { json: () => {
return { return {
state: true, error: ERROR_TYPE.SUCCESS,
message: 'Connexion confirmée', data: {token: 'token'}
token: 'token' };
}
}, },
}) })
}); });
@ -186,13 +164,9 @@ test("connect good credentials no consent", () => {
return Promise.resolve({ return Promise.resolve({
json: () => { json: () => {
return { return {
state: false, error: ERROR_TYPE.NO_CONSENT,
message: 'pas de consent', data: {}
token: '', };
data: {
consent: false,
}
}
}, },
}) })
}); });
@ -205,17 +179,16 @@ test("connect good credentials, fail save token", () => {
return Promise.resolve({ return Promise.resolve({
json: () => { json: () => {
return { return {
state: true, error: ERROR_TYPE.SUCCESS,
message: 'Connexion confirmée', data: {token: 'token'}
token: 'token' };
}
}, },
}) })
}); });
jest.spyOn(ConnectionManager.prototype, 'saveLogin').mockImplementationOnce(() => { jest.spyOn(ConnectionManager.prototype, 'saveLogin').mockImplementationOnce(() => {
return Promise.reject(false); return Promise.reject(false);
}); });
return expect(c.connect('email', 'password')).rejects.toBe(ERROR_TYPE.SAVE_TOKEN); return expect(c.connect('email', 'password')).rejects.toBe(ERROR_TYPE.UNKNOWN);
}); });
test("connect connection error", () => { test("connect connection error", () => {
@ -249,7 +222,10 @@ test("authenticatedRequest success", () => {
jest.spyOn(global, 'fetch').mockImplementationOnce(() => { jest.spyOn(global, 'fetch').mockImplementationOnce(() => {
return Promise.resolve({ return Promise.resolve({
json: () => { json: () => {
return {state: true, message: 'Connexion vérifiée', data: {coucou: 'toi'}} return {
error: ERROR_TYPE.SUCCESS,
data: {coucou: 'toi'}
};
}, },
}) })
}); });
@ -264,12 +240,15 @@ test("authenticatedRequest error wrong token", () => {
jest.spyOn(global, 'fetch').mockImplementationOnce(() => { jest.spyOn(global, 'fetch').mockImplementationOnce(() => {
return Promise.resolve({ return Promise.resolve({
json: () => { json: () => {
return {state: false, message: 'Le champ token sélectionné est invalide.'} return {
error: ERROR_TYPE.BAD_TOKEN,
data: {}
};
}, },
}) })
}); });
return expect(c.authenticatedRequest('https://www.amicale-insat.fr/api/token/check')) return expect(c.authenticatedRequest('https://www.amicale-insat.fr/api/token/check'))
.rejects.toBe(ERROR_TYPE.BAD_CREDENTIALS); .rejects.toBe(ERROR_TYPE.BAD_TOKEN);
}); });
test("authenticatedRequest error bogus response", () => { test("authenticatedRequest error bogus response", () => {
@ -279,7 +258,9 @@ test("authenticatedRequest error bogus response", () => {
jest.spyOn(global, 'fetch').mockImplementationOnce(() => { jest.spyOn(global, 'fetch').mockImplementationOnce(() => {
return Promise.resolve({ return Promise.resolve({
json: () => { json: () => {
return {state: true, message: 'Connexion vérifiée'} return {
error: ERROR_TYPE.SUCCESS,
};
}, },
}) })
}); });
@ -302,13 +283,6 @@ test("authenticatedRequest error no token", () => {
jest.spyOn(ConnectionManager.prototype, 'getToken').mockImplementationOnce(() => { jest.spyOn(ConnectionManager.prototype, 'getToken').mockImplementationOnce(() => {
return null; return null;
}); });
jest.spyOn(global, 'fetch').mockImplementationOnce(() => {
return Promise.resolve({
json: () => {
return {state: false, message: 'Le champ token sélectionné est invalide.'}
},
})
});
return expect(c.authenticatedRequest('https://www.amicale-insat.fr/api/token/check')) return expect(c.authenticatedRequest('https://www.amicale-insat.fr/api/token/check'))
.rejects.toBe(ERROR_TYPE.NO_TOKEN); .rejects.toBe(ERROR_TYPE.UNKNOWN);
}); });

View file

@ -10,7 +10,7 @@ import BasicLoadingScreen from "../Custom/BasicLoadingScreen";
type Props = { type Props = {
navigation: Object, navigation: Object,
theme: Object, theme: Object,
link: string, links: Array<{link: string, mandatory: boolean}>,
renderFunction: Function, renderFunction: Function,
} }
@ -27,7 +27,7 @@ class AuthenticatedScreen extends React.Component<Props, State> {
currentUserToken: string | null; currentUserToken: string | null;
connectionManager: ConnectionManager; connectionManager: ConnectionManager;
errorCode: number; errorCode: number;
data: Object; data: Array<Object>;
colors: Object; colors: Object;
constructor(props) { constructor(props) {
@ -35,6 +35,7 @@ class AuthenticatedScreen extends React.Component<Props, State> {
this.colors = props.theme.colors; this.colors = props.theme.colors;
this.connectionManager = ConnectionManager.getInstance(); this.connectionManager = ConnectionManager.getInstance();
this.props.navigation.addListener('focus', this.onScreenFocus.bind(this)); this.props.navigation.addListener('focus', this.onScreenFocus.bind(this));
this.data = new Array(this.props.links.length);
} }
onScreenFocus() { onScreenFocus() {
@ -46,25 +47,53 @@ class AuthenticatedScreen extends React.Component<Props, State> {
if (!this.state.loading) if (!this.state.loading)
this.setState({loading: true}); this.setState({loading: true});
if (this.connectionManager.isLoggedIn()) { if (this.connectionManager.isLoggedIn()) {
this.connectionManager.authenticatedRequest(this.props.link) for (let i = 0; i < this.props.links.length; i++) {
.then((data) => { this.connectionManager.authenticatedRequest(this.props.links[i].link)
this.onFinishedLoading(data, -1); .then((data) => {
}) this.onFinishedLoading(data, i, -1);
.catch((error) => { })
this.onFinishedLoading(undefined, error); .catch((error) => {
}); this.onFinishedLoading(null, i, error);
});
}
} else { } else {
this.onFinishedLoading(undefined, ERROR_TYPE.BAD_CREDENTIALS); this.onFinishedLoading(null, -1, ERROR_TYPE.BAD_CREDENTIALS);
} }
}; };
onFinishedLoading(data: Object, error: number) { onFinishedLoading(data: Object, index: number, error: number) {
this.data = data; if (index >= 0 && index < this.props.links.length)
this.data[index] = data;
this.currentUserToken = data !== undefined this.currentUserToken = data !== undefined
? this.connectionManager.getToken() ? this.connectionManager.getToken()
: null; : null;
this.errorCode = error; this.errorCode = error;
this.setState({loading: false});
if (this.allRequestsFinished())
this.setState({loading: false});
}
allRequestsFinished() {
let finished = true;
for (let i = 0; i < this.data.length; i++) {
if (this.data[i] === undefined) {
finished = false;
break;
}
}
return finished;
}
allRequestsValid() {
let valid = true;
for (let i = 0; i < this.data.length; i++) {
if (this.data[i] === null && this.props.links[i].mandatory) {
valid = false;
break;
}
}
return valid;
} }
getErrorRender() { getErrorRender() {
@ -75,6 +104,10 @@ class AuthenticatedScreen extends React.Component<Props, State> {
message = i18n.t("loginScreen.errors.credentials"); message = i18n.t("loginScreen.errors.credentials");
icon = "account-alert-outline"; icon = "account-alert-outline";
break; break;
case ERROR_TYPE.BAD_TOKEN:
message = "BAD TOKEN"; // TODO translate
icon = "access-point-network-off";
break;
case ERROR_TYPE.CONNECTION_ERROR: case ERROR_TYPE.CONNECTION_ERROR:
message = i18n.t("loginScreen.errors.connection"); message = i18n.t("loginScreen.errors.connection");
icon = "access-point-network-off"; icon = "access-point-network-off";
@ -99,7 +132,7 @@ class AuthenticatedScreen extends React.Component<Props, State> {
return ( return (
this.state.loading this.state.loading
? <BasicLoadingScreen/> ? <BasicLoadingScreen/>
: (this.data !== undefined : (this.allRequestsValid()
? this.props.renderFunction(this.data) ? this.props.renderFunction(this.data)
: this.getErrorRender()) : this.getErrorRender())
); );

View file

@ -69,6 +69,12 @@ class SideBar extends React.Component<Props, State> {
icon: "account-group", icon: "account-group",
onlyWhenLoggedIn: true, onlyWhenLoggedIn: true,
}, },
{
name: "VOTE",
route: "VoteScreen",
icon: "vote",
onlyWhenLoggedIn: true,
},
{ {
name: i18n.t('screens.logout'), name: i18n.t('screens.logout'),
route: 'disconnect', route: 'disconnect',

View file

@ -3,14 +3,35 @@
import * as SecureStore from 'expo-secure-store'; import * as SecureStore from 'expo-secure-store';
export const ERROR_TYPE = { export const ERROR_TYPE = {
BAD_CREDENTIALS: 0, SUCCESS: 0,
CONNECTION_ERROR: 1, BAD_CREDENTIALS: 1,
SAVE_TOKEN: 2, BAD_TOKEN: 2,
NO_TOKEN: 3, NO_CONSENT: 3,
NO_CONSENT: 4, BAD_INPUT: 400,
FORBIDDEN: 403,
CONNECTION_ERROR: 404,
SERVER_ERROR: 500,
UNKNOWN: 999,
}; };
const AUTH_URL = "https://www.amicale-insat.fr/api/password"; type response_format = {
error: number,
data: Object,
}
/**
* champ: error
*
* 0 : SUCCESS -> pas d'erreurs
* 1 : BAD_CREDENTIALS -> email ou mdp invalide
* 2 : BAD_TOKEN -> session expirée
* 3 : NO_CONSENT
* 403 : FORBIDDEN -> accès a la ressource interdit
* 500 : SERVER_ERROR -> pb coté serveur
*/
const API_ENDPOINT = "https://www.amicale-insat.fr/api/";
const AUTH_PATH = "password";
export default class ConnectionManager { export default class ConnectionManager {
static instance: ConnectionManager | null = null; static instance: ConnectionManager | null = null;
@ -110,7 +131,7 @@ export default class ConnectionManager {
password: password, password: password,
}; };
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
fetch(AUTH_URL, { fetch(API_ENDPOINT + AUTH_PATH, {
method: 'POST', method: 'POST',
headers: new Headers({ headers: new Headers({
'Accept': 'application/json', 'Accept': 'application/json',
@ -118,22 +139,18 @@ export default class ConnectionManager {
}), }),
body: JSON.stringify(data) body: JSON.stringify(data)
}).then(async (response) => response.json()) }).then(async (response) => response.json())
.then((data) => { .then((response: response_format) => {
if (this.isConnectionResponseValid(data)) { if (this.isConnectionResponseValid(response)) {
if (data.state) { if (response.error === ERROR_TYPE.SUCCESS) {
this.saveLogin(email, data.token) this.saveLogin(email, response.data.token)
.then(() => { .then(() => {
resolve(true); resolve(true);
}) })
.catch(() => { .catch(() => {
reject(ERROR_TYPE.SAVE_TOKEN); reject(ERROR_TYPE.UNKNOWN);
}); });
} else if (data.data !== undefined } else
&& data.data.consent !== undefined reject(response.error);
&& !data.data.consent)
reject(ERROR_TYPE.NO_CONSENT);
else
reject(ERROR_TYPE.BAD_CREDENTIALS);
} else } else
reject(ERROR_TYPE.CONNECTION_ERROR); reject(ERROR_TYPE.CONNECTION_ERROR);
}) })
@ -143,35 +160,32 @@ export default class ConnectionManager {
}); });
} }
isRequestResponseValid(response: Object) { isResponseValid(response: response_format) {
let valid = response !== undefined let valid = response !== undefined
&& response.state !== undefined && response.error !== undefined
&& typeof response.state === "boolean"; && typeof response.error === "number";
if (valid && response.state) valid = valid
valid = valid && response.data !== undefined
&& response.data !== undefined && typeof response.data === "object";
&& typeof response.data === "object";
return valid; return valid;
} }
isConnectionResponseValid(response: Object) { isConnectionResponseValid(response: response_format) {
let valid = response !== undefined let valid = this.isResponseValid(response);
&& response.state !== undefined
&& typeof response.state === "boolean";
if (valid && response.state) if (valid && response.error === ERROR_TYPE.SUCCESS)
valid = valid valid = valid
&& response.token !== undefined && response.data.token !== undefined
&& response.token !== '' && response.data.token !== ''
&& typeof response.token === "string"; && typeof response.data.token === "string";
return valid; return valid;
} }
async authenticatedRequest(url: string) { async authenticatedRequest(path: string) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
if (this.getToken() !== null) { if (this.getToken() !== null) {
fetch(url, { fetch(API_ENDPOINT + path, {
method: 'POST', method: 'POST',
headers: new Headers({ headers: new Headers({
'Accept': 'application/json', 'Accept': 'application/json',
@ -179,12 +193,13 @@ export default class ConnectionManager {
}), }),
body: JSON.stringify({token: this.getToken()}) body: JSON.stringify({token: this.getToken()})
}).then(async (response) => response.json()) }).then(async (response) => response.json())
.then((data) => { .then((response: response_format) => {
if (this.isRequestResponseValid(data)) { console.log(response);
if (data.state) if (this.isResponseValid(response)) {
resolve(data.data); if (response.error === ERROR_TYPE.SUCCESS)
resolve(response.data);
else else
reject(ERROR_TYPE.BAD_CREDENTIALS); reject(response.error);
} else } else
reject(ERROR_TYPE.CONNECTION_ERROR); reject(ERROR_TYPE.CONNECTION_ERROR);
}) })
@ -192,7 +207,7 @@ export default class ConnectionManager {
reject(ERROR_TYPE.CONNECTION_ERROR); reject(ERROR_TYPE.CONNECTION_ERROR);
}); });
} else } else
reject(ERROR_TYPE.NO_TOKEN); reject(ERROR_TYPE.UNKNOWN);
}); });
} }
} }

View file

@ -20,6 +20,7 @@ import ProfileScreen from "../screens/Amicale/ProfileScreen";
import ClubListScreen from "../screens/Amicale/Clubs/ClubListScreen"; import ClubListScreen from "../screens/Amicale/Clubs/ClubListScreen";
import ClubDisplayScreen from "../screens/Amicale/Clubs/ClubDisplayScreen"; import ClubDisplayScreen from "../screens/Amicale/Clubs/ClubDisplayScreen";
import ClubAboutScreen from "../screens/Amicale/Clubs/ClubAboutScreen"; import ClubAboutScreen from "../screens/Amicale/Clubs/ClubAboutScreen";
import VoteScreen from "../screens/Amicale/VoteScreen";
const defaultScreenOptions = { const defaultScreenOptions = {
gestureEnabled: true, gestureEnabled: true,
@ -239,6 +240,31 @@ function ProfileStackComponent() {
); );
} }
const VoteStack = createStackNavigator();
function VoteStackComponent() {
return (
<VoteStack.Navigator
initialRouteName="VoteScreen"
headerMode="float"
screenOptions={defaultScreenOptions}
>
<VoteStack.Screen
name="VoteScreen"
component={VoteScreen}
options={({navigation}) => {
const openDrawer = getDrawerButton.bind(this, navigation);
return {
title: "VoteScreen",
headerLeft: openDrawer
};
}}
/>
</VoteStack.Navigator>
);
}
const ClubStack = createStackNavigator(); const ClubStack = createStackNavigator();
function ClubStackComponent() { function ClubStackComponent() {
@ -341,6 +367,10 @@ export default function DrawerNavigator() {
name="ClubListScreen" name="ClubListScreen"
component={ClubStackComponent} component={ClubStackComponent}
/> />
<Drawer.Screen
name="VoteScreen"
component={VoteStackComponent}
/>
</Drawer.Navigator> </Drawer.Navigator>
); );
} }

View file

@ -71,7 +71,7 @@ class ClubListScreen extends React.Component<Props, State> {
* @return {*} * @return {*}
*/ */
getHeaderButtons = () => { getHeaderButtons = () => {
const onPress = () => this.props.navigation.navigate( "ClubAboutScreen"); const onPress = () => this.props.navigation.navigate("ClubAboutScreen");
return <HeaderButton icon={'information'} onPress={onPress}/>; return <HeaderButton icon={'information'} onPress={onPress}/>;
}; };
@ -91,11 +91,11 @@ class ClubListScreen extends React.Component<Props, State> {
itemLayout = (data, index) => ({length: LIST_ITEM_HEIGHT, offset: LIST_ITEM_HEIGHT * index, index}); itemLayout = (data, index) => ({length: LIST_ITEM_HEIGHT, offset: LIST_ITEM_HEIGHT * index, index});
getScreen = (data: Object) => { getScreen = (data: Object) => {
this.categories = data.categories; this.categories = data[0].categories;
return ( return (
//$FlowFixMe //$FlowFixMe
<FlatList <FlatList
data={data.clubs} data={data[0].clubs}
keyExtractor={this.keyExtractor} keyExtractor={this.keyExtractor}
renderItem={this.getRenderItem} renderItem={this.getRenderItem}
ListHeaderComponent={this.getListHeader()} ListHeaderComponent={this.getListHeader()}
@ -193,7 +193,12 @@ class ClubListScreen extends React.Component<Props, State> {
return ( return (
<AuthenticatedScreen <AuthenticatedScreen
{...this.props} {...this.props}
link={'https://www.amicale-insat.fr/api/clubs/list'} links={[
{
link: 'clubs/list',
mandatory: true,
}
]}
renderFunction={this.getScreen} renderFunction={this.getScreen}
/> />
); );

View file

@ -149,18 +149,18 @@ class LoginScreen extends React.Component<Props, State> {
const title = i18n.t("loginScreen.errors.title"); const title = i18n.t("loginScreen.errors.title");
let message; let message;
switch (error) { switch (error) {
case ERROR_TYPE.CONNECTION_ERROR:
message = i18n.t("loginScreen.errors.connection");
break;
case ERROR_TYPE.BAD_CREDENTIALS: case ERROR_TYPE.BAD_CREDENTIALS:
message = i18n.t("loginScreen.errors.credentials"); message = i18n.t("loginScreen.errors.credentials");
break; break;
case ERROR_TYPE.SAVE_TOKEN:
message = i18n.t("loginScreen.errors.saveToken");
break;
case ERROR_TYPE.NO_CONSENT: case ERROR_TYPE.NO_CONSENT:
message = i18n.t("loginScreen.errors.consent"); message = i18n.t("loginScreen.errors.consent");
break; break;
case ERROR_TYPE.CONNECTION_ERROR:
message = i18n.t("loginScreen.errors.connection");
break;
case ERROR_TYPE.SERVER_ERROR:
message = "SERVER ERROR"; // TODO translate
break;
default: default:
message = i18n.t("loginScreen.errors.unknown"); message = i18n.t("loginScreen.errors.unknown");
break; break;

View file

@ -1,7 +1,7 @@
// @flow // @flow
import * as React from 'react'; import * as React from 'react';
import {FlatList, StyleSheet, View} from "react-native"; import {FlatList, ScrollView, StyleSheet} from "react-native";
import {Avatar, Button, Card, Divider, List, withTheme} from 'react-native-paper'; import {Avatar, Button, Card, Divider, List, withTheme} from 'react-native-paper';
import AuthenticatedScreen from "../../components/Amicale/AuthenticatedScreen"; import AuthenticatedScreen from "../../components/Amicale/AuthenticatedScreen";
import {openBrowser} from "../../utils/WebBrowser"; import {openBrowser} from "../../utils/WebBrowser";
@ -28,16 +28,9 @@ class ProfileScreen extends React.Component<Props, State> {
data: Object; data: Object;
flatListData: Array<Object>;
constructor(props) { constructor(props) {
super(props); super(props);
this.colors = props.theme.colors; this.colors = props.theme.colors;
this.flatListData = [
{id: '0'},
{id: '1'},
{id: '2'},
]
} }
componentDidMount() { componentDidMount() {
@ -47,44 +40,29 @@ class ProfileScreen extends React.Component<Props, State> {
}); });
} }
showDisconnectDialog = () => this.setState({ dialogVisible: true }); showDisconnectDialog = () => this.setState({dialogVisible: true});
hideDisconnectDialog = () => this.setState({ dialogVisible: false }); hideDisconnectDialog = () => this.setState({dialogVisible: false});
getHeaderButtons() { getHeaderButtons() {
return <HeaderButton icon={'logout'} onPress={this.showDisconnectDialog}/>; return <HeaderButton icon={'logout'} onPress={this.showDisconnectDialog}/>;
} }
getScreen(data: Object) { getScreen = (data: Object) => {
this.data = data; this.data = data[0];
return ( return (
<View> <ScrollView>
<FlatList {this.getPersonalCard()}
renderItem={item => this.getRenderItem(item)} {this.getClubCard()}
keyExtractor={item => item.id} {this.getMembershipCar()}
data={this.flatListData}
/>
<LogoutDialog <LogoutDialog
{...this.props} {...this.props}
visible={this.state.dialogVisible} visible={this.state.dialogVisible}
onDismiss={this.hideDisconnectDialog} onDismiss={this.hideDisconnectDialog}
/> />
</View> </ScrollView>
) )
} };
getRenderItem({item}: Object): any {
switch (item.id) {
case '0':
return this.getPersonalCard();
case '1':
return this.getClubCard();
case '2':
return this.getMembershipCar();
}
}
getPersonalCard() { getPersonalCard() {
return ( return (
@ -232,8 +210,13 @@ class ProfileScreen extends React.Component<Props, State> {
return ( return (
<AuthenticatedScreen <AuthenticatedScreen
{...this.props} {...this.props}
link={'https://www.amicale-insat.fr/api/user/profile'} links={[
renderFunction={(data) => this.getScreen(data)} {
link: 'user/profile',
mandatory: true,
}
]}
renderFunction={this.getScreen}
/> />
); );
} }

View file

@ -0,0 +1,130 @@
// @flow
import * as React from 'react';
import {ScrollView, StyleSheet} from "react-native";
import {Avatar, Card, Paragraph, withTheme} from 'react-native-paper';
import AuthenticatedScreen from "../../components/Amicale/AuthenticatedScreen";
const ICON_AMICALE = require('../../../assets/amicale.png');
type Props = {
navigation: Object,
theme: Object,
}
type State = {}
class VoteScreen extends React.Component<Props, State> {
state = {};
colors: Object;
constructor(props) {
super(props);
this.colors = props.theme.colors;
}
getScreen = (data: Object) => {
console.log(data);
return (
<ScrollView>
{this.getTitleCard()}
{this.getVoteCard()}
</ScrollView>
);
};
getTitleCard() {
return (
<Card style={styles.card}>
<Card.Title
title={"VOTE"}
subtitle={"WHY"}
left={(props) => <Avatar.Image
{...props}
source={ICON_AMICALE}
style={styles.icon}
/>}
/>
<Card.Content>
<Paragraph>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus rhoncus porttitor
suscipit. Quisque hendrerit, quam id vestibulum vestibulum, lorem nisi hendrerit nisi, a
eleifend sapien diam ut elit. Curabitur sit amet vulputate lectus. Donec semper cursus sapien
vel finibus.
</Paragraph>
<Paragraph>
Sed et venenatis turpis. Fusce malesuada magna urna, sed vehicula sem luctus in. Vivamus
faucibus vel eros a ultricies. In sed laoreet ante, luctus mattis tellus. Etiam vitae ipsum
sagittis, consequat purus sed, blandit risus.
</Paragraph>
</Card.Content>
</Card>
);
}
getVoteCard() {
return (
<Card style={styles.card}>
<Card.Title
title={"VOTE OPEN"}
subtitle={"VALID UNTIL DATE END"}
/>
<Card.Content>
<Paragraph>TEAM1</Paragraph>
<Paragraph>TEAM2</Paragraph>
</Card.Content>
</Card>
);
}
getVoteResultCard() {
return (
<Card style={styles.card}>
<Card.Title
title={"VOTE RESULTS"}
subtitle={"DATE END RESULTS"}
/>
<Card.Content>
<Paragraph>TEAM1</Paragraph>
<Paragraph>TEAM2</Paragraph>
</Card.Content>
</Card>
);
}
getEmptyVoteCard() {
}
render() {
return (
<AuthenticatedScreen
{...this.props}
links={[
{
link: 'elections/teams',
mandatory: false,
},
{
link: 'elections/dates',
mandatory: true,
},
]}
renderFunction={this.getScreen}
/>
);
}
}
const styles = StyleSheet.create({
card: {
margin: 10,
},
icon: {
backgroundColor: 'transparent'
},
});
export default withTheme(VoteScreen);