├── .watchmanconfig ├── .node-version ├── .ruby-version ├── app.json ├── .bundle └── config ├── android ├── app │ ├── debug.keystore │ ├── src │ │ ├── main │ │ │ ├── res │ │ │ │ ├── values │ │ │ │ │ ├── strings.xml │ │ │ │ │ └── styles.xml │ │ │ │ ├── mipmap-hdpi │ │ │ │ │ ├── ic_launcher.png │ │ │ │ │ └── ic_launcher_round.png │ │ │ │ ├── mipmap-mdpi │ │ │ │ │ ├── ic_launcher.png │ │ │ │ │ └── ic_launcher_round.png │ │ │ │ ├── mipmap-xhdpi │ │ │ │ │ ├── ic_launcher.png │ │ │ │ │ └── ic_launcher_round.png │ │ │ │ ├── mipmap-xxhdpi │ │ │ │ │ ├── ic_launcher.png │ │ │ │ │ └── ic_launcher_round.png │ │ │ │ ├── mipmap-xxxhdpi │ │ │ │ │ ├── ic_launcher.png │ │ │ │ │ └── ic_launcher_round.png │ │ │ │ └── drawable │ │ │ │ │ └── rn_edit_text_material.xml │ │ │ ├── jni │ │ │ │ ├── CMakeLists.txt │ │ │ │ ├── MainApplicationModuleProvider.h │ │ │ │ ├── OnLoad.cpp │ │ │ │ ├── MainComponentsRegistry.h │ │ │ │ ├── MainApplicationModuleProvider.cpp │ │ │ │ ├── MainApplicationTurboModuleManagerDelegate.h │ │ │ │ ├── MainApplicationTurboModuleManagerDelegate.cpp │ │ │ │ └── MainComponentsRegistry.cpp │ │ │ ├── AndroidManifest.xml │ │ │ └── java │ │ │ │ └── com │ │ │ │ └── ecommapp │ │ │ │ ├── newarchitecture │ │ │ │ ├── components │ │ │ │ │ └── MainComponentsRegistry.java │ │ │ │ ├── modules │ │ │ │ │ └── MainApplicationTurboModuleManagerDelegate.java │ │ │ │ └── MainApplicationReactNativeHost.java │ │ │ │ ├── MainActivity.java │ │ │ │ └── MainApplication.java │ │ └── debug │ │ │ ├── AndroidManifest.xml │ │ │ └── java │ │ │ └── com │ │ │ └── ecommapp │ │ │ └── ReactNativeFlipper.java │ ├── proguard-rules.pro │ ├── build_defs.bzl │ ├── _BUCK │ └── build.gradle ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── settings.gradle ├── build.gradle ├── gradle.properties ├── gradlew.bat └── gradlew ├── babel.config.js ├── ios ├── EcommApp │ ├── Images.xcassets │ │ ├── Contents.json │ │ └── AppIcon.appiconset │ │ │ └── Contents.json │ ├── AppDelegate.h │ ├── main.m │ ├── Info.plist │ ├── LaunchScreen.storyboard │ └── AppDelegate.mm ├── EcommApp.xcworkspace │ └── contents.xcworkspacedata ├── .xcode.env ├── EcommAppTests │ ├── Info.plist │ └── EcommAppTests.m ├── Podfile ├── EcommApp.xcodeproj │ ├── xcshareddata │ │ └── xcschemes │ │ │ └── EcommApp.xcscheme │ └── project.pbxproj └── Podfile.lock ├── .buckconfig ├── .prettierrc.js ├── Gemfile ├── index.js ├── __tests__ └── App-test.tsx ├── metro.config.js ├── tsconfig.json ├── .eslintrc.js ├── src ├── screens │ ├── HomeScreen │ │ └── index.tsx │ ├── ProductScreen │ │ ├── styles.ts │ │ └── index.tsx │ └── ShoppingCartScreen │ │ └── index.tsx ├── components │ ├── ImageCarousel │ │ ├── styles.ts │ │ └── index.tsx │ ├── Button │ │ └── index.tsx │ ├── ProductItem │ │ ├── styles.ts │ │ └── index.tsx │ ├── CartProductItem │ │ ├── styles.ts │ │ └── index.tsx │ └── QuantitySelector │ │ └── index.tsx └── data │ ├── product.ts │ ├── cart.ts │ ├── data.MD │ └── products.ts ├── App.tsx ├── .gitignore ├── package.json └── Gemfile.lock /.watchmanconfig: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /.node-version: -------------------------------------------------------------------------------- 1 | 16 2 | -------------------------------------------------------------------------------- /.ruby-version: -------------------------------------------------------------------------------- 1 | 2.7.5 2 | -------------------------------------------------------------------------------- /app.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "EcommApp", 3 | "displayName": "EcommApp" 4 | } -------------------------------------------------------------------------------- /.bundle/config: -------------------------------------------------------------------------------- 1 | BUNDLE_PATH: "vendor/bundle" 2 | BUNDLE_FORCE_RUBY_PLATFORM: 1 3 | -------------------------------------------------------------------------------- /android/app/debug.keystore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AbeTavarez/EcomRNApp/main/android/app/debug.keystore -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: ['module:metro-react-native-babel-preset'], 3 | }; 4 | -------------------------------------------------------------------------------- /android/app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | EcommApp 3 | 4 | -------------------------------------------------------------------------------- /ios/EcommApp/Images.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AbeTavarez/EcomRNApp/main/android/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /.buckconfig: -------------------------------------------------------------------------------- 1 | 2 | [android] 3 | target = Google Inc.:Google APIs:23 4 | 5 | [maven_repositories] 6 | central = https://repo1.maven.org/maven2 7 | -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AbeTavarez/EcomRNApp/main/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AbeTavarez/EcomRNApp/main/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AbeTavarez/EcomRNApp/main/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AbeTavarez/EcomRNApp/main/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AbeTavarez/EcomRNApp/main/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AbeTavarez/EcomRNApp/main/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AbeTavarez/EcomRNApp/main/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AbeTavarez/EcomRNApp/main/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AbeTavarez/EcomRNApp/main/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AbeTavarez/EcomRNApp/main/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /.prettierrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | arrowParens: 'avoid', 3 | bracketSameLine: true, 4 | bracketSpacing: false, 5 | singleQuote: true, 6 | trailingComma: 'all', 7 | }; 8 | -------------------------------------------------------------------------------- /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.7.5' 5 | 6 | gem 'cocoapods', '~> 1.11', '>= 1.11.2' 7 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @format 3 | */ 4 | 5 | import {AppRegistry} from 'react-native'; 6 | import App from './App'; 7 | import {name as appName} from './app.json'; 8 | 9 | AppRegistry.registerComponent(appName, () => App); 10 | -------------------------------------------------------------------------------- /ios/EcommApp/AppDelegate.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | 4 | @interface AppDelegate : UIResponder 5 | 6 | @property (nonatomic, strong) UIWindow *window; 7 | 8 | @end 9 | -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-all.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /ios/EcommApp/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 | -------------------------------------------------------------------------------- /ios/EcommApp.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /android/app/src/main/jni/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.13) 2 | 3 | # Define the library name here. 4 | project(ecommapp_appmodules) 5 | 6 | # This file includes all the necessary to let you build your application with the New Architecture. 7 | include(${REACT_ANDROID_DIR}/cmake-utils/ReactNative-application.cmake) 8 | -------------------------------------------------------------------------------- /__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: test renderer must be required after react-native. 10 | import renderer from 'react-test-renderer'; 11 | 12 | it('renders correctly', () => { 13 | renderer.create(); 14 | }); 15 | -------------------------------------------------------------------------------- /android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /metro.config.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Metro configuration for React Native 3 | * https://github.com/facebook/react-native 4 | * 5 | * @format 6 | */ 7 | 8 | module.exports = { 9 | transformer: { 10 | getTransformOptions: async () => ({ 11 | transform: { 12 | experimentalImportSupport: false, 13 | inlineRequires: true, 14 | }, 15 | }), 16 | }, 17 | }; 18 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | // prettier-ignore 2 | { 3 | "extends": "@tsconfig/react-native/tsconfig.json", /* Recommended React Native TSConfig base */ 4 | "compilerOptions": { 5 | /* Visit https://aka.ms/tsconfig.json to read more about this file */ 6 | 7 | /* Completeness */ 8 | "skipLibCheck": true /* Skip type checking all .d.ts files. */ 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | extends: '@react-native-community', 4 | parser: '@typescript-eslint/parser', 5 | plugins: ['@typescript-eslint'], 6 | overrides: [ 7 | { 8 | files: ['*.ts', '*.tsx'], 9 | rules: { 10 | '@typescript-eslint/no-shadow': ['error'], 11 | 'no-shadow': 'off', 12 | 'no-undef': 'off', 13 | }, 14 | }, 15 | ], 16 | }; 17 | -------------------------------------------------------------------------------- /android/app/src/main/jni/MainApplicationModuleProvider.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include 7 | 8 | namespace facebook { 9 | namespace react { 10 | 11 | std::shared_ptr MainApplicationModuleProvider( 12 | const std::string &moduleName, 13 | const JavaTurboModule::InitParams ¶ms); 14 | 15 | } // namespace react 16 | } // namespace facebook 17 | -------------------------------------------------------------------------------- /android/app/src/main/jni/OnLoad.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "MainApplicationTurboModuleManagerDelegate.h" 3 | #include "MainComponentsRegistry.h" 4 | 5 | JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *) { 6 | return facebook::jni::initialize(vm, [] { 7 | facebook::react::MainApplicationTurboModuleManagerDelegate:: 8 | registerNatives(); 9 | facebook::react::MainComponentsRegistry::registerNatives(); 10 | }); 11 | } 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 | -------------------------------------------------------------------------------- /src/screens/HomeScreen/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import {View, StyleSheet} from 'react-native'; 3 | import ProductItem from '../../components/ProductItem'; 4 | import products from '../../data/products'; 5 | 6 | const HomeScreen = () => { 7 | return ( 8 | 9 | 10 | 11 | ); 12 | }; 13 | 14 | const styles = StyleSheet.create({ 15 | page: { 16 | padding: 10, 17 | }, 18 | }); 19 | 20 | export default HomeScreen; 21 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /src/screens/ProductScreen/styles.ts: -------------------------------------------------------------------------------- 1 | import { StyleSheet } from "react-native"; 2 | 3 | const styles = StyleSheet.create({ 4 | root: { 5 | padding: 10, 6 | backgroundColor: '#fff', 7 | }, 8 | price: { 9 | fontSize: 18, 10 | fontWeight: '600', 11 | }, 12 | oldPrice: { 13 | fontSize: 12, 14 | fontWeight: 'normal', 15 | textDecorationLine: 'line-through', 16 | }, 17 | description: { 18 | marginVertical: 10, 19 | lineHeight: 20 20 | }, 21 | title: {}, 22 | }); 23 | 24 | export default styles; -------------------------------------------------------------------------------- /android/app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /android/settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'EcommApp' 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 | 6 | if (settings.hasProperty("newArchEnabled") && settings.newArchEnabled == "true") { 7 | include(":ReactAndroid") 8 | project(":ReactAndroid").projectDir = file('../node_modules/react-native/ReactAndroid') 9 | include(":ReactAndroid:hermes-engine") 10 | project(":ReactAndroid:hermes-engine").projectDir = file('../node_modules/react-native/ReactAndroid/hermes-engine') 11 | } 12 | -------------------------------------------------------------------------------- /src/components/ImageCarousel/styles.ts: -------------------------------------------------------------------------------- 1 | import { StyleSheet, Dimensions } from "react-native"; 2 | const windowWidth = Dimensions.get('window').width; 3 | 4 | const styles = StyleSheet.create({ 5 | root: { 6 | 7 | }, 8 | image: { 9 | width: windowWidth - 40, 10 | margin: 10, 11 | height: 250, 12 | resizeMode: 'contain', 13 | }, 14 | dot: { 15 | width: 10, 16 | height: 10, 17 | borderRadius: 25, 18 | borderWidth: 1, 19 | backgroundColor: '#ededed', 20 | borderColor: '#c9c9c9', 21 | margin: 5, 22 | }, 23 | dots: { 24 | flexDirection: 'row', 25 | justifyContent: 'center' 26 | }, 27 | }); 28 | 29 | export default styles; -------------------------------------------------------------------------------- /android/app/build_defs.bzl: -------------------------------------------------------------------------------- 1 | """Helper definitions to glob .aar and .jar targets""" 2 | 3 | def create_aar_targets(aarfiles): 4 | for aarfile in aarfiles: 5 | name = "aars__" + aarfile[aarfile.rindex("/") + 1:aarfile.rindex(".aar")] 6 | lib_deps.append(":" + name) 7 | android_prebuilt_aar( 8 | name = name, 9 | aar = aarfile, 10 | ) 11 | 12 | def create_jar_targets(jarfiles): 13 | for jarfile in jarfiles: 14 | name = "jars__" + jarfile[jarfile.rindex("/") + 1:jarfile.rindex(".jar")] 15 | lib_deps.append(":" + name) 16 | prebuilt_jar( 17 | name = name, 18 | binary_jar = jarfile, 19 | ) 20 | -------------------------------------------------------------------------------- /src/screens/ShoppingCartScreen/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import {View, StyleSheet, FlatList} from 'react-native'; 3 | import CartProductItem from '../../components/CartProductItem'; 4 | import products from '../../data/cart'; 5 | 6 | const ShoppingCartScreen = () => { 7 | return ( 8 | 9 | } 12 | keyExtractor={({id}) => id} 13 | showsVerticalScrollIndicator={false} 14 | /> 15 | 16 | ); 17 | }; 18 | 19 | const styles = StyleSheet.create({ 20 | page: { 21 | padding: 10, 22 | }, 23 | }); 24 | 25 | export default ShoppingCartScreen; 26 | -------------------------------------------------------------------------------- /ios/EcommAppTests/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 | -------------------------------------------------------------------------------- /src/components/Button/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import {Text, Pressable, StyleSheet} from 'react-native'; 3 | 4 | interface ButtonProps { 5 | text: string; 6 | onPress: () => void; 7 | containerStyles?: object; 8 | } 9 | 10 | const Button = ({text, onPress, containerStyles}: ButtonProps) => { 11 | return ( 12 | 13 | {text} 14 | 15 | ); 16 | }; 17 | 18 | const styles = StyleSheet.create({ 19 | root: { 20 | backgroundColor: '#e77600', 21 | marginVertical: 10, 22 | height: 40, 23 | justifyContent: 'center', 24 | alignItems: 'center', 25 | borderRadius: 5, 26 | borderWidth: 1, 27 | borderColor: '#D5D9D9', 28 | }, 29 | text: { 30 | color: '#0F1111', 31 | fontSize: 18, 32 | fontWeight: '300', 33 | }, 34 | }); 35 | 36 | export default Button; 37 | -------------------------------------------------------------------------------- /src/components/ProductItem/styles.ts: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line prettier/prettier 2 | import { StyleSheet } from 'react-native'; 3 | 4 | const styles = StyleSheet.create({ 5 | root: { 6 | flexDirection: 'row', 7 | borderWidth: 1, 8 | borderColor: '#d1d1d1', 9 | borderRadius: 10, 10 | backgroundColor: '#fff', 11 | marginVertical: 5, 12 | }, 13 | productImage: { 14 | flex: 2, 15 | height: 150, 16 | resizeMode: 'contain', 17 | }, 18 | rightContainer: { 19 | padding: 10, 20 | flex: 3, 21 | }, 22 | title: { 23 | fontSize: 18, 24 | fontWeight: '400', 25 | }, 26 | price: { 27 | fontSize: 18, 28 | fontWeight: '600', 29 | }, 30 | ratingContainer: { 31 | flexDirection: 'row', 32 | alignItems: 'center', 33 | marginVertical: 10, 34 | }, 35 | star: { 36 | margin: 2, 37 | }, 38 | oldPrice: { 39 | fontSize: 12, 40 | fontWeight: 'normal', 41 | textDecorationLine: 'line-through', 42 | }, 43 | }); 44 | 45 | export default styles; -------------------------------------------------------------------------------- /src/components/CartProductItem/styles.ts: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line prettier/prettier 2 | import { StyleSheet } from 'react-native'; 3 | 4 | const styles = StyleSheet.create({ 5 | root: { 6 | flexDirection: 'row', 7 | borderWidth: 1, 8 | borderColor: '#d1d1d1', 9 | borderRadius: 10, 10 | backgroundColor: '#fff', 11 | marginVertical: 5, 12 | }, 13 | productImage: { 14 | flex: 2, 15 | height: 150, 16 | resizeMode: 'contain', 17 | }, 18 | rightContainer: { 19 | padding: 10, 20 | flex: 3, 21 | }, 22 | title: { 23 | fontSize: 18, 24 | fontWeight: '400', 25 | }, 26 | price: { 27 | fontSize: 18, 28 | fontWeight: '600', 29 | }, 30 | ratingContainer: { 31 | flexDirection: 'row', 32 | alignItems: 'center', 33 | marginVertical: 10, 34 | }, 35 | star: { 36 | margin: 2, 37 | }, 38 | oldPrice: { 39 | fontSize: 12, 40 | fontWeight: 'normal', 41 | textDecorationLine: 'line-through', 42 | }, 43 | }); 44 | 45 | export default styles; -------------------------------------------------------------------------------- /android/app/src/main/jni/MainComponentsRegistry.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | namespace facebook { 9 | namespace react { 10 | 11 | class MainComponentsRegistry 12 | : public facebook::jni::HybridClass { 13 | public: 14 | // Adapt it to the package you used for your Java class. 15 | constexpr static auto kJavaDescriptor = 16 | "Lcom/ecommapp/newarchitecture/components/MainComponentsRegistry;"; 17 | 18 | static void registerNatives(); 19 | 20 | MainComponentsRegistry(ComponentFactory *delegate); 21 | 22 | private: 23 | static std::shared_ptr 24 | sharedProviderRegistry(); 25 | 26 | static jni::local_ref initHybrid( 27 | jni::alias_ref, 28 | ComponentFactory *delegate); 29 | }; 30 | 31 | } // namespace react 32 | } // namespace facebook 33 | -------------------------------------------------------------------------------- /App.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * Sample React Native App 3 | * https://github.com/facebook/react-native 4 | * 5 | * Generated with the TypeScript template 6 | * https://github.com/react-native-community/react-native-template-typescript 7 | * 8 | * @format 9 | */ 10 | import Icon from 'react-native-vector-icons/FontAwesome'; 11 | import React, {type PropsWithChildren} from 'react'; 12 | import {SafeAreaView, StatusBar, useColorScheme} from 'react-native'; 13 | 14 | import {Colors} from 'react-native/Libraries/NewAppScreen'; 15 | 16 | import HomeScreen from './src/screens/HomeScreen'; 17 | const App = () => { 18 | const isDarkMode = useColorScheme() === 'dark'; 19 | 20 | const backgroundStyle = { 21 | backgroundColor: isDarkMode ? Colors.darker : Colors.lighter, 22 | }; 23 | 24 | return ( 25 | 26 | 30 | 31 | 32 | ); 33 | }; 34 | 35 | export default App; 36 | -------------------------------------------------------------------------------- /android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 13 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /ios/EcommApp/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 | -------------------------------------------------------------------------------- /android/app/src/main/jni/MainApplicationModuleProvider.cpp: -------------------------------------------------------------------------------- 1 | #include "MainApplicationModuleProvider.h" 2 | 3 | #include 4 | #include 5 | 6 | namespace facebook { 7 | namespace react { 8 | 9 | std::shared_ptr MainApplicationModuleProvider( 10 | const std::string &moduleName, 11 | const JavaTurboModule::InitParams ¶ms) { 12 | // Here you can provide your own module provider for TurboModules coming from 13 | // either your application or from external libraries. The approach to follow 14 | // is similar to the following (for a library called `samplelibrary`: 15 | // 16 | // auto module = samplelibrary_ModuleProvider(moduleName, params); 17 | // if (module != nullptr) { 18 | // return module; 19 | // } 20 | // return rncore_ModuleProvider(moduleName, params); 21 | 22 | // Module providers autolinked by RN CLI 23 | auto rncli_module = rncli_ModuleProvider(moduleName, params); 24 | if (rncli_module != nullptr) { 25 | return rncli_module; 26 | } 27 | 28 | return rncore_ModuleProvider(moduleName, params); 29 | } 30 | 31 | } // namespace react 32 | } // namespace facebook 33 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # OSX 2 | # 3 | .DS_Store 4 | 5 | # Xcode 6 | # 7 | build/ 8 | *.pbxuser 9 | !default.pbxuser 10 | *.mode1v3 11 | !default.mode1v3 12 | *.mode2v3 13 | !default.mode2v3 14 | *.perspectivev3 15 | !default.perspectivev3 16 | xcuserdata 17 | *.xccheckout 18 | *.moved-aside 19 | DerivedData 20 | *.hmap 21 | *.ipa 22 | *.xcuserstate 23 | ios/.xcode.env.local 24 | 25 | # Android/IntelliJ 26 | # 27 | build/ 28 | .idea 29 | .gradle 30 | local.properties 31 | *.iml 32 | *.hprof 33 | .cxx/ 34 | 35 | # node.js 36 | # 37 | node_modules/ 38 | npm-debug.log 39 | yarn-error.log 40 | 41 | # BUCK 42 | buck-out/ 43 | \.buckd/ 44 | *.keystore 45 | !debug.keystore 46 | 47 | # fastlane 48 | # 49 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 50 | # screenshots whenever they are needed. 51 | # For more information about the recommended setup visit: 52 | # https://docs.fastlane.tools/best-practices/source-control/ 53 | 54 | **/fastlane/report.xml 55 | **/fastlane/Preview.html 56 | **/fastlane/screenshots 57 | **/fastlane/test_output 58 | 59 | # Bundle artifact 60 | *.jsbundle 61 | 62 | # Ruby / CocoaPods 63 | /ios/Pods/ 64 | /vendor/bundle/ 65 | -------------------------------------------------------------------------------- /src/data/product.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | id: '5', 3 | title: "Logitech MX Master 3 Advanced Wireless Mouse for Mac - Bluetooth/USB", 4 | description: `Features & details 5 | - MAGSPEED WHEEL: Ultra-fast, precise, quiet MagSpeed electromagnetic scrolling 6 | - DARKFIELD 4000 DPI SENSOR: Darkfield 4000 DPI sensor for precise tracking on any surface, even glass (up to 4mm in thickness) 7 | - COMFORTABLE DESIGN: Tactile reference for hand positioning makes it easy to stay oriented and in your flow 8 | - FLOW CROSS-COMPUTER CONTROL: Supports flow cross-computer control across multiple screens. Pair up to 3 devices via Bluetooth Low Energy or Unifying USB receiver`, 9 | image: 'https://notjustdev-dummy.s3.us-east-2.amazonaws.com/images/products/mouse1.jpg', 10 | images: [ 11 | 'https://notjustdev-dummy.s3.us-east-2.amazonaws.com/images/products/mouse1.jpg', 12 | 'https://notjustdev-dummy.s3.us-east-2.amazonaws.com/images/products/mouse2.jpg', 13 | 'https://notjustdev-dummy.s3.us-east-2.amazonaws.com/images/products/mouse3.jpg', 14 | ], 15 | options: [ 16 | 'Black', 17 | 'Space Grey' 18 | ], 19 | avgRating: 4.8, 20 | ratings: 2989, 21 | price: 99.98, 22 | oldPrice: 120.06, 23 | }; 24 | -------------------------------------------------------------------------------- /src/data/cart.ts: -------------------------------------------------------------------------------- 1 | export default [ 2 | { 3 | id: '1', 4 | quantity: 1, 5 | item: { 6 | id: '1', 7 | title: "Clean Architecture: A Craftsman's Guide to Software Structure and Design", 8 | image: 'https://notjustdev-dummy.s3.us-east-2.amazonaws.com/images/products/cleanarchitecture.jpg', 9 | avgRating: 4.2, 10 | ratings: 1325, 11 | price: 20.98, 12 | oldPrice: 24.06, 13 | } 14 | }, 15 | { 16 | id: '2', 17 | quantity: 2, 18 | item: { 19 | id: '2', 20 | title: "Clean Code: A Handbook of Agile Software Craftsmanship", 21 | image: 'https://notjustdev-dummy.s3.us-east-2.amazonaws.com/images/products/cleancode.jpg', 22 | avgRating: 4.8, 23 | ratings: 2989, 24 | price: 32.98, 25 | oldPrice: 34.06, 26 | } 27 | }, 28 | { 29 | id: '3', 30 | quantity: 1, 31 | option: 'Space Grey', 32 | item: { 33 | id: '5', 34 | title: "Mouse Havit Mechanical Keyboard Wired 89 Keys Gaming Keyboard", 35 | image: 'https://notjustdev-dummy.s3.us-east-2.amazonaws.com/images/products/mouse2.jpg', 36 | avgRating: 4.8, 37 | ratings: 2989, 38 | price: 99.98, 39 | oldPrice: 120.06, 40 | } 41 | }, 42 | ]; -------------------------------------------------------------------------------- /android/app/src/main/jni/MainApplicationTurboModuleManagerDelegate.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | #include 6 | 7 | namespace facebook { 8 | namespace react { 9 | 10 | class MainApplicationTurboModuleManagerDelegate 11 | : public jni::HybridClass< 12 | MainApplicationTurboModuleManagerDelegate, 13 | TurboModuleManagerDelegate> { 14 | public: 15 | // Adapt it to the package you used for your Java class. 16 | static constexpr auto kJavaDescriptor = 17 | "Lcom/ecommapp/newarchitecture/modules/MainApplicationTurboModuleManagerDelegate;"; 18 | 19 | static jni::local_ref initHybrid(jni::alias_ref); 20 | 21 | static void registerNatives(); 22 | 23 | std::shared_ptr getTurboModule( 24 | const std::string &name, 25 | const std::shared_ptr &jsInvoker) override; 26 | std::shared_ptr getTurboModule( 27 | const std::string &name, 28 | const JavaTurboModule::InitParams ¶ms) override; 29 | 30 | /** 31 | * Test-only method. Allows user to verify whether a TurboModule can be 32 | * created by instances of this class. 33 | */ 34 | bool canCreateTurboModule(const std::string &name); 35 | }; 36 | 37 | } // namespace react 38 | } // namespace facebook 39 | -------------------------------------------------------------------------------- /android/app/src/main/java/com/ecommapp/newarchitecture/components/MainComponentsRegistry.java: -------------------------------------------------------------------------------- 1 | package com.ecommapp.newarchitecture.components; 2 | 3 | import com.facebook.jni.HybridData; 4 | import com.facebook.proguard.annotations.DoNotStrip; 5 | import com.facebook.react.fabric.ComponentFactory; 6 | import com.facebook.soloader.SoLoader; 7 | 8 | /** 9 | * Class responsible to load the custom Fabric Components. This class has native methods and needs a 10 | * corresponding C++ implementation/header file to work correctly (already placed inside the jni/ 11 | * folder for you). 12 | * 13 | *

