├── .watchmanconfig ├── jest.config.js ├── .bundle └── config ├── app.json ├── .eslintrc.js ├── tsconfig.json ├── babel.config.js ├── android ├── app │ ├── debug.keystore │ ├── src │ │ ├── main │ │ │ ├── res │ │ │ │ ├── values │ │ │ │ │ ├── strings.xml │ │ │ │ │ └── styles.xml │ │ │ │ ├── raw │ │ │ │ │ └── ringtone.mp3 │ │ │ │ ├── mipmap-hdpi │ │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-mdpi │ │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-xhdpi │ │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-xxhdpi │ │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-xxxhdpi │ │ │ │ │ └── ic_launcher.png │ │ │ │ ├── package.json │ │ │ │ └── drawable │ │ │ │ │ └── rn_edit_text_material.xml │ │ │ ├── java │ │ │ │ └── com │ │ │ │ │ └── videocall │ │ │ │ │ ├── MainActivity.kt │ │ │ │ │ └── MainApplication.kt │ │ │ └── AndroidManifest.xml │ │ └── debug │ │ │ └── AndroidManifest.xml │ ├── proguard-rules.pro │ ├── google-services.json │ └── build.gradle ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── settings.gradle ├── build.gradle ├── gradle.properties ├── gradlew.bat └── gradlew ├── ios ├── videoCall │ ├── Images.xcassets │ │ ├── Contents.json │ │ └── AppIcon.appiconset │ │ │ └── Contents.json │ ├── AppDelegate.h │ ├── main.m │ ├── AppDelegate.mm │ ├── PrivacyInfo.xcprivacy │ ├── Info.plist │ └── LaunchScreen.storyboard ├── .xcode.env ├── videoCallTests │ ├── Info.plist │ └── videoCallTests.m ├── Podfile └── videoCall.xcodeproj │ ├── xcshareddata │ └── xcschemes │ │ └── videoCall.xcscheme │ └── project.pbxproj ├── .prettierrc.js ├── metro.config.js ├── src ├── screens │ ├── LoadingScreen.tsx │ ├── Login.tsx │ └── VideoCallScreen.tsx ├── hook │ ├── useSocketConnection.ts │ ├── useWebRTC.ts │ ├── api.ts │ └── useUser.tsx ├── components │ ├── LoginForm.tsx │ ├── VideoStreamView.tsx │ └── CallControls.tsx ├── remoteNotification │ └── RemoteNotification.ts └── localNotification │ └── LocalNotification.ts ├── Gemfile ├── __tests__ └── App.test.tsx ├── codemagic.yaml ├── .gitignore ├── App.tsx ├── package.json ├── index.js └── README.md /.watchmanconfig: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | preset: 'react-native', 3 | }; 4 | -------------------------------------------------------------------------------- /.bundle/config: -------------------------------------------------------------------------------- 1 | BUNDLE_PATH: "vendor/bundle" 2 | BUNDLE_FORCE_RUBY_PLATFORM: 1 3 | -------------------------------------------------------------------------------- /app.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "videoCall", 3 | "displayName": "videoCall" 4 | } 5 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | extends: '@react-native', 4 | }; 5 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@react-native/typescript-config/tsconfig.json" 3 | } 4 | -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: ['module:@react-native/babel-preset'], 3 | }; 4 | -------------------------------------------------------------------------------- /android/app/debug.keystore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darshan15062002/video-call-react-native/HEAD/android/app/debug.keystore -------------------------------------------------------------------------------- /android/app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | videoCall 3 | 4 | -------------------------------------------------------------------------------- /ios/videoCall/Images.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /ios/videoCall/AppDelegate.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | 4 | @interface AppDelegate : RCTAppDelegate 5 | 6 | @end 7 | -------------------------------------------------------------------------------- /android/app/src/main/res/raw/ringtone.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darshan15062002/video-call-react-native/HEAD/android/app/src/main/res/raw/ringtone.mp3 -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darshan15062002/video-call-react-native/HEAD/android/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /.prettierrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | arrowParens: 'avoid', 3 | bracketSameLine: true, 4 | bracketSpacing: false, 5 | singleQuote: true, 6 | trailingComma: 'all', 7 | }; 8 | -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darshan15062002/video-call-react-native/HEAD/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darshan15062002/video-call-react-native/HEAD/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darshan15062002/video-call-react-native/HEAD/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darshan15062002/video-call-react-native/HEAD/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darshan15062002/video-call-react-native/HEAD/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /ios/videoCall/main.m: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | #import "AppDelegate.h" 4 | 5 | int main(int argc, char *argv[]) 6 | { 7 | @autoreleasepool { 8 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /android/settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'videoCall' 2 | apply from: file("../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesSettingsGradle(settings) 3 | include ':app' 4 | includeBuild('../node_modules/@react-native/gradle-plugin') 5 | -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-all.zip 4 | networkTimeout=10000 5 | validateDistributionUrl=true 6 | zipStoreBase=GRADLE_USER_HOME 7 | zipStorePath=wrapper/dists 8 | -------------------------------------------------------------------------------- /metro.config.js: -------------------------------------------------------------------------------- 1 | const {getDefaultConfig, mergeConfig} = require('@react-native/metro-config'); 2 | 3 | /** 4 | * Metro configuration 5 | * https://reactnative.dev/docs/metro 6 | * 7 | * @type {import('metro-config').MetroConfig} 8 | */ 9 | const config = {}; 10 | 11 | module.exports = mergeConfig(getDefaultConfig(__dirname), config); 12 | -------------------------------------------------------------------------------- /src/screens/LoadingScreen.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import {View, ActivityIndicator} from 'react-native'; 3 | 4 | const LoadingScreen = () => { 5 | return ( 6 | 7 | 8 | 9 | ); 10 | }; 11 | 12 | export default LoadingScreen; 13 | -------------------------------------------------------------------------------- /android/app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 9 | 10 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | # You may use http://rbenv.org/ or https://rvm.io/ to install and use this version 4 | ruby ">= 2.6.10" 5 | 6 | # Cocoapods 1.15 introduced a bug which break the build. We will remove the upper 7 | # bound in the template on Cocoapods with next React Native release. 8 | gem 'cocoapods', '>= 1.13', '< 1.15' 9 | gem 'activesupport', '>= 6.1.7.5', '< 7.1.0' 10 | -------------------------------------------------------------------------------- /__tests__/App.test.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * @format 3 | */ 4 | 5 | import 'react-native'; 6 | import React from 'react'; 7 | import App from '../App'; 8 | 9 | // Note: import explicitly to use the types shipped with jest. 10 | import {it} from '@jest/globals'; 11 | 12 | // Note: test renderer must be required after react-native. 13 | import renderer from 'react-test-renderer'; 14 | 15 | it('renders correctly', () => { 16 | renderer.create(); 17 | }); 18 | -------------------------------------------------------------------------------- /ios/.xcode.env: -------------------------------------------------------------------------------- 1 | # This `.xcode.env` file is versioned and is used to source the environment 2 | # used when running script phases inside Xcode. 3 | # To customize your local environment, you can create an `.xcode.env.local` 4 | # file that is not versioned. 5 | 6 | # NODE_BINARY variable contains the PATH to the node executable. 7 | # 8 | # Customize the NODE_BINARY variable here. 9 | # For example, to use nvm with brew, add the following line 10 | # . "$(brew --prefix nvm)/nvm.sh" --no-use 11 | export NODE_BINARY=$(command -v node) 12 | -------------------------------------------------------------------------------- /android/app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /usr/local/Cellar/android-sdk/24.3.3/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | -keep class org.webrtc.** { *; } 13 | -------------------------------------------------------------------------------- /android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 8 | 12 | 13 | -------------------------------------------------------------------------------- /android/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | ext { 3 | buildToolsVersion = "34.0.0" 4 | minSdkVersion = 23 5 | compileSdkVersion = 34 6 | targetSdkVersion = 34 7 | ndkVersion = "26.1.10909125" 8 | kotlinVersion = "1.9.22" 9 | } 10 | repositories { 11 | google() 12 | mavenCentral() 13 | } 14 | dependencies { 15 | classpath("com.android.tools.build:gradle") 16 | classpath("com.facebook.react:react-native-gradle-plugin") 17 | classpath("org.jetbrains.kotlin:kotlin-gradle-plugin") 18 | classpath("com.google.gms:google-services:4.4.0") 19 | } 20 | } 21 | 22 | apply plugin: "com.facebook.react.rootproject" 23 | -------------------------------------------------------------------------------- /android/app/google-services.json: -------------------------------------------------------------------------------- 1 | { 2 | "project_info": { 3 | "project_number": "1068459975610", 4 | "project_id": "videocall-webrtc-d5695", 5 | "storage_bucket": "videocall-webrtc-d5695.appspot.com" 6 | }, 7 | "client": [ 8 | { 9 | "client_info": { 10 | "mobilesdk_app_id": "1:1068459975610:android:8104384fbc0e8005533383", 11 | "android_client_info": { 12 | "package_name": "com.videocall" 13 | } 14 | }, 15 | "oauth_client": [], 16 | "api_key": [ 17 | { 18 | "current_key": "AIzaSyBPOoU_iRF7qoFszTWwUyLtAGyiGu5yJHI" 19 | } 20 | ], 21 | "services": { 22 | "appinvite_service": { 23 | "other_platform_oauth_client": [] 24 | } 25 | } 26 | } 27 | ], 28 | "configuration_version": "1" 29 | } -------------------------------------------------------------------------------- /ios/videoCallTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /codemagic.yaml: -------------------------------------------------------------------------------- 1 | workflows: 2 | react-native-android: 3 | name: React Native Android Build 4 | max_build_duration: 120 5 | instance_type: mac_mini_m2 6 | environment: 7 | vars: 8 | PACKAGE_NAME: 'com.videoCall.package' 9 | scripts: 10 | - name: Set Android SDK location 11 | script: | 12 | echo "sdk.dir=$ANDROID_SDK_ROOT" > "$CM_BUILD_DIR/android/local.properties" 13 | - name: Install npm dependencies 14 | script: | 15 | npm install 16 | - name: Set executable permission for Gradle wrapper 17 | script: | 18 | cd android 19 | chmod +x gradlew 20 | - name: Build Android release APK 21 | script: | 22 | cd android # Ensure we're in the android folder 23 | ./gradlew assembleRelease 24 | artifacts: 25 | - android/app/build/outputs/**/*.apk 26 | -------------------------------------------------------------------------------- /ios/videoCall/AppDelegate.mm: -------------------------------------------------------------------------------- 1 | #import "AppDelegate.h" 2 | 3 | #import 4 | 5 | @implementation AppDelegate 6 | 7 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 8 | { 9 | self.moduleName = @"videoCall"; 10 | // You can add your custom initial props in the dictionary below. 11 | // They will be passed down to the ViewController used by React Native. 12 | self.initialProps = @{}; 13 | 14 | return [super application:application didFinishLaunchingWithOptions:launchOptions]; 15 | } 16 | 17 | - (NSURL *)sourceURLForBridge:(RCTBridge *)bridge 18 | { 19 | return [self bundleURL]; 20 | } 21 | 22 | - (NSURL *)bundleURL 23 | { 24 | #if DEBUG 25 | return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index"]; 26 | #else 27 | return [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"]; 28 | #endif 29 | } 30 | 31 | @end 32 | -------------------------------------------------------------------------------- /android/app/src/main/java/com/videocall/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.videocall 2 | 3 | import com.facebook.react.ReactActivity 4 | import com.facebook.react.ReactActivityDelegate 5 | import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint.fabricEnabled 6 | import com.facebook.react.defaults.DefaultReactActivityDelegate 7 | 8 | class MainActivity : ReactActivity() { 9 | 10 | /** 11 | * Returns the name of the main component registered from JavaScript. This is used to schedule 12 | * rendering of the component. 13 | */ 14 | override fun getMainComponentName(): String = "videoCall" 15 | 16 | /** 17 | * Returns the instance of the [ReactActivityDelegate]. We use [DefaultReactActivityDelegate] 18 | * which allows you to enable New Architecture with a single boolean flags [fabricEnabled] 19 | */ 20 | override fun createReactActivityDelegate(): ReactActivityDelegate = 21 | DefaultReactActivityDelegate(this, mainComponentName, fabricEnabled) 22 | } 23 | -------------------------------------------------------------------------------- /ios/videoCall/Images.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "scale" : "2x", 6 | "size" : "20x20" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "scale" : "3x", 11 | "size" : "20x20" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "scale" : "2x", 16 | "size" : "29x29" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "scale" : "3x", 21 | "size" : "29x29" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "scale" : "2x", 26 | "size" : "40x40" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "scale" : "3x", 31 | "size" : "40x40" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "scale" : "2x", 36 | "size" : "60x60" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "scale" : "3x", 41 | "size" : "60x60" 42 | }, 43 | { 44 | "idiom" : "ios-marketing", 45 | "scale" : "1x", 46 | "size" : "1024x1024" 47 | } 48 | ], 49 | "info" : { 50 | "author" : "xcode", 51 | "version" : 1 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/hook/useSocketConnection.ts: -------------------------------------------------------------------------------- 1 | import {useState, useEffect, useRef} from 'react'; 2 | import {io, Socket} from 'socket.io-client'; 3 | 4 | export const useSocketConnection = ( 5 | handleNewUserJoin: (data: any) => void, 6 | handleIncommingCall: (data: any) => void, 7 | handleCallAccepted: (data: any) => void 8 | ) => { 9 | const [socket, setSocket] = useState(null); 10 | 11 | useEffect(() => { 12 | const _socket = io('https://ice-server-socket.onrender.com'); 13 | setSocket(_socket); 14 | 15 | return () => { 16 | _socket.disconnect(); // Ensure proper cleanup 17 | }; 18 | }, []); 19 | 20 | useEffect(() => { 21 | if (socket) { 22 | socket.on('user_joined', handleNewUserJoin); 23 | socket.on('incomming_call', handleIncommingCall); 24 | socket.on('call_accepted', handleCallAccepted); 25 | 26 | return () => { 27 | socket.off('user_joined', handleNewUserJoin); 28 | socket.off('incomming_call', handleIncommingCall); 29 | socket.off('call_accepted', handleCallAccepted); 30 | }; 31 | } 32 | }, [socket]); 33 | 34 | return socket; 35 | }; 36 | -------------------------------------------------------------------------------- /src/hook/useWebRTC.ts: -------------------------------------------------------------------------------- 1 | import {useEffect, useRef, useState} from 'react'; 2 | import {mediaDevices, RTCPeerConnection, MediaStream} from 'react-native-webrtc'; 3 | import { Socket } from 'socket.io-client'; 4 | 5 | export const useWebRTC = (socket: Socket | null) => { 6 | const [stream, setStream] = useState(null); 7 | const [remoteStream, setRemoteStream] = useState(null); 8 | const peerConnection = useRef( 9 | new RTCPeerConnection({ 10 | iceServers: [ 11 | {urls: 'stun:stun.l.google.com:19302'}, 12 | {urls: 'stun:stun1.l.google.com:19302'}, 13 | ], 14 | }) 15 | ); 16 | 17 | useEffect(() => { 18 | const startStream = async () => { 19 | const _stream = await mediaDevices.getUserMedia({ 20 | video: {facingMode: 'user'}, 21 | audio: true, 22 | }); 23 | setStream(_stream); 24 | _stream.getTracks().forEach(track => peerConnection.current.addTrack(track, _stream)); 25 | }; 26 | 27 | socket?.on('joined_room', () => startStream()); 28 | }, [socket]); 29 | 30 | return {stream, remoteStream, peerConnection, setRemoteStream}; 31 | }; 32 | -------------------------------------------------------------------------------- /ios/videoCall/PrivacyInfo.xcprivacy: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | NSPrivacyCollectedDataTypes 6 | 7 | 8 | NSPrivacyAccessedAPITypes 9 | 10 | 11 | NSPrivacyAccessedAPIType 12 | NSPrivacyAccessedAPICategoryFileTimestamp 13 | NSPrivacyAccessedAPITypeReasons 14 | 15 | C617.1 16 | 17 | 18 | 19 | NSPrivacyAccessedAPIType 20 | NSPrivacyAccessedAPICategoryUserDefaults 21 | NSPrivacyAccessedAPITypeReasons 22 | 23 | CA92.1 24 | 25 | 26 | 27 | NSPrivacyAccessedAPIType 28 | NSPrivacyAccessedAPICategorySystemBootTime 29 | NSPrivacyAccessedAPITypeReasons 30 | 31 | 35F9.1 32 | 33 | 34 | 35 | NSPrivacyTracking 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /ios/Podfile: -------------------------------------------------------------------------------- 1 | # Resolve react_native_pods.rb with node to allow for hoisting 2 | require Pod::Executable.execute_command('node', ['-p', 3 | 'require.resolve( 4 | "react-native/scripts/react_native_pods.rb", 5 | {paths: [process.argv[1]]}, 6 | )', __dir__]).strip 7 | 8 | platform :ios, min_ios_version_supported 9 | prepare_react_native_project! 10 | 11 | linkage = ENV['USE_FRAMEWORKS'] 12 | if linkage != nil 13 | Pod::UI.puts "Configuring Pod with #{linkage}ally linked Frameworks".green 14 | use_frameworks! :linkage => linkage.to_sym 15 | end 16 | 17 | target 'videoCall' do 18 | config = use_native_modules! 19 | 20 | use_react_native!( 21 | :path => config[:reactNativePath], 22 | # An absolute path to your application root. 23 | :app_path => "#{Pod::Config.instance.installation_root}/.." 24 | ) 25 | 26 | target 'videoCallTests' do 27 | inherit! :complete 28 | # Pods for testing 29 | end 30 | 31 | post_install do |installer| 32 | # https://github.com/facebook/react-native/blob/main/packages/react-native/scripts/react_native_pods.rb#L197-L202 33 | react_native_post_install( 34 | installer, 35 | config[:reactNativePath], 36 | :mac_catalyst_enabled => false, 37 | # :ccache_enabled => true 38 | ) 39 | end 40 | end 41 | -------------------------------------------------------------------------------- /src/components/LoginForm.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import {StyleSheet} from 'react-native'; 3 | import {TextInput, Button, View} from 'react-native'; 4 | 5 | interface LoginFormProps { 6 | phone: string; 7 | password: string; 8 | setPhone: (value: string) => void; 9 | setPassword: (value: string) => void; 10 | handleLogin: () => void; 11 | styles: any; 12 | } 13 | 14 | const LoginForm: React.FC = ({ 15 | phone, 16 | password, 17 | setPhone, 18 | setPassword, 19 | handleLogin, 20 | styles, 21 | }) => { 22 | return ( 23 | 31 | 38 | 46 |