diff --git a/docs/en/Blog-Posts/2024-09-17-My-Impressions-at-DotNext-2024-Conference/banner.png b/docs/en/Blog-Posts/2024-09-17-My-Impressions-at-DotNext-2024-Conference/banner.png index 040e8470df..a25baf863a 100644 Binary files a/docs/en/Blog-Posts/2024-09-17-My-Impressions-at-DotNext-2024-Conference/banner.png and b/docs/en/Blog-Posts/2024-09-17-My-Impressions-at-DotNext-2024-Conference/banner.png differ diff --git a/docs/en/Blog-Posts/2024-09-17-My-Impressions-at-DotNext-2024-Conference/boat-trip.jpg b/docs/en/Blog-Posts/2024-09-17-My-Impressions-at-DotNext-2024-Conference/boat-trip.jpg index e8b25c8391..7a9b89732a 100644 Binary files a/docs/en/Blog-Posts/2024-09-17-My-Impressions-at-DotNext-2024-Conference/boat-trip.jpg and b/docs/en/Blog-Posts/2024-09-17-My-Impressions-at-DotNext-2024-Conference/boat-trip.jpg differ diff --git a/docs/en/Blog-Posts/2024-09-17-My-Impressions-at-DotNext-2024-Conference/collage-moscow.jpg b/docs/en/Blog-Posts/2024-09-17-My-Impressions-at-DotNext-2024-Conference/collage-moscow.jpg index 1acfee01a3..69652780b7 100644 Binary files a/docs/en/Blog-Posts/2024-09-17-My-Impressions-at-DotNext-2024-Conference/collage-moscow.jpg and b/docs/en/Blog-Posts/2024-09-17-My-Impressions-at-DotNext-2024-Conference/collage-moscow.jpg differ diff --git a/docs/en/Blog-Posts/2024-09-17-My-Impressions-at-DotNext-2024-Conference/general-collage.jpg b/docs/en/Blog-Posts/2024-09-17-My-Impressions-at-DotNext-2024-Conference/general-collage.jpg index 9310e1312f..459f151e25 100644 Binary files a/docs/en/Blog-Posts/2024-09-17-My-Impressions-at-DotNext-2024-Conference/general-collage.jpg and b/docs/en/Blog-Posts/2024-09-17-My-Impressions-at-DotNext-2024-Conference/general-collage.jpg differ diff --git a/docs/en/Blog-Posts/2024-09-17-My-Impressions-at-DotNext-2024-Conference/halil-talk.jpg b/docs/en/Blog-Posts/2024-09-17-My-Impressions-at-DotNext-2024-Conference/halil-talk.jpg index 9f0e62bf77..8d2a116524 100644 Binary files a/docs/en/Blog-Posts/2024-09-17-My-Impressions-at-DotNext-2024-Conference/halil-talk.jpg and b/docs/en/Blog-Posts/2024-09-17-My-Impressions-at-DotNext-2024-Conference/halil-talk.jpg differ diff --git a/docs/en/Blog-Posts/2024-09-17-My-Impressions-at-DotNext-2024-Conference/my-talk-2.png b/docs/en/Blog-Posts/2024-09-17-My-Impressions-at-DotNext-2024-Conference/my-talk-2.png index b2a0ae3581..34acae63da 100644 Binary files a/docs/en/Blog-Posts/2024-09-17-My-Impressions-at-DotNext-2024-Conference/my-talk-2.png and b/docs/en/Blog-Posts/2024-09-17-My-Impressions-at-DotNext-2024-Conference/my-talk-2.png differ diff --git a/docs/en/Blog-Posts/2024-09-17-My-Impressions-at-DotNext-2024-Conference/my-talk-pro-pictures.jpg b/docs/en/Blog-Posts/2024-09-17-My-Impressions-at-DotNext-2024-Conference/my-talk-pro-pictures.jpg index 20f411243b..8cd11d2d11 100644 Binary files a/docs/en/Blog-Posts/2024-09-17-My-Impressions-at-DotNext-2024-Conference/my-talk-pro-pictures.jpg and b/docs/en/Blog-Posts/2024-09-17-My-Impressions-at-DotNext-2024-Conference/my-talk-pro-pictures.jpg differ diff --git a/docs/en/Blog-Posts/2024-09-17-My-Impressions-at-DotNext-2024-Conference/my-talk.png b/docs/en/Blog-Posts/2024-09-17-My-Impressions-at-DotNext-2024-Conference/my-talk.png index 1206f5144c..caa9194c3f 100644 Binary files a/docs/en/Blog-Posts/2024-09-17-My-Impressions-at-DotNext-2024-Conference/my-talk.png and b/docs/en/Blog-Posts/2024-09-17-My-Impressions-at-DotNext-2024-Conference/my-talk.png differ diff --git a/docs/en/cli/index.md b/docs/en/cli/index.md index ba3e6aabf8..3fd8eee2f4 100644 --- a/docs/en/cli/index.md +++ b/docs/en/cli/index.md @@ -152,7 +152,7 @@ For more samples, go to [ABP CLI Create Solution Samples](new-command-samples.md * `--tiered`: The Auth Server project comes as a separate project and runs at a different endpoint. It separates the Auth Server from the API Host application. If not specified, you will have a single endpoint in the server side. (*Available for* ***Team*** *or higher licenses*) * `--mobile` or `-m`: Specifies the mobile application framework. Default value is `none`. Available frameworks: * `none`: Without any mobile application. - * `react-native`: React Native. + * `react-native`: React Native. This mobile option is only available for active **license owners**. * `maui`: MAUI. This mobile option is only available for ABP. (*Available for* ***Team*** *or higher licenses*) * `--database-provider` or `-d`: Specifies the database provider. Default provider is `ef`. Available providers: * `ef`: Entity Framework Core. diff --git a/docs/en/cli/new-command-samples.md b/docs/en/cli/new-command-samples.md index 06099a3e29..6b168b538c 100644 --- a/docs/en/cli/new-command-samples.md +++ b/docs/en/cli/new-command-samples.md @@ -1,6 +1,6 @@ # ABP CLI - New Solution Sample Commands -The `abp new` command creates an ABP solution or other artifacts based on an ABP template. [ABP CLI](../cli/index.md) has several parameters to create a new ABP solution. In this document we will show you some sample commands to create a new solution. All the project names are `Acme.BookStore`. Currently, the available mobile projects are `React Native` and `MAUI` mobile app. Available database providers are `Entity Framework Core` and `MongoDB`. All the commands starts with `abp new`. +The `abp new` command creates an ABP solution or other artifacts based on an ABP template. [ABP CLI](../cli/index.md) has several parameters to create a new ABP solution. In this document we will show you some sample commands to create a new solution. All the project names are `Acme.BookStore`. Currently, the available mobile projects are `React Native` and `MAUI` mobile app (they are *available for* ***Team*** *or higher licenses*). Available database providers are `Entity Framework Core` and `MongoDB`. All the commands starts with `abp new`. ## Angular diff --git a/docs/en/framework/ui/angular/images/fullscreen-true.png b/docs/en/framework/ui/angular/images/fullscreen-true.png index 841946176a..d14bc774d6 100644 Binary files a/docs/en/framework/ui/angular/images/fullscreen-true.png and b/docs/en/framework/ui/angular/images/fullscreen-true.png differ diff --git a/docs/en/framework/ui/react-native/index.md b/docs/en/framework/ui/react-native/index.md index f79d5bb3d1..3dd60b6348 100644 --- a/docs/en/framework/ui/react-native/index.md +++ b/docs/en/framework/ui/react-native/index.md @@ -7,6 +7,8 @@ # Getting Started with the React Native +> React Native mobile option is *available for* ***Team*** *or higher licenses* + ABP platform provide basic [React Native](https://reactnative.dev/) startup template to develop mobile applications **integrated to your ABP based backends**. ![React Native gif](../../../images/react-native-introduction.gif) diff --git a/docs/en/solution-templates/layered-web-application/index.md b/docs/en/solution-templates/layered-web-application/index.md index fa0b565888..d6d78864e8 100644 --- a/docs/en/solution-templates/layered-web-application/index.md +++ b/docs/en/solution-templates/layered-web-application/index.md @@ -60,7 +60,7 @@ abp new Acme.BookStore -d mongodb This template supports the following mobile application frameworks: -- `react-native`: React Native +- `react-native`: React Native (*Available for* ***Team*** *or higher licenses*) Use the `-m` (or `--mobile`) option to specify the mobile application framework: diff --git a/docs/en/tutorials/mobile/react-native/index.md b/docs/en/tutorials/mobile/react-native/index.md index 3178574627..359cdc510d 100644 --- a/docs/en/tutorials/mobile/react-native/index.md +++ b/docs/en/tutorials/mobile/react-native/index.md @@ -1,5 +1,7 @@ # Mobile Application Development Tutorial - React Native +React Native mobile option is *available for* ***Team*** *or higher licenses*. Therefore, if you don't have a commercial license, it's suggested to follow the article by downloading the source code of the sample application as described in the next chapter. + ## About This Tutorial - This tutorial assumes that you have completed the [Web Application Development tutorial](../../book-store/part-01.md) and built an ABP based application named `Acme.BookStore` with [React Native](../../../framework/ui/react-native) as the mobile option.. Therefore, if you haven't completed the [Web Application Development tutorial](../../book-store/part-01.md), you either need to complete it or download the source code from down below and follow this tutorial. diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/NewCommand.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/NewCommand.cs index 5d228cc176..c014f52d0e 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/NewCommand.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/NewCommand.cs @@ -220,6 +220,7 @@ public class NewCommand : ProjectCreationCommandBase, IConsoleCommand, ITransien sb.AppendLine(" abp new Acme.BookStore -u angular -d mongodb"); sb.AppendLine(" abp new Acme.BookStore -m none"); sb.AppendLine(" abp new Acme.BookStore -m react-native"); + sb.AppendLine(" abp new Acme.BookStore -m maui"); sb.AppendLine(" abp new Acme.BookStore -d mongodb"); sb.AppendLine(" abp new Acme.BookStore -d mongodb -o d:\\my-project"); sb.AppendLine(" abp new Acme.BookStore -t module"); diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/ProjectCreationCommandBase.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/ProjectCreationCommandBase.cs index d1e54868c4..6b607d4454 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/ProjectCreationCommandBase.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/ProjectCreationCommandBase.cs @@ -137,7 +137,7 @@ public abstract class ProjectCreationCommandBase Logger.LogInformation("Public Web Site: yes"); } - var mobileApp = GetMobilePreference(commandLineArgs); + var mobileApp = GetMobilePreference(commandLineArgs, template); if (mobileApp != MobileApp.None) { Logger.LogInformation("Mobile App: " + mobileApp); @@ -635,7 +635,7 @@ public abstract class ProjectCreationCommandBase } } - protected virtual MobileApp GetMobilePreference(CommandLineArgs commandLineArgs) + protected virtual MobileApp GetMobilePreference(CommandLineArgs commandLineArgs, string template) { var optionValue = commandLineArgs.Options.GetOrNull(Options.Mobile.Short, Options.Mobile.Long); @@ -644,9 +644,9 @@ public abstract class ProjectCreationCommandBase case null: case "none": return MobileApp.None; - case "react-native": + case "react-native" when template is AppProTemplate.TemplateName or MicroserviceProTemplate.TemplateName: return MobileApp.ReactNative; - case "maui": + case "maui" when template is AppProTemplate.TemplateName or MicroserviceProTemplate.TemplateName: return MobileApp.Maui; default: throw new CliUsageException(ExceptionMessageHelper.GetInvalidOptionExceptionMessage("Mobile App")); diff --git a/templates/app/react-native/.eslintrc.json b/templates/app/react-native/.eslintrc.json deleted file mode 100644 index 6702dcefd6..0000000000 --- a/templates/app/react-native/.eslintrc.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "extends": ["airbnb", "prettier", "prettier/react"], - "parser": "babel-eslint", - "env": { - "jest": true - }, - "rules": { - "no-use-before-define": 0, - "react/jsx-filename-extension": 0, - "react/prop-types": ["error", { "ignore": ["navigation", "children"] }], - "react/require-default-props": 0, - "react/jsx-props-no-spreading": 0, - "react/forbid-prop-types": 0, - "import/prefer-default-export": 0, - "comma-dangle": 0, - "no-underscore-dangle": 1, - "no-plusplus": ["error", { "allowForLoopAfterthoughts": true }], - "no-param-reassign": 0, - "operator-linebreak": 0, - "global-require": 0 - }, - "globals": { - "fetch": false - } -} diff --git a/templates/app/react-native/.expo-shared/assets.json b/templates/app/react-native/.expo-shared/assets.json deleted file mode 100644 index 1e6decfbb5..0000000000 --- a/templates/app/react-native/.expo-shared/assets.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "12bb71342c6255bbf50437ec8f4441c083f47cdb74bd89160c15e4f43e52a1cb": true, - "40b842e832070c58deac6aa9e08fa459302ee3f9da492c7e77d93d2fbf4a56fd": true -} diff --git a/templates/app/react-native/.gitignore b/templates/app/react-native/.gitignore deleted file mode 100644 index ec8a36a257..0000000000 --- a/templates/app/react-native/.gitignore +++ /dev/null @@ -1,14 +0,0 @@ -node_modules/ -.expo/ -dist/ -npm-debug.* -*.jks -*.p8 -*.p12 -*.key -*.mobileprovision -*.orig.* -web-build/ - -# macOS -.DS_Store diff --git a/templates/app/react-native/.prettierrc b/templates/app/react-native/.prettierrc deleted file mode 100644 index 471fac2824..0000000000 --- a/templates/app/react-native/.prettierrc +++ /dev/null @@ -1,9 +0,0 @@ -{ - "trailingComma": "all", - "singleQuote": true, - "jsxSingleQuote": false, - "printWidth": 80, - "semi": true, - "jsxBracketSameLine": true, - "arrowParens": "avoid" -} diff --git a/templates/app/react-native/.vscode/extensions.json b/templates/app/react-native/.vscode/extensions.json deleted file mode 100644 index d7df89c9cd..0000000000 --- a/templates/app/react-native/.vscode/extensions.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "recommendations": ["esbenp.prettier-vscode", "dbaeumer.vscode-eslint"] -} diff --git a/templates/app/react-native/App.js b/templates/app/react-native/App.js deleted file mode 100644 index 6505569f2b..0000000000 --- a/templates/app/react-native/App.js +++ /dev/null @@ -1,101 +0,0 @@ -import { NavigationContainer } from '@react-navigation/native'; -import { createNativeStackNavigator } from '@react-navigation/native-stack'; -import i18n from 'i18n-js'; -import { NativeBaseProvider } from 'native-base'; -import React, { useEffect, useMemo, useState } from 'react'; -import { enableScreens } from 'react-native-screens'; -import { Provider } from 'react-redux'; -import { PersistGate } from 'redux-persist/integration/react'; -import { getEnvVars } from './Environment'; -import Loading from './src/components/Loading/Loading'; -import { LocalizationContext } from './src/contexts/LocalizationContext'; -import { initAPIInterceptor } from './src/interceptors/APIInterceptor'; -import AuthNavigator from './src/navigators/AuthNavigator'; -import DrawerNavigator from './src/navigators/DrawerNavigator'; -import { persistor, store } from './src/store'; -import AppActions from './src/store/actions/AppActions'; -import PersistentStorageActions from './src/store/actions/PersistentStorageActions'; -import { createLanguageSelector } from './src/store/selectors/AppSelectors'; -import { createTokenSelector } from './src/store/selectors/PersistentStorageSelectors'; -import { connectToRedux } from './src/utils/ReduxConnect'; -import { isTokenValid } from './src/utils/TokenUtils'; - -const Stack = createNativeStackNavigator(); - -const { localization } = getEnvVars(); - -i18n.defaultSeparator = '::'; - -const cloneT = i18n.t; -i18n.t = (key, ...args) => { - if (key.slice(0, 2) === '::') { - key = localization.defaultResourceName + key; - } - return cloneT(key, ...args); -}; - -enableScreens(); -initAPIInterceptor(store); - -export default function App() { - const language = createLanguageSelector()(store.getState()); - const [isReady, setIsReady] = useState(false); - - const localizationContextValue = useMemo( - () => ({ - t: i18n.t, - locale: (language || {}).cultureName, - }), - [language] - ); - - useEffect(() => { - store.dispatch( - AppActions.fetchAppConfigAsync({ - callback: () => setIsReady(true), - showLoading: true, - }) - ); - }, []); - - return ( - - - - - {isReady ? ( - - - - ) : null} - - - - - - ); -} - -function AppContainer({token, setToken}) { - const isValid = useMemo(() => isTokenValid(token), [token]); - - useEffect(() => { - if (!isValid && token && token.access_token) { - setToken({}) - } - }, [isValid]); - - - return isValid ? : -} - - -const ConnectedAppContainer = connectToRedux({ - component: AppContainer, - stateProps: (state) => ({ - token: createTokenSelector()(state), - }), - dispatchProps: { - setToken: PersistentStorageActions.setToken, - }, -}); diff --git a/templates/app/react-native/Environment.js b/templates/app/react-native/Environment.js deleted file mode 100644 index a4a23995f7..0000000000 --- a/templates/app/react-native/Environment.js +++ /dev/null @@ -1,32 +0,0 @@ -const yourIP = 'localhost'; // See the docs https://docs.abp.io/en/abp/latest/Getting-Started-React-Native?Tiered=No -const port = 44305; -const apiUrl = `http://${yourIP}:${port}`; -const ENV = { - dev: { - apiUrl: apiUrl, - oAuthConfig: { - issuer: apiUrl, - clientId: 'MyProjectName_App', - scope: 'offline_access MyProjectName', - }, - localization: { - defaultResourceName: 'MyProjectName', - }, - }, - prod: { - apiUrl: 'http://localhost:44305', - oAuthConfig: { - issuer: 'http://localhost:44305', - clientId: 'MyProjectName_App', - scope: 'offline_access MyProjectName', - }, - localization: { - defaultResourceName: 'MyProjectName', - }, - }, -}; - -export const getEnvVars = () => { - // eslint-disable-next-line no-undef - return __DEV__ ? ENV.dev : ENV.prod; -}; diff --git a/templates/app/react-native/app.json b/templates/app/react-native/app.json deleted file mode 100644 index 5b78afa519..0000000000 --- a/templates/app/react-native/app.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "expo": { - "name": "MyProjectName", - "slug": "MyProjectName", - "version": "1.0.0", - "orientation": "portrait", - "icon": "./assets/icon.png", - "splash": { - "image": "./assets/splash.png", - "resizeMode": "cover", - "backgroundColor": "#38003c" - }, - "updates": { - "fallbackToCacheTimeout": 0 - }, - "assetBundlePatterns": ["**/*"], - "ios": { - "supportsTablet": true, - "bundleIdentifier": "com.MyCompanyName.MyProjectName", - "buildNumber": "1.0.0" - }, - "android": { - "package": "com.MyCompanyName.MyProjectName", - "versionCode": 1, - "adaptiveIcon": { - "foregroundImage": "./assets/adaptive-icon.png", - "backgroundColor": "#FFFFFF" - } - }, - "web": { - "favicon": "./assets/icon.png" - } - } -} diff --git a/templates/app/react-native/assets/adaptive-icon.png b/templates/app/react-native/assets/adaptive-icon.png deleted file mode 100644 index 03d6f6b6c6..0000000000 Binary files a/templates/app/react-native/assets/adaptive-icon.png and /dev/null differ diff --git a/templates/app/react-native/assets/avatar.png b/templates/app/react-native/assets/avatar.png deleted file mode 100644 index 8a1daa0121..0000000000 Binary files a/templates/app/react-native/assets/avatar.png and /dev/null differ diff --git a/templates/app/react-native/assets/icon.png b/templates/app/react-native/assets/icon.png deleted file mode 100644 index 528c8711d7..0000000000 Binary files a/templates/app/react-native/assets/icon.png and /dev/null differ diff --git a/templates/app/react-native/assets/logo.png b/templates/app/react-native/assets/logo.png deleted file mode 100644 index b9b1e36c50..0000000000 Binary files a/templates/app/react-native/assets/logo.png and /dev/null differ diff --git a/templates/app/react-native/assets/splash.png b/templates/app/react-native/assets/splash.png deleted file mode 100644 index 0d5f0ec026..0000000000 Binary files a/templates/app/react-native/assets/splash.png and /dev/null differ diff --git a/templates/app/react-native/babel.config.js b/templates/app/react-native/babel.config.js deleted file mode 100644 index d715221e05..0000000000 --- a/templates/app/react-native/babel.config.js +++ /dev/null @@ -1,7 +0,0 @@ -module.exports = function(api) { - api.cache(true); - return { - presets: ['babel-preset-expo'], - plugins: ['react-native-reanimated/plugin'], - }; -}; \ No newline at end of file diff --git a/templates/app/react-native/package.json b/templates/app/react-native/package.json deleted file mode 100644 index 9fbe23ea4b..0000000000 --- a/templates/app/react-native/package.json +++ /dev/null @@ -1,44 +0,0 @@ -{ - "name": "myprojectname", - "version": "1.0.0", - "main": "node_modules/expo/AppEntry.js", - "scripts": { - "start": "expo start --port 19000", - "android": "expo start --android", - "ios": "expo start --ios", - "web": "expo start --web", - "eject": "expo eject" - }, - "dependencies": { - "@react-native-async-storage/async-storage": "1.18.2", - "@react-navigation/drawer": "^6.5.4", - "@react-navigation/native": "^6.1.0", - "@react-navigation/native-stack": "^6.9.5", - "@reduxjs/toolkit": "^1.7.1", - "axios": "~1.2.1", - "expo": "^49.0.0", - "expo-status-bar": "~1.6.0", - "formik": "^2.2.9", - "i18n-js": "^3.8.0", - "native-base": "^3.4.25", - "prop-types": "^15.8.1", - "react": "18.2.0", - "react-dom": "18.2.0", - "react-native": "0.72.10", - "react-native-chart-kit": "^6.11.0", - "react-native-gesture-handler": "~2.12.0", - "react-native-reanimated": "~3.3.0", - "react-native-safe-area-context": "4.6.3", - "react-native-screens": "~3.22.0", - "react-native-svg": "13.9.0", - "react-native-web": "~0.19.6", - "react-redux": "^8.0.5", - "redux-persist": "^6.0.0", - "redux-saga": "^1.2.1", - "yup": "^0.32.11" - }, - "devDependencies": { - "@babel/core": "^7.19.3" - }, - "private": true -} diff --git a/templates/app/react-native/src/api/API.js b/templates/app/react-native/src/api/API.js deleted file mode 100644 index dc604f62e9..0000000000 --- a/templates/app/react-native/src/api/API.js +++ /dev/null @@ -1,11 +0,0 @@ -import axios from 'axios'; -import { getEnvVars } from '../../Environment'; - -const { apiUrl } = getEnvVars(); - -const axiosInstance = axios.create({ - baseURL: apiUrl, - withCredentials: false -}); - -export default axiosInstance; diff --git a/templates/app/react-native/src/api/AccountAPI.js b/templates/app/react-native/src/api/AccountAPI.js deleted file mode 100644 index ddf49579d3..0000000000 --- a/templates/app/react-native/src/api/AccountAPI.js +++ /dev/null @@ -1,62 +0,0 @@ -import api from './API'; -import { getEnvVars } from '../../Environment'; - -const { oAuthConfig } = getEnvVars(); - -getLoginData = (username, password) => { - const formData = { - grant_type: 'password', - scope: oAuthConfig.scope, - username: username, - password: password, - client_id: oAuthConfig.clientId, - }; - - if (oAuthConfig.clientSecret) - formData['client_secret'] = oAuthConfig.clientSecret; - - return Object.entries(formData) - .map(([key, value]) => `${key}=${encodeURIComponent(value)}`) - .join('&'); -}; - -export const login = ({ username, password }) => - api({ - method: 'POST', - url: '/connect/token', - headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, - data: getLoginData(username, password), - baseURL: oAuthConfig.issuer, - }).then(({ data }) => data); - -export const Logout = ( - input = { client_id: '', token: '', token_type_hint: '' }, -) => { - if (!input.token_type_hint) { - input.token_type_hint = 'access_token'; - } - - const _data = Object.entries(input) - .map(([key, value]) => `${key}=${encodeURIComponent(value)}`) - .join('&'); - - return api({ - method: 'POST', - url: '/connect/revocat', - headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, - data: _data, - baseURL: oAuthConfig.issuer, - }).then(({ data }) => data); -}; - -export const getTenant = tenantName => - api({ - method: 'GET', - url: `/api/abp/multi-tenancy/tenants/by-name/${tenantName}`, - }).then(({ data }) => data); - -export const getTenantById = tenantId => - api({ - method: 'GET', - url: `/api/abp/multi-tenancy/tenants/by-id/${tenantId}`, - }).then(({ data }) => data); diff --git a/templates/app/react-native/src/api/ApplicationConfigurationAPI.js b/templates/app/react-native/src/api/ApplicationConfigurationAPI.js deleted file mode 100644 index 96fcbea5cd..0000000000 --- a/templates/app/react-native/src/api/ApplicationConfigurationAPI.js +++ /dev/null @@ -1,30 +0,0 @@ -import i18n from 'i18n-js'; -import api from './API'; - -export const getApplicationConfiguration = () => - api - .get('/api/abp/application-configuration') - .then(({ data }) => data) - .then(async config => { - const { cultureName } = config.localization.currentCulture; - i18n.locale = cultureName; - - Object.keys(config.localization.values).forEach(key => { - const resource = config.localization.values[key]; - - if (typeof resource !== 'object') return; - - Object.keys(resource).forEach(key2 => { - if (/'{|{/g.test(resource[key2])) { - resource[key2] = resource[key2].replace(/'{|{/g, '{{').replace(/}'|}/g, '}}'); - } - }); - }); - - i18n.translations[cultureName] = { - ...config.localization.values, - ...(i18n.translations[cultureName] || {}), - }; - - return config; - }); diff --git a/templates/app/react-native/src/api/IdentityAPI.js b/templates/app/react-native/src/api/IdentityAPI.js deleted file mode 100644 index 9ae81ad2b5..0000000000 --- a/templates/app/react-native/src/api/IdentityAPI.js +++ /dev/null @@ -1,27 +0,0 @@ -import api from './API'; - - -export const getAllRoles = () => api.get('/api/identity/roles/all').then(({ data }) => data.items); - -export const getUserRoles = id => - api.get(`/api/identity/users/${id}/roles`).then(({ data }) => data.items); - -export const getUsers = (params = { maxResultCount: 10, skipCount: 0 }) => - api.get('/api/identity/users', { params }).then(({ data }) => data); - -export const getUserById = id => api.get(`/api/identity/users/${id}`).then(({ data }) => data); - -export const createUser = body => api.post('/api/identity/users', body).then(({ data }) => data); - -export const updateUser = (body, id) => - api.put(`/api/identity/users/${id}`, body).then(({ data }) => data); - -export const removeUser = id => api.delete(`/api/identity/users/${id}`); - -export const getProfileDetail = () => api.get('/api/account/my-profile').then(({ data }) => data); - -export const updateProfileDetail = body => - api.put('/api/account/my-profile', body).then(({ data }) => data); - -export const changePassword = body => - api.post('/api/account/my-profile/change-password', body).then(({ data }) => data); diff --git a/templates/app/react-native/src/api/TenantManagementAPI.js b/templates/app/react-native/src/api/TenantManagementAPI.js deleted file mode 100644 index f60ed96450..0000000000 --- a/templates/app/react-native/src/api/TenantManagementAPI.js +++ /dev/null @@ -1,21 +0,0 @@ -import api from './API'; - -export function getTenants(params = {}) { - return api.get('/api/multi-tenancy/tenants', { params }).then(({ data }) => data); -} - -export function createTenant(body) { - return api.post('/api/multi-tenancy/tenants', body).then(({ data }) => data); -} - -export function getTenantById(id) { - return api.get(`/api/multi-tenancy/tenants/${id}`).then(({ data }) => data); -} - -export function updateTenant(body, id) { - return api.put(`/api/multi-tenancy/tenants/${id}`, body).then(({ data }) => data); -} - -export function removeTenant(id) { - return api.delete(`/api/multi-tenancy/tenants/${id}`).then(({ data }) => data); -} diff --git a/templates/app/react-native/src/components/AddIcon/AddIcon.js b/templates/app/react-native/src/components/AddIcon/AddIcon.js deleted file mode 100644 index b4cc26f36f..0000000000 --- a/templates/app/react-native/src/components/AddIcon/AddIcon.js +++ /dev/null @@ -1,16 +0,0 @@ -import { Ionicons } from '@expo/vector-icons'; -import { Icon } from 'native-base'; -import React from 'react'; - -export default function AddIcon({ onPress, ...iconProps }) { - return ( - - ); -} diff --git a/templates/app/react-native/src/components/DataList/DataList.js b/templates/app/react-native/src/components/DataList/DataList.js deleted file mode 100644 index 9dce6d9562..0000000000 --- a/templates/app/react-native/src/components/DataList/DataList.js +++ /dev/null @@ -1,143 +0,0 @@ -import { Ionicons } from '@expo/vector-icons'; -import { useFocusEffect } from '@react-navigation/native'; -import i18n from 'i18n-js'; -import { Box, Center, FlatList, Icon, Input, Spinner, Text } from 'native-base'; -import PropTypes from 'prop-types'; -import React, { forwardRef, useCallback, useEffect, useState } from 'react'; -import { StyleSheet, View } from 'react-native'; -import LoadingActions from '../../store/actions/LoadingActions'; -import { debounce } from '../../utils/Debounce'; -import { connectToRedux } from '../../utils/ReduxConnect'; -import LoadingButton from '../LoadingButton/LoadingButton'; - -function DataList({ - navigation, - fetchFn, - render, - maxResultCount = 15, - debounceTime = 350, - ...props -}) { - const [records, setRecords] = useState([]); - const [totalCount, setTotalCount] = useState(0); - const [loading, setLoading] = useState(false); - const [searchLoading, setSearchLoading] = useState(false); - const [buttonLoading, setButtonLoading] = useState(false); - const [skipCount, setSkipCount] = useState(0); - const [filter, setFilter] = useState(''); - - const fetch = (skip = 0, isRefreshingActive = true) => { - if (isRefreshingActive) setLoading(true); - return fetchFn({ filter, maxResultCount, skipCount: skip }) - .then(({ items, totalCount: total }) => { - setTotalCount(total); - setRecords(skip ? [...records, ...items] : items); - setSkipCount(skip); - }) - .finally(() => { - if (isRefreshingActive) setLoading(false); - }); - }; - - const fetchPartial = () => { - if (loading || records.length === totalCount) return; - - setButtonLoading(true); - fetch(skipCount + maxResultCount, false).finally(() => - setButtonLoading(false) - ); - }; - - useFocusEffect( - useCallback(() => { - setSkipCount(0); - fetch(0, false); - }, []) - ); - - useEffect(() => { - function searchFetch() { - setSearchLoading(true); - return fetch(0, false).finally(() => - setTimeout(() => setSearchLoading(false), 150) - ); - } - debounce(searchFetch, debounceTime)(); - }, [filter]); - - return ( -
- - - ) : ( - - ) - } - /> - ( - <> - {render(...args)} - {args.index + 1 === skipCount + maxResultCount && - totalCount > records.length ? ( - - fetchPartial()} - > - {i18n.t('AbpUi::LoadMore')} - - - ) : null} - - )} - {...props} - /> - -
- ); -} - -DataList.propTypes = { - ...FlatList.propTypes, - fetchFn: PropTypes.func.isRequired, - render: PropTypes.func.isRequired, - maxResultCount: PropTypes.number, - debounceTime: PropTypes.number, -}; - -const styles = StyleSheet.create({ - container: { flex: 1 }, - list: {}, -}); - -const Forwarded = forwardRef((props, ref) => ( - -)); - -export default connectToRedux({ - component: Forwarded, - dispatchProps: { - startLoading: LoadingActions.start, - stopLoading: LoadingActions.stop, - }, -}); diff --git a/templates/app/react-native/src/components/DrawerContent/DrawerContent.js b/templates/app/react-native/src/components/DrawerContent/DrawerContent.js deleted file mode 100644 index 4f7792fab5..0000000000 --- a/templates/app/react-native/src/components/DrawerContent/DrawerContent.js +++ /dev/null @@ -1,104 +0,0 @@ -import { Ionicons } from '@expo/vector-icons'; -import Constants from 'expo-constants'; -import i18n from 'i18n-js'; -import { List, Text, View } from 'native-base'; -import PropTypes from 'prop-types'; -import React from 'react'; -import { Image, StyleSheet } from 'react-native'; -import { SafeAreaView } from 'react-native-safe-area-context'; -import { withPermission } from '../../hocs/PermissionHOC'; - -const screens = { - HomeStack: { label: '::Menu:Home', iconName: 'home' }, - UsersStack: { - label: 'AbpIdentity::Users', - iconName: 'people', - requiredPolicy: 'AbpIdentity.Users', - }, - TenantsStack: { - label: 'AbpTenantManagement::Tenants', - iconName: 'book-outline', - requiredPolicy: 'AbpTenantManagement.Tenants', - }, - SettingsStack: { label: 'AbpSettingManagement::Settings', iconName: 'cog' }, -}; - -const ListItemWithPermission = withPermission(List.Item); - -function DrawerContent({ - navigation, - state: { routeNames, index: currentScreenIndex }, -}) { - const navigate = (screen) => { - navigation.navigate(screen); - navigation.closeDrawer(); - }; - - return ( - - - - - - - {routeNames.map((name) => ( - navigate(name)} - my="0" - > - - {i18n.t(screens[name].label)} - - ))} - - - - - © MyProjectName - - - v{Constants.expoConfig.version} - - - - ); -} - -const styles = StyleSheet.create({ - container: { - flexGrow: 1, - }, - logo: { - marginTop: 20, - marginBottom: 15, - }, - headerView: { - alignItems: 'center', - }, - footer: { - backgroundColor: '#eee', - flexDirection: 'row', - justifyContent: 'space-between', - }, - copyRight: { - margin: 15, - }, - version: { - margin: 15, - }, -}); - -DrawerContent.propTypes = { - state: PropTypes.object.isRequired, -}; - -export default DrawerContent; diff --git a/templates/app/react-native/src/components/FormButtons/FormButtons.js b/templates/app/react-native/src/components/FormButtons/FormButtons.js deleted file mode 100644 index d844f7747a..0000000000 --- a/templates/app/react-native/src/components/FormButtons/FormButtons.js +++ /dev/null @@ -1,78 +0,0 @@ -import i18n from 'i18n-js'; -import { Button, Text } from 'native-base'; -import PropTypes from 'prop-types'; -import React, { forwardRef } from 'react'; -import { Alert, StyleSheet, View } from 'react-native'; - -function FormButtons({ - submit, - remove, - removeMessage, - isRemoveDisabled, - isSubmitDisabled, - isShowRemove = false, - isShowSubmit = true, -}) { - const confirmation = () => { - Alert.alert( - i18n.t('AbpUi::AreYouSure'), - removeMessage, - [ - { - text: i18n.t('AbpUi::Cancel'), - style: 'cancel', - }, - { text: i18n.t('AbpUi::Yes'), onPress: () => remove() }, - ], - { cancelable: true }, - ); - }; - - return ( - - {isShowRemove ? ( - - ) : null} - {isShowSubmit ? ( - - ) : null} - - ); -} - -FormButtons.propTypes = { - submit: PropTypes.func.isRequired, - remove: PropTypes.func, - removeMessage: PropTypes.string, - style: PropTypes.any, - isRemoveDisabled: PropTypes.bool, - isSubmitDisabled: PropTypes.bool, - isShowRemove: PropTypes.bool, - isShowSubmit: PropTypes.bool, -}; - -const styles = StyleSheet.create({ - container: { - width: '100%', - justifyContent: 'center', - alignItems: 'center', - position: 'absolute', - bottom: 0, - flexDirection: 'row', - }, -}); - -const Forwarded = forwardRef((props, ref) => ); - -export default Forwarded; diff --git a/templates/app/react-native/src/components/FormButtons/index.js b/templates/app/react-native/src/components/FormButtons/index.js deleted file mode 100644 index bf8864e7e0..0000000000 --- a/templates/app/react-native/src/components/FormButtons/index.js +++ /dev/null @@ -1 +0,0 @@ -export { default as FormButtons } from './FormButtons'; diff --git a/templates/app/react-native/src/components/HamburgerIcon/HamburgerIcon.js b/templates/app/react-native/src/components/HamburgerIcon/HamburgerIcon.js deleted file mode 100644 index 2d165f8249..0000000000 --- a/templates/app/react-native/src/components/HamburgerIcon/HamburgerIcon.js +++ /dev/null @@ -1,17 +0,0 @@ -import { Ionicons } from '@expo/vector-icons'; -import { Icon } from 'native-base'; -import React from 'react'; -import { Platform } from 'react-native'; - -export default function HamburgerIcon({ navigation, ...iconProps }) { - return ( - navigation.openDrawer()} - as={Ionicons} - name={Platform.OS ? 'ios-menu' : 'md-menu'} - size="8" - marginLeft={2} - {...iconProps} - /> - ); -} diff --git a/templates/app/react-native/src/components/Loading/Loading.js b/templates/app/react-native/src/components/Loading/Loading.js deleted file mode 100644 index bd8f5ff180..0000000000 --- a/templates/app/react-native/src/components/Loading/Loading.js +++ /dev/null @@ -1,62 +0,0 @@ -import { Spinner, View } from 'native-base'; -import PropTypes from 'prop-types'; -import React, { forwardRef } from 'react'; -import { StyleSheet } from 'react-native'; -import { - createLoadingSelector, - createOpacitySelector -} from '../../store/selectors/LoadingSelectors'; -import { connectToRedux } from '../../utils/ReduxConnect'; - -function Loading({ loading, opacity }) { - return loading ? ( - - - - - ) : null; -} -const Forwarded = forwardRef((props, ref) => ); - -const backdropStyle = { - position: 'absolute', - top: 0, - left: 0, - width: '100%', - height: '100%', - backgroundColor: '#fff', -}; - -export const styles = StyleSheet.create({ - container: { - ...backdropStyle, - backgroundColor: 'transparent', - // zIndex: activeTheme.zIndex.indicator, // TODO - alignItems: 'center', - justifyContent: 'center', - }, - backdrop: backdropStyle, - spinner: { - // color: activeTheme.brandPrimary, // TODO - fontSize: 100, - }, -}); - -Loading.propTypes = { - style: PropTypes.objectOf(PropTypes.any), - loading: PropTypes.bool, - opacity: PropTypes.number, -}; - -export default connectToRedux({ - component: Forwarded, - stateProps: state => ({ - loading: createLoadingSelector()(state), - opacity: createOpacitySelector()(state), - }), -}); diff --git a/templates/app/react-native/src/components/LoadingButton/LoadingButton.js b/templates/app/react-native/src/components/LoadingButton/LoadingButton.js deleted file mode 100644 index d36c7fc68c..0000000000 --- a/templates/app/react-native/src/components/LoadingButton/LoadingButton.js +++ /dev/null @@ -1,22 +0,0 @@ -import { Button, Spinner } from 'native-base'; -import PropTypes from 'prop-types'; -import React from 'react'; -import { StyleSheet } from 'react-native'; - -export default function LoadingButton({ loading = false, style, children, ...props }) { - return ( - - ); -} - -LoadingButton.propTypes = { - ...Button.propTypes, - loading: PropTypes.bool.isRequired, -}; - -const styles = StyleSheet.create({ - button: { marginTop: 20, marginBottom: 30, height: 30 }, -}); \ No newline at end of file diff --git a/templates/app/react-native/src/components/TenantBox/TenantBox.js b/templates/app/react-native/src/components/TenantBox/TenantBox.js deleted file mode 100644 index 939efb3c88..0000000000 --- a/templates/app/react-native/src/components/TenantBox/TenantBox.js +++ /dev/null @@ -1,143 +0,0 @@ -import i18n from 'i18n-js'; -import { Box, Button, FormControl, Input, Text } from 'native-base'; -import PropTypes from 'prop-types'; -import React, { forwardRef, useState } from 'react'; -import { Alert, StyleSheet, View } from 'react-native'; -import { getTenant } from '../../api/AccountAPI'; -import PersistentStorageActions from '../../store/actions/PersistentStorageActions'; -import { createTenantSelector } from '../../store/selectors/PersistentStorageSelectors'; -import { connectToRedux } from '../../utils/ReduxConnect'; - -function TenantBox({ - tenant = {}, - setTenant, - showTenantSelection, - toggleTenantSelection, -}) { - const [tenantName, setTenantName] = useState(tenant.name); - - const findTenant = () => { - if (!tenantName) { - setTenant({}); - toggleTenantSelection(); - return; - } - - getTenant(tenantName).then(({ success, ...data }) => { - if (!success) { - Alert.alert( - i18n.t('AbpUi::Error'), - i18n.t('AbpUiMultiTenancy::GivenTenantIsNotAvailable', { - 0: tenantName, - }), - [{ text: i18n.t('AbpUi::Ok') }] - ); - return; - } - setTenant(data); - toggleTenantSelection(); - }); - }; - - return ( - <> - - - - {i18n.t('AbpUiMultiTenancy::Tenant')} - - - {tenant.name - ? tenant.name - : i18n.t('AbpUiMultiTenancy::NotSelected')} - - - - - {showTenantSelection ? ( - - - - {i18n.t('AbpUiMultiTenancy::Name')} - - - - - {i18n.t('AbpUiMultiTenancy::SwitchTenantHint')} - - - - - - - ) : null} - - ); -} - -TenantBox.propTypes = { - setTenant: PropTypes.func.isRequired, - showTenantSelection: PropTypes.bool.isRequired, - toggleTenantSelection: PropTypes.func.isRequired, - tenant: PropTypes.object.isRequired, -}; - -const styles = StyleSheet.create({ - button: { marginTop: 20, width: '49%' }, - - tenant: { color: '#777' }, - title: { - marginRight: 10, - fontSize: 13, - fontWeight: '600', - textTransform: 'uppercase', - }, - hint: { color: '#bbb', textAlign: 'left' }, -}); - -const Forwarded = forwardRef((props, ref) => ( - -)); - -export default connectToRedux({ - component: Forwarded, - dispatchProps: { - setTenant: PersistentStorageActions.setTenant, - }, - stateProps: (state) => ({ - tenant: createTenantSelector()(state), - }), -}); \ No newline at end of file diff --git a/templates/app/react-native/src/components/ValidationMessage/ValidationMessage.js b/templates/app/react-native/src/components/ValidationMessage/ValidationMessage.js deleted file mode 100644 index c2a398f379..0000000000 --- a/templates/app/react-native/src/components/ValidationMessage/ValidationMessage.js +++ /dev/null @@ -1,16 +0,0 @@ -import i18n from 'i18n-js'; -import React, { forwardRef } from 'react'; -import { Text } from 'react-native'; - -const ValidationMessage = ({ children, ...props }) => - children ? {i18n.t(children)} : null; - -const styles = { - fontSize: 12, - marginTop: 3, - color: '#ed2f2f', -}; - -const Forwarded = forwardRef((props, ref) => ); - -export default Forwarded diff --git a/templates/app/react-native/src/contexts/LocalizationContext.js b/templates/app/react-native/src/contexts/LocalizationContext.js deleted file mode 100644 index 83c68ba2bc..0000000000 --- a/templates/app/react-native/src/contexts/LocalizationContext.js +++ /dev/null @@ -1,3 +0,0 @@ -import React from 'react'; - -export const LocalizationContext = React.createContext(); diff --git a/templates/app/react-native/src/hocs/PermissionHOC.js b/templates/app/react-native/src/hocs/PermissionHOC.js deleted file mode 100644 index 6cf8025428..0000000000 --- a/templates/app/react-native/src/hocs/PermissionHOC.js +++ /dev/null @@ -1,17 +0,0 @@ -import React, { forwardRef } from 'react'; -import PropTypes from 'prop-types'; -import { usePermission } from '../hooks/UsePermission'; - -export function withPermission(Component, policyKey) { - const Forwarded = forwardRef((props, ref) => { - const isGranted = - policyKey || props.policyKey ? usePermission(policyKey || props.policyKey) : true; - return isGranted ? : null; - }); - - Forwarded.propTypes = { - policyKey: PropTypes.string, - }; - - return Forwarded; -} diff --git a/templates/app/react-native/src/hooks/UsePermission.js b/templates/app/react-native/src/hooks/UsePermission.js deleted file mode 100644 index a50d8f7fa1..0000000000 --- a/templates/app/react-native/src/hooks/UsePermission.js +++ /dev/null @@ -1,16 +0,0 @@ -import { useEffect, useState } from 'react'; -import { store } from '../store'; -import { createGrantedPolicySelector } from '../store/selectors/AppSelectors'; - -export function usePermission(key) { - const [permission, setPermission] = useState(false); - - const state = store.getState(); - const policy = createGrantedPolicySelector(key)(state); - - useEffect(() => { - setPermission(policy); - }, [policy]); - - return permission; -} diff --git a/templates/app/react-native/src/interceptors/APIInterceptor.js b/templates/app/react-native/src/interceptors/APIInterceptor.js deleted file mode 100644 index b5ffc56a3c..0000000000 --- a/templates/app/react-native/src/interceptors/APIInterceptor.js +++ /dev/null @@ -1,100 +0,0 @@ -import i18n from 'i18n-js'; -import { Toast } from 'native-base'; -import api from '../api/API'; -import LoadingActions from '../store/actions/LoadingActions'; -import PersistentStorageActions from '../store/actions/PersistentStorageActions'; - -export function initAPIInterceptor(store) { - api.interceptors.request.use( - async request => { - const { - persistentStorage: { token, language, tenant }, - } = store.getState(); - - if (!request.headers.Authorization && token && token.access_token) { - request.headers.Authorization = `${token.token_type} ${token.access_token}`; - } - - if (!request.headers['Content-Type']) { - request.headers['Content-Type'] = 'application/json'; - } - - if (!request.headers['Accept-Language'] && language) { - request.headers['Accept-Language'] = language; - } - - if (!request.headers.__tenant && tenant && tenant.tenantId) { - request.headers.__tenant = tenant.tenantId; - } - - return request; - }, - error => console.error(error), - ); - - api.interceptors.response.use( - response => response, - error => { - store.dispatch(LoadingActions.clear()); - const errorRes = error.response; - if (errorRes) { - if (errorRes.headers._abperrorformat && errorRes.status === 401) { - store.dispatch(PersistentStorageActions.setToken({})); - } - - showError({ error: errorRes.data.error || {}, status: errorRes.status }); - } else { - Toast.show({ - title: 'An unexpected error has occurred', - isClosable: true, - duration: 10000, - backgroundColor: 'danger.500', - }); - } - - return Promise.reject(error); - }, - ); -} - -function showError({ error = {}, status }) { - let message = ''; - let title = i18n.t('AbpAccount::DefaultErrorMessage'); - - if (typeof error === 'string') { - message = error; - } else if (error.details) { - message = error.details; - title = error.message; - } else if (error.message) { - message = error.message; - } else { - switch (status) { - case 401: - title = i18n.t('AbpAccount::DefaultErrorMessage401'); - message = i18n.t('AbpAccount::DefaultErrorMessage401Detail'); - break; - case 403: - title = i18n.t('AbpAccount::DefaultErrorMessage403'); - message = i18n.t('AbpAccount::DefaultErrorMessage403Detail'); - break; - case 404: - title = i18n.t('AbpAccount::DefaultErrorMessage404'); - message = i18n.t('AbpAccount::DefaultErrorMessage404Detail'); - break; - case 500: - title = i18n.t('AbpAccount::500Message'); - message = i18n.t('AbpAccount::InternalServerErrorMessage'); - break; - default: - break; - } - } - - Toast.show({ - title: `${title}\n${message}`, - isClosable: true, - duration: 10000, - backgroundColor: 'danger.500', - }); -} diff --git a/templates/app/react-native/src/navigators/AuthNavigator.js b/templates/app/react-native/src/navigators/AuthNavigator.js deleted file mode 100644 index 0311556deb..0000000000 --- a/templates/app/react-native/src/navigators/AuthNavigator.js +++ /dev/null @@ -1,22 +0,0 @@ -import { createNativeStackNavigator } from '@react-navigation/native-stack'; -import React, { useContext } from 'react'; -import { LocalizationContext } from '../contexts/LocalizationContext'; -import LoginScreen from '../screens/Login/LoginScreen'; - -const Stack = createNativeStackNavigator(); - -export default function AuthNavigator() { - const {t} = useContext(LocalizationContext); - - return ( - - ({ - title: t('AbpAccount::Login'), - })} - /> - - ); -} diff --git a/templates/app/react-native/src/navigators/DrawerNavigator.js b/templates/app/react-native/src/navigators/DrawerNavigator.js deleted file mode 100644 index 3cd83c8a13..0000000000 --- a/templates/app/react-native/src/navigators/DrawerNavigator.js +++ /dev/null @@ -1,43 +0,0 @@ -import { createDrawerNavigator } from '@react-navigation/drawer'; -import React from 'react'; -import DrawerContent from '../components/DrawerContent/DrawerContent'; -import HamburgerIcon from '../components/HamburgerIcon/HamburgerIcon'; -import { LocalizationContext } from '../contexts/LocalizationContext'; -import HomeStackNavigator from './HomeNavigator'; -import SettingsStackNavigator from './SettingsNavigator'; -import TenantsStackNavigator from './TenantsNavigator'; -import UsersStackNavigator from './UsersNavigator'; - -const Drawer = createDrawerNavigator(); - -export default function DrawerNavigator() { - const { t } = React.useContext(LocalizationContext); - - return ( - - ({ - title: t('::Menu:Home'), - headerLeft: () => , - })} - /> - null }} - /> - null }} - /> - null }} - /> - - ); -} diff --git a/templates/app/react-native/src/navigators/HomeNavigator.js b/templates/app/react-native/src/navigators/HomeNavigator.js deleted file mode 100644 index 8f9e588edd..0000000000 --- a/templates/app/react-native/src/navigators/HomeNavigator.js +++ /dev/null @@ -1,17 +0,0 @@ -import { createNativeStackNavigator } from '@react-navigation/native-stack'; -import React from 'react'; -import HomeScreen from '../screens/Home/HomeScreen'; - -const Stack = createNativeStackNavigator(); - -export default function HomeStackNavigator() { - return ( - - null}} - /> - - ); -} diff --git a/templates/app/react-native/src/navigators/SettingsNavigator.js b/templates/app/react-native/src/navigators/SettingsNavigator.js deleted file mode 100644 index 370da97b93..0000000000 --- a/templates/app/react-native/src/navigators/SettingsNavigator.js +++ /dev/null @@ -1,41 +0,0 @@ -import { createNativeStackNavigator } from '@react-navigation/native-stack'; -import i18n from 'i18n-js'; -import React from 'react'; -import HamburgerIcon from '../components/HamburgerIcon/HamburgerIcon'; -import { LocalizationContext } from '../contexts/LocalizationContext'; -import ChangePasswordScreen from '../screens/ChangePassword/ChangePasswordScreen'; -import ManageProfileScreen from '../screens/ManageProfile/ManageProfileScreen'; -import SettingsScreen from '../screens/Settings/SettingsScreen'; - -const Stack = createNativeStackNavigator(); - -export default function SettingsStackNavigator() { - const { t } = React.useContext(LocalizationContext); - - return ( - - ({ - headerLeft: () => , - title: t('AbpSettingManagement::Settings'), - })} - /> - - - - ); -} diff --git a/templates/app/react-native/src/navigators/TenantsNavigator.js b/templates/app/react-native/src/navigators/TenantsNavigator.js deleted file mode 100644 index 94ae711d42..0000000000 --- a/templates/app/react-native/src/navigators/TenantsNavigator.js +++ /dev/null @@ -1,35 +0,0 @@ - -import { createNativeStackNavigator } from '@react-navigation/native-stack'; -import React from 'react'; -import AddIcon from '../components/AddIcon/AddIcon'; -import HamburgerIcon from '../components/HamburgerIcon/HamburgerIcon'; -import { LocalizationContext } from '../contexts/LocalizationContext'; -import CreateUpdateTenantScreen from '../screens/CreateUpdateTenant/CreateUpdateTenantScreen'; -import TenantsScreen from '../screens/Tenants/TenantsScreen'; - -const Stack = createNativeStackNavigator(); - -export default function TenantsStackNavigator() { - const { t } = React.useContext(LocalizationContext); - - return ( - - ({ - title: t('AbpTenantManagement::Tenants'), - headerLeft: () => , - headerRight: () => navigation.navigate('CreateUpdateTenant')}/>, - })} - /> - ({ - title: t(route.params?.tenantId ? 'AbpTenantManagement::Edit' : 'AbpTenantManagement::NewTenant'), - })} - /> - - ); -} diff --git a/templates/app/react-native/src/navigators/UsersNavigator.js b/templates/app/react-native/src/navigators/UsersNavigator.js deleted file mode 100644 index 537129be14..0000000000 --- a/templates/app/react-native/src/navigators/UsersNavigator.js +++ /dev/null @@ -1,34 +0,0 @@ -import { createNativeStackNavigator } from '@react-navigation/native-stack'; -import React from 'react'; -import AddIcon from '../components/AddIcon/AddIcon'; -import HamburgerIcon from '../components/HamburgerIcon/HamburgerIcon'; -import { LocalizationContext } from '../contexts/LocalizationContext'; -import CreateUpdateUserScreen from '../screens/CreateUpdateUser/CreateUpdateUserScreen'; -import UsersScreen from '../screens/Users/UsersScreen'; - -const Stack = createNativeStackNavigator(); - -export default function UsersStackNavigator() { - const { t } = React.useContext(LocalizationContext); - - return ( - - ({ - title: t('AbpIdentity::Users'), - headerLeft: () => , - headerRight: () => navigation.navigate('CreateUpdateUser')}/>, - })} - /> - ({ - title: t(route.params?.userId ? 'AbpIdentity::Edit' : 'AbpIdentity::NewUser'), - })} - /> - - ); -} diff --git a/templates/app/react-native/src/screens/ChangePassword/ChangePasswordForm.js b/templates/app/react-native/src/screens/ChangePassword/ChangePasswordForm.js deleted file mode 100644 index 8621d00a99..0000000000 --- a/templates/app/react-native/src/screens/ChangePassword/ChangePasswordForm.js +++ /dev/null @@ -1,121 +0,0 @@ -import { useFormik } from 'formik'; -import i18n from 'i18n-js'; -import { - Box, - FormControl, - Input, - KeyboardAvoidingView, - Stack, - Icon -} from 'native-base'; -import PropTypes from 'prop-types'; -import React, { useRef, useState } from 'react'; -import * as Yup from 'yup'; -import { FormButtons } from '../../components/FormButtons'; -import ValidationMessage from '../../components/ValidationMessage/ValidationMessage'; -import { Ionicons } from '@expo/vector-icons'; - -const ValidationSchema = Yup.object().shape({ - currentPassword: Yup.string().required('AbpAccount::ThisFieldIsRequired.'), - newPassword: Yup.string().required('AbpAccount::ThisFieldIsRequired.'), -}); - -function ChangePasswordForm({ submit, cancel }) { - const [showCurrentPassword, setShowCurrentPassword] = useState(false); - const [showNewPassword, setShowNewPassword] = useState(false); - - const currentPasswordRef = useRef(); - const newPasswordRef = useRef(); - - const onSubmit = (values) => { - submit({ - ...values, - newPasswordConfirm: values.newPassword, - }); - }; - - const formik = useFormik({ - enableReinitialize: true, - validationSchema: ValidationSchema, - initialValues: { - currentPassword: '', - newPassword: '', - }, - onSubmit, - }); - - return ( - <> - - - - - {i18n.t('AbpIdentity::DisplayName:CurrentPassword')} - - newPasswordRef?.current?.focus()} - returnKeyType="next" - onChangeText={formik.handleChange('currentPassword')} - onBlur={formik.handleBlur('currentPassword')} - value={formik.values.currentPassword} - textContentType="password" - secureTextEntry={!showCurrentPassword} - InputRightElement={ - setShowCurrentPassword(!showCurrentPassword)} - /> - } - /> - - {formik.errors.currentPassword} - - - - - - - - {i18n.t('AbpIdentity::DisplayName:NewPassword')} - - setShowNewPassword(!showNewPassword)} - /> - } - /> - {formik.errors.newPassword} - - - - - - ); -} - -ChangePasswordForm.propTypes = { - submit: PropTypes.func.isRequired, - cancel: PropTypes.func.isRequired, -}; - -export default ChangePasswordForm; diff --git a/templates/app/react-native/src/screens/ChangePassword/ChangePasswordScreen.js b/templates/app/react-native/src/screens/ChangePassword/ChangePasswordScreen.js deleted file mode 100644 index 196c762a38..0000000000 --- a/templates/app/react-native/src/screens/ChangePassword/ChangePasswordScreen.js +++ /dev/null @@ -1,33 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; -import { changePassword } from '../../api/IdentityAPI'; -import LoadingActions from '../../store/actions/LoadingActions'; -import { connectToRedux } from '../../utils/ReduxConnect'; -import ChangePasswordForm from './ChangePasswordForm'; - -function ChangePasswordScreen({ navigation, startLoading, stopLoading }) { - const submit = data => { - startLoading({ key: 'changePassword' }); - - changePassword(data) - .then(() => { - navigation.goBack(); - }) - .finally(() => stopLoading({ key: 'changePassword' })); - }; - - return navigation.goBack()} />; -} - -ChangePasswordScreen.propTypes = { - startLoading: PropTypes.func.isRequired, - stopLoading: PropTypes.func.isRequired, -}; - -export default connectToRedux({ - component: ChangePasswordScreen, - dispatchProps: { - startLoading: LoadingActions.start, - stopLoading: LoadingActions.stop, - }, -}); diff --git a/templates/app/react-native/src/screens/CreateUpdateTenant/CreateUpdateTenantForm.js b/templates/app/react-native/src/screens/CreateUpdateTenant/CreateUpdateTenantForm.js deleted file mode 100644 index b76f356062..0000000000 --- a/templates/app/react-native/src/screens/CreateUpdateTenant/CreateUpdateTenantForm.js +++ /dev/null @@ -1,144 +0,0 @@ -import { Ionicons } from '@expo/vector-icons'; -import { useFormik } from 'formik'; -import i18n from 'i18n-js'; -import { Box, FormControl, Icon, Input, Stack } from 'native-base'; -import PropTypes from 'prop-types'; -import React, { useRef, useState } from 'react'; -import * as Yup from 'yup'; -import { FormButtons } from '../../components/FormButtons'; -import ValidationMessage from '../../components/ValidationMessage/ValidationMessage'; -import { usePermission } from '../../hooks/UsePermission'; - -const validations = { - name: Yup.string().required('AbpAccount::ThisFieldIsRequired.'), -}; - -function CreateUpdateTenantForm({ editingTenant = {}, submit, remove }) { - const tenantNameRef = useRef(); - const adminEmailRef = useRef(); - const adminPasswordRef = useRef(); - - const [showAdminPassword, setShowAdminPassword] = useState(false); - const hasRemovePermission = usePermission('AbpTenantManagement.Tenants.Delete'); - - const adminEmailAddressValidation = Yup.lazy(() => - Yup.string() - .required('AbpAccount::ThisFieldIsRequired.') - .email('AbpAccount::ThisFieldIsNotAValidEmailAddress.'), - ); - - const adminPasswordValidation = Yup.lazy(() => - Yup.string().required('AbpAccount::ThisFieldIsRequired.'), - ); - - const onSubmit = values => { - submit({ - ...editingTenant, - ...values, - }); - }; - - const formik = useFormik({ - enableReinitialize: true, - validationSchema: Yup.object().shape({ - ...validations, - ...(!editingTenant.id && { - adminEmailAddress: adminEmailAddressValidation, - adminPassword: adminPasswordValidation, - }), - }), - initialValues: { - lockoutEnabled: false, - twoFactorEnabled: false, - ...editingTenant, - }, - onSubmit, - }); - - return ( - <> - - - - {i18n.t('AbpTenantManagement::TenantName')} - - {formik.errors.name} - - - - {!editingTenant.id ? ( - <> - - - - {i18n.t('AbpTenantManagement::DisplayName:AdminEmailAddress')} - - adminPasswordRef?.current?.focus()} - returnKeyType="next" - /> - {formik.errors.adminEmailAddress} - - - - - - - {i18n.t('AbpTenantManagement::DisplayName:AdminPassword')} - - setShowAdminPassword(!showAdminPassword)} - /> - } - /> - {formik.errors.adminPassword} - - - - ) : null} - - - - ); -} - -CreateUpdateTenantForm.propTypes = { - editingTenant: PropTypes.object, - submit: PropTypes.func.isRequired, - remove: PropTypes.func.isRequired, -}; - -export default CreateUpdateTenantForm; diff --git a/templates/app/react-native/src/screens/CreateUpdateTenant/CreateUpdateTenantScreen.js b/templates/app/react-native/src/screens/CreateUpdateTenant/CreateUpdateTenantScreen.js deleted file mode 100644 index a3f59a8cf7..0000000000 --- a/templates/app/react-native/src/screens/CreateUpdateTenant/CreateUpdateTenantScreen.js +++ /dev/null @@ -1,81 +0,0 @@ -import { useFocusEffect } from '@react-navigation/native'; -import PropTypes from 'prop-types'; -import React, { useCallback, useState } from 'react'; -import { - createTenant, - getTenantById, - removeTenant, - updateTenant -} from '../../api/TenantManagementAPI'; -import LoadingActions from '../../store/actions/LoadingActions'; -import { createLoadingSelector } from '../../store/selectors/LoadingSelectors'; -import { connectToRedux } from '../../utils/ReduxConnect'; -import CreateUpdateTenantForm from './CreateUpdateTenantForm'; - -function CreateUpdateTenantScreen({ navigation, route, startLoading, stopLoading }) { - const [tenant, setTenant] = useState(); - const tenantId = route.params?.tenantId; - - const remove = () => { - startLoading({ key: 'removeTenant' }); - removeTenant(tenantId) - .then(() => navigation.goBack()) - .finally(() => stopLoading({ key: 'removeTenant' })); - }; - - useFocusEffect( - useCallback(() => { - if (tenantId) { - getTenantById(tenantId).then((data = {}) => setTenant(data)); - } - }, []), - ); - - const submit = data => { - startLoading({ key: 'saveTenant' }); - let request; - if (data.id) { - request = updateTenant(data, tenantId); - } else { - request = createTenant(data); - } - - request - .then(() => { - navigation.goBack(); - }) - .finally(() => stopLoading({ key: 'saveTenant' })); - }; - - const renderForm = () => ( - - ); - - if (tenantId && tenant) { - return renderForm(); - } - - if (!tenantId) { - return renderForm(); - } - - return null; -} - -CreateUpdateTenantScreen.propTypes = { - startLoading: PropTypes.func.isRequired, - stopLoading: PropTypes.func.isRequired, -}; - -export default connectToRedux({ - component: CreateUpdateTenantScreen, - stateProps: state => ({ loading: createLoadingSelector()(state) }), - dispatchProps: { - startLoading: LoadingActions.start, - stopLoading: LoadingActions.stop, - }, -}); diff --git a/templates/app/react-native/src/screens/CreateUpdateUser/CreateUpdateUserForm.js b/templates/app/react-native/src/screens/CreateUpdateUser/CreateUpdateUserForm.js deleted file mode 100644 index bb394232ba..0000000000 --- a/templates/app/react-native/src/screens/CreateUpdateUser/CreateUpdateUserForm.js +++ /dev/null @@ -1,272 +0,0 @@ -import { Ionicons } from '@expo/vector-icons'; -import { useFormik } from 'formik'; -import i18n from 'i18n-js'; -import { - Box, - Button, - Checkbox, - FormControl, - Icon, - Input, - KeyboardAvoidingView, - Stack -} from 'native-base'; -import PropTypes from 'prop-types'; -import React, { useRef, useState } from 'react'; -import { Platform } from 'react-native'; -import * as Yup from 'yup'; -import { FormButtons } from '../../components/FormButtons'; -import ValidationMessage from '../../components/ValidationMessage/ValidationMessage'; -import { usePermission } from '../../hooks/UsePermission'; -import UserRoles from './UserRoles'; - -const validations = { - userName: Yup.string().required('AbpAccount::ThisFieldIsRequired.'), - email: Yup.string() - .email('AbpAccount::ThisFieldIsNotAValidEmailAddress.') - .required('AbpAccount::ThisFieldIsRequired.'), -}; - -let roleNames = []; - -function onChangeRoles(roles) { - roleNames = roles; -} - -function CreateUpdateUserForm({ editingUser = {}, submit, remove }) { - const [selectedTab, setSelectedTab] = useState(0); - const [showPassword, setShowPassword] = useState(false); - - const usernameRef = useRef(); - const nameRef = useRef(); - const surnameRef = useRef(); - const emailRef = useRef(); - const phoneNumberRef = useRef(); - const passwordRef = useRef(); - - const hasRemovePermission = usePermission('AbpIdentity.Users.Delete'); - - const onSubmit = (values) => { - submit({ - ...editingUser, - ...values, - roleNames, - }); - }; - - const passwordValidation = Yup.lazy(() => { - if (editingUser.id) { - return Yup.string(); - } - return Yup.string().required('AbpAccount::ThisFieldIsRequired.'); - }); - - const formik = useFormik({ - enableReinitialize: true, - validationSchema: Yup.object().shape({ - ...validations, - password: passwordValidation, - }), - initialValues: { - lockoutEnabled: false, - ...editingUser, - }, - onSubmit, - }); - - return ( - <> - - - - - - - - {selectedTab === 0 ? ( - <> - - - - {i18n.t('AbpIdentity::UserName')} - - nameRef.current.focus()} - returnKeyType="next" - onChangeText={formik.handleChange('userName')} - onBlur={formik.handleBlur('userName')} - value={formik.values.userName} - autoCapitalize="none" - /> - - {formik.errors.userName} - - - - - - - - {i18n.t('AbpIdentity::DisplayName:Name')} - - surnameRef.current.focus()} - returnKeyType="next" - onChangeText={formik.handleChange('name')} - onBlur={formik.handleBlur('name')} - value={formik.values.name} - /> - - - - - - - {i18n.t('AbpIdentity::DisplayName:Surname')} - - emailRef.current.focus()} - returnKeyType="next" - onChangeText={formik.handleChange('surname')} - onBlur={formik.handleBlur('surname')} - value={formik.values.surname} - /> - - - - - - - {i18n.t('AbpIdentity::EmailAddress')} - - phoneNumberRef.current.focus()} - returnKeyType="next" - onChangeText={formik.handleChange('email')} - onBlur={formik.handleBlur('email')} - value={formik.values.email} - autoCapitalize="none" - /> - {formik.errors.email} - - - - - - - {i18n.t('AbpIdentity::PhoneNumber')} - - passwordRef?.current?.focus()} - returnKeyType={!editingUser.id ? 'next' : 'default'} - onChangeText={formik.handleChange('phoneNumber')} - onBlur={formik.handleBlur('phoneNumber')} - value={formik.values.phoneNumber} - /> - - - - {!editingUser.id ? ( - - - - {i18n.t('AbpIdentity::Password')} - - setShowPassword(!showPassword)} - /> - } - /> - - {formik.errors.password} - - - - ) : null} - - - - - formik.setFieldValue( - 'lockoutEnabled', - !formik.values.lockoutEnabled - ) - } - > - {i18n.t('AbpIdentity::DisplayName:LockoutEnabled')} - - - - - ) : ( - - )} - - - - - ); -} - -CreateUpdateUserForm.propTypes = { - editingUser: PropTypes.object, - submit: PropTypes.func.isRequired, - remove: PropTypes.func.isRequired, -}; - -export default CreateUpdateUserForm; diff --git a/templates/app/react-native/src/screens/CreateUpdateUser/CreateUpdateUserScreen.js b/templates/app/react-native/src/screens/CreateUpdateUser/CreateUpdateUserScreen.js deleted file mode 100644 index e900fde8fc..0000000000 --- a/templates/app/react-native/src/screens/CreateUpdateUser/CreateUpdateUserScreen.js +++ /dev/null @@ -1,69 +0,0 @@ -import PropTypes from 'prop-types'; -import React, { useEffect, useState } from 'react'; -import { createUser, getUserById, removeUser, updateUser } from '../../api/IdentityAPI'; -import LoadingActions from '../../store/actions/LoadingActions'; -import { createLoadingSelector } from '../../store/selectors/LoadingSelectors'; -import { connectToRedux } from '../../utils/ReduxConnect'; -import CreateUpdateUserForm from './CreateUpdateUserForm'; - -function CreateUpdateUserScreen({ navigation, route, startLoading, stopLoading }) { - const [user, setUser] = useState(); - const userId = route.params?.userId; - - const remove = () => { - startLoading({ key: 'remove user' }); - removeUser(userId) - .then(() => navigation.goBack()) - .finally(() => stopLoading({ key: 'remove user' })); - }; - - useEffect(() => { - if (userId) { - getUserById(userId).then((data = {}) => setUser(data)); - } - }, []); - - const submit = data => { - startLoading({ key: 'saveUser' }); - let request; - if (data.id) { - request = updateUser(data, userId); - } else { - request = createUser(data); - } - - request - .then(() => { - navigation.goBack(); - }) - .finally(() => stopLoading({ key: 'saveUser' })); - }; - - const renderForm = () => ( - - ); - - if (userId && user) { - return renderForm(); - } - - if (!userId) { - return renderForm(); - } - - return null; -} - -CreateUpdateUserScreen.propTypes = { - startLoading: PropTypes.func.isRequired, - stopLoading: PropTypes.func.isRequired, -}; - -export default connectToRedux({ - component: CreateUpdateUserScreen, - stateProps: state => ({ loading: createLoadingSelector()(state) }), - dispatchProps: { - startLoading: LoadingActions.start, - stopLoading: LoadingActions.stop, - }, -}); diff --git a/templates/app/react-native/src/screens/CreateUpdateUser/UserRoles.js b/templates/app/react-native/src/screens/CreateUpdateUser/UserRoles.js deleted file mode 100644 index 25db76afee..0000000000 --- a/templates/app/react-native/src/screens/CreateUpdateUser/UserRoles.js +++ /dev/null @@ -1,58 +0,0 @@ -import { Box, Checkbox, List } from 'native-base'; -import PropTypes from 'prop-types'; -import React, { useEffect, useState } from 'react'; -import { getAllRoles, getUserRoles } from '../../api/IdentityAPI'; - -function UserRoles({ editingUser = {}, onChangeRoles }) { - const [roles, setRoles] = useState([]); - - const onPress = index => { - setRoles( - roles.map((role, i) => ({ - ...role, - isSelected: index === i ? !role.isSelected : role.isSelected, - })), - ); - }; - - useEffect(() => { - const requests = [getAllRoles()]; - if (editingUser.id) requests.push(getUserRoles(editingUser.id)); - - Promise.all(requests).then(([allRoles = [], userRoles = []]) => { - setRoles( - allRoles.map(role => ({ - ...role, - isSelected: editingUser.id - ? !!userRoles?.find(userRole => userRole?.id === role?.id) - : role.isDefault, - })), - ); - }); - }, []); - - useEffect(() => { - onChangeRoles(roles.filter(role => role.isSelected).map(role => role.name)); - }, [roles]); - - return ( - - - {roles.map((role, index) => ( - - onPress(index)} > - {role.name} - - - ))} - - - ); -} - -UserRoles.propTypes = { - editingUser: PropTypes.objectOf(PropTypes.any).isRequired, - onChangeRoles: PropTypes.func.isRequired, -}; - -export default UserRoles; diff --git a/templates/app/react-native/src/screens/Home/HomeScreen.js b/templates/app/react-native/src/screens/Home/HomeScreen.js deleted file mode 100644 index 82ca221e2d..0000000000 --- a/templates/app/react-native/src/screens/Home/HomeScreen.js +++ /dev/null @@ -1,30 +0,0 @@ -import i18n from 'i18n-js'; -import { Box, Center, Heading, Text } from 'native-base'; -import React from 'react'; -import { StyleSheet } from 'react-native'; - -function HomeScreen() { - return ( -
- - {i18n.t('::Welcome')} - - {i18n.t('::LongWelcomeMessage')} - - -
- ); -} - -const styles = StyleSheet.create({ - centeredText: { - textAlign: 'center', - marginBottom: 5 - }, -}); - -export default HomeScreen; diff --git a/templates/app/react-native/src/screens/Login/LoginScreen.js b/templates/app/react-native/src/screens/Login/LoginScreen.js deleted file mode 100644 index acb72076fa..0000000000 --- a/templates/app/react-native/src/screens/Login/LoginScreen.js +++ /dev/null @@ -1,154 +0,0 @@ -import { useFormik } from 'formik'; -import i18n from 'i18n-js'; -import { - Box, - Button, - Center, - FormControl, Image, Input, - Stack, - WarningOutlineIcon -} from 'native-base'; -import PropTypes from 'prop-types'; -import React, { useRef, useState } from 'react'; -import { View } from 'react-native'; -import { object, string } from 'yup'; -import { login } from '../../api/AccountAPI'; -import TenantBox from '../../components/TenantBox/TenantBox'; -import ValidationMessage from '../../components/ValidationMessage/ValidationMessage'; -import AppActions from '../../store/actions/AppActions'; -import LoadingActions from '../../store/actions/LoadingActions'; -import PersistentStorageActions from '../../store/actions/PersistentStorageActions'; -import { connectToRedux } from '../../utils/ReduxConnect'; - -const ValidationSchema = object().shape({ - username: string().required('AbpAccount::ThisFieldIsRequired.'), - password: string().required('AbpAccount::ThisFieldIsRequired.'), -}); - -function LoginScreen({ startLoading, stopLoading, setToken, fetchAppConfig }) { - const [showTenantSelection, setShowTenantSelection] = useState(false); - const passwordRef = useRef(null); - - const toggleTenantSelection = () => { - setShowTenantSelection(!showTenantSelection); - }; - - const submit = ({ username, password }) => { - startLoading({ key: 'login' }); - login({ username, password }) - .then((data) => - setToken({ - ...data, - expire_time: new Date().valueOf() + data.expires_in, - scope: undefined, - }) - ) - .then( - () => - new Promise((resolve) => - fetchAppConfig({ - showLoading: false, - callback: () => resolve(true), - }) - ) - ) - .finally(() => stopLoading({ key: 'login' })); - }; - - const formik = useFormik({ - validationSchema: ValidationSchema, - initialValues: { username: '', password: '' }, - onSubmit: submit, - }); - - return ( -
- - Image - - - - - - - - {i18n.t('AbpAccount::UserNameOrEmailAddress')} - - passwordRef?.current?.focus()} - size="lg" - /> - {formik.errors.username} - - - - - - - {i18n.t('AbpAccount::Password')} - - - } - > - {formik.errors.password} - - - - - - - - -
- ); -} - -LoginScreen.propTypes = { - startLoading: PropTypes.func.isRequired, - stopLoading: PropTypes.func.isRequired, - setToken: PropTypes.func.isRequired, - fetchAppConfig: PropTypes.func.isRequired, -}; - -export default connectToRedux({ - component: LoginScreen, - dispatchProps: { - startLoading: LoadingActions.start, - stopLoading: LoadingActions.stop, - fetchAppConfig: AppActions.fetchAppConfigAsync, - setToken: PersistentStorageActions.setToken, - }, -}); diff --git a/templates/app/react-native/src/screens/ManageProfile/ManageProfileForm.js b/templates/app/react-native/src/screens/ManageProfile/ManageProfileForm.js deleted file mode 100644 index 2dffd3624b..0000000000 --- a/templates/app/react-native/src/screens/ManageProfile/ManageProfileForm.js +++ /dev/null @@ -1,153 +0,0 @@ -import { useFormik } from 'formik'; -import i18n from 'i18n-js'; -import { - Box, - FormControl, - Input, - KeyboardAvoidingView, - Stack, -} from 'native-base'; -import PropTypes from 'prop-types'; -import React, { useRef } from 'react'; -import * as Yup from 'yup'; -import FormButtons from '../../components/FormButtons/FormButtons'; -import ValidationMessage from '../../components/ValidationMessage/ValidationMessage'; - -const ValidationSchema = Yup.object().shape({ - userName: Yup.string().required('AbpAccount::ThisFieldIsRequired.'), - email: Yup.string() - .required('AbpAccount::ThisFieldIsRequired.') - .email('AbpAccount::ThisFieldIsNotAValidEmailAddress.'), -}); - -function ManageProfileForm({ editingUser = {}, submit, cancel }) { - const usernameRef = useRef(); - const nameRef = useRef(); - const surnameRef = useRef(); - const emailRef = useRef(); - const phoneNumberRef = useRef(); - - const onSubmit = (values) => { - submit({ - ...editingUser, - ...values, - }); - }; - - const formik = useFormik({ - enableReinitialize: true, - validationSchema: ValidationSchema, - initialValues: { - ...editingUser, - }, - onSubmit, - }); - - return ( - <> - - - - - - {i18n.t('AbpIdentity::UserName')} - - nameRef?.current?.focus()} - returnKeyType="next" - onChangeText={formik.handleChange('userName')} - onBlur={formik.handleBlur('userName')} - value={formik.values.userName} - /> - {formik.errors.userName} - - - - - - - {i18n.t('AbpIdentity::DisplayName:Name')} - - surnameRef?.current?.focus()} - returnKeyType="next" - onChangeText={formik.handleChange('name')} - onBlur={formik.handleBlur('name')} - value={formik.values.name} - /> - - - - - - - {i18n.t('AbpIdentity::DisplayName:Surname')} - - phoneNumberRef?.current?.focus()} - returnKeyType="next" - onChangeText={formik.handleChange('surname')} - onBlur={formik.handleBlur('surname')} - value={formik.values.surname} - /> - - - - - - - {i18n.t('AbpIdentity::PhoneNumber')} - - emailRef?.current?.focus()} - returnKeyType="next" - onChangeText={formik.handleChange('phoneNumber')} - onBlur={formik.handleBlur('phoneNumber')} - value={formik.values.phoneNumber} - /> - - - - - - - {i18n.t('AbpIdentity::EmailAddress')} - - - {formik.errors.email} - - - - - - - ); -} - -ManageProfileForm.propTypes = { - editingUser: PropTypes.object.isRequired, - submit: PropTypes.func.isRequired, - cancel: PropTypes.func.isRequired, -}; - -export default ManageProfileForm; diff --git a/templates/app/react-native/src/screens/ManageProfile/ManageProfileScreen.js b/templates/app/react-native/src/screens/ManageProfile/ManageProfileScreen.js deleted file mode 100644 index 1f2e577a37..0000000000 --- a/templates/app/react-native/src/screens/ManageProfile/ManageProfileScreen.js +++ /dev/null @@ -1,50 +0,0 @@ -import React, { useState, useEffect } from 'react'; -import PropTypes from 'prop-types'; -import { updateProfileDetail, getProfileDetail } from '../../api/IdentityAPI'; -import ManageProfileForm from './ManageProfileForm'; -import LoadingActions from '../../store/actions/LoadingActions'; -import { connectToRedux } from '../../utils/ReduxConnect'; - -function ManageProfileScreen({ navigation, startLoading, stopLoading }) { - const [user, setUser] = useState(); - - useEffect(() => { - if (!user) { - startLoading({ key: 'manageProfile' }); - getProfileDetail() - .then((data = {}) => setUser(data)) - .finally(() => stopLoading({ key: 'manageProfile' })); - } - }); - - const submit = data => { - startLoading({ key: 'manageProfile' }); - - updateProfileDetail(data) - .then(() => { - navigation.goBack(); - }) - .finally(() => stopLoading({ key: 'manageProfile' })); - }; - - return ( - <> - {user ? ( - navigation.goBack()} /> - ) : null} - - ); -} - -ManageProfileScreen.propTypes = { - startLoading: PropTypes.func.isRequired, - stopLoading: PropTypes.func.isRequired, -}; - -export default connectToRedux({ - component: ManageProfileScreen, - dispatchProps: { - startLoading: LoadingActions.start, - stopLoading: LoadingActions.stop, - }, -}); diff --git a/templates/app/react-native/src/screens/Settings/SettingsScreen.js b/templates/app/react-native/src/screens/Settings/SettingsScreen.js deleted file mode 100644 index 58ede9cbb5..0000000000 --- a/templates/app/react-native/src/screens/Settings/SettingsScreen.js +++ /dev/null @@ -1,157 +0,0 @@ -import { Ionicons } from '@expo/vector-icons'; -import { useFocusEffect } from '@react-navigation/native'; -import i18n from 'i18n-js'; -import { - Avatar, - Button, - Divider, - FormControl, - List, - Select, - Stack, - Text, - View, -} from 'native-base'; -import PropTypes from 'prop-types'; -import React, { useCallback, useState } from 'react'; -import { getProfileDetail } from '../../api/IdentityAPI'; -import AppActions from '../../store/actions/AppActions'; -import { - createLanguageSelector, - createLanguagesSelector, -} from '../../store/selectors/AppSelectors'; -import { createTenantSelector } from '../../store/selectors/PersistentStorageSelectors'; -import { connectToRedux } from '../../utils/ReduxConnect'; -import { store } from '../../store/index'; -import { getEnvVars } from '../../../Environment'; - -const env = getEnvVars(); - -function SettingsScreen({ - navigation, - language, - languages, - setLanguageAsync, - logoutAsync, - tenant = {}, -}) { - const [user, setUser] = useState({}); - const [token, setToken] = useState(store.getState().persistentStorage.token); - - const fetchUser = () => { - getProfileDetail().then(data => { - setUser(data || {}); - }); - }; - - useFocusEffect( - useCallback(() => { - fetchUser(); - }, []), - ); - - const logout = () => { - const { clientId } = env.oAuthConfig; - const { access_token, refresh_token } = token; - - logoutAsync({ - client_id: clientId, - token: access_token, - refresh_token: refresh_token, - }); - }; - - return ( - - - navigation.navigate('ManageProfile')}> - - - - - {tenant.name ? `${tenant.name}/` : ''} - {user.userName ? `${user.userName}` : ''} - - - - - - - - navigation.navigate('ChangePassword')}> - - {i18n.t('AbpUi::ChangePassword')} - - - - - - - - - {i18n.t('AbpUi::Language')} - - - - - - - - - ); -} - -SettingsScreen.propTypes = { - setLanguageAsync: PropTypes.func.isRequired, - logoutAsync: PropTypes.func.isRequired, - language: PropTypes.object.isRequired, - languages: PropTypes.array.isRequired, - tenant: PropTypes.object.isRequired, -}; - -export default connectToRedux({ - component: SettingsScreen, - stateProps: state => ({ - languages: createLanguagesSelector()(state), - language: createLanguageSelector()(state), - tenant: createTenantSelector()(state), - }), - dispatchProps: { - setLanguageAsync: AppActions.setLanguageAsync, - logoutAsync: AppActions.logoutAsync, - }, -}); diff --git a/templates/app/react-native/src/screens/Tenants/TenantsScreen.js b/templates/app/react-native/src/screens/Tenants/TenantsScreen.js deleted file mode 100644 index da3dac53af..0000000000 --- a/templates/app/react-native/src/screens/Tenants/TenantsScreen.js +++ /dev/null @@ -1,51 +0,0 @@ -import { Box, HStack, Pressable, Text } from 'native-base'; -import React from 'react'; -import { getTenants } from '../../api/TenantManagementAPI'; -import DataList from '../../components/DataList/DataList'; -import { LocalizationContext } from '../../contexts/LocalizationContext'; - -function TenantsScreen({ navigation }) { - const { t } = React.useContext(LocalizationContext); - - return ( - - ( - navigateToCreateUpdateTenantScreen(navigation, item)} - > - - - {t('AbpTenantManagement::TenantName')}: - - {item.name} - - - - - )} - /> - - ); -} - -const navigateToCreateUpdateTenantScreen = (navigation, tenant = {}) => { - navigation.navigate('CreateUpdateTenant', { - tenantId: tenant.id, - }); -}; - -export default TenantsScreen; diff --git a/templates/app/react-native/src/screens/Users/UsersScreen.js b/templates/app/react-native/src/screens/Users/UsersScreen.js deleted file mode 100644 index b49658cb24..0000000000 --- a/templates/app/react-native/src/screens/Users/UsersScreen.js +++ /dev/null @@ -1,62 +0,0 @@ -import { Box, HStack, Pressable, Text } from 'native-base'; -import React from 'react'; -import { getUsers } from '../../api/IdentityAPI'; -import DataList from '../../components/DataList/DataList'; -import { LocalizationContext } from '../../contexts/LocalizationContext'; - -function UsersScreen({ navigation }) { - const { t } = React.useContext(LocalizationContext); - - return ( - ( - navigateToCreateUpdateUserScreen(navigation, item)} - > - - - {t('AbpIdentity::UserName')}: - - {item.userName} - - - - {t('AbpIdentity::EmailAddress')}: - - {item.email} - - - - {t('AbpIdentity::DisplayName:Name')}: - - {item.name} - - - - {t('AbpIdentity::DisplayName:Surname')}: - - {item.surname} - - - - - )} - /> - ); -} - -const navigateToCreateUpdateUserScreen = (navigation, user = {}) => { - navigation.navigate('CreateUpdateUser', { - userId: user.id, - }); -}; - -export default UsersScreen; diff --git a/templates/app/react-native/src/store/actions/AppActions.js b/templates/app/react-native/src/store/actions/AppActions.js deleted file mode 100644 index 413d923129..0000000000 --- a/templates/app/react-native/src/store/actions/AppActions.js +++ /dev/null @@ -1,26 +0,0 @@ -import { createAction } from '@reduxjs/toolkit'; - -const fetchAppConfigAsync = createAction( - 'app/fetchAppConfigAsync', - ({ callback = () => {}, showLoading = true } = {}) => ({ - payload: { callback, showLoading }, - }), -); - -const setAppConfig = createAction('app/setAppConfig'); - -const setLanguageAsync = createAction('app/setLanguageAsync'); - -const logoutAsync = createAction( - 'app/logoutAsync', - ({ client_id = '', token = '', refresh_token = '' } = {}) => ({ - payload: { client_id, token, refresh_token }, - }), -); - -export default { - fetchAppConfigAsync, - setAppConfig, - setLanguageAsync, - logoutAsync, -}; diff --git a/templates/app/react-native/src/store/actions/LoadingActions.js b/templates/app/react-native/src/store/actions/LoadingActions.js deleted file mode 100644 index 9705dc4e0f..0000000000 --- a/templates/app/react-native/src/store/actions/LoadingActions.js +++ /dev/null @@ -1,13 +0,0 @@ -import { createAction } from '@reduxjs/toolkit'; - -const start = createAction('loading/start'); - -const stop = createAction('loading/stop'); - -const clear = createAction('loading/clear'); - -export default { - start, - stop, - clear, -}; diff --git a/templates/app/react-native/src/store/actions/PersistentStorageActions.js b/templates/app/react-native/src/store/actions/PersistentStorageActions.js deleted file mode 100644 index 4b32d9ff31..0000000000 --- a/templates/app/react-native/src/store/actions/PersistentStorageActions.js +++ /dev/null @@ -1,13 +0,0 @@ -import { createAction } from '@reduxjs/toolkit'; - -const setToken = createAction('persistentStorage/setToken'); - -const setLanguage = createAction('persistentStorage/setLanguage'); - -const setTenant = createAction('persistentStorage/setTenant'); - -export default { - setToken, - setLanguage, - setTenant, -}; diff --git a/templates/app/react-native/src/store/index.js b/templates/app/react-native/src/store/index.js deleted file mode 100644 index d30a0890dd..0000000000 --- a/templates/app/react-native/src/store/index.js +++ /dev/null @@ -1,25 +0,0 @@ -import AsyncStorage from '@react-native-async-storage/async-storage'; -import { configureStore } from '@reduxjs/toolkit'; -import { persistReducer, persistStore } from 'redux-persist'; -import createSagaMiddleware from 'redux-saga'; -import rootReducer from './reducers'; -import { rootSaga } from './sagas'; - -const sagaMiddleware = createSagaMiddleware(); - -const persistConfig = { - key: 'root', - storage: AsyncStorage, - whitelist: ['persistentStorage'], -}; - -const persistedReducer = persistReducer(persistConfig, rootReducer); - -export const store = configureStore({ - reducer: persistedReducer, - middleware: [sagaMiddleware], -}); - -export const persistor = persistStore(store); - -sagaMiddleware.run(rootSaga); diff --git a/templates/app/react-native/src/store/reducers/AppReducer.js b/templates/app/react-native/src/store/reducers/AppReducer.js deleted file mode 100644 index a628f7f802..0000000000 --- a/templates/app/react-native/src/store/reducers/AppReducer.js +++ /dev/null @@ -1,12 +0,0 @@ -import { createReducer } from '@reduxjs/toolkit'; -import AppActions from '../actions/AppActions'; - -const initialState = { - appConfig: {}, -}; - -export default createReducer(initialState, builder => - builder.addCase(AppActions.setAppConfig, (state, action) => { - state.appConfig = action.payload; - }), -); diff --git a/templates/app/react-native/src/store/reducers/LoadingReducer.js b/templates/app/react-native/src/store/reducers/LoadingReducer.js deleted file mode 100644 index 99ccb14149..0000000000 --- a/templates/app/react-native/src/store/reducers/LoadingReducer.js +++ /dev/null @@ -1,23 +0,0 @@ -import { createReducer } from '@reduxjs/toolkit'; -import LoadingActions from '../actions/LoadingActions'; - -const initialState = { activeLoadings: {}, loading: false }; - -export default createReducer(initialState, builder => - builder - .addCase(LoadingActions.start, (state, action) => { - const { key, opacity } = action.payload; - return { - ...state, - actives: { ...state.activeLoadings, [key]: action }, - loading: true, - opacity, - }; - }) - .addCase(LoadingActions.stop, (state, action) => { - delete state.activeLoadings[action.payload.key]; - - state.loading = !!Object.keys(state.activeLoadings).length; - }) - .addCase(LoadingActions.clear, () => ({})), -); diff --git a/templates/app/react-native/src/store/reducers/PersistentStorageReducer.js b/templates/app/react-native/src/store/reducers/PersistentStorageReducer.js deleted file mode 100644 index d4d8f9a32b..0000000000 --- a/templates/app/react-native/src/store/reducers/PersistentStorageReducer.js +++ /dev/null @@ -1,17 +0,0 @@ -import { createReducer } from '@reduxjs/toolkit'; -import PersistentStorageActions from '../actions/PersistentStorageActions'; - -const initialState = { token: {}, language: null, tenant: {} }; - -export default createReducer(initialState, builder => - builder - .addCase(PersistentStorageActions.setToken, (state, action) => { - state.token = action.payload; - }) - .addCase(PersistentStorageActions.setLanguage, (state, action) => { - state.language = action.payload; - }) - .addCase(PersistentStorageActions.setTenant, (state, action) => { - state.tenant = action.payload; - }), -); diff --git a/templates/app/react-native/src/store/reducers/index.js b/templates/app/react-native/src/store/reducers/index.js deleted file mode 100644 index 0479999c14..0000000000 --- a/templates/app/react-native/src/store/reducers/index.js +++ /dev/null @@ -1,12 +0,0 @@ -import { combineReducers } from '@reduxjs/toolkit'; -import AppReducer from './AppReducer'; -import LoadingReducer from './LoadingReducer'; -import PersistentStorageReducer from './PersistentStorageReducer'; - -const rootReducer = combineReducers({ - loading: LoadingReducer, - app: AppReducer, - persistentStorage: PersistentStorageReducer, -}); - -export default rootReducer; diff --git a/templates/app/react-native/src/store/sagas/AppSaga.js b/templates/app/react-native/src/store/sagas/AppSaga.js deleted file mode 100644 index 8eb795a971..0000000000 --- a/templates/app/react-native/src/store/sagas/AppSaga.js +++ /dev/null @@ -1,50 +0,0 @@ -import { all, call, put, takeLatest } from 'redux-saga/effects'; -import { Logout } from '../../api/AccountAPI'; -import { getApplicationConfiguration } from '../../api/ApplicationConfigurationAPI'; -import AppActions from '../actions/AppActions'; -import LoadingActions from '../actions/LoadingActions'; -import PersistentStorageActions from '../actions/PersistentStorageActions'; - -function* fetchAppConfig({ payload: { showLoading, callback } }) { - if (showLoading) { - yield put(LoadingActions.start({ key: 'appConfig', opacity: 1 })); - } - - const data = yield call(getApplicationConfiguration); - yield put(AppActions.setAppConfig(data)); - yield put( - PersistentStorageActions.setLanguage( - data.localization.currentCulture.cultureName, - ), - ); - if (showLoading) yield put(LoadingActions.stop({ key: 'appConfig' })); - callback(); -} - -function* setLanguage(action) { - yield put(PersistentStorageActions.setLanguage(action.payload)); - yield put(AppActions.fetchAppConfigAsync()); -} - -function* logout({ payload: { client_id, token, refresh_token } }) { - const data = { client_id, token }; - - yield call(Logout, data); - - if (!!refresh_token) { - data.token = refresh_token; - data.token_type_hint = 'refresh_token'; - yield call(Logout, data); - } - - yield put(PersistentStorageActions.setToken({})); - yield put(AppActions.fetchAppConfigAsync()); -} - -export default function* () { - yield all([ - takeLatest(AppActions.setLanguageAsync.type, setLanguage), - takeLatest(AppActions.fetchAppConfigAsync.type, fetchAppConfig), - takeLatest(AppActions.logoutAsync.type, logout), - ]); -} diff --git a/templates/app/react-native/src/store/sagas/index.js b/templates/app/react-native/src/store/sagas/index.js deleted file mode 100644 index 1b56c35c2c..0000000000 --- a/templates/app/react-native/src/store/sagas/index.js +++ /dev/null @@ -1,6 +0,0 @@ -import { all, fork } from 'redux-saga/effects'; -import AppSaga from './AppSaga'; - -export function* rootSaga() { - yield all([fork(AppSaga)]); -} diff --git a/templates/app/react-native/src/store/selectors/AppSelectors.js b/templates/app/react-native/src/store/selectors/AppSelectors.js deleted file mode 100644 index 82e0000b71..0000000000 --- a/templates/app/react-native/src/store/selectors/AppSelectors.js +++ /dev/null @@ -1,19 +0,0 @@ -import { createSelector } from 'reselect'; - -const getApp = state => state.app; - -export function createAppConfigSelector() { - return createSelector([getApp], state => state.appConfig); -} - -export function createLanguageSelector() { - return createSelector([getApp], state => state?.appConfig?.localization?.currentCulture); -} - -export function createLanguagesSelector() { - return createSelector([getApp], state => state?.appConfig?.localization?.languages); -} - -export function createGrantedPolicySelector(key) { - return createSelector([getApp], state => state?.appConfig?.auth?.grantedPolicies[key] ?? false); -} diff --git a/templates/app/react-native/src/store/selectors/LoadingSelectors.js b/templates/app/react-native/src/store/selectors/LoadingSelectors.js deleted file mode 100644 index 47a798fe2c..0000000000 --- a/templates/app/react-native/src/store/selectors/LoadingSelectors.js +++ /dev/null @@ -1,11 +0,0 @@ -import { createSelector } from 'reselect'; - -const getLoading = state => state.loading; - -export function createLoadingSelector() { - return createSelector([getLoading], loading => loading.loading); -} - -export function createOpacitySelector() { - return createSelector([getLoading], loading => loading.opacity); -} diff --git a/templates/app/react-native/src/store/selectors/PersistentStorageSelectors.js b/templates/app/react-native/src/store/selectors/PersistentStorageSelectors.js deleted file mode 100644 index d5d86f8b7d..0000000000 --- a/templates/app/react-native/src/store/selectors/PersistentStorageSelectors.js +++ /dev/null @@ -1,11 +0,0 @@ -import { createSelector } from 'reselect'; - -const getPersistentStorage = state => state.persistentStorage; - -export function createTokenSelector() { - return createSelector([getPersistentStorage], persistentStorage => persistentStorage.token); -} - -export function createTenantSelector() { - return createSelector([getPersistentStorage], persistentStorage => persistentStorage.tenant); -} diff --git a/templates/app/react-native/src/utils/DateExtensions.js b/templates/app/react-native/src/utils/DateExtensions.js deleted file mode 100644 index 890a6fdfc5..0000000000 --- a/templates/app/react-native/src/utils/DateExtensions.js +++ /dev/null @@ -1,5 +0,0 @@ -export function toLocalISOString(date) { - const timezoneOffset = date.getTimezoneOffset(); - - return new Date(date.getTime() - timezoneOffset * 60000).toISOString(); -} diff --git a/templates/app/react-native/src/utils/Debounce.js b/templates/app/react-native/src/utils/Debounce.js deleted file mode 100644 index 34588c63d4..0000000000 --- a/templates/app/react-native/src/utils/Debounce.js +++ /dev/null @@ -1,14 +0,0 @@ -export function debounce(func, wait, immediate) { - let timeout; - return (...args) => { - const context = this; - const later = () => { - timeout = null; - if (!immediate) func.apply(context, args); - }; - const callNow = immediate && !timeout; - clearTimeout(timeout); - timeout = setTimeout(later, wait); - if (callNow) func.apply(context, args); - }; -} diff --git a/templates/app/react-native/src/utils/RandomColor.js b/templates/app/react-native/src/utils/RandomColor.js deleted file mode 100644 index a925d77763..0000000000 --- a/templates/app/react-native/src/utils/RandomColor.js +++ /dev/null @@ -1,12 +0,0 @@ -export function getRandomColors(count) { - const colors = []; - - for (let i = 0; i < count; i++) { - const r = ((i + 5) * (i + 5) * 474) % 255; - const g = ((i + 5) * (i + 5) * 1600) % 255; - const b = ((i + 5) * (i + 5) * 84065) % 255; - colors.push(`rgba(${r}, ${g}, ${b})`); - } - - return colors; -} diff --git a/templates/app/react-native/src/utils/ReduxConnect.js b/templates/app/react-native/src/utils/ReduxConnect.js deleted file mode 100644 index be68b186af..0000000000 --- a/templates/app/react-native/src/utils/ReduxConnect.js +++ /dev/null @@ -1,9 +0,0 @@ -import { connect } from 'react-redux'; - -export function connectToRedux({ component, stateProps = () => ({}), dispatchProps = () => ({}) }) { - const mapStateToProps = () => stateProps; - - const mapDispatchToProps = dispatchProps; - - return connect(mapStateToProps, mapDispatchToProps)(component); -} diff --git a/templates/app/react-native/src/utils/TokenUtils.js b/templates/app/react-native/src/utils/TokenUtils.js deleted file mode 100644 index ab1925061b..0000000000 --- a/templates/app/react-native/src/utils/TokenUtils.js +++ /dev/null @@ -1,7 +0,0 @@ -export function isTokenValid(token) { - if (!token || typeof token !== 'object' || !token.expire_time) return false; - - const now = new Date().valueOf(); - - return now < token.expire_time; -}