Please note that this class is used ONLY if you opt-in for the New Architecture (see the 14 | * `newArchEnabled` property). Is ignored otherwise. 15 | */ 16 | @DoNotStrip 17 | public class MainComponentsRegistry { 18 | static { 19 | SoLoader.loadLibrary("fabricjni"); 20 | } 21 | 22 | @DoNotStrip private final HybridData mHybridData; 23 | 24 | @DoNotStrip 25 | private native HybridData initHybrid(ComponentFactory componentFactory); 26 | 27 | @DoNotStrip 28 | private MainComponentsRegistry(ComponentFactory componentFactory) { 29 | mHybridData = initHybrid(componentFactory); 30 | } 31 | 32 | @DoNotStrip 33 | public static MainComponentsRegistry register(ComponentFactory componentFactory) { 34 | return new MainComponentsRegistry(componentFactory); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "EcommApp", 3 | "version": "0.0.1", 4 | "private": true, 5 | "scripts": { 6 | "android": "react-native run-android", 7 | "ios": "react-native run-ios", 8 | "start": "react-native start", 9 | "test": "jest", 10 | "lint": "eslint . --ext .js,.jsx,.ts,.tsx" 11 | }, 12 | "dependencies": { 13 | "@react-native-picker/picker": "^2.4.8", 14 | "react": "18.1.0", 15 | "react-native": "0.70.3", 16 | "react-native-vector-icons": "^9.2.0" 17 | }, 18 | "devDependencies": { 19 | "@babel/core": "^7.12.9", 20 | "@babel/runtime": "^7.12.5", 21 | "@react-native-community/eslint-config": "^2.0.0", 22 | "@tsconfig/react-native": "^2.0.2", 23 | "@types/jest": "^26.0.23", 24 | "@types/react": "^18.0.21", 25 | "@types/react-native": "^0.70.4", 26 | "@types/react-test-renderer": "^18.0.0", 27 | "@typescript-eslint/eslint-plugin": "^5.37.0", 28 | "@typescript-eslint/parser": "^5.37.0", 29 | "babel-jest": "^26.6.3", 30 | "eslint": "^7.32.0", 31 | "jest": "^26.6.3", 32 | "metro-react-native-babel-preset": "0.72.3", 33 | "react-test-renderer": "18.1.0", 34 | "typescript": "^4.8.3" 35 | }, 36 | "jest": { 37 | "preset": "react-native", 38 | "moduleFileExtensions": [ 39 | "ts", 40 | "tsx", 41 | "js", 42 | "jsx", 43 | "json", 44 | "node" 45 | ] 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/data/data.MD: -------------------------------------------------------------------------------- 1 | # Dummy Data for Amazon Clone 2 | 3 | ## Product Images 4 | 5 | - https://notjustdev-dummy.s3.us-east-2.amazonaws.com/images/products/cleanarchitecture.jpg 6 | 7 | - https://notjustdev-dummy.s3.us-east-2.amazonaws.com/images/products/cleancode.jpg 8 | 9 | - https://notjustdev-dummy.s3.us-east-2.amazonaws.com/images/products/imac1.jpg 10 | 11 | - https://notjustdev-dummy.s3.us-east-2.amazonaws.com/images/products/imac2.jpg 12 | 13 | - https://notjustdev-dummy.s3.us-east-2.amazonaws.com/images/products/keyboard1.jpg 14 | 15 | - https://notjustdev-dummy.s3.us-east-2.amazonaws.com/images/products/keyboard2.jpg 16 | 17 | - https://notjustdev-dummy.s3.us-east-2.amazonaws.com/images/products/mouse1.jpg 18 | 19 | - https://notjustdev-dummy.s3.us-east-2.amazonaws.com/images/products/mouse2.jpg 20 | 21 | - https://notjustdev-dummy.s3.us-east-2.amazonaws.com/images/products/mouse3.jpg 22 | 23 | ## Files 24 | - **products.ts**: A list of products having: 25 | - id 26 | - title 27 | - image 28 | - avgRating 29 | - ratings 30 | - price 31 | - oldPrice (optional) 32 | - **product.ts**: Product details 33 | - id 34 | - title 35 | - *description* 36 | - image 37 | - *images* (array of images) 38 | - *options* (array if possible variation/options) 39 | - avgRating 40 | - ratings 41 | - price 42 | - oldPrice (optional) 43 | - **cart.ts**: Items in the cart 44 | - id 45 | - item 46 | - quantity 47 | - option (selected option) -------------------------------------------------------------------------------- /src/components/QuantitySelector/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import {View, Text, Pressable, StyleSheet} from 'react-native'; 3 | 4 | interface QuantityProps { 5 | quantity: number; 6 | setQuantity: (value: number) => void; 7 | } 8 | 9 | const QuantitySelector = ({quantity, setQuantity}: QuantityProps) => { 10 | const onMinus = () => { 11 | setQuantity(Math.max(0, quantity - 1)); 12 | }; 13 | const onPlus = () => { 14 | setQuantity(quantity + 1); 15 | }; 16 | return ( 17 | 18 | 19 | - 20 | 21 | 22 | {quantity} 23 | 24 | 25 | + 26 | 27 | 28 | ); 29 | }; 30 | 31 | const styles = StyleSheet.create({ 32 | root: { 33 | flexDirection: 'row', 34 | alignItems: 'center', 35 | justifyContent: 'space-between', 36 | width: 130, 37 | borderWidth: 1, 38 | borderColor: '#e3e3e3', 39 | }, 40 | button: { 41 | width: 35, 42 | height: 35, 43 | alignItems: 'center', 44 | justifyContent: 'center', 45 | backgroundColor: '#d1d1d1', 46 | }, 47 | buttonText: { 48 | fontSize: 18, 49 | }, 50 | quantity: { 51 | color: '#007eb9', 52 | }, 53 | }); 54 | 55 | export default QuantitySelector; 56 | -------------------------------------------------------------------------------- /android/app/_BUCK: -------------------------------------------------------------------------------- 1 | # To learn about Buck see [Docs](https://buckbuild.com/). 2 | # To run your application with Buck: 3 | # - install Buck 4 | # - `npm start` - to start the packager 5 | # - `cd android` 6 | # - `keytool -genkey -v -keystore keystores/debug.keystore -storepass android -alias androiddebugkey -keypass android -dname "CN=Android Debug,O=Android,C=US"` 7 | # - `./gradlew :app:copyDownloadableDepsToLibs` - make all Gradle compile dependencies available to Buck 8 | # - `buck install -r android/app` - compile, install and run application 9 | # 10 | 11 | load(":build_defs.bzl", "create_aar_targets", "create_jar_targets") 12 | 13 | lib_deps = [] 14 | 15 | create_aar_targets(glob(["libs/*.aar"])) 16 | 17 | create_jar_targets(glob(["libs/*.jar"])) 18 | 19 | android_library( 20 | name = "all-libs", 21 | exported_deps = lib_deps, 22 | ) 23 | 24 | android_library( 25 | name = "app-code", 26 | srcs = glob([ 27 | "src/main/java/**/*.java", 28 | ]), 29 | deps = [ 30 | ":all-libs", 31 | ":build_config", 32 | ":res", 33 | ], 34 | ) 35 | 36 | android_build_config( 37 | name = "build_config", 38 | package = "com.ecommapp", 39 | ) 40 | 41 | android_resource( 42 | name = "res", 43 | package = "com.ecommapp", 44 | res = "src/main/res", 45 | ) 46 | 47 | android_binary( 48 | name = "app", 49 | keystore = "//android/keystores:debug", 50 | manifest = "src/main/AndroidManifest.xml", 51 | package_type = "debug", 52 | deps = [ 53 | ":app-code", 54 | ], 55 | ) 56 | -------------------------------------------------------------------------------- /ios/Podfile: -------------------------------------------------------------------------------- 1 | require_relative '../node_modules/react-native/scripts/react_native_pods' 2 | require_relative '../node_modules/@react-native-community/cli-platform-ios/native_modules' 3 | 4 | platform :ios, '12.4' 5 | install! 'cocoapods', :deterministic_uuids => false 6 | 7 | target 'EcommApp' do 8 | config = use_native_modules! 9 | 10 | # Flags change depending on the env values. 11 | flags = get_default_flags() 12 | 13 | use_react_native!( 14 | :path => config[:reactNativePath], 15 | # Hermes is now enabled by default. Disable by setting this flag to false. 16 | # Upcoming versions of React Native may rely on get_default_flags(), but 17 | # we make it explicit here to aid in the React Native upgrade process. 18 | :hermes_enabled => true, 19 | :fabric_enabled => flags[:fabric_enabled], 20 | # Enables Flipper. 21 | # 22 | # Note that if you have use_frameworks! enabled, Flipper will not work and 23 | # you should disable the next line. 24 | :flipper_configuration => FlipperConfiguration.enabled, 25 | # An absolute path to your application root. 26 | :app_path => "#{Pod::Config.instance.installation_root}/.." 27 | ) 28 | 29 | target 'EcommAppTests' do 30 | inherit! :complete 31 | # Pods for testing 32 | end 33 | 34 | post_install do |installer| 35 | react_native_post_install( 36 | installer, 37 | # Set `mac_catalyst_enabled` to `true` in order to apply patches 38 | # necessary for Mac Catalyst builds 39 | :mac_catalyst_enabled => false 40 | ) 41 | __apply_Xcode_12_5_M1_post_install_workaround(installer) 42 | end 43 | end 44 | -------------------------------------------------------------------------------- /src/components/ProductItem/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import {View, Text, Image} from 'react-native'; 3 | import FontAwesome from 'react-native-vector-icons/FontAwesome'; 4 | import styles from './styles'; 5 | 6 | interface ProductItemsProps { 7 | item: { 8 | id: string; 9 | title: string; 10 | image: string; 11 | avgRating: number; 12 | price: number; 13 | oldPrice?: number; 14 | }; 15 | } 16 | 17 | const ProductItem = (props: ProductItemsProps) => { 18 | const {item} = props; 19 | return ( 20 | 21 | 27 | 28 | 29 | {item.title} 30 | 31 | 32 | {[...new Array(5)].map((el, idx) => ( 33 | 40 | ))} 41 | {item.avgRating} 42 | 43 | 44 | from: ${item.price}{' '} 45 | {item.oldPrice && ( 46 | ${item?.oldPrice} 47 | )} 48 | 49 | 50 | 51 | ); 52 | }; 53 | 54 | export default ProductItem; 55 | -------------------------------------------------------------------------------- /android/app/src/main/jni/MainApplicationTurboModuleManagerDelegate.cpp: -------------------------------------------------------------------------------- 1 | #include "MainApplicationTurboModuleManagerDelegate.h" 2 | #include "MainApplicationModuleProvider.h" 3 | 4 | namespace facebook { 5 | namespace react { 6 | 7 | jni::local_ref 8 | MainApplicationTurboModuleManagerDelegate::initHybrid( 9 | jni::alias_ref) { 10 | return makeCxxInstance(); 11 | } 12 | 13 | void MainApplicationTurboModuleManagerDelegate::registerNatives() { 14 | registerHybrid({ 15 | makeNativeMethod( 16 | "initHybrid", MainApplicationTurboModuleManagerDelegate::initHybrid), 17 | makeNativeMethod( 18 | "canCreateTurboModule", 19 | MainApplicationTurboModuleManagerDelegate::canCreateTurboModule), 20 | }); 21 | } 22 | 23 | std::shared_ptr 24 | MainApplicationTurboModuleManagerDelegate::getTurboModule( 25 | const std::string &name, 26 | const std::shared_ptr &jsInvoker) { 27 | // Not implemented yet: provide pure-C++ NativeModules here. 28 | return nullptr; 29 | } 30 | 31 | std::shared_ptr 32 | MainApplicationTurboModuleManagerDelegate::getTurboModule( 33 | const std::string &name, 34 | const JavaTurboModule::InitParams ¶ms) { 35 | return MainApplicationModuleProvider(name, params); 36 | } 37 | 38 | bool MainApplicationTurboModuleManagerDelegate::canCreateTurboModule( 39 | const std::string &name) { 40 | return getTurboModule(name, nullptr) != nullptr || 41 | getTurboModule(name, {.moduleName = name}) != nullptr; 42 | } 43 | 44 | } // namespace react 45 | } // namespace facebook 46 | -------------------------------------------------------------------------------- /src/components/ImageCarousel/index.tsx: -------------------------------------------------------------------------------- 1 | import React, {useState, useCallback} from 'react'; 2 | import {View, FlatList, Image, useWindowDimensions} from 'react-native'; 3 | import styles from './styles'; 4 | 5 | interface ImageCarouselProps { 6 | images: [string]; 7 | } 8 | 9 | const ImageCarousel = ({images}: ImageCarouselProps) => { 10 | const [activeIndex, setActiveIndex] = useState(0); 11 | const windowWidth = useWindowDimensions().width; 12 | 13 | const onFlatListUpdate = useCallback(({viewableItems}: any) => { 14 | if (viewableItems.length > 0) { 15 | setActiveIndex(viewableItems[0].index || 0); 16 | } 17 | }, []); 18 | 19 | return ( 20 | 21 | ( 24 | 25 | )} 26 | horizontal 27 | showsHorizontalScrollIndicator={false} 28 | snapToInterval={windowWidth - 20} 29 | snapToAlignment={'center'} 30 | decelerationRate={'fast'} 31 | viewabilityConfig={{ 32 | viewAreaCoveragePercentThreshold: 50, 33 | // minimumViewTime: 300, 34 | }} 35 | onViewableItemsChanged={onFlatListUpdate} 36 | /> 37 | 38 | {images.map((dot, idx) => ( 39 | 45 | ))} 46 | 47 | 48 | ); 49 | }; 50 | 51 | export default ImageCarousel; 52 | -------------------------------------------------------------------------------- /android/app/src/main/java/com/ecommapp/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.ecommapp; 2 | 3 | import com.facebook.react.ReactActivity; 4 | import com.facebook.react.ReactActivityDelegate; 5 | import com.facebook.react.ReactRootView; 6 | 7 | public class MainActivity extends ReactActivity { 8 | 9 | /** 10 | * Returns the name of the main component registered from JavaScript. This is used to schedule 11 | * rendering of the component. 12 | */ 13 | @Override 14 | protected String getMainComponentName() { 15 | return "EcommApp"; 16 | } 17 | 18 | /** 19 | * Returns the instance of the {@link ReactActivityDelegate}. There the RootView is created and 20 | * you can specify the renderer you wish to use - the new renderer (Fabric) or the old renderer 21 | * (Paper). 22 | */ 23 | @Override 24 | protected ReactActivityDelegate createReactActivityDelegate() { 25 | return new MainActivityDelegate(this, getMainComponentName()); 26 | } 27 | 28 | public static class MainActivityDelegate extends ReactActivityDelegate { 29 | public MainActivityDelegate(ReactActivity activity, String mainComponentName) { 30 | super(activity, mainComponentName); 31 | } 32 | 33 | @Override 34 | protected ReactRootView createRootView() { 35 | ReactRootView reactRootView = new ReactRootView(getContext()); 36 | // If you opted-in for the New Architecture, we enable the Fabric Renderer. 37 | reactRootView.setIsFabric(BuildConfig.IS_NEW_ARCHITECTURE_ENABLED); 38 | return reactRootView; 39 | } 40 | 41 | @Override 42 | protected boolean isConcurrentRootEnabled() { 43 | // If you opted-in for the New Architecture, we enable Concurrent Root (i.e. React 18). 44 | // More on this on https://reactjs.org/blog/2022/03/29/react-v18.html 45 | return BuildConfig.IS_NEW_ARCHITECTURE_ENABLED; 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /android/build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | ext { 5 | buildToolsVersion = "31.0.0" 6 | minSdkVersion = 21 7 | compileSdkVersion = 31 8 | targetSdkVersion = 31 9 | 10 | if (System.properties['os.arch'] == "aarch64") { 11 | // For M1 Users we need to use the NDK 24 which added support for aarch64 12 | ndkVersion = "24.0.8215888" 13 | } else { 14 | // Otherwise we default to the side-by-side NDK version from AGP. 15 | ndkVersion = "21.4.7075529" 16 | } 17 | } 18 | repositories { 19 | google() 20 | mavenCentral() 21 | } 22 | dependencies { 23 | classpath("com.android.tools.build:gradle:7.2.1") 24 | classpath("com.facebook.react:react-native-gradle-plugin") 25 | classpath("de.undercouch:gradle-download-task:5.0.1") 26 | // NOTE: Do not place your application dependencies here; they belong 27 | // in the individual module build.gradle files 28 | } 29 | } 30 | 31 | allprojects { 32 | repositories { 33 | maven { 34 | // All of React Native (JS, Obj-C sources, Android binaries) is installed from npm 35 | url("$rootDir/../node_modules/react-native/android") 36 | } 37 | maven { 38 | // Android JSC is installed from npm 39 | url("$rootDir/../node_modules/jsc-android/dist") 40 | } 41 | mavenCentral { 42 | // We don't want to fetch react-native from Maven Central as there are 43 | // older versions over there. 44 | content { 45 | excludeGroup "com.facebook.react" 46 | } 47 | } 48 | google() 49 | maven { url 'https://www.jitpack.io' } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/screens/ProductScreen/index.tsx: -------------------------------------------------------------------------------- 1 | import React, {useState} from 'react'; 2 | import {View, Text} from 'react-native'; 3 | import {Picker} from '@react-native-picker/picker'; 4 | import QuantitySelector from '../../components/QuantitySelector'; 5 | import Button from '../../components/Button'; 6 | import styles from './styles'; 7 | import product from '../../data/product'; 8 | 9 | const ProductScreen = () => { 10 | const [selectedOption, setSelectedOption] = useState( 11 | product.options[0] ? product.options[0] : null, 12 | ); 13 | const [quantity, setQuantity] = useState(1); 14 | 15 | return ( 16 | 17 | {product.title} 18 | 19 | {/* Image carousel */} 20 | 21 | {/* option selector */} 22 | setSelectedOption(itemValue)}> 25 | {product.options.map(op => ( 26 | 27 | ))} 28 | 29 | 30 | {/* Price */} 31 | 32 | from: ${product.price}{' '} 33 | {product.oldPrice && ( 34 | ${product?.oldPrice} 35 | )} 36 | 37 | 38 | {/* Description */} 39 | {product.description} 40 | 41 | {/* Quantity Selector */} 42 | 43 | 44 | {/* Button */} 45 |