Serverless Mobile App Development -1
By: Abdullatif Topçu
Tags: Lambda, JavaScript, Java, Aws S3, React Native

The App

The application I made here is a special application for the education sector. I developed a mobile application where students preparing for exams can ask questions. After the student asks a question, a notification is sent to the phone of the relevant teacher according to the selected lesson type. Then the teacher solves the question and uploads it to the application. The student receives a solution notification.

Why did I use React Native in the application?

In recent years, React Native has started to make a name for itself among the libraries used for mobile application development. Writing with JS, compiling common code for Android and IOS, and simplicity are the highlights for me. If you like JS or TS, React Native is for you.

The React Native Template That I selected: Now UI React Native Template

Design is important in mobile application development. We, the developers are not designers and I think it is best to leave this job to the experts. For this reason, I found and used the attached template among the free react native templates I was looking for on the web. It is very robust, clear, extendable, and easy to learn. I highly recommend it.

Project Code Repo

You may find and download the codes of the project here. Contributions are welcome as well.

React Native Folder Structure and Important Files

The file structure that comes when you create an empty React Native project is quite sufficient for general projects. Two of the important files in a react native project are package.json, package-lock.json files. These are the files that contain the list and versions of the js libraries you will use in your react-native project. One Note; Before starting a React Native project, you need to install a package manager. I use Node Package Manager in my project.

You may find the whole React-Native related codes under the folder bulutasor/BulutaSorFrontend2. Here are the folders that should be examined:

screens: All screen codes are under this folder.

Sample Screens Code:

/* eslint-disable no-console */

import React from 'react';

import {

StyleSheet, Dimensions, ScrollView, Alert

} from 'react-native';// cache app images



// import * as Notifications from 'expo-notifications';

import { connect } from 'react-redux';

import {

Block, Text, theme, withGalio

} from 'galio-framework';

import AnimatedLoader from 'react-native-animated-loader';

import { Card } from '../components';



const { width } = Dimensions.get('screen');



class StudentsSolvedQuestionListScreen extends React.Component {

constructor(props) {

super(props);

this.state = {

visible: false,

error: null,

};

}



componentDidMount() {

this.state.visible = false;

this.state.error = null;

}



renderArticles = () => {

const { error } = this.state;

const { questions } = this.props;

return (



<ScrollView showsVerticalScrollIndicator={false} contentContainerStyle={styles.articles}>

<Block flex>

{error ? <p>{error.message}</p> : null}

{

(Array.isArray(questions))

? questions.filter((item) => item.state === 'passive').map(

(question) => <Card item={question} key={question.s3Key} cevapGoster="true" horizontal />

)

: (

<Text>

Henüz çözülmüş bir sorun yok.

</Text>

)

}

</Block>

</ScrollView>

);

};



render() {

const { visible } = this.state;

return (

<ScrollView showsVerticalScrollIndicator={false} contentContainerStyle={styles.articles}>

<Block flex style={styles.home}>

<Block center style={{ flex: 30 }}>

<AnimatedLoader

visible={visible}

overlayColor="rgba(255,255,255,0.75)"

source={require('./spinner.json')}

animationStyle={styles.lottie}

speed={1}

/>

{this.renderArticles()}

</Block>

</Block>

</ScrollView>

);

}

}



const styles = StyleSheet.create({

home: {

width,

},

articles: {

width: width - theme.SIZES.BASE * 2,

paddingVertical: theme.SIZES.BASE,

paddingHorizontal: 2,

fontFamily: 'montserrat-regular',

},

});



function mapStateToProps(storeState) {

return {

userName: storeState.userName,

password: storeState.password,

questions: storeState.questions

};

}



function mapDispatchToProps() {

return {

// setQuestions()

};

}

export default withGalio(connect(mapStateToProps, mapDispatchToProps)(StudentsSolvedQuestionListScreen));

components: Under this folder, you can find the component library that comes with the React Native template.

import React, { useState } from 'react';

import {

Alert,

Modal,

StyleSheet,

TouchableWithoutFeedback,

Keyboard,

View,

Dimensions,

TouchableOpacity,

} from 'react-native';

import {

Text, theme, Block

} from 'galio-framework';

import { useNavigation } from '@react-navigation/native';

import { useSelector } from 'react-redux';

import ArButton from './Button';

import Icon from './Icon';

import nowTheme from '../constants/Theme';



const DismissKeyboard = ({ children }) => (

<TouchableWithoutFeedback onPress={() => Keyboard.dismiss()}>{children}</TouchableWithoutFeedback>

);



const { width, height } = Dimensions.get('screen');



const SessionBar = (props) => {

const [modalVisible, setModalVisible] = useState(0);

const user = useSelector((state) => state.user);

const navigation = useNavigation();

let userType = 'Öğrenci';

const { isTeacher } = user;

if (isTeacher) {

userType = 'Öğretmen';

}

console.log(`isTeacher:${isTeacher}`);

console.log(`userType:${userType}`);

return (

<Block>

<Modal

animationType="slide"

visible={modalVisible}

style={styles.modalView}

transparent

onRequestClose={() => {

Alert.alert('Modal has been closed.');

}}

>

<View

style={{

flex: 1,

justifyContent: 'center',

alignItems: 'center',

margin: 80,

padding: 80,

borderColor: nowTheme.COLORS.BLACK,

borderRadius: 10,

backgroundColor: nowTheme.COLORS.WHITE,

}}

>

<ArButton

color="info"

round

style={styles.createButton}

onPress={() => { setModalVisible(false); }}

title="Kapat"

>

<Text

style={{ fontFamily: 'montserrat-bold' }}

size={14}

color={nowTheme.COLORS.WHITE}

>

Kapat

</Text>

</ArButton>

<Block>

<Text

size={16}

muted

style={{

width: '100%',

color: '#2c2c2c',

fontWeight: 'bold',

lineHeight: 20,

fontSize: 19,

fontFamily: 'montserrat-bold',

margin: 10,

zIndex: 2,

textAlign: 'center',

}}

>

{userType}

</Text>

<Text

size={16}

muted

style={{

width: '100%',

color: '#2c2c2c',

fontWeight: 'bold',

lineHeight: 20,

fontSize: 19,

fontFamily: 'montserrat-bold',

margin: 10,

zIndex: 2,

textAlign: 'center',

}}

>

{user.userName}

</Text>

</Block>

<ArButton

color="primary"

round

style={styles.createButton}

onPress={() => { setModalVisible(false); logout(); navigation.navigate('LoginScreen'); }}

title="Oturumu Kapat"

>

<Text

style={{ fontFamily: 'montserrat-bold' }}

size={14}

color={nowTheme.COLORS.WHITE}

>

Oturumu Kapat

</Text>

</ArButton>

</View>

</Modal>

<Block flex row right>

<TouchableOpacity

style={[styles.profileButton]}

onPress={() => {

setModalVisible(true);

}}

>

<Text>{user.userName}</Text>

<Icon

family="NowExtra"

size={16}

name="basket2x"

color={nowTheme.COLORS.WHITE}

/>



</TouchableOpacity>

</Block>

</Block>

);

};

export default SessionBar;



const styles = StyleSheet.create({

registerContainer: {

marginTop: 55,

width: width * 0.9,

height: height < 812 ? height * 0.8 : height * 0.8,

backgroundColor: nowTheme.COLORS.WHITE,

borderRadius: 4,

shadowColor: nowTheme.COLORS.BLACK,

shadowOffset: {

width: 0,

height: 4,

},

shadowRadius: 8,

shadowOpacity: 0.1,

elevation: 1,

overflow: 'hidden',

},



centeredView: {

flex: 1,

justifyContent: 'flex-start',

alignItems: 'center',

margin: 20,

backgroundColor: nowTheme.COLORS.WHITE,

padding: 20,

},

modalView: {

backgroundColor: theme.COLORS.WHITE,

borderRadius: 20,

margin: 35,

padding: 35,

height: height * 0.6,

width: width * 0.6,

justifyContent: 'flex-start',

alignItems: 'stretch',

borderColor: theme.COLORS.BLACK,



},

openButton: {

backgroundColor: theme.COLORS.WHITE,

borderRadius: 20,

padding: 10,

elevation: 2

},

title: {

flex: 2,

height: height * 0.07,

alignItems: 'center',

justifyContent: 'center',

},

titleTextStyle: {

fontWeight: '400',

fontSize: theme.SIZES.FONT * 2,

color: theme.COLORS.BLACK,

paddingTop: 20

},



createButton: {

width: width * 0.5,

marginTop: 25,

marginBottom: 40,

},



profileButton: {

padding: 12,

position: 'relative',

width: width * 0.2,

},



cikisButton: {

padding: 12,

position: 'relative',

width: width * 0.2,

}

});

Android and IOS: In these folders, you can find environment-specific configurations produced from react-native codes during compilation. Some third-party library uses require operating-system-specific settings. In this case, the codes we will intervene in are here. Under normal circumstances, we do not make any development in these folders.

Appium: When we develop a mobile application, we need to test our application on different devices. Because in general, our application may work very differently depending on the operating system model and version, memory, and screen size, or worse, it may not work. :( It can be very useful to test our application in a device farm in order to catch this situation before the end-users experience it in our application. I definitely recommend it. You can find AWS Device Farm here.

Redux

Redux is a data store. It’s usually good practice to separate data with application screens. In this way, data consistency is ensured between screens, or between different components on the same screen. Redux is now a must-use component in JS libraries such as React Native, Vue, or Angular. You can access the details from the addresses below.

And one Turkish Article From Zafer Ayan

Conclusion

In this article, I tried to present my mobile App’s react-native Code, maybe it will inspire someone. In the second article of this series, I will explain Backend.

Wish you all a lovely life