Sign Up
parent
10ac84df72
commit
8b7f244812
|
@ -311,3 +311,9 @@ def isNewArchitectureEnabled() {
|
|||
// - Set an environment variable `ORG_GRADLE_PROJECT_newArchEnabled=true`
|
||||
return project.hasProperty("newArchEnabled") && project.newArchEnabled == "true"
|
||||
}
|
||||
|
||||
project.ext.vectoricons = [
|
||||
iconFontNames: [ 'MaterialIcons.ttf', 'MaterialCommunityIcons.ttf', 'FontAwesome.ttf', 'Ionicons.ttf' ] // Name of the font files you want to copy
|
||||
]
|
||||
|
||||
apply from: "../../node_modules/react-native-vector-icons/fonts.gradle"
|
|
@ -3,13 +3,87 @@ import {AppRegistry} from 'react-native';
|
|||
|
||||
import App from './src/App';
|
||||
|
||||
//AppRegistry.registerComponent("App", () => App)
|
||||
// @ts-ignore
|
||||
import outfitFont from './web/public/fonts/Outfit.ttf';
|
||||
// @ts-ignore
|
||||
import FontAwesome from 'react-native-vector-icons/Fonts/FontAwesome.ttf';
|
||||
// @ts-ignore
|
||||
import MaterialIcons from 'react-native-vector-icons/Fonts/MaterialIcons.ttf';
|
||||
// @ts-ignore
|
||||
import Ionicons from 'react-native-vector-icons/Fonts/Ionicons.ttf';
|
||||
// @ts-ignore
|
||||
import MaterialCommunityIcons from 'react-native-vector-icons/Fonts/MaterialCommunityIcons.ttf';
|
||||
|
||||
/*
|
||||
AppRegistry.runApplication("App", {
|
||||
initialProps: {},
|
||||
rootTag: document.getElementById("root"),
|
||||
})*/
|
||||
const iconFontStyles = `@font-face {
|
||||
src: url(${MaterialCommunityIcons});
|
||||
font-family: MaterialCommunityIcons;
|
||||
}
|
||||
@font-face {
|
||||
src: url(${FontAwesome});
|
||||
font-family: FontAwesome;
|
||||
}
|
||||
@font-face {
|
||||
src: url(${MaterialIcons});
|
||||
font-family: MaterialIcons;
|
||||
}
|
||||
@font-face {
|
||||
src: url(${Ionicons});
|
||||
font-family: Ionicons;
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'Outfit-Thin';
|
||||
src: url(${outfitFont});
|
||||
font-weight: 100;
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'Outfit-ExtraLight';
|
||||
src: url(${outfitFont});
|
||||
font-weight: 200;
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'Outfit-Light';
|
||||
src: url(${outfitFont});
|
||||
font-weight: 300;
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'Outfit-Regular';
|
||||
src: url(${outfitFont});
|
||||
font-weight: 400;
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'Outfit-Medium';
|
||||
src: url(${outfitFont});
|
||||
font-weight: 500;
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'Outfit-SemiBold';
|
||||
src: url(${outfitFont});
|
||||
font-weight: 600;
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'Outfit-Bold';
|
||||
src: url(${outfitFont});
|
||||
font-weight: 700;
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'Outfit-ExtraBold';
|
||||
src: url(${outfitFont});
|
||||
font-weight: 800;
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'Outfit-Black';
|
||||
src: url(${outfitFont});
|
||||
font-weight: 900;
|
||||
}
|
||||
|
||||
`;
|
||||
|
||||
const style = document.createElement('style');
|
||||
style.type = 'text/css';
|
||||
|
||||
style.appendChild(document.createTextNode(iconFontStyles));
|
||||
|
||||
document.head.appendChild(style);
|
||||
|
||||
const root = createRoot(document.getElementById('root') as HTMLElement);
|
||||
root.render(<App />);
|
||||
|
|
|
@ -8,12 +8,14 @@
|
|||
"name": "ClickAndJoinApp",
|
||||
"version": "0.0.1",
|
||||
"dependencies": {
|
||||
"@react-native-masked-view/masked-view": "^0.2.8",
|
||||
"@react-navigation/bottom-tabs": "^6.5.2",
|
||||
"@react-navigation/native": "^6.1.1",
|
||||
"@react-navigation/native-stack": "^6.9.7",
|
||||
"@react-spring/native": "^9.6.1",
|
||||
"@react-spring/web": "^9.6.1",
|
||||
"@reduxjs/toolkit": "^1.9.1",
|
||||
"@types/react-native-vector-icons": "^6.4.12",
|
||||
"babel-preset-es2015": "^6.24.1",
|
||||
"babel-preset-esnext": "^1.1.3",
|
||||
"babel-preset-react": "^6.24.1",
|
||||
|
@ -26,8 +28,12 @@
|
|||
"react-native-reanimated": "^2.13.0",
|
||||
"react-native-safe-area-context": "^4.4.1",
|
||||
"react-native-screens": "^3.18.2",
|
||||
"react-native-svg": "^13.6.0",
|
||||
"react-native-user-agent": "^2.3.1",
|
||||
"react-native-vector-icons": "^9.2.0",
|
||||
"react-native-web": "^0.18.10",
|
||||
"react-redux": "^8.0.5"
|
||||
"react-redux": "^8.0.5",
|
||||
"react-string-replace": "^1.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.12.9",
|
||||
|
@ -4964,6 +4970,15 @@
|
|||
"integrity": "sha512-+zDZ20NUnSWghj7Ku5aFphMzuM9JulqCW+aPXT6IfIXFbb8tzYTTOSeRFOtuekJ99ibW2fUCSsjuKNlwDIbHFg==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@react-native-masked-view/masked-view": {
|
||||
"version": "0.2.8",
|
||||
"resolved": "https://registry.npmjs.org/@react-native-masked-view/masked-view/-/masked-view-0.2.8.tgz",
|
||||
"integrity": "sha512-+1holBPDF1yi/y0uc1WB6lA5tSNHhM7PpTMapT3ypvSnKQ9+C6sy/zfjxNxRA/llBQ1Ci6f94EaK56UCKs5lTA==",
|
||||
"peerDependencies": {
|
||||
"react": ">=16",
|
||||
"react-native": ">=0.57"
|
||||
}
|
||||
},
|
||||
"node_modules/@react-native/assets": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@react-native/assets/-/assets-1.0.0.tgz",
|
||||
|
@ -5906,11 +5921,19 @@
|
|||
"version": "0.70.7",
|
||||
"resolved": "https://registry.npmjs.org/@types/react-native/-/react-native-0.70.7.tgz",
|
||||
"integrity": "sha512-hBzeUWwk8sfj3vDfwEXb4hbjWjl0jb5CvWlu2gLrOUJyFHVzJ+x6Y9ilO2eVtJW7l5QmmNLILE1PkVfKRkqYuQ==",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@types/react": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/react-native-vector-icons": {
|
||||
"version": "6.4.12",
|
||||
"resolved": "https://registry.npmjs.org/@types/react-native-vector-icons/-/react-native-vector-icons-6.4.12.tgz",
|
||||
"integrity": "sha512-gSXtv3NMOsRwSXJ/gvGebm7CNjHbkeFKCse9h/Pvi+x2yjCLOkJR1FBfec06DhaFJpsK7Y8WRQpwOS0eLqx5Rg==",
|
||||
"dependencies": {
|
||||
"@types/react": "*",
|
||||
"@types/react-native": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/retry": {
|
||||
"version": "0.12.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.0.tgz",
|
||||
|
@ -8154,8 +8177,7 @@
|
|||
"node_modules/boolbase": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz",
|
||||
"integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==",
|
||||
"peer": true
|
||||
"integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww=="
|
||||
},
|
||||
"node_modules/brace-expansion": {
|
||||
"version": "1.1.11",
|
||||
|
@ -8955,7 +8977,6 @@
|
|||
"version": "5.1.0",
|
||||
"resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz",
|
||||
"integrity": "sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"boolbase": "^1.0.0",
|
||||
"css-what": "^6.1.0",
|
||||
|
@ -8971,7 +8992,6 @@
|
|||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.1.3.tgz",
|
||||
"integrity": "sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"mdn-data": "2.0.14",
|
||||
"source-map": "^0.6.1"
|
||||
|
@ -8984,7 +9004,6 @@
|
|||
"version": "6.1.0",
|
||||
"resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz",
|
||||
"integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">= 6"
|
||||
},
|
||||
|
@ -9304,7 +9323,6 @@
|
|||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz",
|
||||
"integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"domelementtype": "^2.3.0",
|
||||
"domhandler": "^5.0.2",
|
||||
|
@ -9329,8 +9347,7 @@
|
|||
"type": "github",
|
||||
"url": "https://github.com/sponsors/fb55"
|
||||
}
|
||||
],
|
||||
"peer": true
|
||||
]
|
||||
},
|
||||
"node_modules/domexception": {
|
||||
"version": "2.0.1",
|
||||
|
@ -9357,7 +9374,6 @@
|
|||
"version": "5.0.3",
|
||||
"resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz",
|
||||
"integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"domelementtype": "^2.3.0"
|
||||
},
|
||||
|
@ -9372,7 +9388,6 @@
|
|||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/domutils/-/domutils-3.0.1.tgz",
|
||||
"integrity": "sha512-z08c1l761iKhDFtfXO04C7kTdPBLi41zwOZl00WS8b5eiaebNpY00HKbztwBq+e3vyqWNwWF3mP9YLUeqIrF+Q==",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"dom-serializer": "^2.0.0",
|
||||
"domelementtype": "^2.3.0",
|
||||
|
@ -9463,7 +9478,6 @@
|
|||
"version": "4.4.0",
|
||||
"resolved": "https://registry.npmjs.org/entities/-/entities-4.4.0.tgz",
|
||||
"integrity": "sha512-oYp7156SP8LkeGD0GF85ad1X9Ai79WtRsZ2gxJqtBuzH+98YUV6jkHEKlZkMbcrjJjIVJNIDP/3WL9wQkoPbWA==",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=0.12"
|
||||
},
|
||||
|
@ -14123,9 +14137,9 @@
|
|||
"dev": true
|
||||
},
|
||||
"node_modules/json5": {
|
||||
"version": "2.2.1",
|
||||
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz",
|
||||
"integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==",
|
||||
"version": "2.2.2",
|
||||
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.2.tgz",
|
||||
"integrity": "sha512-46Tk9JiOL2z7ytNQWFLpj99RZkVgeHf87yGQKsIkaPz1qSH9UczKH1rO7K3wgRselo0tYMUNfecYpm/p1vC7tQ==",
|
||||
"bin": {
|
||||
"json5": "lib/cli.js"
|
||||
},
|
||||
|
@ -14481,8 +14495,7 @@
|
|||
"node_modules/mdn-data": {
|
||||
"version": "2.0.14",
|
||||
"resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz",
|
||||
"integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==",
|
||||
"peer": true
|
||||
"integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow=="
|
||||
},
|
||||
"node_modules/media-typer": {
|
||||
"version": "0.3.0",
|
||||
|
@ -15730,7 +15743,6 @@
|
|||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz",
|
||||
"integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"boolbase": "^1.0.0"
|
||||
},
|
||||
|
@ -16849,7 +16861,6 @@
|
|||
"version": "13.6.0",
|
||||
"resolved": "https://registry.npmjs.org/react-native-svg/-/react-native-svg-13.6.0.tgz",
|
||||
"integrity": "sha512-1wjHCMJ8siyZbDZ0MX5wM+Jr7YOkb6GADn4/Z+/u1UwJX8WfjarypxDF3UO1ugMHa+7qor39oY+URMcrgPpiww==",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"css-select": "^5.1.0",
|
||||
"css-tree": "^1.1.3"
|
||||
|
@ -16859,6 +16870,116 @@
|
|||
"react-native": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/react-native-user-agent": {
|
||||
"version": "2.3.1",
|
||||
"resolved": "https://registry.npmjs.org/react-native-user-agent/-/react-native-user-agent-2.3.1.tgz",
|
||||
"integrity": "sha512-AIFr1VgJHwgWmMwCOmIGxuBeAaADlouXKc10UyR4fzWneUbt5uIJIoRu2oExlfCtiT8IyCp106khDD5vx7RUjw==",
|
||||
"peerDependencies": {
|
||||
"react-native": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/react-native-vector-icons": {
|
||||
"version": "9.2.0",
|
||||
"resolved": "https://registry.npmjs.org/react-native-vector-icons/-/react-native-vector-icons-9.2.0.tgz",
|
||||
"integrity": "sha512-wKYLaFuQST/chH3AJRjmOLoLy3JEs1JR6zMNgTaemFpNoXs0ztRnTxcxFD9xhX7cJe1/zoN5BpQYe7kL0m5yyA==",
|
||||
"dependencies": {
|
||||
"prop-types": "^15.7.2",
|
||||
"yargs": "^16.1.1"
|
||||
},
|
||||
"bin": {
|
||||
"fa5-upgrade": "bin/fa5-upgrade.sh",
|
||||
"generate-icon": "bin/generate-icon.js"
|
||||
}
|
||||
},
|
||||
"node_modules/react-native-vector-icons/node_modules/ansi-styles": {
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
|
||||
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
|
||||
"dependencies": {
|
||||
"color-convert": "^2.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/react-native-vector-icons/node_modules/cliui": {
|
||||
"version": "7.0.4",
|
||||
"resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz",
|
||||
"integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==",
|
||||
"dependencies": {
|
||||
"string-width": "^4.2.0",
|
||||
"strip-ansi": "^6.0.0",
|
||||
"wrap-ansi": "^7.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/react-native-vector-icons/node_modules/color-convert": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
|
||||
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
|
||||
"dependencies": {
|
||||
"color-name": "~1.1.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=7.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/react-native-vector-icons/node_modules/color-name": {
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
|
||||
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
|
||||
},
|
||||
"node_modules/react-native-vector-icons/node_modules/wrap-ansi": {
|
||||
"version": "7.0.0",
|
||||
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
|
||||
"integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
|
||||
"dependencies": {
|
||||
"ansi-styles": "^4.0.0",
|
||||
"string-width": "^4.1.0",
|
||||
"strip-ansi": "^6.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/chalk/wrap-ansi?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/react-native-vector-icons/node_modules/y18n": {
|
||||
"version": "5.0.8",
|
||||
"resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
|
||||
"integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==",
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/react-native-vector-icons/node_modules/yargs": {
|
||||
"version": "16.2.0",
|
||||
"resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz",
|
||||
"integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==",
|
||||
"dependencies": {
|
||||
"cliui": "^7.0.2",
|
||||
"escalade": "^3.1.1",
|
||||
"get-caller-file": "^2.0.5",
|
||||
"require-directory": "^2.1.1",
|
||||
"string-width": "^4.2.0",
|
||||
"y18n": "^5.0.5",
|
||||
"yargs-parser": "^20.2.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/react-native-vector-icons/node_modules/yargs-parser": {
|
||||
"version": "20.2.9",
|
||||
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz",
|
||||
"integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==",
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/react-native-web": {
|
||||
"version": "0.18.10",
|
||||
"resolved": "https://registry.npmjs.org/react-native-web/-/react-native-web-0.18.10.tgz",
|
||||
|
@ -16958,6 +17079,14 @@
|
|||
"react": "^16.0.0 || ^17.0.0 || ^18.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/react-string-replace": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/react-string-replace/-/react-string-replace-1.1.0.tgz",
|
||||
"integrity": "sha512-N6RalSDFGbOHs0IJi1H611WbZsvk3ZT47Jl2JEXFbiS3kTwsdCYij70Keo/tWtLy7sfhDsYm7CwNM/WmjXIaMw==",
|
||||
"engines": {
|
||||
"node": ">=0.12.0"
|
||||
}
|
||||
},
|
||||
"node_modules/react-test-renderer": {
|
||||
"version": "18.1.0",
|
||||
"resolved": "https://registry.npmjs.org/react-test-renderer/-/react-test-renderer-18.1.0.tgz",
|
||||
|
@ -24109,6 +24238,12 @@
|
|||
"integrity": "sha512-+zDZ20NUnSWghj7Ku5aFphMzuM9JulqCW+aPXT6IfIXFbb8tzYTTOSeRFOtuekJ99ibW2fUCSsjuKNlwDIbHFg==",
|
||||
"dev": true
|
||||
},
|
||||
"@react-native-masked-view/masked-view": {
|
||||
"version": "0.2.8",
|
||||
"resolved": "https://registry.npmjs.org/@react-native-masked-view/masked-view/-/masked-view-0.2.8.tgz",
|
||||
"integrity": "sha512-+1holBPDF1yi/y0uc1WB6lA5tSNHhM7PpTMapT3ypvSnKQ9+C6sy/zfjxNxRA/llBQ1Ci6f94EaK56UCKs5lTA==",
|
||||
"requires": {}
|
||||
},
|
||||
"@react-native/assets": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@react-native/assets/-/assets-1.0.0.tgz",
|
||||
|
@ -24892,11 +25027,19 @@
|
|||
"version": "0.70.7",
|
||||
"resolved": "https://registry.npmjs.org/@types/react-native/-/react-native-0.70.7.tgz",
|
||||
"integrity": "sha512-hBzeUWwk8sfj3vDfwEXb4hbjWjl0jb5CvWlu2gLrOUJyFHVzJ+x6Y9ilO2eVtJW7l5QmmNLILE1PkVfKRkqYuQ==",
|
||||
"peer": true,
|
||||
"requires": {
|
||||
"@types/react": "*"
|
||||
}
|
||||
},
|
||||
"@types/react-native-vector-icons": {
|
||||
"version": "6.4.12",
|
||||
"resolved": "https://registry.npmjs.org/@types/react-native-vector-icons/-/react-native-vector-icons-6.4.12.tgz",
|
||||
"integrity": "sha512-gSXtv3NMOsRwSXJ/gvGebm7CNjHbkeFKCse9h/Pvi+x2yjCLOkJR1FBfec06DhaFJpsK7Y8WRQpwOS0eLqx5Rg==",
|
||||
"requires": {
|
||||
"@types/react": "*",
|
||||
"@types/react-native": "*"
|
||||
}
|
||||
},
|
||||
"@types/retry": {
|
||||
"version": "0.12.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.0.tgz",
|
||||
|
@ -26820,8 +26963,7 @@
|
|||
"boolbase": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz",
|
||||
"integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==",
|
||||
"peer": true
|
||||
"integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww=="
|
||||
},
|
||||
"brace-expansion": {
|
||||
"version": "1.1.11",
|
||||
|
@ -27432,7 +27574,6 @@
|
|||
"version": "5.1.0",
|
||||
"resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz",
|
||||
"integrity": "sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==",
|
||||
"peer": true,
|
||||
"requires": {
|
||||
"boolbase": "^1.0.0",
|
||||
"css-what": "^6.1.0",
|
||||
|
@ -27445,7 +27586,6 @@
|
|||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.1.3.tgz",
|
||||
"integrity": "sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==",
|
||||
"peer": true,
|
||||
"requires": {
|
||||
"mdn-data": "2.0.14",
|
||||
"source-map": "^0.6.1"
|
||||
|
@ -27454,8 +27594,7 @@
|
|||
"css-what": {
|
||||
"version": "6.1.0",
|
||||
"resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz",
|
||||
"integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==",
|
||||
"peer": true
|
||||
"integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw=="
|
||||
},
|
||||
"cssom": {
|
||||
"version": "0.4.4",
|
||||
|
@ -27692,7 +27831,6 @@
|
|||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz",
|
||||
"integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==",
|
||||
"peer": true,
|
||||
"requires": {
|
||||
"domelementtype": "^2.3.0",
|
||||
"domhandler": "^5.0.2",
|
||||
|
@ -27708,8 +27846,7 @@
|
|||
"domelementtype": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz",
|
||||
"integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==",
|
||||
"peer": true
|
||||
"integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw=="
|
||||
},
|
||||
"domexception": {
|
||||
"version": "2.0.1",
|
||||
|
@ -27732,7 +27869,6 @@
|
|||
"version": "5.0.3",
|
||||
"resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz",
|
||||
"integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==",
|
||||
"peer": true,
|
||||
"requires": {
|
||||
"domelementtype": "^2.3.0"
|
||||
}
|
||||
|
@ -27741,7 +27877,6 @@
|
|||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/domutils/-/domutils-3.0.1.tgz",
|
||||
"integrity": "sha512-z08c1l761iKhDFtfXO04C7kTdPBLi41zwOZl00WS8b5eiaebNpY00HKbztwBq+e3vyqWNwWF3mP9YLUeqIrF+Q==",
|
||||
"peer": true,
|
||||
"requires": {
|
||||
"dom-serializer": "^2.0.0",
|
||||
"domelementtype": "^2.3.0",
|
||||
|
@ -27810,8 +27945,7 @@
|
|||
"entities": {
|
||||
"version": "4.4.0",
|
||||
"resolved": "https://registry.npmjs.org/entities/-/entities-4.4.0.tgz",
|
||||
"integrity": "sha512-oYp7156SP8LkeGD0GF85ad1X9Ai79WtRsZ2gxJqtBuzH+98YUV6jkHEKlZkMbcrjJjIVJNIDP/3WL9wQkoPbWA==",
|
||||
"peer": true
|
||||
"integrity": "sha512-oYp7156SP8LkeGD0GF85ad1X9Ai79WtRsZ2gxJqtBuzH+98YUV6jkHEKlZkMbcrjJjIVJNIDP/3WL9wQkoPbWA=="
|
||||
},
|
||||
"envinfo": {
|
||||
"version": "7.8.1",
|
||||
|
@ -31309,9 +31443,9 @@
|
|||
"dev": true
|
||||
},
|
||||
"json5": {
|
||||
"version": "2.2.1",
|
||||
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz",
|
||||
"integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA=="
|
||||
"version": "2.2.2",
|
||||
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.2.tgz",
|
||||
"integrity": "sha512-46Tk9JiOL2z7ytNQWFLpj99RZkVgeHf87yGQKsIkaPz1qSH9UczKH1rO7K3wgRselo0tYMUNfecYpm/p1vC7tQ=="
|
||||
},
|
||||
"jsonfile": {
|
||||
"version": "4.0.0",
|
||||
|
@ -31591,8 +31725,7 @@
|
|||
"mdn-data": {
|
||||
"version": "2.0.14",
|
||||
"resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz",
|
||||
"integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==",
|
||||
"peer": true
|
||||
"integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow=="
|
||||
},
|
||||
"media-typer": {
|
||||
"version": "0.3.0",
|
||||
|
@ -32625,7 +32758,6 @@
|
|||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz",
|
||||
"integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==",
|
||||
"peer": true,
|
||||
"requires": {
|
||||
"boolbase": "^1.0.0"
|
||||
}
|
||||
|
@ -33473,12 +33605,93 @@
|
|||
"version": "13.6.0",
|
||||
"resolved": "https://registry.npmjs.org/react-native-svg/-/react-native-svg-13.6.0.tgz",
|
||||
"integrity": "sha512-1wjHCMJ8siyZbDZ0MX5wM+Jr7YOkb6GADn4/Z+/u1UwJX8WfjarypxDF3UO1ugMHa+7qor39oY+URMcrgPpiww==",
|
||||
"peer": true,
|
||||
"requires": {
|
||||
"css-select": "^5.1.0",
|
||||
"css-tree": "^1.1.3"
|
||||
}
|
||||
},
|
||||
"react-native-user-agent": {
|
||||
"version": "2.3.1",
|
||||
"resolved": "https://registry.npmjs.org/react-native-user-agent/-/react-native-user-agent-2.3.1.tgz",
|
||||
"integrity": "sha512-AIFr1VgJHwgWmMwCOmIGxuBeAaADlouXKc10UyR4fzWneUbt5uIJIoRu2oExlfCtiT8IyCp106khDD5vx7RUjw==",
|
||||
"requires": {}
|
||||
},
|
||||
"react-native-vector-icons": {
|
||||
"version": "9.2.0",
|
||||
"resolved": "https://registry.npmjs.org/react-native-vector-icons/-/react-native-vector-icons-9.2.0.tgz",
|
||||
"integrity": "sha512-wKYLaFuQST/chH3AJRjmOLoLy3JEs1JR6zMNgTaemFpNoXs0ztRnTxcxFD9xhX7cJe1/zoN5BpQYe7kL0m5yyA==",
|
||||
"requires": {
|
||||
"prop-types": "^15.7.2",
|
||||
"yargs": "^16.1.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"ansi-styles": {
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
|
||||
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
|
||||
"requires": {
|
||||
"color-convert": "^2.0.1"
|
||||
}
|
||||
},
|
||||
"cliui": {
|
||||
"version": "7.0.4",
|
||||
"resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz",
|
||||
"integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==",
|
||||
"requires": {
|
||||
"string-width": "^4.2.0",
|
||||
"strip-ansi": "^6.0.0",
|
||||
"wrap-ansi": "^7.0.0"
|
||||
}
|
||||
},
|
||||
"color-convert": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
|
||||
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
|
||||
"requires": {
|
||||
"color-name": "~1.1.4"
|
||||
}
|
||||
},
|
||||
"color-name": {
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
|
||||
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
|
||||
},
|
||||
"wrap-ansi": {
|
||||
"version": "7.0.0",
|
||||
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
|
||||
"integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
|
||||
"requires": {
|
||||
"ansi-styles": "^4.0.0",
|
||||
"string-width": "^4.1.0",
|
||||
"strip-ansi": "^6.0.0"
|
||||
}
|
||||
},
|
||||
"y18n": {
|
||||
"version": "5.0.8",
|
||||
"resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
|
||||
"integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA=="
|
||||
},
|
||||
"yargs": {
|
||||
"version": "16.2.0",
|
||||
"resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz",
|
||||
"integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==",
|
||||
"requires": {
|
||||
"cliui": "^7.0.2",
|
||||
"escalade": "^3.1.1",
|
||||
"get-caller-file": "^2.0.5",
|
||||
"require-directory": "^2.1.1",
|
||||
"string-width": "^4.2.0",
|
||||
"y18n": "^5.0.5",
|
||||
"yargs-parser": "^20.2.2"
|
||||
}
|
||||
},
|
||||
"yargs-parser": {
|
||||
"version": "20.2.9",
|
||||
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz",
|
||||
"integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"react-native-web": {
|
||||
"version": "0.18.10",
|
||||
"resolved": "https://registry.npmjs.org/react-native-web/-/react-native-web-0.18.10.tgz",
|
||||
|
@ -33537,6 +33750,11 @@
|
|||
"react-is": "^16.12.0 || ^17.0.0 || ^18.0.0"
|
||||
}
|
||||
},
|
||||
"react-string-replace": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/react-string-replace/-/react-string-replace-1.1.0.tgz",
|
||||
"integrity": "sha512-N6RalSDFGbOHs0IJi1H611WbZsvk3ZT47Jl2JEXFbiS3kTwsdCYij70Keo/tWtLy7sfhDsYm7CwNM/WmjXIaMw=="
|
||||
},
|
||||
"react-test-renderer": {
|
||||
"version": "18.1.0",
|
||||
"resolved": "https://registry.npmjs.org/react-test-renderer/-/react-test-renderer-18.1.0.tgz",
|
||||
|
|
10
package.json
10
package.json
|
@ -12,12 +12,14 @@
|
|||
"lint": "eslint ."
|
||||
},
|
||||
"dependencies": {
|
||||
"@react-native-masked-view/masked-view": "^0.2.8",
|
||||
"@react-navigation/bottom-tabs": "^6.5.2",
|
||||
"@react-navigation/native": "^6.1.1",
|
||||
"@react-navigation/native-stack": "^6.9.7",
|
||||
"@react-spring/native": "^9.6.1",
|
||||
"@react-spring/web": "^9.6.1",
|
||||
"@reduxjs/toolkit": "^1.9.1",
|
||||
"@types/react-native-vector-icons": "^6.4.12",
|
||||
"babel-preset-es2015": "^6.24.1",
|
||||
"babel-preset-esnext": "^1.1.3",
|
||||
"babel-preset-react": "^6.24.1",
|
||||
|
@ -30,8 +32,12 @@
|
|||
"react-native-reanimated": "^2.13.0",
|
||||
"react-native-safe-area-context": "^4.4.1",
|
||||
"react-native-screens": "^3.18.2",
|
||||
"react-native-svg": "^13.6.0",
|
||||
"react-native-user-agent": "^2.3.1",
|
||||
"react-native-vector-icons": "^9.2.0",
|
||||
"react-native-web": "^0.18.10",
|
||||
"react-redux": "^8.0.5"
|
||||
"react-redux": "^8.0.5",
|
||||
"react-string-replace": "^1.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.12.9",
|
||||
|
@ -59,7 +65,7 @@
|
|||
"webpack-dev-server": "^4.11.1"
|
||||
},
|
||||
"jest": {
|
||||
"preset": "react-native",
|
||||
"preset": "react-native-web",
|
||||
"transform": {
|
||||
"^.+\\.(js)$": "<rootDir>/node_modules/babel-jest",
|
||||
"\\.(ts|tsx)$": "ts-jest"
|
||||
|
|
|
@ -6,7 +6,7 @@ import {NavigationContainer} from '@react-navigation/native';
|
|||
import {getBackgroundColor, theme, ThemeSwitcher} from '@caj/configs/colors';
|
||||
|
||||
import StatusBar from './StatusBar';
|
||||
import Navigation, {linking} from './Navigation';
|
||||
import Navigation, {linking} from './caj/Navigation';
|
||||
|
||||
import {Provider, useSelector} from 'react-redux';
|
||||
import {RootState, store} from '@caj/redux/store';
|
||||
|
@ -44,8 +44,8 @@ const OtherProviders = () => {
|
|||
};
|
||||
|
||||
return (
|
||||
<NavigationContainer theme={navigationTheme} linking={linking}>
|
||||
<NativeBaseProvider theme={theme}>
|
||||
<NavigationContainer theme={navigationTheme} /*linking={linking}*/>
|
||||
<NativeBaseProvider theme={theme(globalTheme)}>
|
||||
<MainComponent />
|
||||
</NativeBaseProvider>
|
||||
</NavigationContainer>
|
||||
|
|
|
@ -23,7 +23,7 @@ function onAppStart() {
|
|||
console.log('finish');
|
||||
setTimeout(() => {
|
||||
store.dispatch(appNonSaveVarActions.setAppStatus(appStatus.APP_RUNNING));
|
||||
}, 500);
|
||||
}, 250);
|
||||
//store.dispatch(actions.loadPreferences(appVar));
|
||||
});
|
||||
}
|
||||
|
|
|
@ -34,25 +34,24 @@ const styles = StyleSheet.create({
|
|||
});
|
||||
|
||||
export const linking: LinkingOptions<{
|
||||
Auth: string;
|
||||
Maps: string;
|
||||
Home: string;
|
||||
Table: string;
|
||||
Loading: string;
|
||||
Chat: string;
|
||||
Settings: string;
|
||||
}> = {
|
||||
prefixes: ['http://'],
|
||||
config: {
|
||||
initialRouteName: 'Loading',
|
||||
screens: {
|
||||
Auth: 'auth',
|
||||
Home: 'home',
|
||||
Table: 'table',
|
||||
Loading: 'loading',
|
||||
Maps: 'mapss',
|
||||
Home: 'account',
|
||||
Chat: 'chats',
|
||||
Settings: 'settingss',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export type HomeStackNavigatorParamList = {
|
||||
Home: undefined;
|
||||
Account: undefined;
|
||||
Maps: undefined;
|
||||
Chat: undefined;
|
||||
Test: undefined;
|
||||
|
@ -100,12 +99,21 @@ function HomeScreen() {
|
|||
);
|
||||
}
|
||||
|
||||
export type SettingsStackNavigatorParamList = {
|
||||
Chat: undefined;
|
||||
Settings: undefined;
|
||||
};
|
||||
|
||||
export type SettingsScreenNavigationProp =
|
||||
NativeStackNavigationProp<SettingsStackNavigatorParamList>;
|
||||
|
||||
function SettingsScreen() {
|
||||
const navigation = useNavigation<HomeScreenNavigationProp>();
|
||||
const navigation = useNavigation<SettingsScreenNavigationProp>();
|
||||
const navigation2 = useNavigation<HomeScreenNavigationProp>();
|
||||
return (
|
||||
<View style={{flex: 1, justifyContent: 'center', alignItems: 'center'}}>
|
||||
<Text>Settings screen</Text>
|
||||
<Button onPress={() => navigation.navigate('Chat')}>Go to Chat</Button>
|
||||
<Button onPress={() => navigation2.navigate('Maps')}>Go to Chat</Button>
|
||||
</View>
|
||||
);
|
||||
}
|
|
@ -0,0 +1,126 @@
|
|||
import React, {useState, useEffect} from 'react';
|
||||
|
||||
import {StyleSheet, Appearance, Dimensions} from 'react-native';
|
||||
import {SafeAreaProvider, SafeAreaView} from 'react-native-safe-area-context';
|
||||
|
||||
import {useSelector, useDispatch} from 'react-redux';
|
||||
import {RootState} from '@caj/redux/store';
|
||||
import {appVarActions} from '@caj/configs/appVarReducer';
|
||||
|
||||
import imgSrc from '@caj/img/maimg.png';
|
||||
import {placeholder} from '@caj/lang/default';
|
||||
import {getBackgroundColor} from '@caj/configs/colors';
|
||||
import {saveVarChanges} from '@caj/helper/appData';
|
||||
|
||||
import {Box, Input, VStack, Center, Avatar, Text, Button} from 'native-base';
|
||||
import {View} from 'react-native';
|
||||
|
||||
import {
|
||||
LinkingOptions,
|
||||
NavigationContainer,
|
||||
NavigatorScreenParams,
|
||||
useNavigation,
|
||||
} from '@react-navigation/native';
|
||||
import {
|
||||
createNativeStackNavigator,
|
||||
NativeStackNavigationProp,
|
||||
} from '@react-navigation/native-stack';
|
||||
import {createBottomTabNavigator} from '@react-navigation/bottom-tabs';
|
||||
import AccountTab, {
|
||||
AccountStackNavigatorParamList,
|
||||
AccountTabName,
|
||||
} from './tabs/main/AccountTab';
|
||||
import CalendarTab, {
|
||||
CalendarStackNavigatorParamList,
|
||||
} from './tabs/main/CalendarTab';
|
||||
import MapsTab, {MapsStackNavigatorParamList} from './tabs/main/MapsTab';
|
||||
import ChatTab, {ChatStackNavigatorParamList} from './tabs/main/ChatTab';
|
||||
import {
|
||||
FadeInView,
|
||||
SlideFromLeftView,
|
||||
SlideFromRightView,
|
||||
} from './helper/animations';
|
||||
import {
|
||||
LoginStackNavigatorParamList,
|
||||
RegisterScreenAnim,
|
||||
} from './components/NotLoggedIn';
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
height: '100%',
|
||||
flex: 1,
|
||||
},
|
||||
});
|
||||
|
||||
export const linking: LinkingOptions<{}> = {
|
||||
prefixes: ['http://'],
|
||||
};
|
||||
|
||||
export type RootStackNavigatorParamList = {
|
||||
Home: NavigatorScreenParams<HomeStackNavigatorParamList>;
|
||||
Register: NavigatorScreenParams<LoginStackNavigatorParamList>;
|
||||
};
|
||||
|
||||
export type RootScreenNavigationProp =
|
||||
NativeStackNavigationProp<RootStackNavigatorParamList>;
|
||||
|
||||
export default function Navigation() {
|
||||
return (
|
||||
<Stack.Navigator screenOptions={{headerShown: false}}>
|
||||
<Stack.Screen name="Home" component={HomeStack} />
|
||||
<Stack.Screen name="Register" component={RegisterScreenAnim} />
|
||||
</Stack.Navigator>
|
||||
);
|
||||
}
|
||||
|
||||
const Stack = createNativeStackNavigator<RootStackNavigatorParamList>();
|
||||
|
||||
export type HomeStackNavigatorParamList = {
|
||||
Account: NavigatorScreenParams<AccountStackNavigatorParamList>;
|
||||
Calendar: NavigatorScreenParams<CalendarStackNavigatorParamList>;
|
||||
Maps: NavigatorScreenParams<MapsStackNavigatorParamList>;
|
||||
Chat: NavigatorScreenParams<ChatStackNavigatorParamList>;
|
||||
};
|
||||
|
||||
function AccountTabAnim(props: any) {
|
||||
return (
|
||||
<SlideFromLeftView>
|
||||
<AccountTab {...props} />
|
||||
</SlideFromLeftView>
|
||||
);
|
||||
}
|
||||
|
||||
function CalendarTabAnim(props: any) {
|
||||
return (
|
||||
<FadeInView>
|
||||
<CalendarTab {...props} />
|
||||
</FadeInView>
|
||||
);
|
||||
}
|
||||
function MapsTabAnim(props: any) {
|
||||
return (
|
||||
<FadeInView>
|
||||
<MapsTab {...props} />
|
||||
</FadeInView>
|
||||
);
|
||||
}
|
||||
function ChatTabAnim(props: any) {
|
||||
return (
|
||||
<SlideFromRightView>
|
||||
<ChatTab {...props} />
|
||||
</SlideFromRightView>
|
||||
);
|
||||
}
|
||||
|
||||
function HomeStack() {
|
||||
return (
|
||||
<Tab.Navigator screenOptions={{headerShown: false, unmountOnBlur: false}}>
|
||||
<Tab.Screen name="Account" component={AccountTabAnim} />
|
||||
<Tab.Screen name="Calendar" component={CalendarTabAnim} />
|
||||
<Tab.Screen name="Maps" component={MapsTabAnim} />
|
||||
<Tab.Screen name="Chat" component={ChatTabAnim} />
|
||||
</Tab.Navigator>
|
||||
);
|
||||
}
|
||||
|
||||
const Tab = createBottomTabNavigator<HomeStackNavigatorParamList>();
|
|
@ -0,0 +1,5 @@
|
|||
import {Center} from 'native-base';
|
||||
|
||||
export default function AccountInfoBanner() {
|
||||
return <Center>Account</Center>;
|
||||
}
|
|
@ -0,0 +1,146 @@
|
|||
import {Box, Center, HStack, Input, Pressable, Text} from 'native-base';
|
||||
import {useEffect, useRef, useState} from 'react';
|
||||
import {
|
||||
TextInput,
|
||||
NativeSyntheticEvent,
|
||||
TextInputChangeEventData,
|
||||
} from 'react-native';
|
||||
|
||||
function RenderCell(props: {
|
||||
index: number;
|
||||
text: string | number;
|
||||
maxIndex: number;
|
||||
isFocus: boolean;
|
||||
disabled: boolean;
|
||||
rest: any;
|
||||
}) {
|
||||
const display: string = props.text ? props.text.toString() : '';
|
||||
|
||||
const [toggle, setToggle] = useState(true);
|
||||
|
||||
useEffect(() => {
|
||||
if (props.isFocus === false) return;
|
||||
|
||||
let timer = setInterval(() => {
|
||||
setToggle(!toggle);
|
||||
}, 500);
|
||||
return () => {
|
||||
clearInterval(timer);
|
||||
};
|
||||
});
|
||||
|
||||
return (
|
||||
<Pressable
|
||||
{...props.rest}
|
||||
w={10}
|
||||
h={10}
|
||||
borderColor={props.isFocus ? 'primary.300' : 'black.100'}
|
||||
backgroundColor={
|
||||
props.disabled ? 'black.300' : props.isFocus ? '#ff9b7933' : null
|
||||
}
|
||||
borderWidth={1}
|
||||
borderRadius={5}>
|
||||
<Center w={'100%'} h={'100%'}>
|
||||
<Text
|
||||
fontSize={'2xl'}
|
||||
color={props.disabled ? 'white.100' : 'white.900'}
|
||||
{...props.rest}>
|
||||
{props.isFocus ? (toggle ? '|' : '') : display}
|
||||
</Text>
|
||||
</Center>
|
||||
</Pressable>
|
||||
);
|
||||
}
|
||||
|
||||
function ConfirmationCodeField(props: {
|
||||
cellCount: number;
|
||||
charType: 'number' | 'letter';
|
||||
onFinish?: Function;
|
||||
onChange?: Function;
|
||||
disabled?: boolean;
|
||||
rest?: any;
|
||||
}) {
|
||||
const [values, setValues] = useState({input: ''});
|
||||
const [isFocus, setFocus] = useState(false);
|
||||
|
||||
const inputRef = useRef<TextInput>(null);
|
||||
|
||||
return (
|
||||
<Box {...props.rest}>
|
||||
<TextInput
|
||||
autoFocus
|
||||
ref={inputRef}
|
||||
value={values.input}
|
||||
keyboardType={props.charType === 'number' ? 'numeric' : 'default'}
|
||||
onFocus={() => setFocus(true)}
|
||||
onBlur={() => setFocus(false)}
|
||||
editable={!props.disabled}
|
||||
onChange={(event: NativeSyntheticEvent<TextInputChangeEventData>) => {
|
||||
let text = event.nativeEvent.text;
|
||||
let vals = {...values};
|
||||
|
||||
if (props.charType === 'number')
|
||||
vals.input = text.replace(/[^0-9]/g, '');
|
||||
else if (props.charType === 'letter') vals.input = text;
|
||||
|
||||
vals.input = vals.input.slice(0, props.cellCount);
|
||||
|
||||
setValues(vals);
|
||||
|
||||
if (props.onChange) props.onChange(vals.input);
|
||||
|
||||
if (vals.input.length === props.cellCount) {
|
||||
if (inputRef.current !== null) {
|
||||
inputRef.current.blur();
|
||||
if (props.onFinish) props.onFinish(vals.input);
|
||||
}
|
||||
}
|
||||
}}
|
||||
style={{
|
||||
position: 'absolute',
|
||||
opacity: 0,
|
||||
width: 1,
|
||||
height: 1,
|
||||
|
||||
padding: 0,
|
||||
margin: 0,
|
||||
}}
|
||||
/>
|
||||
<HStack space={3} justifyContent="center">
|
||||
{(() => {
|
||||
let cells = [];
|
||||
for (let i = 0; i < props.cellCount; i++) {
|
||||
cells.push(
|
||||
<RenderCell
|
||||
key={'ConfirmationCodeFieldCell' + i}
|
||||
index={i}
|
||||
isFocus={isFocus === true ? values.input.length === i : false}
|
||||
text={values.input[i]}
|
||||
maxIndex={props.cellCount}
|
||||
disabled={props.disabled || false}
|
||||
rest={{
|
||||
onPress: !props.disabled
|
||||
? () => {
|
||||
let vals = {...values};
|
||||
vals.input = vals.input.slice(0, i);
|
||||
setValues(vals);
|
||||
|
||||
if (props.onChange) props.onChange(vals.input);
|
||||
|
||||
if (inputRef.current !== null) {
|
||||
inputRef.current.focus();
|
||||
}
|
||||
}
|
||||
: undefined,
|
||||
}}
|
||||
/>,
|
||||
);
|
||||
}
|
||||
return cells;
|
||||
})()}
|
||||
</HStack>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
export default ConfirmationCodeField;
|
|
@ -0,0 +1,30 @@
|
|||
import {AccountName, Username} from '@caj/helper/types';
|
||||
import {RootState} from '@caj/redux/store';
|
||||
import {HStack, Text} from 'native-base';
|
||||
import {useSelector} from 'react-redux';
|
||||
|
||||
export default function NameDisplay(props: {
|
||||
UserName: Username;
|
||||
AccountName: AccountName;
|
||||
fontSize?: number;
|
||||
}) {
|
||||
const theme = useSelector(
|
||||
(state: RootState) => state.appVariables.preferences.theme,
|
||||
);
|
||||
const fontSize = props.fontSize || 15;
|
||||
const lineHeight = fontSize * 1.25;
|
||||
|
||||
return (
|
||||
<HStack space={fontSize / 30} alignItems={'flex-end'}>
|
||||
<Text fontSize={fontSize} color="primary.400">
|
||||
{props.UserName !== '' ? props.UserName : '----'}
|
||||
</Text>
|
||||
<Text
|
||||
fontSize={fontSize / 1.5}
|
||||
fontFamily={'Outfit-Light'}
|
||||
color="light.400">
|
||||
{props.AccountName !== '' ? props.AccountName : '----'}
|
||||
</Text>
|
||||
</HStack>
|
||||
);
|
||||
}
|
|
@ -0,0 +1,960 @@
|
|||
import {RegisterProcess, ThemeMode} from '@caj/configs/appVar';
|
||||
import {appVarActions} from '@caj/configs/appVarReducer';
|
||||
import {defaultHeaderStyle} from '@caj/configs/colors';
|
||||
import {SlideFromLeftView} from '@caj/helper/animations';
|
||||
import {saveVarChanges} from '@caj/helper/appData';
|
||||
import {apiBackendRequest, makeRequest} from '@caj/helper/request';
|
||||
import {
|
||||
accountNameOptions,
|
||||
EMail,
|
||||
emailOptions,
|
||||
passwordOptions,
|
||||
userNameOptions,
|
||||
XToken,
|
||||
} from '@caj/helper/types';
|
||||
import {RootScreenNavigationProp} from '@caj/Navigation';
|
||||
import {RootState, store} from '@caj/redux/store';
|
||||
import {useNavigation} from '@react-navigation/native';
|
||||
import {
|
||||
createNativeStackNavigator,
|
||||
NativeStackNavigationProp,
|
||||
} from '@react-navigation/native-stack';
|
||||
import {
|
||||
Box,
|
||||
Button,
|
||||
Center,
|
||||
Container,
|
||||
FormControl,
|
||||
Heading,
|
||||
HStack,
|
||||
Icon,
|
||||
IconButton,
|
||||
Input,
|
||||
Pressable,
|
||||
ScrollView,
|
||||
Spinner,
|
||||
Text,
|
||||
useColorModeValue,
|
||||
useTheme,
|
||||
useToast,
|
||||
VStack,
|
||||
WarningOutlineIcon,
|
||||
} from 'native-base';
|
||||
|
||||
import MaterialIcons from 'react-native-vector-icons/MaterialIcons';
|
||||
|
||||
import {baseFontSize} from 'native-base/lib/typescript/theme/tools';
|
||||
import {useEffect, useRef, useState} from 'react';
|
||||
import {useDispatch, useSelector} from 'react-redux';
|
||||
import reactStringReplace from 'react-string-replace';
|
||||
import ConfirmationCodeField from './ConfirmationCodeField';
|
||||
import NameDisplay from './NameDisplay';
|
||||
import showToast from './Toast';
|
||||
import {NativeSyntheticEvent, TextInputFocusEventData} from 'react-native';
|
||||
|
||||
const validateEmail = (email: EMail) => {
|
||||
return emailOptions.isAllowed(email);
|
||||
};
|
||||
|
||||
export default function NotLoggedIn() {
|
||||
const lang = useSelector((state: RootState) => state.appVariables.lang);
|
||||
const theme = useSelector(
|
||||
(state: RootState) => state.appVariables.preferences.theme,
|
||||
);
|
||||
|
||||
const toast = useToast();
|
||||
|
||||
const navigation = useNavigation<RootScreenNavigationProp>();
|
||||
|
||||
return (
|
||||
<Box alignItems="center" mt={5}>
|
||||
<Text color="primary.400">{lang.appName}</Text>
|
||||
<Text color="white.100">{lang.appNameDesc}</Text>
|
||||
<VStack mt={5} space={4} alignItems="center">
|
||||
<Button
|
||||
w="72"
|
||||
colorScheme="primary"
|
||||
rounded="xl"
|
||||
_text={{fontSize: 'xl'}}
|
||||
onPress={() => {
|
||||
navigation.navigate('Register', {screen: 'RegStepOne'});
|
||||
}}>
|
||||
Sign up
|
||||
</Button>
|
||||
<Button
|
||||
w="72"
|
||||
colorScheme="black"
|
||||
variant={theme === ThemeMode.Darkest ? 'outline' : 'subtle'}
|
||||
rounded="xl"
|
||||
_text={{fontSize: 'xl', color: 'white.900'}}>
|
||||
Log in
|
||||
</Button>
|
||||
</VStack>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
export function RegisterScreenAnim(props: any) {
|
||||
return (
|
||||
<SlideFromLeftView>
|
||||
<RegisterScreen {...props} />
|
||||
</SlideFromLeftView>
|
||||
);
|
||||
}
|
||||
|
||||
export type LoginStackNavigatorParamList = {
|
||||
RegStepOne: undefined;
|
||||
RegStepTwo: undefined;
|
||||
RegStepFinal: undefined;
|
||||
};
|
||||
|
||||
const LoginStack = createNativeStackNavigator<LoginStackNavigatorParamList>();
|
||||
|
||||
export type LoginScreenNavigationProp =
|
||||
NativeStackNavigationProp<LoginStackNavigatorParamList>;
|
||||
|
||||
function RegisterScreen() {
|
||||
const lang = useSelector((state: RootState) => state.appVariables.lang);
|
||||
const theme = useSelector(
|
||||
(state: RootState) => state.appVariables.preferences.theme,
|
||||
);
|
||||
|
||||
return (
|
||||
<LoginStack.Navigator>
|
||||
<LoginStack.Screen
|
||||
name="RegStepOne"
|
||||
options={{
|
||||
animation: 'slide_from_left',
|
||||
title: lang.account.registration.registration,
|
||||
headerShown: true,
|
||||
...defaultHeaderStyle(theme, 'registration'),
|
||||
}}
|
||||
component={StepOne}
|
||||
/>
|
||||
<LoginStack.Screen
|
||||
name="RegStepTwo"
|
||||
options={{
|
||||
animation: 'slide_from_right',
|
||||
title: lang.account.registration.registration,
|
||||
headerShown: true,
|
||||
...defaultHeaderStyle(theme, 'registration'),
|
||||
}}
|
||||
component={StepTwo}
|
||||
/>
|
||||
<LoginStack.Screen
|
||||
name="RegStepFinal"
|
||||
options={{
|
||||
animation: 'slide_from_right',
|
||||
title: lang.account.registration.registration,
|
||||
headerShown: true,
|
||||
...defaultHeaderStyle(theme, 'registration'),
|
||||
}}
|
||||
component={StepFinal}
|
||||
/>
|
||||
</LoginStack.Navigator>
|
||||
);
|
||||
}
|
||||
|
||||
function Agreement() {
|
||||
const toast = useToast();
|
||||
const lang = useSelector((state: RootState) => state.appVariables.lang);
|
||||
|
||||
const textColor = useColorModeValue('blue.700', 'cyan.400');
|
||||
|
||||
let replacedText = reactStringReplace(
|
||||
lang.account.registration.info,
|
||||
'${TermsOfUse}',
|
||||
(match, i) => (
|
||||
<Text
|
||||
key={match + i}
|
||||
color={textColor}
|
||||
bold
|
||||
onPress={() => {
|
||||
showToast(toast, {
|
||||
title: lang.account.registration.termsOfUse,
|
||||
variant: 'solid',
|
||||
status: 'info',
|
||||
description: undefined,
|
||||
isClosable: true,
|
||||
rest: {colorScheme: 'primary'},
|
||||
});
|
||||
}}>
|
||||
{lang.account.registration.termsOfUse}
|
||||
</Text>
|
||||
),
|
||||
);
|
||||
|
||||
replacedText = reactStringReplace(
|
||||
replacedText,
|
||||
'${privacyPolicy}',
|
||||
(match, i) => (
|
||||
<Text
|
||||
key={match + i}
|
||||
color={textColor}
|
||||
bold
|
||||
onPress={() => {
|
||||
showToast(toast, {
|
||||
title: lang.account.registration.privacyPolicy,
|
||||
variant: 'solid',
|
||||
status: 'info',
|
||||
description: undefined,
|
||||
isClosable: true,
|
||||
rest: {colorScheme: 'primary'},
|
||||
});
|
||||
}}>
|
||||
{lang.account.registration.privacyPolicy}
|
||||
</Text>
|
||||
),
|
||||
);
|
||||
|
||||
return (
|
||||
<Text textAlign={'justify'} color={'white.900'}>
|
||||
{replacedText}
|
||||
</Text>
|
||||
);
|
||||
}
|
||||
|
||||
function resendMail(email: EMail, toast: any): Promise<XToken> {
|
||||
return new Promise<XToken>((resolve, reject) => {
|
||||
makeRequest({
|
||||
path: apiBackendRequest.REGISTER_RESEND_MAIL,
|
||||
|
||||
requestHeader: {},
|
||||
request: {
|
||||
Email: email,
|
||||
},
|
||||
//response: {
|
||||
// XToken: undefined,
|
||||
//},
|
||||
})
|
||||
.then(resp => {
|
||||
console.log(1);
|
||||
let token =
|
||||
store.getState().appVariables.preferences.RegisterProcess.XToken;
|
||||
if (token !== undefined /*resp.response.XToken !== undefined*/) {
|
||||
showToast(toast, {
|
||||
title: store.getState().appVariables.lang.info,
|
||||
variant: 'solid',
|
||||
status: 'info',
|
||||
description:
|
||||
store.getState().appVariables.lang.account.registration.stepTwo
|
||||
.resend[2],
|
||||
isClosable: true,
|
||||
rest: {},
|
||||
});
|
||||
|
||||
resolve(token);
|
||||
} else {
|
||||
reject(500);
|
||||
showToast(toast, {
|
||||
title: store.getState().appVariables.lang.error,
|
||||
variant: 'solid',
|
||||
status: 'error',
|
||||
description: 'XToken is undefined',
|
||||
isClosable: true,
|
||||
rest: {},
|
||||
});
|
||||
}
|
||||
})
|
||||
.catch(resp => {
|
||||
let text = 'unknown error ' + resp.status;
|
||||
if (resp.status !== undefined) {
|
||||
const _text =
|
||||
store.getState().appVariables.lang.account.registration.stepTwo
|
||||
.resendError[resp.status as number];
|
||||
if (_text !== undefined) text = _text;
|
||||
}
|
||||
|
||||
showToast(toast, {
|
||||
title: store.getState().appVariables.lang.error,
|
||||
variant: 'solid',
|
||||
status: 'error',
|
||||
description: text,
|
||||
isClosable: true,
|
||||
rest: {},
|
||||
});
|
||||
|
||||
reject(resp.status);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function StepOne() {
|
||||
const lang = useSelector((state: RootState) => state.appVariables.lang);
|
||||
const regPro = useSelector(
|
||||
(state: RootState) => state.appVariables.preferences.RegisterProcess,
|
||||
);
|
||||
|
||||
const dispatch = useDispatch();
|
||||
const toast = useToast();
|
||||
|
||||
const navigation = useNavigation<RootScreenNavigationProp>();
|
||||
|
||||
const initNoErrors = {
|
||||
wrongFormat: false,
|
||||
alreadyExists: false,
|
||||
noEntered: false,
|
||||
unknown: undefined,
|
||||
};
|
||||
|
||||
const [errors, setErrors] = useState(initNoErrors);
|
||||
|
||||
const isError =
|
||||
errors.wrongFormat ||
|
||||
errors.alreadyExists ||
|
||||
errors.noEntered ||
|
||||
errors.unknown !== undefined;
|
||||
|
||||
const errorText = () => {
|
||||
if (errors.wrongFormat) {
|
||||
return lang.account.registration.stepOne.addressInvalid;
|
||||
}
|
||||
if (errors.alreadyExists) {
|
||||
return lang.account.registration.stepOne.addressExists;
|
||||
}
|
||||
if (errors.noEntered) {
|
||||
return lang.account.registration.stepOne.noMailEntered;
|
||||
}
|
||||
if (errors.unknown !== undefined) {
|
||||
return errors.unknown;
|
||||
}
|
||||
};
|
||||
|
||||
const [isLoading, setLoading] = useState(false);
|
||||
|
||||
const [values, setValues] = useState({email: regPro.EMail});
|
||||
|
||||
useEffect(() => {
|
||||
if (regPro.isRegistering === 'stepTwo') {
|
||||
setLoading(true);
|
||||
setErrors(initNoErrors);
|
||||
|
||||
setTimeout(nextStep, 500);
|
||||
} else if (regPro.isRegistering === 'stepFinal') {
|
||||
setLoading(true);
|
||||
setErrors(initNoErrors);
|
||||
|
||||
setTimeout(nextStep, 500);
|
||||
}
|
||||
}, []);
|
||||
|
||||
const nextStep = () => {
|
||||
setLoading(true);
|
||||
setErrors(initNoErrors);
|
||||
|
||||
makeRequest({
|
||||
path: apiBackendRequest.REGISTER_STEP_1,
|
||||
requestHeader: {},
|
||||
request: {
|
||||
Email: values.email,
|
||||
},
|
||||
response: {
|
||||
XToken: undefined,
|
||||
},
|
||||
})
|
||||
.then(resp => {
|
||||
let rp = {...regPro};
|
||||
rp.isRegistering = 'stepTwo';
|
||||
rp.EMail = values.email;
|
||||
rp.XToken = resp.response.XToken;
|
||||
|
||||
dispatch(appVarActions.setRegisterProcess(rp));
|
||||
saveVarChanges();
|
||||
|
||||
showToast(toast, {
|
||||
title: lang.account.registration.stepOne.success,
|
||||
variant: 'solid',
|
||||
status: 'success',
|
||||
description: undefined,
|
||||
isClosable: true,
|
||||
rest: {colorScheme: 'primary'},
|
||||
});
|
||||
|
||||
navigation.navigate('Register', {screen: 'RegStepTwo'});
|
||||
setLoading(false);
|
||||
})
|
||||
.catch(resp => {
|
||||
if (resp.status === 401 || resp.status === 204) {
|
||||
if (regPro.XToken !== undefined) {
|
||||
let rp = {...regPro};
|
||||
|
||||
if (resp.status === 401) {
|
||||
rp.isRegistering = 'stepTwo';
|
||||
rp.EMail = values.email;
|
||||
|
||||
dispatch(appVarActions.setRegisterProcess(rp));
|
||||
saveVarChanges();
|
||||
|
||||
navigation.navigate('Register', {screen: 'RegStepTwo'});
|
||||
} else if (resp.status === 204) {
|
||||
rp.isRegistering = 'stepFinal';
|
||||
rp.EMail = values.email;
|
||||
|
||||
dispatch(appVarActions.setRegisterProcess(rp));
|
||||
saveVarChanges();
|
||||
|
||||
navigation.navigate('Register', {screen: 'RegStepFinal'});
|
||||
}
|
||||
|
||||
setLoading(false);
|
||||
} else {
|
||||
resendMail(values.email, toast)
|
||||
.then(() => {
|
||||
setLoading(false);
|
||||
})
|
||||
.catch(() => {
|
||||
setLoading(false);
|
||||
});
|
||||
}
|
||||
} else {
|
||||
showToast(toast, {
|
||||
title: 'Error',
|
||||
variant: 'solid',
|
||||
status: 'error',
|
||||
description: resp.status,
|
||||
isClosable: true,
|
||||
rest: {colorScheme: 'primary'},
|
||||
});
|
||||
setLoading(false);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<ScrollView keyboardShouldPersistTaps="handled">
|
||||
<Box alignItems="center" mt={5}>
|
||||
<FormControl
|
||||
w="75%"
|
||||
maxW="350px"
|
||||
isRequired
|
||||
isDisabled={isLoading}
|
||||
isInvalid={isError}>
|
||||
<FormControl.Label>
|
||||
{lang.account.registration.stepOne.title}
|
||||
</FormControl.Label>
|
||||
<Input
|
||||
autoFocus
|
||||
placeholder={lang.account.registration.stepOne.title}
|
||||
value={values.email}
|
||||
autoCapitalize={'none'}
|
||||
maxLength={emailOptions.maxLength}
|
||||
keyboardType={'email-address'}
|
||||
onChangeText={text => {
|
||||
const mail = text.replaceAll(' ', '');
|
||||
setValues({email: mail});
|
||||
|
||||
if (errors.noEntered && mail !== '') {
|
||||
let err = errors;
|
||||
err.noEntered = false;
|
||||
setErrors({...err});
|
||||
}
|
||||
if (errors.wrongFormat && validateEmail(mail)) {
|
||||
let err = errors;
|
||||
err.wrongFormat = false;
|
||||
setErrors({...err});
|
||||
}
|
||||
if (errors.alreadyExists) {
|
||||
let err = errors;
|
||||
err.alreadyExists = false;
|
||||
setErrors({...err});
|
||||
}
|
||||
}}
|
||||
/>
|
||||
|
||||
<FormControl.ErrorMessage leftIcon={<WarningOutlineIcon size="xs" />}>
|
||||
{errorText()}
|
||||
</FormControl.ErrorMessage>
|
||||
</FormControl>
|
||||
<Container marginY={5}>
|
||||
<Agreement />
|
||||
</Container>
|
||||
<Button
|
||||
w="75%"
|
||||
maxW="350px"
|
||||
colorScheme="primary"
|
||||
rounded="xl"
|
||||
_text={{fontSize: 'xl'}}
|
||||
isLoading={isLoading}
|
||||
onPress={() => {
|
||||
if (values.email === '') {
|
||||
let err = errors;
|
||||
err.noEntered = true;
|
||||
setErrors({...err});
|
||||
} else if (validateEmail(values.email)) {
|
||||
nextStep();
|
||||
} else {
|
||||
let err = errors;
|
||||
err.wrongFormat = true;
|
||||
setErrors({...err});
|
||||
}
|
||||
}}>
|
||||
{lang.account.registration.stepOne.button}
|
||||
</Button>
|
||||
</Box>
|
||||
</ScrollView>
|
||||
);
|
||||
}
|
||||
|
||||
function StepTwo() {
|
||||
const lang = useSelector((state: RootState) => state.appVariables.lang);
|
||||
const regPro = useSelector(
|
||||
(state: RootState) => state.appVariables.preferences.RegisterProcess,
|
||||
);
|
||||
|
||||
const dispatch = useDispatch();
|
||||
|
||||
const cellCount = 6;
|
||||
const {colors} = useTheme();
|
||||
|
||||
const toast = useToast();
|
||||
|
||||
const navigation = useNavigation<RootScreenNavigationProp>();
|
||||
|
||||
const initNoErrors = {
|
||||
noEntered: false,
|
||||
};
|
||||
|
||||
const [errors, setErrors] = useState(initNoErrors);
|
||||
|
||||
const [isLoading, setLoading] = useState(false);
|
||||
|
||||
const [values, setValues] = useState({code: ''});
|
||||
|
||||
const headerText = () => {
|
||||
return reactStringReplace(
|
||||
lang.account.registration.stepTwo.title,
|
||||
'${EMail}',
|
||||
(match, i) => (
|
||||
<Text key={match + i} color={'primary.400'}>
|
||||
{regPro.EMail}
|
||||
</Text>
|
||||
),
|
||||
);
|
||||
};
|
||||
|
||||
const resendText = () => {
|
||||
return reactStringReplace(
|
||||
lang.account.registration.stepTwo.resend[0],
|
||||
'${resend}',
|
||||
(match, i) => (
|
||||
<Text
|
||||
key={match + i}
|
||||
color={'primary.400'}
|
||||
onPress={() => {
|
||||
setLoading(true);
|
||||
resendMail(
|
||||
store.getState().appVariables.preferences.RegisterProcess.EMail,
|
||||
toast,
|
||||
)
|
||||
.then(() => {
|
||||
setLoading(false);
|
||||
})
|
||||
.catch(() => {
|
||||
setLoading(false);
|
||||
});
|
||||
}}>
|
||||
{lang.account.registration.stepTwo.resend[1]}
|
||||
</Text>
|
||||
),
|
||||
);
|
||||
};
|
||||
|
||||
const validate = (text: string) => {
|
||||
setLoading(true);
|
||||
setTimeout(() => {
|
||||
makeRequest({
|
||||
path: apiBackendRequest.REGISTER_STEP_2,
|
||||
|
||||
requestHeader: {},
|
||||
requestGET: {':verifyId': text, ':xToken': regPro.XToken || ''},
|
||||
})
|
||||
.then(resp => {
|
||||
let rp = {...regPro};
|
||||
rp.isRegistering = 'stepFinal';
|
||||
|
||||
dispatch(appVarActions.setRegisterProcess(rp));
|
||||
saveVarChanges();
|
||||
|
||||
showToast(toast, {
|
||||
title: lang.account.registration.stepTwo.success,
|
||||
variant: 'solid',
|
||||
status: 'success',
|
||||
description: undefined,
|
||||
isClosable: true,
|
||||
rest: {colorScheme: 'primary'},
|
||||
});
|
||||
|
||||
navigation.navigate('Register', {screen: 'RegStepFinal'});
|
||||
setLoading(false);
|
||||
})
|
||||
.catch(resp => {
|
||||
let text = 'unknown error ' + resp.status;
|
||||
if (resp.status !== undefined) {
|
||||
const _text =
|
||||
lang.account.registration.stepTwo.verificationError[
|
||||
resp.status as number
|
||||
];
|
||||
if (_text !== undefined) text = _text;
|
||||
}
|
||||
|
||||
showToast(toast, {
|
||||
title: lang.error,
|
||||
variant: 'solid',
|
||||
status: 'error',
|
||||
description: text,
|
||||
isClosable: true,
|
||||
rest: {},
|
||||
});
|
||||
|
||||
setLoading(false);
|
||||
if (resp.status === 422) {
|
||||
let rp = {...regPro};
|
||||
rp.isRegistering = false;
|
||||
|
||||
dispatch(appVarActions.setRegisterProcess(rp));
|
||||
saveVarChanges();
|
||||
navigation.navigate('Register', {screen: 'RegStepOne'});
|
||||
}
|
||||
});
|
||||
}, 500);
|
||||
};
|
||||
|
||||
return (
|
||||
<ScrollView keyboardShouldPersistTaps="handled">
|
||||
<Box alignItems="center" mt={5}>
|
||||
<Center w="75%" maxW="1000px">
|
||||
<Text>{headerText()}</Text>
|
||||
<Box>
|
||||
<FormControl isDisabled={isLoading} isInvalid={errors.noEntered}>
|
||||
<ConfirmationCodeField
|
||||
cellCount={cellCount}
|
||||
charType="number"
|
||||
disabled={isLoading}
|
||||
rest={{mt: 5}}
|
||||
onChange={(text: string) => {
|
||||
setValues({code: text});
|
||||
setErrors(initNoErrors);
|
||||
}}
|
||||
onFinish={(text: string) => validate(text)}
|
||||
/>
|
||||
|
||||
<FormControl.ErrorMessage
|
||||
leftIcon={<WarningOutlineIcon size="xs" />}>
|
||||
{lang.account.registration.stepTwo.noCodeEntered}
|
||||
</FormControl.ErrorMessage>
|
||||
</FormControl>
|
||||
</Box>
|
||||
</Center>
|
||||
<Container marginY={5}>
|
||||
<Agreement />
|
||||
</Container>
|
||||
<Button
|
||||
w="75%"
|
||||
maxW="350px"
|
||||
colorScheme="primary"
|
||||
rounded="xl"
|
||||
_text={{fontSize: 'xl'}}
|
||||
isLoading={isLoading}
|
||||
onPress={() => {
|
||||
if (values.code.length === cellCount) {
|
||||
validate(values.code);
|
||||
} else {
|
||||
let err = {...errors};
|
||||
err.noEntered = true;
|
||||
setErrors(err);
|
||||
}
|
||||
}}>
|
||||
{lang.account.registration.stepTwo.button}
|
||||
</Button>
|
||||
<Container marginY={5}>
|
||||
<Text textAlign={'justify'} color={'white.900'}>
|
||||
{resendText()}
|
||||
</Text>
|
||||
</Container>
|
||||
</Box>
|
||||
</ScrollView>
|
||||
);
|
||||
}
|
||||
function StepFinal() {
|
||||
const lang = useSelector((state: RootState) => state.appVariables.lang);
|
||||
const regPro = useSelector(
|
||||
(state: RootState) => state.appVariables.preferences.RegisterProcess,
|
||||
);
|
||||
|
||||
const dispatch = useDispatch();
|
||||
|
||||
const {colors} = useTheme();
|
||||
|
||||
const toast = useToast();
|
||||
|
||||
const navigation = useNavigation<RootScreenNavigationProp>();
|
||||
|
||||
const [isLoading, setLoading] = useState(false);
|
||||
const [showPassword, setShowPassword] = useState(false);
|
||||
|
||||
interface inputElementType {
|
||||
label: string;
|
||||
input: string;
|
||||
autoCapitalize: 'none' | 'words';
|
||||
errorIndex: 'none' | string;
|
||||
errorTextObject: any;
|
||||
isPassword: boolean | 'passwordRepeat';
|
||||
minLength: number;
|
||||
maxLength: number;
|
||||
onTextChange: any;
|
||||
textChangeTimeout: number;
|
||||
isAllowed: any;
|
||||
}
|
||||
|
||||
const accountNameRef = useRef(setTimeout(() => {}));
|
||||
const accountNameFetchRef = useRef(setTimeout(() => {}));
|
||||
|
||||
const accountName = {
|
||||
label: lang.account.registration.stepFinal.accountName,
|
||||
input: '',
|
||||
errorIndex: 'none',
|
||||
errorTextObject: lang.account.registration.stepFinal.accountNameError,
|
||||
minLength: accountNameOptions.minLength,
|
||||
maxLength: accountNameOptions.maxLength,
|
||||
isAllowed: accountNameOptions.isAllowed,
|
||||
isPassword: false,
|
||||
onTextChange: (e: NativeSyntheticEvent<TextInputFocusEventData>) => {
|
||||
let text = e.nativeEvent.text;
|
||||
let self = accountName;
|
||||
|
||||
clearTimeout(accountNameRef.current);
|
||||
|
||||
let obj = {...valuesAccountName};
|
||||
accountNameRef.current = setTimeout(() => {
|
||||
obj.input = text;
|
||||
|
||||
if (text.length < self.minLength) obj.errorIndex = 'tooShort';
|
||||
else if (text.length > self.maxLength) obj.errorIndex = 'tooLong';
|
||||
else if (self.isAllowed(text) === false) obj.errorIndex = 'invalid';
|
||||
else obj.errorIndex = 'none';
|
||||
|
||||
setValuesAccountName(obj);
|
||||
}, 50);
|
||||
|
||||
clearTimeout(accountNameFetchRef.current);
|
||||
accountNameFetchRef.current = setTimeout(() => {
|
||||
console.log(obj);
|
||||
|
||||
if (obj.errorIndex === 'none') {
|
||||
makeRequest({
|
||||
path: apiBackendRequest.REGISTER_STEP_FINAL_ACCOUNT_NAME_CHECK,
|
||||
request: {AccountName: obj.input},
|
||||
})
|
||||
.then(resp => {
|
||||
console.log('OK');
|
||||
})
|
||||
.catch(resp => {
|
||||
if (resp.status !== undefined) {
|
||||
obj.errorIndex = resp.status;
|
||||
setValuesAccountName(obj);
|
||||
}
|
||||
});
|
||||
}
|
||||
}, 750);
|
||||
},
|
||||
} as inputElementType;
|
||||
const [valuesAccountName, setValuesAccountName] = useState(accountName);
|
||||
|
||||
const userNameRef = useRef(setTimeout(() => {}));
|
||||
|
||||
const userName = {
|
||||
label: lang.account.registration.stepFinal.userName,
|
||||
input: '',
|
||||
errorIndex: 'none',
|
||||
errorTextObject: lang.account.registration.stepFinal.userNameError,
|
||||
minLength: userNameOptions.minLength,
|
||||
maxLength: userNameOptions.maxLength,
|
||||
isAllowed: userNameOptions.isAllowed,
|
||||
isPassword: false,
|
||||
onTextChange: (e: NativeSyntheticEvent<TextInputFocusEventData>) => {
|
||||
let text = e.nativeEvent.text;
|
||||
let self = userName;
|
||||
|
||||
clearTimeout(userNameRef.current);
|
||||
|
||||
userNameRef.current = setTimeout(() => {
|
||||
let obj = {...valuesUserName};
|
||||
obj.input = text;
|
||||
|
||||
if (text.length < self.minLength) obj.errorIndex = 'tooShort';
|
||||
else if (text.length > self.maxLength) obj.errorIndex = 'tooLong';
|
||||
else if (self.isAllowed(text) === false) obj.errorIndex = 'invalid';
|
||||
else obj.errorIndex = 'none';
|
||||
|
||||
setValuesUserName(obj);
|
||||
}, 50);
|
||||
},
|
||||
} as inputElementType;
|
||||
const [valuesUserName, setValuesUserName] = useState(userName);
|
||||
|
||||
const passwordRef = useRef(setTimeout(() => {}));
|
||||
|
||||
const password = {
|
||||
label: lang.account.registration.stepFinal.password,
|
||||
input: '',
|
||||
errorIndex: 'none',
|
||||
errorTextObject: lang.account.registration.stepFinal.passwordError,
|
||||
minLength: passwordOptions.minLength,
|
||||
maxLength: passwordOptions.maxLength,
|
||||
isAllowed: passwordOptions.isAllowed,
|
||||
isPassword: true,
|
||||
onTextChange: (e: NativeSyntheticEvent<TextInputFocusEventData>) => {
|
||||
let text = e.nativeEvent.text;
|
||||
let self = password;
|
||||
|
||||
clearTimeout(passwordRef.current);
|
||||
|
||||
passwordRef.current = setTimeout(() => {
|
||||
let obj = {...valuesPassword};
|
||||
obj.input = text;
|
||||
|
||||
if (text.length < self.minLength) obj.errorIndex = 'tooShort';
|
||||
else if (text.length > self.maxLength) obj.errorIndex = 'tooLong';
|
||||
else if (self.isAllowed(text) === false) obj.errorIndex = 'invalid';
|
||||
else obj.errorIndex = 'none';
|
||||
|
||||
setValuesPassword(obj);
|
||||
|
||||
let objRe = {...valuesPasswordRe};
|
||||
if (text !== valuesPasswordRe.input) objRe.errorIndex = 'noMatch';
|
||||
else objRe.errorIndex = 'none';
|
||||
|
||||
setValuesPasswordRe(objRe);
|
||||
}, 50);
|
||||
},
|
||||
} as inputElementType;
|
||||
const [valuesPassword, setValuesPassword] = useState(password);
|
||||
|
||||
const passwordReRef = useRef(setTimeout(() => {}));
|
||||
|
||||
const passwordRe = {
|
||||
label: lang.account.registration.stepFinal.passwordRepeat,
|
||||
input: '',
|
||||
errorIndex: 'none',
|
||||
errorTextObject: lang.account.registration.stepFinal.passwordError,
|
||||
minLength: passwordOptions.minLength,
|
||||
maxLength: passwordOptions.maxLength,
|
||||
isAllowed: passwordOptions.isAllowed,
|
||||
isPassword: 'passwordRepeat',
|
||||
onTextChange: (e: NativeSyntheticEvent<TextInputFocusEventData>) => {
|
||||
let text = e.nativeEvent.text;
|
||||
let self = passwordRe;
|
||||
|
||||
clearTimeout(passwordReRef.current);
|
||||
|
||||
passwordReRef.current = setTimeout(() => {
|
||||
let obj = {...valuesPasswordRe};
|
||||
obj.input = text;
|
||||
console.log(text, valuesPassword.input);
|
||||
|
||||
if (text !== valuesPassword.input) obj.errorIndex = 'noMatch';
|
||||
else obj.errorIndex = 'none';
|
||||
|
||||
setValuesPasswordRe(obj);
|
||||
}, 50);
|
||||
},
|
||||
} as inputElementType;
|
||||
const [valuesPasswordRe, setValuesPasswordRe] = useState(passwordRe);
|
||||
|
||||
const inputElement = (
|
||||
val: inputElementType,
|
||||
set: React.Dispatch<React.SetStateAction<inputElementType>>,
|
||||
valConst: inputElementType,
|
||||
autofocus?: boolean,
|
||||
) => {
|
||||
const isPassword =
|
||||
val.isPassword === true || val.isPassword === 'passwordRepeat';
|
||||
|
||||
return (
|
||||
<FormControl
|
||||
w="75%"
|
||||
maxW="350px"
|
||||
isRequired
|
||||
isDisabled={isLoading}
|
||||
isInvalid={val.errorIndex !== 'none'}>
|
||||
<FormControl.Label>{val.label}</FormControl.Label>
|
||||
<Input
|
||||
autoFocus={autofocus}
|
||||
type={isPassword && showPassword === false ? 'password' : 'text'}
|
||||
placeholder={''}
|
||||
keyboardType={'default'}
|
||||
onChange={valConst.onTextChange}
|
||||
InputRightElement={
|
||||
isPassword ? (
|
||||
<IconButton
|
||||
mr="2"
|
||||
onPress={() => setShowPassword(!showPassword)}
|
||||
icon={
|
||||
<MaterialIcons
|
||||
size={20}
|
||||
name={showPassword ? 'visibility' : 'visibility-off'}
|
||||
/>
|
||||
}
|
||||
borderRadius="full"
|
||||
/>
|
||||
) : undefined
|
||||
}
|
||||
/>
|
||||
|
||||
<FormControl.ErrorMessage leftIcon={<WarningOutlineIcon size="xs" />}>
|
||||
{val.errorTextObject[val.errorIndex] !== undefined
|
||||
? val.errorTextObject[val.errorIndex]
|
||||
.replaceAll('$(minLength)', val.minLength)
|
||||
.replaceAll('$(maxLength)', val.maxLength)
|
||||
: val.errorTextObject[val.errorIndex] !== 'none'
|
||||
? lang.error
|
||||
: null}
|
||||
</FormControl.ErrorMessage>
|
||||
</FormControl>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<ScrollView keyboardShouldPersistTaps="handled">
|
||||
<VStack space={3} alignItems="center" mt={5}>
|
||||
<Container maxWidth={'100%'} alignItems={'center'}>
|
||||
<Center>
|
||||
<Text>{lang.account.registration.stepFinal.displayName}</Text>
|
||||
<NameDisplay
|
||||
UserName={
|
||||
valuesUserName.input !== ''
|
||||
? valuesUserName.input
|
||||
: lang.account.registration.stepFinal.userName
|
||||
}
|
||||
AccountName={
|
||||
valuesAccountName.input !== ''
|
||||
? valuesAccountName.input
|
||||
: lang.account.registration.stepFinal.accountName
|
||||
}
|
||||
/>
|
||||
</Center>
|
||||
</Container>
|
||||
{inputElement(valuesUserName, setValuesUserName, userName)}
|
||||
{inputElement(valuesAccountName, setValuesAccountName, accountName)}
|
||||
{inputElement(valuesPassword, setValuesPassword, password)}
|
||||
{inputElement(valuesPasswordRe, setValuesPasswordRe, passwordRe)}
|
||||
</VStack>
|
||||
<Center>
|
||||
<Container mt={5}>
|
||||
<Agreement />
|
||||
</Container>
|
||||
<Button
|
||||
marginY={5}
|
||||
w="75%"
|
||||
maxW="350px"
|
||||
colorScheme="primary"
|
||||
rounded="xl"
|
||||
_text={{fontSize: 'xl'}}
|
||||
isLoading={isLoading}
|
||||
onPress={() => {}}>
|
||||
{lang.account.registration.stepFinal.button}
|
||||
</Button>
|
||||
</Center>
|
||||
</ScrollView>
|
||||
);
|
||||
}
|
|
@ -0,0 +1,142 @@
|
|||
import {
|
||||
Alert,
|
||||
Button,
|
||||
Center,
|
||||
CloseIcon,
|
||||
HStack,
|
||||
IconButton,
|
||||
Text,
|
||||
VStack,
|
||||
} from 'native-base';
|
||||
import {ResponsiveValue} from 'native-base/lib/typescript/components/types';
|
||||
|
||||
const {useToast} = require('native-base');
|
||||
|
||||
const Toast = () => {
|
||||
const toast = useToast();
|
||||
const ToastDetails = [
|
||||
{
|
||||
title: 'Account verified',
|
||||
variant: 'solid',
|
||||
description: 'Thanks for signing up with us.',
|
||||
isClosable: true,
|
||||
},
|
||||
{
|
||||
title: 'Something went wrong',
|
||||
variant: 'subtle',
|
||||
description: 'Please create a support ticket from the support page',
|
||||
},
|
||||
{
|
||||
title: 'Network connection restored',
|
||||
variant: 'left-accent',
|
||||
description:
|
||||
'This is to inform you that your network connectivity is restored',
|
||||
isClosable: true,
|
||||
},
|
||||
{
|
||||
title: 'Invalid email address',
|
||||
variant: 'top-accent',
|
||||
description: 'Please enter a valid email address',
|
||||
},
|
||||
{
|
||||
title: 'Invalid email address',
|
||||
variant: 'outline',
|
||||
description: 'Please enter a valid email address',
|
||||
},
|
||||
];
|
||||
};
|
||||
|
||||
interface toastType {
|
||||
id?: string;
|
||||
status?: 'info' | (string & {}) | 'error' | 'success' | 'warning';
|
||||
variant: ResponsiveValue<
|
||||
| 'subtle'
|
||||
| 'solid'
|
||||
| 'left-accent'
|
||||
| 'top-accent'
|
||||
| 'outline'
|
||||
| 'outline-light'
|
||||
| (string & {})
|
||||
>;
|
||||
title: any;
|
||||
description: any;
|
||||
isClosable?: boolean;
|
||||
rest: any;
|
||||
}
|
||||
|
||||
interface alertType extends toastType {
|
||||
id: string;
|
||||
}
|
||||
|
||||
function showToast(toast: any, item: toastType) {
|
||||
const ToastAlert = ({
|
||||
id,
|
||||
status,
|
||||
variant,
|
||||
title,
|
||||
description,
|
||||
isClosable,
|
||||
rest,
|
||||
}: alertType) => (
|
||||
<Alert
|
||||
maxWidth="95%"
|
||||
alignSelf="center"
|
||||
flexDirection="row"
|
||||
status={status ? status : 'info'}
|
||||
variant={variant}
|
||||
{...rest}>
|
||||
<VStack space={1} flexShrink={1} w="100%">
|
||||
<HStack
|
||||
flexShrink={1}
|
||||
alignItems="center"
|
||||
justifyContent="space-between">
|
||||
<HStack space={2} flexShrink={1} alignItems="center">
|
||||
<Alert.Icon />
|
||||
<Text
|
||||
fontSize="md"
|
||||
fontWeight="medium"
|
||||
flexShrink={1}
|
||||
color={
|
||||
variant === 'solid'
|
||||
? 'lightText'
|
||||
: variant !== 'outline'
|
||||
? 'darkText'
|
||||
: null
|
||||
}>
|
||||
{title}
|
||||
</Text>
|
||||
</HStack>
|
||||
{isClosable ? (
|
||||
<IconButton
|
||||
variant="unstyled"
|
||||
icon={<CloseIcon size="3" />}
|
||||
_icon={{
|
||||
color: variant === 'solid' ? 'lightText' : 'darkText',
|
||||
}}
|
||||
onPress={() => toast.close(id)}
|
||||
/>
|
||||
) : null}
|
||||
</HStack>
|
||||
<Text
|
||||
px="6"
|
||||
color={
|
||||
variant === 'solid'
|
||||
? 'lightText'
|
||||
: variant !== 'outline'
|
||||
? 'darkText'
|
||||
: null
|
||||
}>
|
||||
{description}
|
||||
</Text>
|
||||
</VStack>
|
||||
</Alert>
|
||||
);
|
||||
|
||||
toast.show({
|
||||
render: ({id}: {id: string}) => {
|
||||
return <ToastAlert id={id} {...item} />;
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
export default showToast;
|
|
@ -1,3 +1,4 @@
|
|||
import {EMail, XToken} from '@caj/helper/types';
|
||||
import {VersionType} from '@caj/helper/version';
|
||||
import {APP_VERSION} from './appNonSaveVar';
|
||||
|
||||
|
@ -43,13 +44,24 @@ export function applyUpdateChanges(appVar: any): Promise<void> {
|
|||
}
|
||||
|
||||
//these variables may be changed by the user and will be saved in storage
|
||||
export interface RegisterProcess {
|
||||
isRegistering: false | 'stepTwo' | 'stepFinal';
|
||||
XToken: XToken | undefined;
|
||||
EMail: EMail;
|
||||
}
|
||||
|
||||
export interface PREFERENCES_VARS {
|
||||
version: VersionType;
|
||||
theme: ThemeMode;
|
||||
RegisterProcess: RegisterProcess;
|
||||
}
|
||||
|
||||
export const preferences_vars_default: PREFERENCES_VARS = {
|
||||
version: APP_VERSION, //version of datatypes in storage
|
||||
theme: ThemeMode.Dark,
|
||||
RegisterProcess: {
|
||||
isRegistering: false,
|
||||
XToken: undefined,
|
||||
EMail: '',
|
||||
},
|
||||
};
|
||||
|
|
|
@ -1,7 +1,12 @@
|
|||
import {createSlice} from '@reduxjs/toolkit';
|
||||
import type {PayloadAction} from '@reduxjs/toolkit';
|
||||
|
||||
import {PREFERENCES_VARS, preferences_vars_default, ThemeMode} from './appVar';
|
||||
import {
|
||||
PREFERENCES_VARS,
|
||||
preferences_vars_default,
|
||||
RegisterProcess,
|
||||
ThemeMode,
|
||||
} from './appVar';
|
||||
import {non_save_vars, NON_SAVE_VARS} from './appNonSaveVar';
|
||||
import LangFormat from '@caj/lang/default';
|
||||
import {lang as defaultLang} from '@caj/lang/en';
|
||||
|
@ -29,6 +34,9 @@ export const appVariablesSlice = createSlice({
|
|||
loadPreferences: (state, action: PayloadAction<PREFERENCES_VARS>) => {
|
||||
state.preferences = action.payload;
|
||||
},
|
||||
setRegisterProcess: (state, action: PayloadAction<RegisterProcess>) => {
|
||||
state.preferences.RegisterProcess = action.payload;
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
|
|
|
@ -1,83 +1,194 @@
|
|||
import {Platform} from 'react-native';
|
||||
import {extendTheme, useColorMode} from 'native-base';
|
||||
import {extendTheme, Theme, useColorMode} from 'native-base';
|
||||
import {ThemeMode} from './appVar';
|
||||
|
||||
import {useSelector} from 'react-redux';
|
||||
import {RootState} from '@caj/redux/store';
|
||||
import {useEffect} from 'react';
|
||||
|
||||
export const theme = extendTheme({
|
||||
config: {
|
||||
// Changing initialColorMode to 'dark'
|
||||
initialColorMode: 'dark',
|
||||
},
|
||||
fonts: {
|
||||
header: 'Outfit-Regular',
|
||||
medium: 'Outfit-Regular',
|
||||
regular: 'Outfit-Regular',
|
||||
semibold: 'Outfit-Regular',
|
||||
},
|
||||
colors: {
|
||||
black: {
|
||||
100: '#C4C4C4',
|
||||
200: '#7C7C7C',
|
||||
300: '#292929',
|
||||
800: '#181725',
|
||||
export const theme = (_theme: ThemeMode) => {
|
||||
return extendTheme({
|
||||
config: {
|
||||
// Changing initialColorMode to 'dark'
|
||||
initialColorMode: 'dark',
|
||||
},
|
||||
fonts: {
|
||||
header: 'Outfit-Regular',
|
||||
medium: 'Outfit-Regular',
|
||||
regular: 'Outfit-Regular',
|
||||
semibold: 'Outfit-Regular',
|
||||
},
|
||||
colors: {
|
||||
black: [
|
||||
{
|
||||
// darkest
|
||||
100: '#414755',
|
||||
200: '#313640',
|
||||
300: '#293037',
|
||||
400: '#282e35',
|
||||
500: '#23272e',
|
||||
600: '#1a1d22',
|
||||
700: '#19191e',
|
||||
800: '#101013',
|
||||
900: '#060607',
|
||||
},
|
||||
{
|
||||
//dark
|
||||
100: '#414755',
|
||||
200: '#313640',
|
||||
300: '#293037',
|
||||
400: '#282e35',
|
||||
500: '#23272e',
|
||||
600: '#1a1d22',
|
||||
700: '#19191e',
|
||||
800: '#101013',
|
||||
900: '#060607',
|
||||
},
|
||||
{
|
||||
//light
|
||||
900: '#e9e8f0',
|
||||
800: '#e4e3ec',
|
||||
700: '#dfdde8',
|
||||
600: '#dad8e4',
|
||||
500: '#d7d5e1',
|
||||
400: '#d4d2de',
|
||||
300: '#d2d0db',
|
||||
200: '#cfcdd8',
|
||||
100: '#cdcbd5',
|
||||
},
|
||||
][_theme],
|
||||
blackBG: [
|
||||
{
|
||||
// darkest
|
||||
100: '#000',
|
||||
200: '#000',
|
||||
300: '#000',
|
||||
400: '#000',
|
||||
500: '#000',
|
||||
600: '#000',
|
||||
700: '#000',
|
||||
800: '#000',
|
||||
900: '#000',
|
||||
},
|
||||
{
|
||||
//dark
|
||||
100: '#414755',
|
||||
200: '#313640',
|
||||
300: '#293037',
|
||||
400: '#282e35',
|
||||
500: '#23272e',
|
||||
600: '#1a1d22',
|
||||
700: '#19191e',
|
||||
800: '#101013',
|
||||
900: '#060607',
|
||||
},
|
||||
{
|
||||
//light
|
||||
900: '#e9e8f0',
|
||||
800: '#e4e3ec',
|
||||
700: '#dfdde8',
|
||||
600: '#dad8e4',
|
||||
500: '#d7d5e1',
|
||||
400: '#d4d2de',
|
||||
300: '#d2d0db',
|
||||
200: '#cfcdd8',
|
||||
100: '#cdcbd5',
|
||||
},
|
||||
][_theme],
|
||||
white: [
|
||||
{
|
||||
// darkest
|
||||
100: '#ccc',
|
||||
200: '#ccc',
|
||||
300: '#ccc',
|
||||
400: '#ccc',
|
||||
500: '#ccc',
|
||||
600: '#ccc',
|
||||
700: '#ccc',
|
||||
800: '#ccc',
|
||||
900: '#ccc',
|
||||
},
|
||||
{
|
||||
//dark
|
||||
|
||||
primary: {
|
||||
50: '#fff4f1',
|
||||
100: '#ffd6c9',
|
||||
200: '#ffb9a1',
|
||||
300: '#ff9b79',
|
||||
400: '#ff7d50',
|
||||
500: '#f96e40',
|
||||
600: '#f26030',
|
||||
700: '#e95321',
|
||||
800: '#d54b1d',
|
||||
900: '#ba4721',
|
||||
},
|
||||
},
|
||||
components: {
|
||||
Divider: {
|
||||
baseStyle: ({colorMode}) => {
|
||||
return {
|
||||
backgroundColor: colorMode === 'dark' ? 'black.100' : 'black.200',
|
||||
};
|
||||
900: '#e9e8f0',
|
||||
800: '#e4e3ec',
|
||||
700: '#dfdde8',
|
||||
600: '#dad8e4',
|
||||
500: '#d7d5e1',
|
||||
400: '#d4d2de',
|
||||
300: '#d2d0db',
|
||||
200: '#cfcdd8',
|
||||
100: '#cdcbd5',
|
||||
},
|
||||
{
|
||||
//light
|
||||
100: '#414755',
|
||||
200: '#313640',
|
||||
300: '#293037',
|
||||
400: '#282e35',
|
||||
500: '#23272e',
|
||||
600: '#1a1d22',
|
||||
700: '#19191e',
|
||||
800: '#101013',
|
||||
900: '#060607',
|
||||
},
|
||||
][_theme],
|
||||
|
||||
primary: {
|
||||
50: '#fff4f1',
|
||||
100: '#ffd6c9',
|
||||
200: '#ffb9a1',
|
||||
300: '#ff9b79',
|
||||
400: '#ff7d4f',
|
||||
500: '#f96e40',
|
||||
600: '#f26030',
|
||||
700: '#e95321',
|
||||
800: '#d54b1d',
|
||||
900: '#ba4721',
|
||||
},
|
||||
},
|
||||
Text: {
|
||||
defaultProps: {
|
||||
size: 'md',
|
||||
fontFamily: 'Outfit-Regular',
|
||||
colorScheme: 'red',
|
||||
},
|
||||
sizes: {
|
||||
xl: {
|
||||
fontSize: '64px',
|
||||
},
|
||||
lg: {
|
||||
fontSize: '32px',
|
||||
},
|
||||
md: {
|
||||
fontSize: '16px',
|
||||
},
|
||||
sm: {
|
||||
fontSize: '12px',
|
||||
components: {
|
||||
Divider: {
|
||||
baseStyle: ({colorMode}) => {
|
||||
return {
|
||||
backgroundColor: colorMode === 'dark' ? 'black.100' : 'black.200',
|
||||
};
|
||||
},
|
||||
},
|
||||
Button: {
|
||||
// Can simply pass default props to change default behaviour of components.
|
||||
baseStyle: {
|
||||
rounded: 'md',
|
||||
},
|
||||
Text: {
|
||||
defaultProps: {
|
||||
colorScheme: 'red',
|
||||
size: 'md',
|
||||
fontFamily: 'Outfit-Regular',
|
||||
colorScheme: 'black',
|
||||
},
|
||||
sizes: {
|
||||
xl: {
|
||||
fontSize: '64px',
|
||||
},
|
||||
lg: {
|
||||
fontSize: '32px',
|
||||
},
|
||||
md: {
|
||||
fontSize: '16px',
|
||||
},
|
||||
sm: {
|
||||
fontSize: '12px',
|
||||
},
|
||||
},
|
||||
Button: {
|
||||
// Can simply pass default props to change default behaviour of components.
|
||||
baseStyle: {
|
||||
rounded: 'md',
|
||||
},
|
||||
defaultProps: {
|
||||
colorScheme: 'primary',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
export function getBackgroundColor(tm: ThemeMode): string {
|
||||
switch (tm) {
|
||||
|
@ -86,7 +197,7 @@ export function getBackgroundColor(tm: ThemeMode): string {
|
|||
case ThemeMode.Darkest:
|
||||
return '#000';
|
||||
default:
|
||||
return '#282f34';
|
||||
return '#1b1c22';
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -117,3 +228,26 @@ export function ThemeSwitcher() {
|
|||
|
||||
return null;
|
||||
}
|
||||
|
||||
export const defaultHeaderStyle = (cur: ThemeMode, place?: 'registration') => {
|
||||
if (place === 'registration') {
|
||||
return {
|
||||
headerTintColor: '#fff',
|
||||
headerStyle: {
|
||||
backgroundColor: theme(cur).colors.primary[500],
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
headerTintColor: theme(cur).colors.primary[400],
|
||||
headerStyle: {
|
||||
backgroundColor:
|
||||
cur === ThemeMode.Light
|
||||
? '#eee'
|
||||
: cur === ThemeMode.Dark
|
||||
? '#181d21'
|
||||
: '#000',
|
||||
},
|
||||
};
|
||||
};
|
||||
|
|
|
@ -0,0 +1,132 @@
|
|||
import {useFocusEffect} from '@react-navigation/native';
|
||||
import {animated, useSpring} from '@react-spring/native';
|
||||
import {useEffect} from 'react';
|
||||
import {Dimensions, View} from 'react-native';
|
||||
|
||||
const AnimationView = animated(View);
|
||||
|
||||
export const FadeInView = (props: any) => {
|
||||
const [motionProps, api] = useSpring(
|
||||
() => ({
|
||||
from: {
|
||||
opacity: 0,
|
||||
},
|
||||
}),
|
||||
[],
|
||||
);
|
||||
|
||||
useFocusEffect(() => {
|
||||
api.start({
|
||||
to: [
|
||||
{
|
||||
opacity: 1,
|
||||
},
|
||||
],
|
||||
});
|
||||
return () => {
|
||||
api.start({
|
||||
to: [
|
||||
{
|
||||
opacity: 0,
|
||||
},
|
||||
],
|
||||
});
|
||||
};
|
||||
});
|
||||
|
||||
return (
|
||||
<AnimationView // Special animatable View
|
||||
style={{
|
||||
flex: 1,
|
||||
opacity: motionProps.opacity, // Bind opacity to animated value
|
||||
}}>
|
||||
{props.children}
|
||||
</AnimationView>
|
||||
);
|
||||
};
|
||||
|
||||
export const SlideFromLeftView = (props: any) => {
|
||||
let SCREEN_WIDTH = Dimensions.get('window').width;
|
||||
|
||||
const [motionProps, api] = useSpring(
|
||||
() => ({
|
||||
from: {
|
||||
translateX: -SCREEN_WIDTH,
|
||||
},
|
||||
}),
|
||||
[],
|
||||
);
|
||||
|
||||
useFocusEffect(() => {
|
||||
api.start({
|
||||
to: [
|
||||
{
|
||||
translateX: 0,
|
||||
},
|
||||
],
|
||||
});
|
||||
return () => {
|
||||
SCREEN_WIDTH = Dimensions.get('window').width;
|
||||
api.start({
|
||||
to: [
|
||||
{
|
||||
translateX: -SCREEN_WIDTH,
|
||||
},
|
||||
],
|
||||
});
|
||||
};
|
||||
});
|
||||
|
||||
return (
|
||||
<AnimationView // Special animatable View
|
||||
style={{
|
||||
flex: 1,
|
||||
transform: [{translateX: motionProps.translateX}],
|
||||
}}>
|
||||
{props.children}
|
||||
</AnimationView>
|
||||
);
|
||||
};
|
||||
|
||||
export const SlideFromRightView = (props: any) => {
|
||||
let SCREEN_WIDTH = Dimensions.get('window').width;
|
||||
|
||||
const [motionProps, api] = useSpring(
|
||||
() => ({
|
||||
from: {
|
||||
translateX: SCREEN_WIDTH,
|
||||
},
|
||||
}),
|
||||
[],
|
||||
);
|
||||
|
||||
useFocusEffect(() => {
|
||||
api.start({
|
||||
to: [
|
||||
{
|
||||
translateX: 0,
|
||||
},
|
||||
],
|
||||
});
|
||||
return () => {
|
||||
SCREEN_WIDTH = Dimensions.get('window').width;
|
||||
api.start({
|
||||
to: [
|
||||
{
|
||||
translateX: SCREEN_WIDTH,
|
||||
},
|
||||
],
|
||||
});
|
||||
};
|
||||
});
|
||||
|
||||
return (
|
||||
<AnimationView // Special animatable View
|
||||
style={{
|
||||
flex: 1,
|
||||
transform: [{translateX: motionProps.translateX}],
|
||||
}}>
|
||||
{props.children}
|
||||
</AnimationView>
|
||||
);
|
||||
};
|
|
@ -0,0 +1,168 @@
|
|||
import {types} from '@babel/core';
|
||||
import {store} from '@caj/redux/store';
|
||||
import {Any} from '@react-spring/types';
|
||||
import {type} from 'os';
|
||||
import {Platform} from 'react-native';
|
||||
|
||||
import getUserAgent from './userAgent';
|
||||
|
||||
import {
|
||||
AccountName,
|
||||
EMail,
|
||||
Password,
|
||||
SessionId,
|
||||
UserId,
|
||||
Username,
|
||||
verifyId,
|
||||
WebSocketSessionId,
|
||||
XToken,
|
||||
} from './types';
|
||||
|
||||
export const apiPath = {
|
||||
backend: {
|
||||
prefix: 'https://alpha-api.clickandjoin.umbach.dev/v1',
|
||||
},
|
||||
};
|
||||
|
||||
export enum apiBackendRequest {
|
||||
REGISTER_STEP_1 = '/admin/users/email',
|
||||
REGISTER_RESEND_MAIL = '/admin/users/email/resend',
|
||||
REGISTER_STEP_2 = '/verify/email/:xToken/:verifyId',
|
||||
REGISTER_STEP_FINAL = '/admin/users',
|
||||
REGISTER_STEP_FINAL_ACCOUNT_NAME_CHECK = '/admin/users/validation/accountname',
|
||||
}
|
||||
|
||||
type requestGET = {[key: string]: string};
|
||||
|
||||
export interface defaultRequest {
|
||||
status?: 200 | 400 | 422 | 500;
|
||||
error?: string;
|
||||
requestGET?: requestGET;
|
||||
}
|
||||
|
||||
interface REGISTER_STEP_1 extends defaultRequest {
|
||||
path: apiBackendRequest.REGISTER_STEP_1;
|
||||
requestHeader: {};
|
||||
request: {
|
||||
Email: EMail;
|
||||
};
|
||||
response: {
|
||||
XToken: XToken | undefined;
|
||||
};
|
||||
}
|
||||
interface REGISTER_RESEND_MAIL extends defaultRequest {
|
||||
path: apiBackendRequest.REGISTER_RESEND_MAIL;
|
||||
requestHeader: {};
|
||||
request: {
|
||||
Email: EMail;
|
||||
};
|
||||
// response: {
|
||||
// XToken: XToken | undefined;
|
||||
//};
|
||||
}
|
||||
|
||||
interface REGISTER_STEP_2 extends defaultRequest {
|
||||
path: apiBackendRequest.REGISTER_STEP_2;
|
||||
requestHeader: {};
|
||||
requestGET: {
|
||||
':xToken': XToken;
|
||||
':verifyId': verifyId;
|
||||
};
|
||||
}
|
||||
|
||||
interface REGISTER_STEP_FINAL_ACCOUNT_NAME_CHECK extends defaultRequest {
|
||||
path: apiBackendRequest.REGISTER_STEP_FINAL_ACCOUNT_NAME_CHECK;
|
||||
|
||||
request: {
|
||||
AccountName: AccountName;
|
||||
};
|
||||
// response: {
|
||||
// XToken: XToken | undefined;
|
||||
//};
|
||||
}
|
||||
|
||||
interface REGISTER_STEP_FINAL extends defaultRequest {
|
||||
path: apiBackendRequest.REGISTER_STEP_FINAL;
|
||||
requestHeader: {
|
||||
XToken: XToken;
|
||||
};
|
||||
request: {
|
||||
AccountName: AccountName;
|
||||
Username: Username;
|
||||
Password: Password;
|
||||
};
|
||||
response?: {
|
||||
SessionId: SessionId;
|
||||
UserId: UserId;
|
||||
WebSocketSessionId: WebSocketSessionId;
|
||||
};
|
||||
}
|
||||
|
||||
type FetchTypes =
|
||||
| REGISTER_STEP_1
|
||||
| REGISTER_RESEND_MAIL
|
||||
| REGISTER_STEP_2
|
||||
| REGISTER_STEP_FINAL
|
||||
| REGISTER_STEP_FINAL_ACCOUNT_NAME_CHECK;
|
||||
|
||||
function isA(obj: any): obj is REGISTER_STEP_1 {
|
||||
return obj.request !== undefined;
|
||||
}
|
||||
|
||||
export function makeRequest<T1 extends FetchTypes>(type: T1): Promise<T1> {
|
||||
let makeRequestObj: any = type;
|
||||
|
||||
let path = type.path.toString();
|
||||
|
||||
if (type.requestGET !== undefined) {
|
||||
for (let key in type.requestGET) {
|
||||
path = path.replaceAll(key, (type.requestGET as requestGET)[key]);
|
||||
}
|
||||
}
|
||||
|
||||
// Simple POST request with a JSON body using fetch
|
||||
|
||||
let headers: HeadersInit = {
|
||||
'Content-Type': 'application/json',
|
||||
'X-App-Version': store
|
||||
.getState()
|
||||
.nonSaveVariables.currentAppVersion.toString(),
|
||||
'X-Language': store.getState().appVariables.lang.details.langCode,
|
||||
};
|
||||
|
||||
if (Platform.OS === 'android' || Platform.OS === 'ios')
|
||||
headers['User-Agent'] = getUserAgent();
|
||||
|
||||
const requestOptions: RequestInit = {
|
||||
method: makeRequestObj.request !== undefined ? 'POST' : 'GET',
|
||||
|
||||
headers,
|
||||
body:
|
||||
makeRequestObj.request !== undefined
|
||||
? JSON.stringify(makeRequestObj.request)
|
||||
: undefined,
|
||||
};
|
||||
|
||||
return new Promise<T1>((resolve, reject) => {
|
||||
fetch(apiPath.backend.prefix + path, requestOptions)
|
||||
.then(response => {
|
||||
makeRequestObj.status = response.status;
|
||||
|
||||
if (makeRequestObj.response === undefined) return {};
|
||||
|
||||
return response.json();
|
||||
})
|
||||
.then(data => {
|
||||
makeRequestObj.response = data;
|
||||
|
||||
//console.log(makeRequestObj);
|
||||
if (makeRequestObj.status !== 200) reject(makeRequestObj);
|
||||
else resolve(makeRequestObj);
|
||||
})
|
||||
.catch(error => {
|
||||
//console.error(error, makeRequestObj);
|
||||
makeRequestObj.error = error;
|
||||
reject(makeRequestObj);
|
||||
});
|
||||
});
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
export type EMail = string;
|
||||
|
||||
export type AccountName = string;
|
||||
export type Username = string;
|
||||
export type Password = string;
|
||||
export type UserAgent = string;
|
||||
export type XToken = string;
|
||||
export type verifyId = string;
|
||||
|
||||
export type SessionId = string;
|
||||
export type UserId = string;
|
||||
export type WebSocketSessionId = string;
|
||||
|
||||
export const accountNameOptions = {
|
||||
minLength: 4,
|
||||
maxLength: 24,
|
||||
isAllowed: (text: string): boolean => {
|
||||
return text.match('^[a-zA-Z0-9_.]+$') !== null;
|
||||
},
|
||||
};
|
||||
export const userNameOptions = {
|
||||
minLength: 2,
|
||||
maxLength: 24,
|
||||
isAllowed: (text: string): boolean => {
|
||||
return true;
|
||||
},
|
||||
};
|
||||
|
||||
export const passwordOptions = {
|
||||
minLength: 6,
|
||||
maxLength: 64,
|
||||
isAllowed: (text: string): boolean => {
|
||||
return true;
|
||||
},
|
||||
};
|
||||
|
||||
export const emailOptions = {
|
||||
maxLength: 48,
|
||||
isAllowed: (email: string) => {
|
||||
return String(email).match(
|
||||
/^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/,
|
||||
);
|
||||
},
|
||||
};
|
|
@ -0,0 +1,3 @@
|
|||
import {getUserAgent} from 'react-native-user-agent';
|
||||
|
||||
export default getUserAgent;
|
|
@ -0,0 +1,2 @@
|
|||
const getUserAgent = undefined;
|
||||
export default getUserAgent;
|
|
@ -9,7 +9,56 @@ export default interface LangFormat {
|
|||
details: LangDetails;
|
||||
curVersion: string;
|
||||
appName: string;
|
||||
appNameDesc: string;
|
||||
startHelper1: string;
|
||||
navigation: {
|
||||
home: {
|
||||
account: string;
|
||||
calendar: string;
|
||||
chat: string;
|
||||
};
|
||||
};
|
||||
info: string;
|
||||
error: string;
|
||||
success: string;
|
||||
account: {
|
||||
registration: {
|
||||
registration: string;
|
||||
info: string;
|
||||
privacyPolicy: string;
|
||||
termsOfUse: string;
|
||||
stepOne: {
|
||||
title: string;
|
||||
success: string;
|
||||
addressExists: string;
|
||||
addressInvalid: string;
|
||||
noMailEntered: string;
|
||||
button: string;
|
||||
};
|
||||
stepTwo: {
|
||||
title: string;
|
||||
verification: string;
|
||||
resend: [string, string, string];
|
||||
noCodeEntered: string;
|
||||
resendError: {[key: number]: string};
|
||||
verificationError: {[key: number]: string};
|
||||
button: string;
|
||||
success: string;
|
||||
};
|
||||
stepFinal: {
|
||||
verification: string;
|
||||
userName: string;
|
||||
accountName: string;
|
||||
password: string;
|
||||
passwordRepeat: string;
|
||||
displayName: string;
|
||||
accountNameError: {[key: string]: string};
|
||||
userNameError: {[key: string]: string};
|
||||
passwordError: {[key: string]: string};
|
||||
button: string;
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
interface LangPlaceholderKeys {
|
||||
|
|
|
@ -8,5 +8,85 @@ export const lang: LangFormat = {
|
|||
},
|
||||
curVersion: 'Your current version is v${version}.',
|
||||
appName: 'Click And Join',
|
||||
appNameDesc: 'an app developed with love by Janex',
|
||||
startHelper1: 'Your data will be loaded :)',
|
||||
navigation: {
|
||||
home: {
|
||||
account: 'My account',
|
||||
calendar: 'Calendar',
|
||||
chat: 'Conversations',
|
||||
},
|
||||
},
|
||||
info: 'Info',
|
||||
error: 'Error',
|
||||
success: 'Success',
|
||||
account: {
|
||||
registration: {
|
||||
registration: 'Registration',
|
||||
info: 'By registering, you agree to our ${TermsOfUse}. You can find out how we collect and use your data in our ${privacyPolicy}.',
|
||||
privacyPolicy: 'privacy policy',
|
||||
termsOfUse: 'Terms of Use',
|
||||
stepOne: {
|
||||
title: 'Enter E-Mail',
|
||||
success: 'A verification has sent to your E-Mail!',
|
||||
addressExists: 'The E-Mail you entered is already in use.',
|
||||
addressInvalid: 'The address you entered has an invalid format.',
|
||||
noMailEntered: 'Please enter your E-Mail',
|
||||
button: 'Next step',
|
||||
},
|
||||
stepTwo: {
|
||||
title: 'Enter the 6-digit code that we sent you to ${EMail}.',
|
||||
verification: 'X-X-X-X-X-X',
|
||||
noCodeEntered: 'Please enter your code',
|
||||
resend: [
|
||||
'E-Mail not arrived? You can also resend the verification E-Mail by ${resend}.',
|
||||
'clicking here',
|
||||
'E-Mail verification has resent',
|
||||
],
|
||||
resendError: {
|
||||
400: 'The E-Mail is already verified!',
|
||||
401: 'Your device have changed. Please use another E-Mail address.',
|
||||
429: 'Too many requests in a too small period of time in a row',
|
||||
},
|
||||
verificationError: {
|
||||
400: 'Something went wrong please try again :( Restart App maybe required',
|
||||
401: 'The code you entered does not match with the code we sent you',
|
||||
422: 'The verification time is expired. Please please try again',
|
||||
},
|
||||
button: 'Verify',
|
||||
success: 'Verification success!',
|
||||
},
|
||||
stepFinal: {
|
||||
verification:
|
||||
'Your Account has been verified. Now enter your user credentials.',
|
||||
userName: 'Username',
|
||||
accountName: 'AccountName',
|
||||
password: 'Password',
|
||||
passwordRepeat: 'Repeat password',
|
||||
displayName: 'Other users see you like this:',
|
||||
accountNameError: {
|
||||
tooLong: 'Too long. Max length are $(maxLength) character.',
|
||||
tooShort: 'Too short. Min length are $(minLength) character.',
|
||||
required: 'This field is required',
|
||||
invalid:
|
||||
'Account names can only contain letters, numbers, underscores (_) and dots (.)',
|
||||
exists: 'The account name you entered already exists.',
|
||||
},
|
||||
userNameError: {
|
||||
tooLong: 'Too long. Max length are $(maxLength) character.',
|
||||
tooShort: 'Too short. Min length are $(minLength) character.',
|
||||
required: 'This field is required',
|
||||
},
|
||||
passwordError: {
|
||||
noMatch: 'Passwords do not match',
|
||||
tooLong: 'Too long. Max length are $(maxLength) character.',
|
||||
tooShort: 'Too short. Min length are $(minLength) character.',
|
||||
required: 'This field is required',
|
||||
weak: 'Password is too weak',
|
||||
},
|
||||
|
||||
button: 'Finish registration',
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
|
@ -0,0 +1,71 @@
|
|||
import AccountInfoBanner from '@caj/components/AccountInfoBanner';
|
||||
import NotLoggedIn from '@caj/components/NotLoggedIn';
|
||||
import {ThemeMode} from '@caj/configs/appVar';
|
||||
import {defaultHeaderStyle} from '@caj/configs/colors';
|
||||
import {RootStackNavigatorParamList} from '@caj/Navigation';
|
||||
import {RootState} from '@caj/redux/store';
|
||||
import {
|
||||
createNativeStackNavigator,
|
||||
NativeStackNavigationProp,
|
||||
} from '@react-navigation/native-stack';
|
||||
import {Box, Center, Container, Text} from 'native-base';
|
||||
import {useSelector} from 'react-redux';
|
||||
|
||||
export const AccountTabName = 'Account';
|
||||
|
||||
export type AccountStackNavigatorParamList = {
|
||||
Overview: undefined;
|
||||
};
|
||||
|
||||
const AccountStack =
|
||||
createNativeStackNavigator<AccountStackNavigatorParamList>();
|
||||
|
||||
export type AccountScreenNavigationProp =
|
||||
NativeStackNavigationProp<AccountStackNavigatorParamList>;
|
||||
|
||||
function AccountTab() {
|
||||
const lang = useSelector((state: RootState) => state.appVariables.lang);
|
||||
const theme = useSelector(
|
||||
(state: RootState) => state.appVariables.preferences.theme,
|
||||
);
|
||||
|
||||
return (
|
||||
<AccountStack.Navigator>
|
||||
<AccountStack.Screen
|
||||
name="Overview"
|
||||
options={{
|
||||
animation: 'slide_from_left',
|
||||
title: lang.navigation.home.account,
|
||||
headerShown: true,
|
||||
...defaultHeaderStyle(theme),
|
||||
}}
|
||||
component={AccountScreen}
|
||||
/>
|
||||
</AccountStack.Navigator>
|
||||
);
|
||||
}
|
||||
|
||||
function AccountScreen() {
|
||||
const theme = useSelector(
|
||||
(state: RootState) => state.appVariables.preferences.theme,
|
||||
);
|
||||
return (
|
||||
<>
|
||||
<Box
|
||||
bg="blackBG.400"
|
||||
{...(theme === ThemeMode.Darkest
|
||||
? {borderBottomWidth: 1, borderColor: 'white.900'}
|
||||
: {})}
|
||||
style={{
|
||||
width: '100%',
|
||||
paddingVertical: 20,
|
||||
borderBottomLeftRadius: 20,
|
||||
}}>
|
||||
<AccountInfoBanner />
|
||||
</Box>
|
||||
<NotLoggedIn />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default AccountTab;
|
|
@ -0,0 +1,53 @@
|
|||
import NotLoggedIn from '@caj/components/NotLoggedIn';
|
||||
import {defaultHeaderStyle} from '@caj/configs/colors';
|
||||
import {RootStackNavigatorParamList} from '@caj/Navigation';
|
||||
import {RootState} from '@caj/redux/store';
|
||||
import {
|
||||
createNativeStackNavigator,
|
||||
NativeStackNavigationProp,
|
||||
} from '@react-navigation/native-stack';
|
||||
import {Center, Text} from 'native-base';
|
||||
import {useSelector} from 'react-redux';
|
||||
|
||||
export const CalendarTabName = 'Calendar';
|
||||
|
||||
export type CalendarStackNavigatorParamList = {
|
||||
Overview: undefined;
|
||||
};
|
||||
|
||||
const CalendarStack =
|
||||
createNativeStackNavigator<CalendarStackNavigatorParamList>();
|
||||
|
||||
export type CalendarScreenNavigationProp =
|
||||
NativeStackNavigationProp<CalendarStackNavigatorParamList>;
|
||||
|
||||
function CalendarTab() {
|
||||
const lang = useSelector((state: RootState) => state.appVariables.lang);
|
||||
const theme = useSelector(
|
||||
(state: RootState) => state.appVariables.preferences.theme,
|
||||
);
|
||||
|
||||
return (
|
||||
<CalendarStack.Navigator>
|
||||
<CalendarStack.Screen
|
||||
name="Overview"
|
||||
options={{
|
||||
title: lang.navigation.home.calendar,
|
||||
headerShown: true,
|
||||
...defaultHeaderStyle(theme),
|
||||
}}
|
||||
component={CalendarScreen}
|
||||
/>
|
||||
</CalendarStack.Navigator>
|
||||
);
|
||||
}
|
||||
|
||||
function CalendarScreen() {
|
||||
return (
|
||||
<Center>
|
||||
<NotLoggedIn />
|
||||
</Center>
|
||||
);
|
||||
}
|
||||
|
||||
export default CalendarTab;
|
|
@ -0,0 +1,52 @@
|
|||
import NotLoggedIn from '@caj/components/NotLoggedIn';
|
||||
import {defaultHeaderStyle} from '@caj/configs/colors';
|
||||
import {RootStackNavigatorParamList} from '@caj/Navigation';
|
||||
import {RootState} from '@caj/redux/store';
|
||||
import {
|
||||
createNativeStackNavigator,
|
||||
NativeStackNavigationProp,
|
||||
} from '@react-navigation/native-stack';
|
||||
import {Center, Text} from 'native-base';
|
||||
import {useSelector} from 'react-redux';
|
||||
|
||||
export const ChatTabName = 'Chat';
|
||||
|
||||
export type ChatStackNavigatorParamList = {
|
||||
Overview: undefined;
|
||||
};
|
||||
|
||||
const ChatStack = createNativeStackNavigator<ChatStackNavigatorParamList>();
|
||||
|
||||
export type ChatScreenNavigationProp =
|
||||
NativeStackNavigationProp<ChatStackNavigatorParamList>;
|
||||
|
||||
function ChatTab() {
|
||||
const lang = useSelector((state: RootState) => state.appVariables.lang);
|
||||
const theme = useSelector(
|
||||
(state: RootState) => state.appVariables.preferences.theme,
|
||||
);
|
||||
|
||||
return (
|
||||
<ChatStack.Navigator>
|
||||
<ChatStack.Screen
|
||||
name="Overview"
|
||||
options={{
|
||||
title: lang.navigation.home.chat,
|
||||
headerShown: true,
|
||||
...defaultHeaderStyle(theme),
|
||||
}}
|
||||
component={ChatScreen}
|
||||
/>
|
||||
</ChatStack.Navigator>
|
||||
);
|
||||
}
|
||||
|
||||
function ChatScreen() {
|
||||
return (
|
||||
<Center>
|
||||
<NotLoggedIn />
|
||||
</Center>
|
||||
);
|
||||
}
|
||||
|
||||
export default ChatTab;
|
|
@ -0,0 +1,47 @@
|
|||
import {defaultHeaderStyle} from '@caj/configs/colors';
|
||||
import {RootStackNavigatorParamList} from '@caj/Navigation';
|
||||
import {RootState} from '@caj/redux/store';
|
||||
import {
|
||||
createNativeStackNavigator,
|
||||
NativeStackNavigationProp,
|
||||
} from '@react-navigation/native-stack';
|
||||
import {Center, Text} from 'native-base';
|
||||
import {useSelector} from 'react-redux';
|
||||
|
||||
export const MapsTabName = 'Maps';
|
||||
|
||||
export type MapsStackNavigatorParamList = {
|
||||
Overview: undefined;
|
||||
};
|
||||
|
||||
const MapsStack = createNativeStackNavigator<MapsStackNavigatorParamList>();
|
||||
|
||||
export type MapsScreenNavigationProp =
|
||||
NativeStackNavigationProp<MapsStackNavigatorParamList>;
|
||||
|
||||
function MapsTab() {
|
||||
const lang = useSelector((state: RootState) => state.appVariables.lang);
|
||||
const theme = useSelector(
|
||||
(state: RootState) => state.appVariables.preferences.theme,
|
||||
);
|
||||
|
||||
return (
|
||||
<MapsStack.Navigator>
|
||||
<MapsStack.Screen
|
||||
name="Overview"
|
||||
options={{
|
||||
title: 'Maps',
|
||||
headerShown: true,
|
||||
...defaultHeaderStyle(theme),
|
||||
}}
|
||||
component={MapsScreen}
|
||||
/>
|
||||
</MapsStack.Navigator>
|
||||
);
|
||||
}
|
||||
|
||||
function MapsScreen() {
|
||||
return <Center>MapsScreen</Center>;
|
||||
}
|
||||
|
||||
export default MapsTab;
|
|
@ -12,52 +12,6 @@
|
|||
--doc--height: 100%;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Outfit-Thin';
|
||||
src: url('/fonts/Outfit.ttf');
|
||||
font-weight: 100;
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'Outfit-ExtraLight';
|
||||
src: url('/fonts/Outfit.ttf');
|
||||
font-weight: 200;
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'Outfit-Light';
|
||||
src: url('/fonts/Outfit.ttf');
|
||||
font-weight: 300;
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'Outfit-Regular';
|
||||
src: url('/fonts/Outfit.ttf');
|
||||
font-weight: 400;
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'Outfit-Medium';
|
||||
src: url('/fonts/Outfit.ttf');
|
||||
font-weight: 500;
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'Outfit-SemiBold';
|
||||
src: url('/fonts/Outfit.ttf');
|
||||
font-weight: 600;
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'Outfit-Bold';
|
||||
src: url('/fonts/Outfit.ttf');
|
||||
font-weight: 700;
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'Outfit-ExtraBold';
|
||||
src: url('/fonts/Outfit.ttf');
|
||||
font-weight: 800;
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'Outfit-Black';
|
||||
src: url('/fonts/Outfit.ttf');
|
||||
font-weight: 900;
|
||||
}
|
||||
|
||||
html,
|
||||
body {
|
||||
padding: 0;
|
||||
|
|
|
@ -11,13 +11,14 @@ const appDirectory = path.resolve(__dirname, '../');
|
|||
// errors. To fix this webpack can be configured to compile to the necessary
|
||||
// `node_module`.
|
||||
const babelLoaderConfiguration = {
|
||||
test: /\.(ts|tsx|js)?$/,
|
||||
test: /\.(ts|tsx|js|jsx)?$/,
|
||||
// Add every directory that needs to be compiled by Babel during the build.
|
||||
include: [
|
||||
path.resolve(appDirectory, 'index.web.tsx'),
|
||||
path.resolve(appDirectory, 'src'),
|
||||
/node_modules\/react-native-/,
|
||||
],
|
||||
exclude: [path.resolve(appDirectory, 'node_modules')],
|
||||
// exclude: [path.resolve(appDirectory, 'node_modules')],
|
||||
use: {
|
||||
loader: 'babel-loader',
|
||||
options: {
|
||||
|
@ -25,14 +26,20 @@ const babelLoaderConfiguration = {
|
|||
// The 'react-native' preset is recommended to match React Native's packager
|
||||
// presets: ['module:metro-react-native-babel-preset'],
|
||||
// presets: ['react-native'],
|
||||
presets: [require.resolve('babel-preset-react-native')],
|
||||
// Re-write paths to import only the modules needed by the app
|
||||
plugins: ['react-native-web'],
|
||||
presets: ['react-native'],
|
||||
|
||||
presets: ['module:metro-react-native-babel-preset'],
|
||||
plugins: [
|
||||
// needed to support async/await
|
||||
'@babel/plugin-transform-runtime',
|
||||
// '@babel/plugin-transform-runtime',
|
||||
'react-native-web',
|
||||
[
|
||||
'module-resolver',
|
||||
{
|
||||
alias: {
|
||||
'^react-native$': 'react-native-web',
|
||||
},
|
||||
},
|
||||
],
|
||||
],
|
||||
},
|
||||
},
|
||||
|
@ -49,9 +56,26 @@ const imageLoaderConfiguration = {
|
|||
},
|
||||
};
|
||||
|
||||
const ttfLoaderConfiguration = {
|
||||
test: /\.ttf$/,
|
||||
loader: 'url-loader', // or directly file-loader
|
||||
include: [
|
||||
path.resolve(appDirectory, 'node_modules/react-native-vector-icons'),
|
||||
path.resolve(appDirectory, 'web/public/fonts'),
|
||||
],
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
mode: 'development',
|
||||
target: 'web',
|
||||
devServer: {
|
||||
headers: {
|
||||
'Access-Control-Allow-Origin': '*',
|
||||
'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, PATCH, OPTIONS',
|
||||
'Access-Control-Allow-Headers':
|
||||
'X-Requested-With, content-type, Authorization',
|
||||
},
|
||||
},
|
||||
entry: [
|
||||
// load any web API polyfills
|
||||
// path.resolve(appDirectory, 'polyfills-web.js'),
|
||||
|
@ -68,7 +92,11 @@ module.exports = {
|
|||
// ...the rest of your config
|
||||
|
||||
module: {
|
||||
rules: [babelLoaderConfiguration, imageLoaderConfiguration],
|
||||
rules: [
|
||||
babelLoaderConfiguration,
|
||||
imageLoaderConfiguration,
|
||||
ttfLoaderConfiguration,
|
||||
],
|
||||
},
|
||||
|
||||
resolve: {
|
||||
|
@ -80,6 +108,15 @@ module.exports = {
|
|||
// If you're working on a multi-platform React Native app, web-specific
|
||||
// module implementations should be written in files using the extension
|
||||
// `.web.js`.
|
||||
extensions: ['.web.js', '.js', '.web.ts', '.ts', '.web.tsx', '.tsx'],
|
||||
extensions: [
|
||||
'.web.js',
|
||||
'.web.jsx',
|
||||
'.js',
|
||||
'.jsx',
|
||||
'.web.ts',
|
||||
'.ts',
|
||||
'.web.tsx',
|
||||
'.tsx',
|
||||
],
|
||||
},
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue