diff --git a/npm/ng-packs/.vscode/settings.json b/npm/ng-packs/.vscode/settings.json
index 9c2678df08..37d9a1e403 100644
--- a/npm/ng-packs/.vscode/settings.json
+++ b/npm/ng-packs/.vscode/settings.json
@@ -6,7 +6,6 @@
"typescript.tsdk": "../node_modules/typescript/lib",
"workbench.colorCustomizations": {
"activityBar.background": "#258ecd",
- "activityBar.activeBackground": "#258ecd",
"activityBar.activeBorder": "#f0aed7",
"activityBar.foreground": "#e7e7e7",
"activityBar.inactiveForeground": "#e7e7e799",
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/.gitignore b/templates/app/react-native/.gitignore
deleted file mode 100644
index c409cf6af4..0000000000
--- a/templates/app/react-native/.gitignore
+++ /dev/null
@@ -1,14 +0,0 @@
-node_modules/**/*
-.expo/*
-npm-debug.*
-*.jks
-*.p8
-*.p12
-*.key
-*.mobileprovision
-*.orig.*
-web-build/
-web-report/
-
-# macOS
-.DS_Store
diff --git a/templates/app/react-native/.prettierrc b/templates/app/react-native/.prettierrc
deleted file mode 100644
index 425031393b..0000000000
--- a/templates/app/react-native/.prettierrc
+++ /dev/null
@@ -1,8 +0,0 @@
-{
- "trailingComma": "all",
- "singleQuote": true,
- "jsxSingleQuote": false,
- "printWidth": 100,
- "semi": true,
- "jsxBracketSameLine": true
-}
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 775a7e1aa5..0000000000
--- a/templates/app/react-native/App.js
+++ /dev/null
@@ -1,25 +0,0 @@
-import { StyleProvider } from 'native-base';
-import React from 'react';
-import { enableScreens } from 'react-native-screens';
-import { Provider } from 'react-redux';
-import { PersistGate } from 'redux-persist/integration/react';
-import AppContainer from './src/components/AppContainer/AppContainer';
-import { store, persistor } from './src/store';
-import getTheme from './src/theme/components';
-import { activeTheme } from './src/theme/variables';
-import { initAPIInterceptor } from './src/interceptors/APIInterceptor';
-
-enableScreens();
-initAPIInterceptor(store);
-
-export default function App() {
- return (
-
-
-
-
-
-
-
- );
-}
diff --git a/templates/app/react-native/Environment.js b/templates/app/react-native/Environment.js
deleted file mode 100644
index 4a7a730d97..0000000000
--- a/templates/app/react-native/Environment.js
+++ /dev/null
@@ -1,31 +0,0 @@
-const ENV = {
- dev: {
- apiUrl: 'http://localhost:44305',
- oAuthConfig: {
- issuer: 'http://localhost:44305',
- clientId: 'MyProjectName_App',
- clientSecret: '1q2w3e*',
- scope: 'MyProjectName',
- },
- localization: {
- defaultResourceName: 'MyProjectName',
- },
- },
- prod: {
- apiUrl: 'http://localhost:44305',
- oAuthConfig: {
- issuer: 'http://localhost:44305',
- clientId: 'MyProjectName_App',
- clientSecret: '1q2w3e*',
- scope: '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 370089879c..0000000000
--- a/templates/app/react-native/app.json
+++ /dev/null
@@ -1,30 +0,0 @@
-{
- "expo": {
- "name": "MyProjectName",
- "slug": "MyProjectName",
- "privacy": "public",
- "sdkVersion": "36.0.0",
- "platforms": ["ios", "android", "web"],
- "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
- }
- }
-}
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 e1ff94e305..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 b672828003..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 884bfd7ef1..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 2900afe9d8..0000000000
--- a/templates/app/react-native/babel.config.js
+++ /dev/null
@@ -1,6 +0,0 @@
-module.exports = function(api) {
- api.cache(true);
- return {
- presets: ['babel-preset-expo'],
- };
-};
diff --git a/templates/app/react-native/package.json b/templates/app/react-native/package.json
deleted file mode 100644
index 38c1b06b43..0000000000
--- a/templates/app/react-native/package.json
+++ /dev/null
@@ -1,64 +0,0 @@
-{
- "main": "node_modules/expo/AppEntry.js",
- "scripts": {
- "start": "expo start",
- "android": "expo start --android",
- "ios": "expo start --ios",
- "web": "expo start --web",
- "eject": "expo eject",
- "lint": "eslint *.js **/*.js",
- "lint:fix": "yarn lint --fix"
- },
- "dependencies": {
- "@expo/vector-icons": "^10.0.6",
- "@react-native-community/masked-view": "0.1.5",
- "@react-navigation/drawer": "^5.0.3",
- "@react-navigation/native": "^5.0.3",
- "@react-navigation/stack": "^5.0.3",
- "@reduxjs/toolkit": "^1.2.3",
- "axios": "^0.19.2",
- "color": "^3.1.2",
- "expo": "~36.0.0",
- "expo-constants": "~8.0.0",
- "expo-font": "~8.0.0",
- "formik": "^2.1.2",
- "i18n-js": "^3.5.1",
- "lodash": "^4.17.15",
- "native-base": "^2.13.8",
- "prop-types": "^15.7.2",
- "react": "~16.9.0",
- "react-dom": "~16.9.0",
- "react-native": "https://github.com/expo/react-native/archive/sdk-36.0.0.tar.gz",
- "react-native-chart-kit": "^4.5.0",
- "react-native-gesture-handler": "~1.5.0",
- "react-native-reanimated": "~1.4.0",
- "react-native-safe-area-context": "0.6.0",
- "react-native-safe-area-view": "^1.0.0",
- "react-native-screens": "2.0.0-alpha.12",
- "react-native-svg": "9.13.3",
- "react-native-web": "~0.11.7",
- "react-redux": "^7.1.3",
- "redux-persist": "^6.0.0",
- "redux-saga": "^1.1.3",
- "reselect": "^4.0.0",
- "yup": "^0.28.0"
- },
- "devDependencies": {
- "@babel/core": "^7.0.0",
- "@types/i18n-js": "^3.0.1",
- "@types/react": "~16.9.0",
- "@types/react-native": "~0.60.23",
- "@types/react-redux": "^7.1.7",
- "@types/yup": "^0.26.29",
- "babel-eslint": "^10.0.3",
- "babel-preset-expo": "~8.0.0",
- "eslint": "^6.8.0",
- "eslint-config-airbnb": "^18.0.1",
- "eslint-config-prettier": "^6.10.0",
- "eslint-plugin-import": "^2.20.1",
- "eslint-plugin-jsx-a11y": "^6.2.3",
- "eslint-plugin-react": "^7.18.3",
- "prettier": "^1.19.1"
- },
- "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 6cf4535b70..0000000000
--- a/templates/app/react-native/src/api/API.js
+++ /dev/null
@@ -1,10 +0,0 @@
-import axios from 'axios';
-import { getEnvVars } from '../../Environment';
-
-const { apiUrl } = getEnvVars();
-
-const axiosInstance = axios.create({
- baseURL: apiUrl,
-});
-
-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 dc2fb61577..0000000000
--- a/templates/app/react-native/src/api/AccountAPI.js
+++ /dev/null
@@ -1,41 +0,0 @@
-import api from './API';
-import { getEnvVars } from '../../Environment';
-
-const { oAuthConfig } = getEnvVars();
-
-export const login = ({ username, password }) => {
- // eslint-disable-next-line no-undef
- const formData = new FormData();
- formData.append('username', username);
- formData.append('password', password);
- formData.append('grant_type', 'password');
- formData.append('scope', `${oAuthConfig.scope} offline_access`);
- formData.append('client_id', oAuthConfig.clientId);
- formData.append('client_secret', oAuthConfig.clientSecret);
-
- return api({
- method: 'POST',
- url: '/connect/token',
- headers: { 'Content-Type': 'multipart/form-data' },
- data: formData,
- baseURL: oAuthConfig.issuer,
- }).then(({ data }) => data);
-};
-
-export const Logout = () =>
- api({
- method: 'GET',
- url: '/api/account/logout',
- }).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 0445057995..0000000000
--- a/templates/app/react-native/src/api/IdentityAPI.js
+++ /dev/null
@@ -1,29 +0,0 @@
-import api from './API';
-
-const maxMaxResultCount = 1000;
-
-export const getProfileDetail = () => api.get('/api/identity/my-profile').then(({ data }) => data);
-
-export const getRoles = (params = { maxResultCount: maxMaxResultCount, skipCount: 0 }) =>
- api.get('/api/identity/roles', { params }).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 updateProfileDetail = body =>
- api.put('/api/identity/my-profile', body).then(({ data }) => data);
-
-export const changePassword = body =>
- api.post('/api/identity/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/AppContainer/AppContainer.js b/templates/app/react-native/src/components/AppContainer/AppContainer.js
deleted file mode 100644
index d07b692466..0000000000
--- a/templates/app/react-native/src/components/AppContainer/AppContainer.js
+++ /dev/null
@@ -1,99 +0,0 @@
-import { Ionicons } from '@expo/vector-icons';
-import * as Font from 'expo-font';
-import i18n from 'i18n-js';
-import PropTypes from 'prop-types';
-import React, { useEffect, useState, useMemo } from 'react';
-import { Platform, StatusBar } from 'react-native';
-import { NavigationContainer } from '@react-navigation/native';
-import { Root } from 'native-base';
-import Loading from '../Loading/Loading';
-import { connectToRedux } from '../../utils/ReduxConnect';
-import { createLanguageSelector } from '../../store/selectors/AppSelectors';
-import { createTokenSelector } from '../../store/selectors/PersistentStorageSelectors';
-import AppActions from '../../store/actions/AppActions';
-import PersistentStorageActions from '../../store/actions/PersistentStorageActions';
-import { LocalizationContext } from '../../contexts/LocalizationContext';
-import { isTokenValid } from '../../utils/TokenUtils';
-import DrawerNavigator from '../../navigators/DrawerNavigator';
-import AuthNavigator from '../../navigators/AuthNavigator';
-import { getEnvVars } from '../../../Environment';
-
-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);
-};
-
-function AppContainer({ language, fetchAppConfig, token, setToken }) {
- const platform = Platform.OS;
- const [isReady, setIsReady] = useState(false);
-
- const localizationContext = useMemo(
- () => ({
- t: i18n.t,
- locale: (language || {}).cultureName,
- }),
- [language],
- );
-
- const isValid = useMemo(() => isTokenValid(token), [token]);
-
- useEffect(() => {
- if (!isValid && token && token.access_token) {
- setToken({});
- }
- }, [isValid]);
-
- useEffect(() => {
- fetchAppConfig();
-
- Promise.all([
- Font.loadAsync({
- Roboto: require('native-base/Fonts/Roboto.ttf'),
- Roboto_medium: require('native-base/Fonts/Roboto_medium.ttf'),
- ...Ionicons.font,
- }),
- ]).then(() => setIsReady(true));
- }, []);
-
- return (
- <>
-
-
- {isReady && language ? (
-
-
- {isValid ? : }
-
-
- ) : null}
-
-
- >
- );
-}
-
-AppContainer.propTypes = {
- language: PropTypes.object,
- token: PropTypes.object.isRequired,
- fetchAppConfig: PropTypes.func.isRequired,
- setToken: PropTypes.func.isRequired,
-};
-
-export default connectToRedux({
- component: AppContainer,
- stateProps: state => ({
- language: createLanguageSelector()(state),
- token: createTokenSelector()(state),
- }),
- dispatchProps: {
- fetchAppConfig: AppActions.fetchAppConfigAsync,
- setToken: PersistentStorageActions.setToken,
- },
-});
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 7c837ec83f..0000000000
--- a/templates/app/react-native/src/components/DataList/DataList.js
+++ /dev/null
@@ -1,139 +0,0 @@
-import { useFocusEffect } from '@react-navigation/native';
-import i18n from 'i18n-js';
-import { connectStyle, Icon, Input, InputGroup, Item, List, Spinner, Text } from 'native-base';
-import PropTypes from 'prop-types';
-import React, { forwardRef, useCallback, useEffect, useState } from 'react';
-import { RefreshControl, StyleSheet, View } from 'react-native';
-import LoadingActions from '../../store/actions/LoadingActions';
-import { activeTheme } from '../../theme/variables';
-import { debounce } from '../../utils/Debounce';
-import { connectToRedux } from '../../utils/ReduxConnect';
-import LoadingButton from '../LoadingButton/LoadingButton';
-
-function DataList({
- style,
- 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 (
- <>
- -
-
-
- {searchLoading ? (
-
-
-
- ) : (
-
- )}
-
-
-
-
}
- dataArray={records}
- renderRow={(data, sectionID, rowId, ...args) => (
- <>
- {render(data, sectionID, rowId, ...args)}
- {rowId + 1 === skipCount + maxResultCount && totalCount > records.length ? (
-
- fetchPartial()}>
- {i18n.t('AbpUi::LoadMore')}
-
-
- ) : null}
- >
- )}
- {...props}
- />
-
- >
- );
-}
-
-DataList.propTypes = {
- ...List.propTypes,
- style: PropTypes.any.isRequired,
- fetchFn: PropTypes.func.isRequired,
- render: PropTypes.func.isRequired,
- maxResultCount: PropTypes.number,
- debounceTime: PropTypes.number,
-};
-
-const styles = StyleSheet.create({
- container: { flex: 1 },
- list: {},
- spinner: {
- transform: [{ scale: 0.5 }],
- position: 'absolute',
- right: 8,
- top: -40,
- color: activeTheme.brandInfo,
- },
-});
-
-const Forwarded = forwardRef((props, ref) => );
-
-export default connectToRedux({
- component: connectStyle('ABP.DataList', styles)(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 1725abaee3..0000000000
--- a/templates/app/react-native/src/components/DrawerContent/DrawerContent.js
+++ /dev/null
@@ -1,121 +0,0 @@
-import { Text, View, List, ListItem, Left, Icon, Body } from 'native-base';
-import React from 'react';
-import { Image, StyleSheet } from 'react-native';
-import SafeAreaView from 'react-native-safe-area-view';
-import i18n from 'i18n-js';
-import PropTypes from 'prop-types';
-import Constants from 'expo-constants';
-import { withPermission } from '../../hocs/PermissionHOC';
-
-const screens = {
- Home: { label: '::Menu:Home', iconName: 'home' },
- Users: {
- label: 'AbpIdentity::Users',
- iconName: 'contacts',
- requiredPolicy: 'AbpIdentity.Users',
- },
- Tenants: {
- label: 'AbpTenantManagement::Tenants',
- iconName: 'people',
- requiredPolicy: 'AbpTenantManagement.Tenants',
- },
- Settings: { label: 'AbpSettingManagement::Settings', iconName: 'cog' },
-};
-
-const ListItemWithPermission = withPermission(ListItem);
-
-function DrawerContent({ navigation, state: { routeNames, index: currentScreenIndex } }) {
- const navigate = screen => {
- navigation.navigate(screen);
- navigation.closeDrawer();
- };
-
- return (
-
-
-
-
-
- item}
- renderRow={name => (
- navigate(name)}
- style={{
- ...styles.navItem,
- backgroundColor: name === routeNames[currentScreenIndex] ? '#38003c' : '#f2f2f2',
- }}>
-
-
-
-
-
- {i18n.t(screens[name].label)}
-
-
-
- )}
- />
-
-
-
- © MyProjectName
-
-
- v{Constants.manifest.version}
-
-
-
- );
-}
-
-const styles = StyleSheet.create({
- container: {
- flexGrow: 1,
- },
- logo: {
- marginTop: 20,
- marginBottom: 15,
- },
- headerView: {
- borderBottomWidth: 1,
- borderColor: '#eee',
- alignItems: 'center',
- },
- navItem: {
- marginLeft: 0,
- marginBottom: 3,
- paddingLeft: 10,
- width: '100%',
- backgroundColor: '#f2f2f2',
- },
- 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 5bbdb388f8..0000000000
--- a/templates/app/react-native/src/components/FormButtons/FormButtons.js
+++ /dev/null
@@ -1,82 +0,0 @@
-import React, { forwardRef } from 'react';
-import PropTypes from 'prop-types';
-import { Button, Text, connectStyle } from 'native-base';
-import { View, StyleSheet, Alert } from 'react-native';
-import i18n from 'i18n-js';
-
-function FormButtons({
- style,
- 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 connectStyle('ABP.FormButtons', styles)(Forwarded);
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 41f0f0693e..0000000000
--- a/templates/app/react-native/src/components/Loading/Loading.js
+++ /dev/null
@@ -1,63 +0,0 @@
-import React, { forwardRef } from 'react';
-import { Spinner, View, connectStyle } from 'native-base';
-import { StyleSheet } from 'react-native';
-import PropTypes from 'prop-types';
-import { activeTheme } from '../../theme/variables';
-import { connectToRedux } from '../../utils/ReduxConnect';
-import {
- createLoadingSelector,
- createOpacitySelector,
-} from '../../store/selectors/LoadingSelectors';
-
-function Loading({ style, 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,
- alignItems: 'center',
- justifyContent: 'center',
- },
- backdrop: backdropStyle,
- spinner: {
- color: activeTheme.brandPrimary,
- fontSize: 100,
- },
-});
-
-Loading.propTypes = {
- style: PropTypes.objectOf(PropTypes.any),
- loading: PropTypes.bool,
- opacity: PropTypes.number,
-};
-
-export default connectToRedux({
- component: connectStyle('ABP.Loading', styles)(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 14de6d840a..0000000000
--- a/templates/app/react-native/src/components/LoadingButton/LoadingButton.js
+++ /dev/null
@@ -1,31 +0,0 @@
-import { Button, connectStyle, Spinner } from 'native-base';
-import PropTypes from 'prop-types';
-import React, { forwardRef } from 'react';
-import { StyleSheet } from 'react-native';
-
-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 },
- spinner: {
- transform: [{ scale: 0.5 }],
- color: 'white',
- marginRight: 5,
- },
-});
-
-const Forwarded = forwardRef((props, ref) => );
-
-export default connectStyle('ABP.LoadingButton', styles)(Forwarded);
diff --git a/templates/app/react-native/src/components/MenuIcon/MenuIcon.js b/templates/app/react-native/src/components/MenuIcon/MenuIcon.js
deleted file mode 100644
index c820d30a7f..0000000000
--- a/templates/app/react-native/src/components/MenuIcon/MenuIcon.js
+++ /dev/null
@@ -1,19 +0,0 @@
-import React from 'react';
-import { TouchableOpacity } from 'react-native';
-import { Icon } from 'native-base';
-import PropTypes from 'prop-types';
-
-function MenuIcon({ onPress, iconName = 'menu' }) {
- return (
-
-
-
- );
-}
-
-MenuIcon.propTypes = {
- onPress: PropTypes.func.isRequired,
- iconName: PropTypes.string,
-};
-
-export default MenuIcon;
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 a944d80dd5..0000000000
--- a/templates/app/react-native/src/components/TenantBox/TenantBox.js
+++ /dev/null
@@ -1,128 +0,0 @@
-import i18n from 'i18n-js';
-import {
- Button,
- connectStyle,
- Content,
- Input,
- InputGroup,
- Label,
- Segment,
- Text,
-} from 'native-base';
-import PropTypes from 'prop-types';
-import React, { forwardRef, useState } from 'react';
-import { StyleSheet, View, Alert } from 'react-native';
-import { getTenant } from '../../api/AccountAPI';
-import PersistentStorageActions from '../../store/actions/PersistentStorageActions';
-import { connectToRedux } from '../../utils/ReduxConnect';
-import { createTenantSelector } from '../../store/selectors/PersistentStorageSelectors';
-
-function TenantBox({ style, 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::SwitchTenantHint')}
-
-
-
-
-
- ) : null}
- >
- );
-}
-
-TenantBox.propTypes = {
- style: PropTypes.any.isRequired,
- setTenant: PropTypes.func.isRequired,
- showTenantSelection: PropTypes.bool.isRequired,
- toggleTenantSelection: PropTypes.func.isRequired,
- tenant: PropTypes.object.isRequired,
-};
-
-const styles = StyleSheet.create({
- container: {
- paddingHorizontal: 20,
- alignItems: 'center',
- justifyContent: 'space-between',
- height: 70,
- },
- button: { marginTop: 20, width: '49%' },
- switchButton: {
- borderTopWidth: 0,
- borderRightWidth: 0,
- borderBottomWidth: 0,
- borderLeftWidth: 0,
- borderRadius: 10,
- backgroundColor: '#38003c',
- height: 35,
- },
- tenant: { color: '#777' },
- title: {
- marginRight: 10,
- color: '#777',
- fontSize: 13,
- fontWeight: '600',
- textTransform: 'uppercase',
- },
- hint: { color: '#bbb', textAlign: 'left' },
-});
-
-const Forwarded = forwardRef((props, ref) => );
-
-export default connectToRedux({
- component: connectStyle('ABP.TenantBox', styles)(Forwarded),
- dispatchProps: {
- setTenant: PersistentStorageActions.setTenant,
- },
- stateProps: state => ({
- tenant: createTenantSelector()(state),
- }),
-});
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 30e7087762..0000000000
--- a/templates/app/react-native/src/components/ValidationMessage/ValidationMessage.js
+++ /dev/null
@@ -1,18 +0,0 @@
-import i18n from 'i18n-js';
-import { connectStyle } from 'native-base';
-import React, { forwardRef } from 'react';
-import { Text } from 'react-native';
-
-const ValidationMessage = ({ children, ...props }) =>
- children ? {i18n.t(children)} : null;
-
-const styles = {
- fontSize: 12,
- marginHorizontal: 10,
- marginTop: -5,
- color: '#ed2f2f',
-};
-
-const Forwarded = forwardRef((props, ref) => );
-
-export default connectStyle('ABP.ValidationMessage', styles)(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 6060dca2b3..0000000000
--- a/templates/app/react-native/src/interceptors/APIInterceptor.js
+++ /dev/null
@@ -1,102 +0,0 @@
-import { Toast } from 'native-base';
-import i18n from 'i18n-js';
-import api from '../api/API';
-import PersistentStorageActions from '../store/actions/PersistentStorageActions';
-import LoadingActions from '../store/actions/LoadingActions';
-
-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({
- text: 'An unexpected error has occurred',
- buttonText: 'x',
- duration: 10000,
- type: 'danger',
- textStyle: { textAlign: 'center' },
- });
- }
-
- 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({
- text: `${title}\n${message}`,
- buttonText: 'x',
- duration: 10000,
- type: 'danger',
- textStyle: { textAlign: 'center' },
- });
-}
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 b6b06d11b5..0000000000
--- a/templates/app/react-native/src/navigators/AuthNavigator.js
+++ /dev/null
@@ -1,22 +0,0 @@
-import { createStackNavigator } from '@react-navigation/stack';
-import React from 'react';
-import { LocalizationContext } from '../contexts/LocalizationContext';
-import LoginScreen from '../screens/Login/LoginScreen';
-
-const Stack = createStackNavigator();
-
-export default function AuthStackNavigator() {
- const { t } = React.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 9b0fde4afc..0000000000
--- a/templates/app/react-native/src/navigators/DrawerNavigator.js
+++ /dev/null
@@ -1,20 +0,0 @@
-import React from 'react';
-import { createDrawerNavigator } from '@react-navigation/drawer';
-import HomeStackNavigator from './HomeNavigator';
-import SettingsStackNavigator from './SettingsNavigator';
-import UsersStackNavigator from './UsersNavigator';
-import TenantsStackNavigator from './TenantsNavigator';
-import DrawerContent from '../components/DrawerContent/DrawerContent';
-
-const Drawer = createDrawerNavigator();
-
-export default function DrawerNavigator() {
- return (
-
-
-
-
-
-
- );
-}
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 7ba440f510..0000000000
--- a/templates/app/react-native/src/navigators/HomeNavigator.js
+++ /dev/null
@@ -1,24 +0,0 @@
-import React from 'react';
-import { createStackNavigator } from '@react-navigation/stack';
-import HomeScreen from '../screens/Home/HomeScreen';
-import MenuIcon from '../components/MenuIcon/MenuIcon';
-import { LocalizationContext } from '../contexts/LocalizationContext';
-
-const Stack = createStackNavigator();
-
-export default function HomeStackNavigator() {
- const { t } = React.useContext(LocalizationContext);
-
- return (
-
- ({
- headerLeft: () => navigation.openDrawer()} />,
- title: t('::Menu:Home'),
- })}
- />
-
- );
-}
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 84d3220473..0000000000
--- a/templates/app/react-native/src/navigators/SettingsNavigator.js
+++ /dev/null
@@ -1,41 +0,0 @@
-import React from 'react';
-import { createStackNavigator } from '@react-navigation/stack';
-import i18n from 'i18n-js';
-import SettingsScreen from '../screens/Settings/SettingsScreen';
-import ChangePasswordScreen from '../screens/ChangePassword/ChangePasswordScreen';
-import ManageProfileScreen from '../screens/ManageProfile/ManageProfileScreen';
-import MenuIcon from '../components/MenuIcon/MenuIcon';
-import { LocalizationContext } from '../contexts/LocalizationContext';
-
-const Stack = createStackNavigator();
-
-export default function SettingsStackNavigator() {
- const { t } = React.useContext(LocalizationContext);
-
- return (
-
- ({
- headerLeft: () => navigation.openDrawer()} />,
- 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 7e38b82674..0000000000
--- a/templates/app/react-native/src/navigators/TenantsNavigator.js
+++ /dev/null
@@ -1,34 +0,0 @@
-import React from 'react';
-import { createStackNavigator } from '@react-navigation/stack';
-import TenantsScreen from '../screens/Tenants/TenantsScreen';
-import CreateUpdateTenantScreen from '../screens/CreateUpdateTenant/CreateUpdateTenantScreen';
-import MenuIcon from '../components/MenuIcon/MenuIcon';
-import { LocalizationContext } from '../contexts/LocalizationContext';
-
-const Stack = createStackNavigator();
-
-export default function TenantsStackNavigator() {
- const { t } = React.useContext(LocalizationContext);
-
- return (
-
- ({
- headerLeft: () => navigation.openDrawer()} />,
- title: t('AbpTenantManagement::Tenants'),
- })}
- />
- ({
- 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 222dfe1550..0000000000
--- a/templates/app/react-native/src/navigators/UsersNavigator.js
+++ /dev/null
@@ -1,32 +0,0 @@
-import React from 'react';
-import { createStackNavigator } from '@react-navigation/stack';
-import UsersScreen from '../screens/Users/UsersScreen';
-import CreateUpdateUserScreen from '../screens/CreateUpdateUser/CreateUpdateUserScreen';
-import MenuIcon from '../components/MenuIcon/MenuIcon';
-import { LocalizationContext } from '../contexts/LocalizationContext';
-
-const Stack = createStackNavigator();
-
-export default function UsersStackNavigator() {
- const { t } = React.useContext(LocalizationContext);
-
- return (
-
- ({
- headerLeft: () => navigation.openDrawer()} />,
- title: t('AbpIdentity::Users'),
- })}
- />
- ({
- 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 03c988c8bf..0000000000
--- a/templates/app/react-native/src/screens/ChangePassword/ChangePasswordForm.js
+++ /dev/null
@@ -1,99 +0,0 @@
-import { Formik } from 'formik';
-import i18n from 'i18n-js';
-import { Container, Content, Form, Input, InputGroup, Item, Icon, Label } from 'native-base';
-import PropTypes from 'prop-types';
-import React, { useRef, useState } from 'react';
-import * as Yup from 'yup';
-import FormButtons from '../../components/FormButtons/FormButtons';
-import ValidationMessage from '../../components/ValidationMessage/ValidationMessage';
-
-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,
- });
- };
-
- return (
- onSubmit(values)}>
- {({ handleChange, handleBlur, handleSubmit, values, errors, isValid }) => (
- <>
-
-
-
-
-
-
- >
- )}
-
- );
-}
-
-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 ff5801f914..0000000000
--- a/templates/app/react-native/src/screens/CreateUpdateTenant/CreateUpdateTenantForm.js
+++ /dev/null
@@ -1,84 +0,0 @@
-import { Formik } from 'formik';
-import i18n from 'i18n-js';
-import { Container, Content, Input, InputGroup, Label } from 'native-base';
-import PropTypes from 'prop-types';
-import React, { useRef } from 'react';
-import { StyleSheet } from 'react-native';
-import * as Yup from 'yup';
-import FormButtons from '../../components/FormButtons/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 hasRemovePermission = usePermission('AbpTenantManagement.Tenants.Delete');
-
- const onSubmit = values => {
- submit({
- ...editingTenant,
- ...values,
- });
- };
-
- return (
- onSubmit(values)}>
- {({ handleChange, handleBlur, handleSubmit, values, errors, isValid }) => (
- <>
-
-
-
-
-
-
- {errors.name}
-
-
-
- >
- )}
-
- );
-}
-
-CreateUpdateTenantForm.propTypes = {
- editingTenant: PropTypes.object,
- submit: PropTypes.func.isRequired,
- remove: PropTypes.func.isRequired,
-};
-
-const styles = StyleSheet.create({
- container: {
- marginBottom: 50,
- },
-});
-
-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 eacbb98a2c..0000000000
--- a/templates/app/react-native/src/screens/CreateUpdateTenant/CreateUpdateTenantScreen.js
+++ /dev/null
@@ -1,77 +0,0 @@
-import PropTypes from 'prop-types';
-import React, { useState, useCallback } from 'react';
-import { useFocusEffect } from '@react-navigation/native';
-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 6757801c38..0000000000
--- a/templates/app/react-native/src/screens/CreateUpdateUser/CreateUpdateUserForm.js
+++ /dev/null
@@ -1,242 +0,0 @@
-import { Formik } from 'formik';
-import i18n from 'i18n-js';
-import {
- Body,
- Button,
- CheckBox,
- Container,
- Content,
- Input,
- InputGroup,
- Item,
- Icon,
- Label,
- ListItem,
- Segment,
- Text,
-} from 'native-base';
-import PropTypes from 'prop-types';
-import React, { useRef, useState } from 'react';
-import { StyleSheet, TouchableOpacity, View } from 'react-native';
-import * as Yup from 'yup';
-import FormButtons from '../../components/FormButtons/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.');
- });
-
- return (
- onSubmit(values)}>
- {({ handleChange, handleBlur, handleSubmit, values, errors, isValid, setFieldValue }) => (
- <>
-
-
-
-
-
-
-
-
-
-
- nameRef.current._root.focus()}
- returnKeyType="next"
- onChangeText={handleChange('userName')}
- onBlur={handleBlur('userName')}
- value={values.userName}
- />
-
- {errors.userName}
-
-
- surnameRef.current._root.focus()}
- returnKeyType="next"
- onChangeText={handleChange('name')}
- onBlur={handleBlur('name')}
- value={values.name}
- />
-
-
-
- emailRef.current._root.focus()}
- returnKeyType="next"
- onChangeText={handleChange('surname')}
- onBlur={handleBlur('surname')}
- value={values.surname}
- />
-
-
-
- phoneNumberRef.current._root.focus()}
- returnKeyType="next"
- onChangeText={handleChange('email')}
- onBlur={handleBlur('email')}
- value={values.email}
- />
-
- {errors.email}
-
-
-
-
- {!editingUser.id ? (
- <>
-
-
- -
-
- setShowPassword(!showPassword)}
- />
-
-
- {errors.password}
- >
- ) : null}
-
- setFieldValue('lockoutEnabled', !values.lockoutEnabled)}
- />
-
- setFieldValue('lockoutEnabled', !values.lockoutEnabled)}>
- {i18n.t('AbpIdentity::DisplayName:LockoutEnabled')}
-
-
-
-
- setFieldValue('twoFactorEnabled', !values.twoFactorEnabled)}
- />
-
- setFieldValue('twoFactorEnabled', !values.twoFactorEnabled)}>
- {i18n.t('AbpIdentity::DisplayName:TwoFactorEnabled')}
-
-
-
-
-
-
-
-
-
-
- >
- )}
-
- );
-}
-
-CreateUpdateUserForm.propTypes = {
- editingUser: PropTypes.object,
- submit: PropTypes.func.isRequired,
- remove: PropTypes.func.isRequired,
-};
-
-const styles = StyleSheet.create({
- container: {
- marginBottom: 50,
- },
-});
-
-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 9e7b45ebf0..0000000000
--- a/templates/app/react-native/src/screens/CreateUpdateUser/UserRoles.js
+++ /dev/null
@@ -1,60 +0,0 @@
-import React, { useEffect, useState } from 'react';
-import PropTypes from 'prop-types';
-import { List, ListItem, CheckBox, Body, Text } from 'native-base';
-import { TouchableOpacity } from 'react-native';
-import { getRoles, 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 = [getRoles()];
- 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)} />
-
- 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 63140d9a8a..0000000000
--- a/templates/app/react-native/src/screens/Home/HomeScreen.js
+++ /dev/null
@@ -1,34 +0,0 @@
-import i18n from 'i18n-js';
-import { Text } from 'native-base';
-import React from 'react';
-import { StyleSheet, View } from 'react-native';
-
-function HomeScreen() {
- return (
-
- {i18n.t('::Welcome')}
- {i18n.t('::LongWelcomeMessage')}
-
- );
-}
-
-const styles = StyleSheet.create({
- container: {
- flex: 1,
- alignItems: 'center',
- justifyContent: 'center',
- paddingHorizontal: 20,
- backgroundColor: '#fff',
- },
- centeredText: {
- textAlign: 'center',
- },
- title: {
- marginBottom: 30,
- fontSize: 32,
- fontWeight: '300',
- textAlign: 'center',
- },
-});
-
-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 9a010a4484..0000000000
--- a/templates/app/react-native/src/screens/Login/LoginScreen.js
+++ /dev/null
@@ -1,128 +0,0 @@
-import { Formik } from 'formik';
-import i18n from 'i18n-js';
-import {
- Button,
- Container,
- Content,
- Form,
- Input,
- InputGroup,
- Item,
- Label,
- Text,
- Icon,
-} from 'native-base';
-import PropTypes from 'prop-types';
-import React, { useState } from 'react';
-import { View } from 'react-native';
-import * as Yup 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 = Yup.object().shape({
- username: Yup.string().required('AbpAccount::ThisFieldIsRequired.'),
- password: Yup.string().required('AbpAccount::ThisFieldIsRequired.'),
-});
-
-function LoginScreen({ startLoading, stopLoading, setToken, fetchAppConfig }) {
- const [showTenantSelection, setShowTenantSelection] = useState(false);
- const [showPassword, setShowPassword] = useState(false);
-
- 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' }));
- };
-
- return (
-
-
- {!showTenantSelection ? (
-
-
- {({ handleChange, handleBlur, handleSubmit, values, errors }) => (
-
- )}
-
-
- ) : null}
-
- );
-}
-
-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 9135df2ade..0000000000
--- a/templates/app/react-native/src/screens/ManageProfile/ManageProfileForm.js
+++ /dev/null
@@ -1,122 +0,0 @@
-import { Formik } from 'formik';
-import i18n from 'i18n-js';
-import { Container, Content, Form, Input, InputGroup, Label } 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,
- });
- };
-
- return (
- onSubmit(values)}>
- {({ handleChange, handleBlur, handleSubmit, values, errors, isValid }) => (
- <>
-
-
-
-
-
-
- >
- )}
-
- );
-}
-
-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 80fc93e0b4..0000000000
--- a/templates/app/react-native/src/screens/Settings/SettingsScreen.js
+++ /dev/null
@@ -1,145 +0,0 @@
-import i18n from 'i18n-js';
-import {
- Body,
- Button,
- Icon,
- Label,
- Left,
- List,
- ListItem,
- Picker,
- Right,
- Text,
- Thumbnail,
-} from 'native-base';
-import PropTypes from 'prop-types';
-import React, { useCallback, useState } from 'react';
-import { View } from 'react-native';
-import { useFocusEffect } from '@react-navigation/native';
-import { getProfileDetail } from '../../api/IdentityAPI';
-import AppActions from '../../store/actions/AppActions';
-import {
- createLanguageSelector,
- createLanguagesSelector,
-} from '../../store/selectors/AppSelectors';
-import { connectToRedux } from '../../utils/ReduxConnect';
-import { createTenantSelector } from '../../store/selectors/PersistentStorageSelectors';
-
-function SettingsScreen({
- navigation,
- language,
- languages,
- setLanguageAsync,
- logoutAsync,
- tenant = {},
-}) {
- const [user, setUser] = useState({});
-
- const fetchUser = () => {
- getProfileDetail().then(data => {
- setUser(data || {});
- });
- };
-
- useFocusEffect(
- useCallback(() => {
- fetchUser();
- }, []),
- );
-
- return (
-
-
-
- navigation.navigate('ManageProfile')}>
-
-
-
-
- {tenant.name ? `${tenant.name} / ` : ''}
- {user.userName ? `${user.userName}` : ''}
-
- {user.email}
-
-
-
-
-
-
-
-
- navigation.navigate('ChangePassword')}>
-
- {i18n.t('AbpUi::ChangePassword')}
-
-
-
-
-
-
-
-
-
-
-
- }
- onValueChange={value => setLanguageAsync(value)}
- selectedValue={language.cultureName}
- textStyle={{ paddingLeft: 0 }}>
- {languages.map(lang => (
-
- ))}
-
-
-
-
-
-
-
- );
-}
-
-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 e937175dfa..0000000000
--- a/templates/app/react-native/src/screens/Tenants/TenantsScreen.js
+++ /dev/null
@@ -1,59 +0,0 @@
-import React from 'react';
-import i18n from 'i18n-js';
-import { ListItem, Text, Icon, Left, Body, Fab } from 'native-base';
-import { StyleSheet } from 'react-native';
-import { getTenants } from '../../api/TenantManagementAPI';
-import { activeTheme } from '../../theme/variables';
-import DataList from '../../components/DataList/DataList';
-import { withPermission } from '../../hocs/PermissionHOC';
-
-const CreateTenantButtonWithPermission = withPermission(Fab, 'AbpTenantManagement.Tenants.Create');
-
-function TenantsScreen({ navigation }) {
- return (
- <>
-